I came across the following problem:
Delete a node in the middle of a singly linked list, given only access to that node. (head is not given)
Now there are a lot of solutions and they all do not work when the element to be deleted is the last node.
Why wouldn't this work?
public static void removeNode (Node n){
if(n.next == null){ //n is the last node
n= null;
return;
}
//handling general case here
}
Java passes parameters by value, so setting n to null has no effect outside of the method. This means the method essentially does nothing when passed the last node of a list.
You need to set null the reference in the previous node, not the variable that references to your last node, something like this:
if(n.next == null) {
prev.next = null;
return;
}
n is local to the method, so changing its value won't affect the list itself. You need to modify the next of the previous node, which you do not have access to.
Related
Alright, so cut a long story short, what I'm trying to do here is remove all instances of value e from a doubly linked list. As far as I know, my logic is at least mostly right, but for some off reason it isn't actually removing any of the nodes in my test cases.
public boolean removeAll(int e) {
DIntNode dummy = head,next = null;
if (head == null)
return false;
while (dummy != null) {
if (dummy.getData() == e) {
next = dummy.getNext();
dummy.getNext().setPrev(null);
dummy = next;
return true;
}
else
dummy = dummy.getNext();
}
return false;
}
This is what I currently have for my code of the metho. My logic here was to use a dummy DIntNode that starts at the head and a "next" node to help me shrink the list, so to speak. In other words, if the list was something like "1<-> 1 <-> 2 <-> 3", the function would change it to "2<->3", in theory. The reason this is a boolean function is because I'm required to return true if the given value is removed form the list.
Is there just another step in the logic that I'm missing, or is the methodology itself just unreliable? I'm very unsure at this point, so any and all help would be greatly appreciated.
You set
dummy.getNext().setPrev(null);
But previous node also have reference to next node you try to remove. You should set this reference to next active value.
That because when you want to get all linked list previous value still know about node you remove, because of next node reference
You can try with the following code:
if (dummy.getData() == e) {
DIntNode temp = dummy.getPrevious();
temp.next = dummy.getNext();
temp = dummy.getNext();
temp.previous = dummy.getPrevious();
return true;
}
This used the previous reference. So the previous node will now have reference to the next node of your dummy node (node to be deleted). And similarly, the next node of dummy node will have reference of previous node of your dummy node. So, the dummy node will loose its connection/link from its doubly link list and that's what we want!
Please try.
Two issues with the code:
When relinking a doubly linked list, where removing B from A - B - C, you need to set the next node for A to be C as well as the previous node for C to be A. With trying to keep you method names:
A.setNext(current.getNext());
C.setNext(current.getPrev());
With your code, if you find an occurrence, you return, which means that no other instances will be removed since you jump out of that method. You will probably need a new boolean removed variable, that is set to false, return true changed to removed = true and return false changed to return removed.
The method exits after the first encounter of 'e'.
If you want to remove all instances of 'e', then you should have something like this:
boolean listChanged = false;
while (dummy != null) {
if (dummy.getData() == e) {
// update list
...
listChanged = true;
}
...
}
return listChanged;
Also, you should not write your code like this:
dummy.getNext().setPrev(...); // throws NPE if next is null
After I made my TODOs
I know the solution is as below
public void deleteNode(Node node) {
node.data = (node.next).data;
node.next = (node.next).next;
System.gc();
}
But my question is that
How above solution differ than below another one
Is both are valid solutions and make the same functionality or not
public void deleteNode(Node node) {
node = (node.next);
System.gc();
}
When you do
node = (node.next);
you change parameter, but doesn't change any data.
Java use call by value approach (it slightly difficult to understand what does it mean to pass reference by value).
Here is little example:
void foo(int i) {
i = 2;
System.out.println(i);
}
when we call it
int j = 1;
foo(j);
System.out.println(j);
we get 2 and 1 on console.
It means that when foo is called copy of the value passed to it.
PS:
You don't need to call System.gc();.
Thanks to #talex
And I visualize the cases to be more clear
Lets assume the problem to delete following node c from the Linked List
And we ONLY have access to this node
First solution will actually delete the node
public void deleteNode(Node node) {
node.data = (node.next).data;
node.next = (node.next).next;
System.gc();
}
By copy next cell (value and pointer) to the parameter cell
So the end result
Parameter cell will be considered as deleted and Linked List will be chained correctly
Hints:
No problem that node d not used by any pointer, GC will clean
This solution will NOT work if we need to delete the last cell
Second solution will NOT delete the node
public void deleteNode(Node node) {
node = (node.next);
System.gc();
}
Thats because its ONLY change pointer of the parameter cell
So the end result
Parameter cell will NOT be deleted and Linked List still have the cell
I am reading someone's code. It is about getting input numbers and convert those number into a Linked list. The part of the code is like this:
class Node {
int value;
Node next;
Node() {
next = null;
}
}
Firstly We need to create a head node to indicate head and we let the head be null like this Node head = null.
My limited experiences of java tell me that head is supposed to be a Node type object here. So why we can use Node head = null without instantiate the head?
I think at least I should create Node head = new Node(); then we can use Node head = null;
Anyone can explain it to me?
Node head = null;
This line states that there are no items in the linked list. This is valid in Java and indicates that although head can contain a Node object (or an object of a derived class), it is currently empty.
To add an item to the list, there is likely some code such as:
public void addItemToLinkedList(int value) {
if (head == null) {
head = new Node();
head.value = value;
} else {
...
}
}
So if there is no first Node (when head equals null) then head is created. Otherwise if head already exists, the else block would execute which would look for the end of the list and add another Node.
head is supposed to be a Node type object here
This is optional. Java allows head to be a Node object, or null, to indicate that head is not referencing any nodes at all.
The value of null is special in Java. It is allowed to go wherever an object can go. It indicates that the variable to which you assign null is empty. This is perfectly fine, assuming that the rest of your program deals with null checking.
I have to write a program that inserts strings in order, such as when i insert dog and cat, regardless of the order I insert them, it should return cat, dog.
As of now when I do it, it isn't inserting in order, it's inserting just like normal. I'm pretty sure my method for switching the head and current works because earlier, it would flip my input, whether it was supposed to or not So if it was supposed to be cat dog, it would return dog cat. For whatever reason it gets to my if statement, it's almost like it skips it. Any tips would be greatly appreciated.
public void insert(String s){
head= new node(s,head);
node current=head.getNext();
if(current == null){
current=head;
while(current.getNext() != null){
if(current.getData().compareTo(s)>0){
current.setNext(head);
head.setNext(current.getNext().getNext());
head=current;
current=head;
}
current= current.getNext();
}
}else{
while(current.getNext() != null){
if(current.getData().compareTo(s)>0){
current.setNext(head);
head.setNext(current.getNext().getNext());
head=current;
current=head;
}
current=current.getNext();
}
}
}
You can sort your list using java.util.Collections class
Ex:
Collections.sort(your_list);
There are a few issues with your code and the logic. I will give hints for fixing below
Everytime you call insert you create a new head for the list (I presume a field of your class). that's not how linkedlists work. You should only create a new head when head is null (empty list)
You are setting current to the next node after the newly created head. Therefore it will have whatever value the constructor of node assigned to it. If it assigns a default value of null, you will never get into the else part of the if statement.
According to the above you will inevitably get in the first of the if statement where you reassign current from null to head. Then you are basically comparing the data (String) of the same node (head) and you never get in the next if.
So basically the function you wrote is equivalent to this (try it out)
public void insert(String s) {
head = new node(s, head);
node current = head.getNext();
}
Which is probably not what you intended. Start changing your code by only creating head when it is null and then return after that (if list only has one element no need to swap). Then insert a new node after head and swap if needed.
So I'm skimming through Cracking the Coding Interview to brush up on some interview stuff and I ran across this linked list implementation, and maybe it's been a while but it's completely going over my head. I understand most of it, except for one specific line, and it's throwing me off. I'll post the code below (for reference, the book doesn't mention language but it appears to be Java.)
class Node {
Node next = null;
int data;
public Node(int d) {
data = d;
}
void appendToTail(int d) {
Node end = new Node(d);
Node n = this;
while(n.next != null) {
n = n.next;
}
n.next = end;
}
}
I'm a little confused on the line: Node n = this - I'm not sure what this is referring to, unless it's talking about next - why not just set it to null in that case?
this refers to a specific instance of an object of a class. Since objects are constructed there can be multiple instances of a class, but using the this keyword allows you to obtain a reference to itself, meaning a reference to the the specific instance of the object whose method is being called.
The linked list is a collection of nodes that are, well, linked together. When you call appendToTail() the node will look at all of the Node objects linked to itself and follow the chain. For it to get a reference to itself to follow its own chain the this keyword is used.
You also ask why null isn't used in this case to initialize n. This would cause a NullPointerException when n.next is first called in the loop constraint, so instead its own reference is used as the starting point for the iteration of the linked-list.
This (pun intended) can be a confusing topic at first, but lets use the example you provided.
Node n = this;
while(n.next != null) {
n = n.next;
}
Let's pretend that there are 4 objects currently linked in our list and for simplicity's sake the Node object that appendToTail() is being called on is the head of the list. Here's the reference value of Node n that's held on each loop iteration from the above snippet.
We're pointing to ourself - this
Pointing to the second item in the linked list. - this.next
Pointing to the following item - this.next.next
Pointing to the last item in the list - this.next.next.next
The loop ended so currently the reference of n = this.next.next.next. We then set n's next value (where n is currently pointing to the end of the linked chain) to the new object we created at the beginning of our method, which makes it the new end of the list. (n.next = end is now equivalent to this.next.next.next.next = end).
Semi-Unnecessary Edit: This is explained in terms of Java. It appears that someone added the C++ tag after I wrote this answer
This is Java.
"this" refers to the specific instance of the class in which the call is being made. In this case, "this" is in reference to the specific class Node you are dealing with. While the variable "end" creates a new and separate version of the Node class which is constructed using the passed int "d".
Since this is a Linked List all Nodes are connected and you have a start Node (root). So when using it it would look like this:
Node root = new Node(6); //need an instance first
root.appendToTail(5);
root.appendToTail(3);
//6->5->3
Since this the nodes are connected I need one start Node and need to check if this has a next node when yes I need to search deeper. When a node did not have a next Node it is the current last one and can add my new Node. So this in Java refers to the current instance of a class. In my example the root Node(because I call root.appendToTail). So the method will search from the root Node (value 6) the next Node without a next Node (the one with value 3) and append it there. If I can get a child reference and would call child3.appendToTail the method would search from child3 instead of starting from my root.
When setting n to null and rewriting the while to go from this.next you would have a problem when the current node you use appendToTail did not have a next Node and an NullPointerException would be thrown.
Node n = this; means n object references to the object which is calling this method.
So method is looping to next object till next object is null and assigning end node to the end.
Lets see
1 -- 2 -- 3 -- 4
*
|
*
obj
you have an obj object that is pointing to node 1. When u call obj.appendToTail(5)
Node end = new Node(d); //new node is created to add to the end.
Node n = this; //local n object is referenced to node 1(or obj)
while(n.next != null) {
n = n.next;
}
//n here is node 4 since there is no next node to 4
n.next = end; //node 5 is tail now
End result:
1 -- 2 -- 3 -- 4 -- 5
As you can see in this code
class Node {
//
void appendToTail( int d ) {
Node *end = new Node( d );
Node n = this;
// ...
}
}
Your class Node has a reference to a Node in it's definition.
The line: Node *end = new Node( d ); means inside a Node there is a reference to another node.
The line Node n = this; means inside a Node the reference to that node itself, is represented by this. Ergo, n is also a reference to said node itself.
Any Node instance can call appendToTail().
Notice howebet, here in fact Node does not append itself to tail of the list, what happens here is that new node is created and added to tail, not the one on which method is invoked.
For this to happen, first we need to find the tail of the list given the current Node.
// n is pointing to current Node
while(n.next != null) {
n = n.next;
}
Once we find node which has next == null, this is tail of the list so we can now append new Node to the tail:
// n points to current tail before next line is invoked
n.next = end;
As to why there is line:
Node n = this;
Well since there is no LinkedList class which maintains reference to the head, you have to be able to iterate from any given Node. That is what happens here, you start iteration from Node on which appendToTail is called, but that Node can be anything at this point, from head to tail.
As a side note, if you implement Linked List by hand, make sure to actually have class LinkedList which will offer methods such as add, get, size, appendToTail and so on, rather then putting these into Node class.