I am trying to write a java class CircularList which contains the usual Node inner class and the instance variables:
OK, I won't give you the full implementation of the class, but instead I'll give you some advices.
You don't need to hold a reference to the last element. Place a Prev and Next reference to your nodes and your last node will be first.Prev
Besides the fact that circular lists have no end, they are quite the same than regular lists, but where you find the last item like this:
Node tmp = first;
while ( tmp.Next != null )
tmp = tmp.Next;
In a circular list the idea is like this:
Node tmp = first;
while ( tmp.Next != first )
tmp = tmp.Next;
Because you will never find a node pointing to null, unless the list is empty. One final advice, if you need to implement an indexer, remember that in a circular list there is no such thing as index out of range, because
list[count] = list[0] = list[count * k]
Keep that in mind, so calculating your index for those methods can be quite tricky. For positive indexes, the main idea is:
index = index % count;
For negative ones is slightly different. I hope I can help you with my words. If you want an implementations, I believe that there should be a few if you ask Google politely :)
Best of luck!
I'm not sure what your issue is, you seem to have everything needed. The only difference between that linked list and a normal one would be adding to the end.
In a regular linked list you would create a new node and make the last element point to that node. In this case, you change the pointer in the •Last node to point to the new node, and make the new node point to •First.
Removal works in the same way as a normal linked list. Whenever you want to remove a node, you find which other node points to that one (either previous, or in case of removing the first, check •Last) and make it point to wherever the one being deleted was pointing.
If this does not resolve your issue let me know and I'll try to help.
Just noticed someone has already asked the exact same question:
Can I use java.util.LinkedList to construct a circular/cyclic linked list?
Hint... circular list should have next and previous instead of first and last. The logic matters
class Node {
int value;
Node next;
Node prev;
Node(int initialValue) {
value = initialValue;
next = null;
prev = null;
}
public int getValue() {
return this.value;
}
}
class NodeList {
Node pointer;
NodeList() {
pointer = null;
}
public void insertNode(int nodeValue) {
Node newNode = new Node(nodeValue);
if( pointer == null ) {
newNode.next = newNode;
newNode.prev = newNode;
}else if( pointer.next == null && pointer.prev == null && pointer != null ) {
newNode.next = pointer;
newNode.prev = pointer;
pointer.prev = newNode;
pointer.next = newNode;
}
else if( pointer != null ) {
newNode.next = pointer.next;
newNode.prev = pointer;
pointer.next.prev = newNode;
pointer.next = newNode;
}
pointer = newNode;
System.out.println(“Successfully inserted : ” + pointer.getValue());
}
public void printRing( boolean direction ) {
Node tempNode = pointer;
do {
System.out.println( “Value = ” + tempNode.getValue() );
tempNode = direction ? tempNode.next : tempNode.prev;
} while( tempNode.value != pointer.value );
}
}
Related
This is a fairly easy question but I'm confused:
Given a Singly Linked List, write a function to delete a given node.
1) It must accept pointer to the start node as first parameter and node to be deleted as second parameter i.e., pointer to head node is not global.
2) It should not return pointer to the head node.
3) It should not accept pointer to pointer to head node.
The solution in Java is as following:
void deleteNode(Node node, Node n) {
if (node == n) {
if (node.next == null) {
System.out.println("There is only one node. The list "
+ "can't be made empty ");
return;
}
node.data = node.next.data;
n = node.next;
node.next = node.next.next;
System.gc();
return;
}
// When not first node, follow the normal deletion process
// find the previous node
Node prev = node;
while (prev.next != null && prev.next != n) {
prev = prev.next;
}
if (prev.next == null) {
System.out.println("Given node is not present in Linked List");
return;
}
prev.next = prev.next.next;
System.gc();
return;
}
I'm confused about why in deleting the head node, we're not modifying the head pointer but copying the fields instead (changing the content), but in deleting other nodes, it's simply prev.next = prev.next.next
Does it work if we just do head = head.next instead when deleting head node?
Thank you!
The reason the code copies the data rather than modifying the variable referencing the head is that other users of the list will have a reference to the head node. Changing the local variable will have no effect on their references so you won't have actually deleted the node. Copying the data to the head node effectively removes it.
So, for example, if you had code that did the following:
Node head = new Node("A");
Node tail = new Node("B");
head.next = tail;
deleteNode(head, head);
Then you would expect head.data to be "B" because the original node has been deleted. If you merely do node = node.next then head will still point to the original deleted node.
There are quite a few issues with the code you've posted so please add a comment if you want suggestions on improvements that should be made. It is not a typical algorithm for deleting nodes from a linked list.
One clear issue you've asked about is the use of System.gc. It is not necessary. There are rare cases when Java code needs to take explicit control of garbage collection. This isn't one of them. There's a good explanation of this in the accepted answer to this question.
You asked in the comments why deleting the head requires moving data while deleting other nodes only requires redirection around the node. The reason is because you don't have access to references to the head (as explained in the answer above). You do have access to references to other nodes (i.e. the previous node's next) so they can be changed directly rather than having to copy data.
For your reference, a much more standard implementation is to have the list itself store a reference to the head. Then the copying of node data can be completely avoided. Also note this compares to a value because the node class is private.
static class LinkedList<T> {
private class Node {
private final T value;
private Node next = null;
public Node(T value) {
this.value = value;
}
}
private Node head = null;
public void add(T value) {
Node node = new Node(value);
node.next = head;
head = node;
}
public void remove(T value) {
while (head != null && head.value.equals(value))
head = head.next;
Node prev = head;
while (prev != null && prev.next != null) {
if (prev.next.value.equals(value))
prev.next = prev.next.next;
else
prev = prev.next;
}
}
}
This avoids the arbitrary restrictions in the example you provided such as not being able to delete the head if it's the only node.
my question is about a exercise in lintcode which requires delet node, but for some reason my simple program won't work.
For example, input (1->2->3->4->null, 3) should output (1->2->4->null), my idea is delete next node and "copy" its value to input THIS node.
/**
* Definition for ListNode.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int val) {
* this.val = val;
* this.next = null;
* }
* }
*/
public class Solution {
/**
* #param node: the node in the list should be deleted
* #return: nothing
*/
public void deleteNode(ListNode node) {
// write your code here
ListNode pnext;
if (node != null) {
if (node.next != null) {
ListNode tempnode = node.next;
if (node.next.next != null) {
pnext = node.next.next;
}
else {
pnext = null;
}
node.next = null; //delete next node
node = tempnode; // give next node to THIS node
node.next = pnext; // link next
}
}
else node = null;
}
}
I am very confused about giving value to node, does node1 = node2 even work? I know node.val can. Can anyone simply guide me please?
You did not include in your post what actually happens, and you did not include the part where you create your list, so I can only assume what happens is that you do not delete 3, but delete 4? Or does it not delete anything at all?
So you have a method that should delete a Node, and the Node you want to delete is given as a parameter. But as your list is only linked one way you have no way of determining the node before it (which holds the reference to the node you want to delete). Actually the delete method should be as easy as this:
public void deleteNextNode(ListNode node) {
if(node == null || node.next == null) return; //nothing to delete
if(node.next.next == null){
node.next = null;
return;
} else{
node.next = node.next.next;
}
}
Although I did not test it. As long as you don't store any other references to your nodes this is sufficient, otherwise you need to call next.null explicitely in the else part.
Edit: My function deletes the Node that follows the Node you pass, but you want a function that deletes the Node you pass it. The problem here is that the previous node stores the reference to the Node that you want to delete, but you have no way of determining that Node with only the reference to the Node you want to delete. So either you use this function and always pass the previous node, or you make a wrapper function and run through the list and always safe the previous Node and call the function with that node:
public ListNode deleteNode(ListNode start, ListNode deleteMe)
{
ListNode prev = start;
if(start == deleteMe) return start.next;
while(prev.next != null) {
if(prev.next == deleteMe)
deleteNextNode(prev);
prev = prev.next;
}
return start;
}
Note that I made the function return a ListNode, this is always the first Node of the List (in case you decide to delete the first node).
I hope this helps
You are complicating it unnecessarily and it is not that tough. As I see, you are just taking the ListNode as the parameter and not the data which you want to delete. Also, since you are using if and not while or for, you'll never end up iterating the whole list.
You should modify your function to take both the node as well as the data and start using a loop to iterate the complete list.
Here is the code snippet:
private void deleteNode(ListNode node, int data) {
while(node != null && node.data != data) {
node = node.next;
}
if(node != null) {
System.out.println("Deleted Node With Data: " + node.data);
node = node.next;
}
}
I think by:
node = tempNode; // give next node to THIS node.
You meant:
node.val = tempNode.val; // give next node value to THIS node.
That way, the next node's value is copied into the current node.
Next you would want to also do:
node.next = tempNode.next;
This way, the node effectively becomes the tempNode. I think this was your intention.. ?
I'm preparing for interviews and wrote up this simple function for recursively reversing a singly linked list. The first node is a sentinel node, head. The following code works fine for: list.reverse(list.head.next), but I can't seem to get it to work if I just pass it head.
public Node<T> reverse(Node<T> current)
{
if (current == null)
return head;
if (current.next == null)
{
head.next = current;
return current;
}
reverse(current.next).next = current;
current.next = null;
return current;
}
I assume it doesn't work when I pass it head instead of head.next because I say current.next = null, but even if I check if current == head or if current.data == null and only use current.next = null when those aren't true, it still doesn't work. I'm sure there's a really simple fix, but I'm just not seeing it right now.
The above if passed head returns an empty list, and if the suggested changes are made, simply doesn't finish running, but I don't get any sort of error.
(EDITED)
I kind of get your problem now:
Simply speaking, the sentinel head acts simply as a pointer to the first node, instead of being part of the linked list. Therefore it will not be involved in the reverse process, and need to handle separately.
which means, the original list looks like:
HEAD -> a -> b -> c -> null
after reverse, it should look like
HEAD -> c -> b -> a -> null
In brief, it should look like (assume your code already works when passing in head.next)
public Node<T> reverse(Node<T> current)
{
if (current == head) {
return reverse(current.next);
}
// rest of your original code.
}
Just a further suggestion:
Your reverse() method, as an public instance method of your list class, shouldn't accept the current node, as it is conceptually meaningless for caller.
I believe you should make this method protected, which means something like:
public void reverse() {
this.head = reverseInternal(head);
}
private Node<T> reverseInternal(Node<T> node) {
// your original reverse logic
}
With such encapsulation, you don't even need to struggle before how to make your reverse works when you pass in the sentinel head: you can simply call reverseInternal(head.next) in your public reverse() method.
First: if it returns an empty list it doesn't "work".
There is no need for head to be an empty node. You should normally just keep the first node (in your case list.head.next) as your list.head. head should be a reference to where the list starts, not a separate node.
The reason your code empties the list when you pass it list.head is it sets list.head.next to null. This is because you assume the node you pass to the list is a regular one, while your head node is special.
Here's a solution for your assumptions (I'll assume someone insisted on this bizarre detached head thing. Just don't do it if you're designing the list yourself. Please...)
public Node<T> reverse(Node<T> current)
{
if (current == null)
return head;
if (current.next == null)
{
head.next = current;
return current;
}
Node<T> temp = current.next;
current.next = null;
head.next = temp;
reverse(temp).next = current;
return current;
}
Explanation: This still sets the last node's next to null, but it pushes the list's head one spot down as it runs through the list, eventually pointing it to the last (now first) member.
This reeks of homework.
But still.
In general:
f(Node<T> current, ...) {
f(current.next, ...);
}
For a list a > b > c > d > e sitting in the midle at d, one
probably has built c > b > a already, so guess what is needed as additional parameter to f?
Good luck.
After comments:
public Node<T> reverse(Node<T> current)
{
return reverseRec(current, null);
}
/**
* #param current to-do (sub-)list.
* #param resultDone done reversed list sofar.
* #return reversed result.
*/
public Node<T> reverseRecursively(Node<T> current, Node<T> resultDone)
{
if (current == null) {
return resultDone;
}
Node<T> next = current.next;
current.next = resultDone;
return reverseRecursively(next, current);
}
I am trying to make an add method for a linked list, but for some reason (that is not obvious to me, in fact I came here to get help finding the error) it goes into an infinite loop every time.
EDIT: I found the error, and I will keep my original code with a comment with the corrected code
public void insert(String majorName)
{
MajorNode newNode = new MajorNode(majorName, 1);
boolean inList = false;
MajorNode current = first;
if(isEmpty())
{
first = newNode;
// inList = true;
}
else
{
while(current.next != null)
{
if(current.majorName.equalsIgnoreCase(majorName))
{
current.frequency++;
inList = true;
break;
}
else
{
current = current.next;
}
}
}
if(!inList)
{
newNode.next = first;
first = newNode;
}
}
Here is my node class if it is needed:
public class MajorNode
{
public String majorName;
public int frequency;
public MajorNode next;
public MajorNode(String majorName, int frequency)
{
this.majorName = majorName;
this.frequency = frequency;
}
public String toString()
{
return majorName + " " + frequency;
}
}
On the first call to insert(), one assumes isEmpty() returns true and consequently first is set to the newNode before newNode's next field is set to the previous (null) value of first. Thus, when the list is non-empty, the loop iterates indefinitely on the last element in the list whose next field points to itself.
Out of curiosity, why are you trying to implement your own linked list functionality rather than build upon available packages (such as java.util.LinkedList<E>)?
When you create the first node you do this:
if(!inList)
{
newNode.next = first;
first = newNode;
}
This points the first nodes next at itself... hence a loop
You should be leaving the newNode.next as null for the first node, so that when you insert the second item, you reach the end of the chain..
You will have an wrong frequency if you add a node which is similar to the last node of your List. Consider this situation (adding 2 similar nodes in the empty list)
You will add a node1 in a blank list. So first & current will point to node1. (but node1.next will be null)
If you add the same node (or a node with a same majorName), you will reach to while loop (because List is not empty now). And also, you will not enter into a while loop as well. (as your current.next is still null)
and you will end up with two noes with same majorName in your list.
I would suggest to use
while(current != null)
instead of
while(current.next != null)
What is a doubly linked list's remove method?
The same algorithm that Bill the Lizard said, but in a graphical way :-)
(source: jaffasoft.co.uk)
The general algorithm is as follows:
Find the node to remove.
node.previous.next = node.next
node.next.previous = node.previous
node.previous = null
node.next = null
Dispose of node if you're in a non-GC environment
You have to check the previous and next nodes for null to see if you're removing the head or the tail, but those are the easy cases.
public void remove ()
{
if (getPreviousNode () != null)
getPreviousNode ().setNextNode (getNextNode ());
if (getNextNode () != null)
getNextNode ().setPreviousNode (getPreviousNode ());
}
Doubly Linked List Implementation Remove Methods (from my second programming assignment):
public void remove(int index) {
if(index<0 || index>size())
throw new IndexOutOfBoundsException("Index out of bounds. Can't remove a node. No node exists at the specified index");
if(size()==0) {
throw new NullPointerException("Empty list");
}
if(!isEmpty()) {
Node current;
//starting next one to our head
current = head.next;
for(int i=0;i<index;i++) {
current = current.next;
}
current.previous.next = current.next;
current.next.previous = current.previous;
numOfNodes--;
sizeChangeCount++;
}
}
public boolean remove(T o) {
Node current = head;
for(int i=0;i<size();i++) {
current=current.next;
if(current.data.equals(o)) {
current.previous.next = current.next;
current.next.previous = current.previous;
numOfNodes--;
sizeChangeCount++;
return true;
}
}
return false;
}
Are you asking for the name of a method in the api? That answer would simply be remove, assuming you are asking about java.util.LinkedList which is in fact a double linked list.
...or are you asking about what the name of the algorithm to remove an element from that type of data structure is called? Well.. the answer for that would also be to remove an element. Now for the actual algorithm to do it... it's really just a matter of changing the next pointer in the previous node and the last pointer in the next node. However, if you are using your data structure from multiple threads, you will need to either synchronize the remove method, or do the removal steps in an order that will make sense for your usage pattern for the data structure.
What about the current pointer pointer? You have to move crnt to the next node.
http://pastebin.ca/1249635