Remove method for linkedList implementation in Java - java

I have this method from lecture on removing elements from linkedList at specified index.
I understand how the method works, but I do not understand why the for-loop leaves the current node pointer two index before the desired index.
Here is the method:
public void remove(int index) {
if (index == 0) {
// removing the first element must be handled specially
front = front.next;
} else {
// removing some element further down in the list;
// traverse to the node before the one we want to remove
ListNode current = front;
for (int i = 0; i < index - 1; i++) {
current = current.next;
}
// change its next pointer to skip past the offending node
current.next = current.next.next;
}
}
The for-loop goes from 0 to < index-1, while I thought it should go from 0 to < index. In this way, the pointer is at one index before the index that needed to be deleted. However, the above method works fine.
For eg:
in the below LinkedList
Lets consider removing Node C. By the above loop-construct, current pointer will be pointing at Node A and current.next will be Node B. current.next.next will be Node C. Doing current.next=current.next.next will result in Node B deletion rather than Node C.
I think something is wrong with my understanding, can somebody explain?

The for-loop goes from 0 to < index-1
In your example, removing C means index is 2. So i only goes to 0, since 1 is not < 1.
current starts at A, the for loops once and current goes to B.
current is B, so current.next.next is D, which effectively removes C.

Related

Delete elements within a Linked List

Looking for help again as my professor seems to do an awful job of explaining things (assumes that we know way too much about java programming, when in fact, it's the first java class most of us are taking).
Not looking for someone to write the code for me, but rather someone who can let me know if I'm on the right track and guide me in the right direction. I really want to learn this stuff, not be spoon-fed it, but the professor is making it very hard to do so, so I turn here for help.
The question is to take a LinkedList and create a function to delete the k-th element in that list. I have figured out how to remove the first item if k == 0, but I'm getting lost on how to access the proper element for the "k" within my loop. Here's what I have so far:
public class MyLinked {
static class Node {
public Node(double item, Node next) {
this.item = item;
this.next = next;
}
public double item;
public Node next;
}
int N;
Node first;
// delete the kth element (where k is between 0 and N-1 inclusive)
public void delete(int k) {
if (k < 0 || k >= N) throw new IllegalArgumentException();
{
if (k == 0) {
remove(first.item);
} else if (k > 0) {
kElem = LinkedList.get();
remove(kElem);
}
}
}
}
I'm trying to assign a variable to the .get function but I am definitely wrong there, but not quite sure how to go about this. I know I need to get the value of the k-th element and delete it, however.
I'm also aware that after this, I need to adjust the pointers within the LinkedList to fill the gap where the element I deleted would have been.
Thank you.
Your Link List looks like this:
On this image prev is the object in front of the object you want to delete. Cur is the object you want to delete.
You loop until the next-pointer targets the object you want to delete. After that you set the next pointer of prev to the the object, which follows cur (cur is the object you want to delete).
In pseudo-code it would look like this:
prev = head;
while(prev.next != cur) {
prev = prev.next
}
After this step the prev is on the correct position.
You can see, that this algorithm works with every case except removing the head. You can make a check if you are removing the head and use a different algorithm or you use a dummy-node. Use the dummy-node as head and a dummy-node as tail (here not displayed, but used in double-linked-lists). This dummy-nodes are called sentinels. You won't ever remove this sentinel but your algorithm works without the additional-check because you will remove elements > 0.
Sources:
https://www.cs.cmu.edu/~adamchik/15-121/lectures/Linked%20Lists/linked%20lists.html
In the comments I saw a discussion about clean-code. If you are learning clean-code you will see, that a lot of algorithms are easier to understand, if the variables express their purpose. For example N should be size. But in a different context it could be an upper-limit-of-elements for a cache. There is a good book on this topic: Clean Architecture: A Craftsman's Guide to Software Structure and Design (Robert C. Martin Series)
What do you think is easier to read:
int[][] a = new int[100][200];
for(int i = 0; i < a.length) {
for(int j = 0; j < a[i].length) {
a[i][j] = i*j;
}
}
or this:
int[][] productOfRowColumns = new int[100][200];
for(int row = 0; i < productOfRowColumns.length) {
for(int column = 0; j < productOfRowColumns[row].length) {
productOfRowColumns[row][column] = row*column;
}
}
First go to the k-1 element. Set element.next=element.next.next. Thats how you skip the element, which should be deleted.
Exception: When k=0 (the head element), just set head=head.next.
Optionally you can set next = null for the deleted element (when you went for k-1 elements, deleted=element.next before setting element.next=element.next.next. then say deleted.next=null to clear its next-pointer.
There is also a second common way where you go to the kth element, but you always save the previous (k-1) element in a variable. Performance wise it is worse, because you update 2 variables in each step. It could be more intuitive. Check that video: https://www.youtube.com/watch?v=2RwWsHePdr8 (I hope yt-links are allowed on SO)
By the way, your
static class Node {
public Node(double item, Node next) {
this.item = item;
this.next = next;
}
public double item;
public Node next;
}
int N;
Node first;
is your implementation of the list. LinkedList is the implementation provided by java. https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html. You can not mix them.
Hints:
Don't forget to decrease the size of the list (N--;)
You can "go" to the n-th element with "Node current=head; for(int i = 0; i < n; i++) current=current.next;"
What I mean with "head" is your "first". It is the first element of the list.
The "get" method does not do what you want. You will need to write the code to iterate to position k-1 and switch the pointer, as you said:-
eg. list 1->2->3->4, k=2
iterate using next pointer upto 2, switch the next pointer to point to 4. You don't need to do anything else(remove etc)

Loop condition for accessing all of a List's Nodes

for(int i=1;i<list.size();i++)
{
if (x.nextNode!=null)
{
if (x.data=='C')
{
x.data='G';
} else if (x.data=='G') {
x.data='C';
} else if (x.data=='A') {
x.data='T';
} else if (x.data=='T') {
x.data='A';
}
}
x=x.nextNode;
}
I have created a list with char Nodes which only contains A G C T and a loop which checks every Node of the list and changes it. G should be changed to C, C should be changed to G, A should be changed to T, T should be changed to A.
My problem is that every Node.char item is changed except for the last Node of the list. How I should edit this code to also change the last Node?
You are starting from 1 so apparently skipping one node. so to traverse whole LinkList (seems like) you should to start from 0
for(int i=0;i<list.size();i++)
// ^
update : when if (x.nextNode!=null) is false mean you have reached the last node.
if (lastNode.nextNode!=null) will be false so no execution will take place ,so to execute the last node , use
if (x!=null)

What does "this" refer to in Linked List example?

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.

Implementation of removeFirst() method in SLinkedList in java

I got the following code from one book for implementing a singly linked list. And I don't understand some lines of code in the removeFirst() method, which removes the first node from the LinkedList.
class ListNode{
private String element;
private ListNode next;
public ListNode(){
element = null;
next = null;
}
public ListNode(String s, ListNode n){
element = s;
next = n;
}
//Access method
public String getElement(){
return element;
}
public ListNode getNext(){
return next;
}
//Modify method
public void setNext(ListNode n){
next = n;
}
}
public String removeFirst(){
if(head == null)
return null;
else{
ListNode temp = head;
head = head.getNext();
temp.setNext(null); //Which I don't understand, is it necessary?
size --;
return temp.getElement();
}
}
It seems that the statement temp.setNext(null); can be omitted. So why it is here, does it has anything to do with the garbage colletion in java. Since I am new to Java, any suggestions or ideas?
It depends on the entire implementation of the linked list, which you have not included in your question. However if it is possible for objects to hold a reference to a node even after if has been removed from the list, then the line is necessary.
Suppose we have a long chain of nodes A -> B -> C -> .... Suppose all of these nodes have been removed from the list, but that we still hold onto a reference to A. If all the nodes still held a reference to the next, this would prevent all of the nodes from being garbage collected. Simply setting the next node to be null ensures that only A cannot be garbage collected.
It is likely that implementations of a linked list do mean that references to nodes can be retained. For example, many implementations of Iterator hold a reference to the current node.
Consider this code:
Iterator<String> iterator = list.iterator();
while (i.hasNext()) {
if ("foo".equals(i.next())) {
i.remove();
break;
}
}
// lots more code
This code searches a list for the first occurrence of the String "foo". If it is found, it removes the "foo" from the list and breaks from the loop. The trouble with this is that the Iterator i is still in scope for the remaining code and still holds a reference to a node. This node may be in the middle of the list if the break occurred. Without setting next to be null, this would prevent all subsequent nodes from being garbage collected while i is still in scope, even if the list is cleared.
Note that you should generally make an iterator local to a loop anyway, like this
for (Iterator<String> i = list.iterator();;i.hasNext())
Let us suppose, single linked list of nodes is : A --> B --> C --> D with head node as A. Now, lets go though your removeFirst() method. When it get called, if(head == null) condition doesnt satisfy because our head node "A" is not NULL. Then it execute else statement,
temp = head //take head reference into temporary variable
head = head.getNext(); //As we want to delete first Node which is head so we are setting head to next node (i.e. head --> next) which is Node "B"
Now, to delete A (first Node) we need to break connection between A (which is previous head)--> B (current head) and that will done by
temp.setNext(null); //so out linked list became A B-->C-->D
and then as one node is deleted so in next statement it decreases size of link by size--.
I think we also set the temp reference to NULL as temp=NULL to make deleted node eligible for garbage collection.

beginner java code regarding an add method for adding two nodes in a linked list

Im currently having trouble trying to understand linked lists. I have some code that uses nodes and have been asked to use an iterative approach to create a new node with the string parameter stored in it, at the index position specified in the integer parameter. The old node at the index position should follow the newly inserted node.
These are the fields:
// a string that contains the full name on the filesystem of an image file.
private String imageName;
// a reference to the next ImageNode in the linked list.
private ImageNode next;
//temporary node created to start the set of nodes
private ImageNode temp = this;
And this is the code i have written so far: Note that getNext() returns the next node.
private void addIter(String imageFileStr, int pos) {
int count = 0;
while(temp.getNext() != null){
temp = temp.getNext();
count++;
if(count == pos){
temp.getNext() = ???
}
}
}
Is this the right way to go about adding two nodes? If so, this would currently only work if the node needs to be added to the end of the set of current nodes. How would i modify the code so that it allows me to add a node in the middle of set and have the old nodes follow it as stated above ("The old node at the index position should now follow the newly inserted node.")?
And finally, how do i create a variable (x) that is equal to the input from addIter so that i can set temp.getNext() = x? (currently depicted by question marks in the code).
It's impossible to completely answer this without seeing more of your implementation, but here are few things:
temp.getNext() = ??? doesn't make sense, you can't assign to a function call. You will need to add a method setNext(ImageNode node) that sets the next node to the given value.
In your add method, You need to create a new node using the input string (lets call it newNode, find the node currently at pos (lets call it existingNode), then you will need to do a couple things:
Set newNode.next to the node currently after existingNode (or null if it's the end of the list)
Set existingNode.next to newNode.
This will probably end up looking something like this:
public void add(String item, int pos) {
if (pos > length) {
// Probably just throw an out of bounds exception
}
Node existingNode = head;
for (int i = 0; i < pos; i++)
existingNode = existingNode.getNext();
Node newNode = new Node(item);
newNode.setNext(existingNode.getNext());
existingNode.setNext(newNode);
}
Let's assume you have nodes A,B,C and want to insert a new node (D) at pos 3. You will need to iterate through your list up to node 2, i.e. B. Then you save the link to the node following B into a temporary variable, say TempC: Node TempC = B.getNext().
After that you set TempC as the next node after the one you are going to insert: D.setNext(TempC). Then you set D as the next node after B: B.setNext(D). The resulting set will be: A, B, D, C
P.S. here I assume that the first node is 1, not 0.
you definitely need to create a new object and save the data into it. New object must point at the next node where you want to add it and then temp must point at the object.

Categories