public void deleteAfter(Node prev){
prev.setNext(prev.next().next());
}
This method deletes the new node after the given prev node. Could someone explain to me what this code does specifically step by step and how I can change it so that it won't error if prev is the last node on the list.
#param prev - The node before the place where it will be inserted.
prev.next().next() gets the node after the next node (from the one given). That's then passed to the prev.setNext method, making it the next node. That essentially removes the node in between prev and the next next node.
Basically, it takes prev -> next_1 -> next_2 ... and turns it into prev -> next_2 ...
If prev is the last node in the list, then next() should return null (I assume). If that's the case, you can do a null check to avoid an error.
public void deleteAfter(Node prev){
if(prev.next() != null) {
prev.setNext(prev.next().next());
}
}
The code sets a new next such that if you had a -> b -> c, now you'll have a -> c.
To avoid the error, you can check if next returns null, or maybe invoke hasNext if such a method exists on Node.
if(prev.next() != null){
...
}
It unlinks the link between the node before the node to be deleted and then links the node before the node to be deleted to the node after the node to be deleted.
You have some Node, somewhere in a list. I've highlighted it.
... - node - node - (prev) - node - node - ...
The first call, is to set the "prev"'s next link prev.setNext(...) but what is that next going to be set to? It will be set to "next's next" or (staring with prev)
... - node - node - (prev) - node - node - ...
The prev.next() would be
... - node - node - prev - (node) - node - ...
And the prev.next().next() would be
... - node - node - prev - node - (node) - ...
So, after the setting operation, your arrangement would look like
... - node - node - prev node--node - ...
\------/
Note that the prev's new "next node" was previously prev's next, next node.
If you ever ask yourself "What is this code doing????", there is an excellent chance that the code can be written in a more descriptive way. For example:
public void deleteNodeAfter(Node index) {
// Borrowed from Bill the Lizard's answer
if (index.next() != null) {
index.setNext(index.next().next());
}
}
To answer you directly: This code deletes a node from a linked list.
Related
I am working on a problem: create a stack using a linked chain that places the new entry (top of stack) at the end of the chain, not the beginning. Part of the solution involves maintaining a reference to the first and last nodes and the next to last node. Also, I cannot traverse the chain. I cannot think of a solution because I cannot think of a way to update the reference to the next to last node when the top entry is popped off the stack?
(This is a textbook question. The beginning of the chain contains a reference to the next node. The end of the chain's reference to the next node is null)
Beginning and end are abstract terms. Just initialize a node to contain the first element. Something like the following:
Node tail = null;
..
..
Then to add a new node.
public void push(T val) {
Node = new Node(val);
Node.next = tail;
tail = node;
}
You're adding it at the tail and then the new node becomes the tail. Then when you iterate thru it you simply start at the tail and move towards the head using the next reference.
To pop the stack.
public T pop() {
if (tail != null) {
object = tail.object;
tail = tail.next;
}
return null;
}
You will need to create a generic class Node. And you may want to have an isEmpty() method.
I'm familiar with the 'this' keyword used in java, it is used to reference the current object. The following piece of code shows how a node of a LinkedList is created:
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;
}
}
But here I'm not sure what the following line in the above code states:
Node n = this;
I'm pretty sure that 'this' here is referenced to the current object, but is this object head, tail or any other node in the LinkedList? Not sure if my question makes perfect sense, but any help is greatly appreciated.
I assume the appendToTail(int d) method appends the newly created node to the end of the list regardless of which Node its called from.
What happens is that one must find the end of the list in order to append the new Node to the end of it. Since we know that the node it is called from is in the list, it's an ideal starting point. Hence we choose the starting point as "this" node. But, this node is not necessarily the end of the list (in fact, it can be anywhere in the list), so we store it in a temporary variable Node n = this and continue changing our temporary variable until its the last node in the list, to which the new node can be added.
It's equivalent to starting from a random point (this) in a list and moving from that point to the end, wherever that is.
Hope this answered your question.
I'm pretty sure that 'this' here is referenced to the current object
Yup.
but is this object head, tail or any other node in the LinkedList?
That depends where the method was called from or if the list contains this Node at all.
All the method does is assign a temporary reference to the current Node so it can be iterated over. You can't say which Node it is without more information.
From comments - If you call appendToTail() on the head, this will be the head. If you call it on the tail, this will be the tail. If you call it on a middle node, this will be that middle node.
I have written a program that removes a node in the single linkedlist given the node.
public class Solution {
/**
* #param node: the node in the list should be deleted
* #return: nothing
*/
public void deleteNode(ListNode node) {
// write your code here
// if node.next==null, we cannot delete the current node without given the previous node
if(node == null || node.next == null) return;
ListNode next = node.next;
node.val = next.val;
node.next = next.next;
// I wonder if this link needs to be removed as well
next.next = null;
}
}
The problem is pretty simple. However, many code samples online do not contain this line I wrote:
next.next = null;
Without this line, we already remove the node. After that, although nothing is pointing to "next", "next" still points to next.next. Without setting next.next = null, will the Java garbage collector remove this deleted node?
Indeed it will. The gc iterates over all objects and checks wether someone else points to it. If not, it is marked for deletion.
I' studying linked lists. I'm practicing problems from this book : Cracking the coding interview. I'm stuck, I can't understand how the author is trying to implement the following code, its supposed to delete a node....
class Node {
Node next = null;
int data;
public Node (int d) {
data = d;
}
Node deleteNode(Node head, int d) {
Node n = head;
if (n.data == d) {
return head.next;
}
while (n.next != null) {
if (n.next.data == d) {
n.next = n.next.next;
return head;
}
n = n.next;
}
return head;
}
I've 3 questions...
Question 1 -
What are we going to pass as the argument for the function deleteNode? What purpose does Node head serve? and what purpose does int d serve? Is the node head the node we want to delete? Or is it our head node? I mean, we are supposed to use the method as following right?
"Name of node".deleteNode("Node name", "integer value");
"Name of node" being the node we want to delete...Isn't that right?
Question 2 - Its clear in the code that the function deleteNode uses only data to confirm the identity of the node we want to delete. E.g. if(n.data ==d). Is that normal practice? I mean what if I have 2 different nodes containing the same integer as the data value? Shouldn't we use the name of the node to specify which node we want to delete?
Question 3 - function deleteNode returns a node. Why is that? In order to delete a node, we only gotta do 3 things...First, unlink the pointer of the node we want to delete. Second, put the pointer of the previous node, to the node where the pointer of the node we wanted to delete was originally pointing. Third, delete the node now that its not linked to the list. I don't see what purpose does return type node serves here...
Question 1 : All along your post, you keep talking about the "name" of the nodes, but the nodes have no name. They have an int value and a successor, that's all. In this deleteNode method, the first argument is the head of the linked list from which you want to remove the first occurrence of the value d.
Question 2 : As I said, the nodes have no name and are identified by their value. As soon as an occurrence of the wanted value is found, the corresponding node is deleted no matter how many occurrences of the same value are in the linked list.
Question 3 : the method returns the head of the list, so that you can chain multiple calls like this
myList.deleteNode(head,3).deleteNode(head,5).addNode(head,10)
If the method had a void return type, you should do
myList.deleteNode(head,3);
myList.deleteNode(head,5);
myList.addNode(head,10);
I have a linear data structure where every node has a level. The parent node has a level of 1, a node that is child of the parent has a level 2, a node that is child of child has node of 3, another parent node would have a level of 1. e.g. below
<node level=1> //parent node
<node level=2> //child of encountered parent node
<node level=2> //child of encountered parent node
<node level=3> //child of encountered child node
<node level=2> //child of encountered parent node
<node level=1> //parent node
<node level=1> //parent node
<node level=2> //child of encountered parent node
<node level=3> //child of encountered child node
<node level=4> //child of encountered child node
<node level=1> //parent node
Essentially I am trying to build a List. (Open to other suggestions), such that each element in the list is a parent node, each parent node will have list of child nodes, each child node can have list of child nodes etc. Each of the element is a node and all properties are same.
I have tried code by keeping track of the current level but than I am not sure how to properly add a child node, that has child node, that has child node, back to the parent node of the first child node. I feel this might be handled best by recursion but I am have never been able to truly implement recursion in an orderly fashion.
You don't have to think about all the nesting. You only have to think about where you are (as in, what level was the previous entry in the list of nodes) and where the next entry goes.
In this case, the solution lies in the way the tree is read in. Notice in your list of nodes, which is the tree input source, that right after a parent node, the next node is a child. If the node after some node isn't a child of that node (i.e. if its level isn't one level lower), it is the child of one of the previous node's ancestors.
So:
If the level on line n is equal to one plus the level on line n-1, line n holds a child of line n-1.
Otherwise, go up the tree from the node for line n-1 until you find one with a level one less than the level on line n. That ancestor node is the parent of node on line n.
You also don't have to do it recursively.
currLevel = 0;
currNode = root;
do {
node = read();
if (somethingRead()) {
// If this one is one level below the last one, it goes in as a child and we're done
if (node.level == currNode.level + 1) {
currNode.addChild(node);
currNode = node;
} else {
// Otherwise this one has to be at a level above this node's child, so back up
while (node.level >= currNode.level) {
currNode = currNode.parent(); // check for root left out here ...
}
if (node.level == currNode.level + 1) {
currNode.addChild(node);
currNode = node;
} else {
// handle illegal condition in list
}
}
}
} while (moreNodesToRead());
Response to Your Solution
Your solution reflects your reluctance to use a fake node as the root of the tree. That's a design choice one can make. Here is my version of it.
I am a little concerned about how you handle incoming data that is fouled up
A node is presented that is more than one level beyond the one before it.
The first node presented isn't at level 1.
A node has a level of 0 or less (no checks for that below)
Also, I suggest you allow currNode to be null when the current node should be the root. Theoretically it could happen in the while loop that backs up the current node but notice that, at that point in the code, you already know the new node has a level above 1 so currNode should never back up beyond the level 1 nodes. It is reasonable to have it generate a NPE if that assumption is wrong.
I suggest these changes:
Node currNode = null;
List<Root> roots = new ArrayList<Root>();
do {
Node node = generateNode(nodesList.next());
if (node.getLevel() == 1) { //implies root level node
roots.add(node);
currNode = node;
} else if (currNode == null) {
// ... handle misformed input ... first node isn't level 1, ignore it
} else if (node.getLevel() == currNode.getLevel() + 1) {
currNode.childrenList.addChild(node);
node.setParent(currNode);
currNode = node;
} else {
Node savedCurrNode = currNode;
while (node.getLevel() <= currNode.getLevel()) {
currNode = currNode.getParent();
}
if (node.getLevel() == currNode.getLevel() + 1) {
currNode.childrenList.addChild(node);
node.setParent(currNode);
currNode = node;
} else {
// ... handle misformed input ... node level > last node level + 1, ignore it
currNode = savedCurrNode;
}
} while (hasMoreNodes(nodesList));
Printing
I rearranged it a bit and changed some names and responsibilities (listed in comments). Just to belabor a point from above, if the root was just a node you wouldn't need the 'printRoots()' method at all. Just call 'printChildren()' on the fake root node with level set to 0. But it would print one extra line at the top.
(It always makes it easier to read if you indent the output.)
Warning: Not tested.
/** Print all the root nodes, each with any children it may have */
private void printRoots(List<Node> roots) {
for (int j = 0; j < roots.size(); j++) {
Node node = roots.get(j);
printContents(node, 1);
}
}
/** Print one node and any children it might have */
private void printContents(Node node, int level) {
for (int i=1 ; i < level ; ++i) {
print(" ");
}
print(node.toString());
println();
printChildren(node, level+1);
}
/** Print each child of the supplied node. Notice how this is just like getting the
* list of children and calling 'printRoots()'
*//
private void printChildren(Node node, int level) {
for (int i = 0; i < node.getChildrenList().size(); i++) {
Node childNode = node.getChildrenList().get(i);
printContents(childNode, level);
}
}