I was reading about nodes in java .. I found this example .. I just can not understand how the ListNode works in java .. I did read about it but I still can not understand it .. Here is the code :
public class SingleLinkedList<E> {
private ListNode<E> first;
/ ** Creates an empty list. * /
public SingleLinkedList() {
first = null;
}
/ ** Returns a list of the elements that match e.
otherwise returned an empty list. * /
public SingleLinkedList<E> allMatches(E e) {
SingleLinkedList<E> res = new SingleLinkedList<E>();
ListNode<E> n = first; // why we create a new node and put it equal to first ?
while (n != null) {
if (n.element.equals(e)) {
ListNode<E> tmp = new ListNode<E>(n.element);
tmp.next = res.first; // what is happening here ?
res.first = tmp; // why we do this step?
}
n = n.next;
}
return res;
}
private static class ListNode<E> {
private E element;
private ListNode<E> next;
/* Creates a listnode which contains e. */
private ListNode(E e) {
element = e;
next = null;
}
}
}
I do not understand the allMatches method ... I put some comments next to each line I did not understand it ...
First question: ListNode<E> n = first; // why we create a new node and put it equal to first ?
Second question: tmp.next = res.first; // what is happening here ?
Third question : res.first = tmp; // why we do this step?
Fourth question :if (n.element.equals(e)) { // can we use == instead of equals in this case?
Please can you answer my questions? thanks
First question: ListNode n = first; // why we create a new node and put it equal to first ?
No new node is created here. A reference is created and it refers to first. New Node is created only when new operator is used. It is assigned with first because we are going to scan through the linked list one by one. Just having the reference to first node is sufficient because first contains reference to the second if it exists.
Second question: tmp.next = res.first; // what is happening here ?
the method allMatches(e) returns a linked list of all nodes which has element value equal to e.element. Whenever there is a match, create a new node. This new node points to the current first element. This is half complete. Read the next question answer and then try to understand.
Third question : res.first = tmp; // why we do this step?
Here res.first is updated with the newly created node. Why? Because we made our new node to point to the current first element. As this new element precedes current first element, we have to update the first element to point to newly created node.
Fourth question :if (n.element.equals(e)) { // can we use == instead of equals in this case?
Nope. Because == works only if both are same object. Here there might be chances that objects are different but there contents are equal. It really depends on how it is being used in the application. In general, the answer is NO.
I think the reason why the the new node n is pointed at first is because you're going to create a new separate linked list called res that is a new linked list of just the results of the search and you want it pointed at the first node in the linked list you will examine namely the list that calls the method.
The reason why tmp.next = res.first is because we are going to insert tmp as the new first element in res and we will attach the old res on after it. Does that make sense? I think drawing a picture of what is going on will help clear up what is happening.
Related
I am trying out my own implementation of a double-linked list. While my code is currently functioning, I can't really figure out why. Below is an exerpt of the code:
public class DLList<E> {
public class Node {
/** The contents of the node is public */
public E elt;
protected Node prev, next;
Node() {
this(null);
}
Node(E elt) {
this.elt = elt;
prev = next = null;
}
}
Node first, last;
DLList() {
first = last = null;
}
// inserts an element at the beginning of the list
public Node addFirst(E e) {
Node node = new Node(e);
if(first==null){
first = node;
last = node;
}else{
node.next = first;
first.prev = node;
first = node;
}
return node;
}
}
In the else-block of the addFirst-function the variable next is set to the reference first and two lines later the reference first is set to the Node-object node. Surspringly (to me) this works. Shouldn't this mean that node.next is actually set to node as we basically get node.next = first = node?
EDIT:
Answers:
You're changing references (pointers) - which is why it does [work]. The last line first = node; simply changes first from pointing to the previous node to point to the current node. – alfasin
I think I figured it out. In my code I am not changing the actual object, I am just changing what objects are being referenced. In plain english my code in the else-block can be read as:
1. Set node.next to reference the object that first is referencing.
2. Set first.prev to reference the object that node is referencing.
3. Lastly, reassign first to reference the object that node is referencing. – erikejan
There are some issues in your code as mentioned in the comments, but to answer your question, no, it's not the same. In Java, you assign variables by value and not by reference. So, if you modify first after assigning it to node, it doesn't modify the value of node.
It's like,
a = 5;
b = a;
a = 4;
Here, value of b will be 5. It doesn't get changed to 4.
Compiler executes each statement sequentially. So it will not know that the value of a will be modified in the future or not.
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.
I have a HW assignment and only one small part of it is to make a copy constructor which makes a Deep Copy of the linked list which you have entered in its parameters.
I understand that this means, that the List you have entered remains unchanged, and that the new linked list is isolated from the "old" one. My code gives me a new list which is exactly the same as the old one (the one you enter as a parameter) and this is what I want, but the old one is changed.
Here is the constructor:
public SortedLinkedSet(SortedLinkedSet<T> copy) {
if (copy == null) {
this.firstNode = null;
} else{
SortedLinkedSetNode firstNode1 = new SortedLinkedSetNode(copy.getFirstNode().value);
this.firstNode = firstNode1;
// so basically I am chaining elements from "copy" to firstNode1 and then making "this" = to firstNode1.
while (copy.firstNode.next !=null) {
firstNode1.add(copy.getFirstNode().next.value);
this.firstNode = firstNode1;
copy.firstNode = copy.firstNode.next;
// at the end of this loop I have a successful new linkedList with the same value, but "copy" has been changed
}
}
}
If for example I enter a linked list which has the values (1,2,3) -- with this constructor i get back a new linked list with values 1,2,3 but the old one just has 1.. If someone can help me with why this is going wrong it would be great. Thanks
UPDATE : As Ireeder pointed out, and with a test I did, I am almost sure that the problem is in the statement :
copy.firstNode = copy.firstNode.next;
i deleted the current code, and did the following test:
SortedLinkedSetNode firstNode = new SortedLinkedSetNode(copy.getFirstNode().value);
this.firstNode=firstNode;
firstNode.add(copy.getFirstNode().next.value);
this.firstNode = firstNode;
firstNode.add(copy.getFirstNode().next.next.value);
this.firstNode = firstNode;
and this Works perfectly(but I knew in advance i'm testing with only 3 element list).How would i do it with a while loop without using such a statement as :
copy.firstNode = copy.firstNode.next;
I have to somehow move along the "copy" list ?
It's hard to say what the problem is without seeing the source for SortedLinkedSetNode, but you seem to be modifying your original with this statement:
copy.firstNode= copy.firstNode.next;
This probably advances firstNode to the end of your original linkedset, resulting in the original having one element. Also, confusingly the original is called "copy". You may want to rename it so you can understand your code better.
When creating a deep copy, you shouldn't modify the structure you want to copy.
In this case, you can just use a temporary variable to store the reference to the current node you are on, without modifying your original data structure. Try this:
this.firstNode = firstNode1;
// so basically I am chaining elements from "copy" to firstNode1 and then making "this" = to firstNode1.
SortedLinkedSetNode currentNode = copy.firstNode;
while (currentNode.next !=null) {
firstNode1.add(currentNode.next.value);
this.firstNode = firstNode1;
currentNode = currentNode.next;
}
First the original to copy from, is called copy, like in do copy this one?
You did have some mix-up with the correct nodes and the code was not kept simple enough.
A recursive solution to simplify things seems appropriate:
public SortedLinkedSet(SortedLinkedSet<T> original) {
Objects.requireNotNull(original);
this.firstNode = copyNodes(orignal.firstNode);
}
private SortedLinkedSetNode copy(SortedLinkedSetNode originalNode) {
if (originalNode == null) {
return null;
}
SortedLinkedSetNode node = new SortedLinkedSetNode(originalNode.value);
node.next = copy(originalNode.next);
return node;
}
If the node's value would need deep copying too, that could be done at one place.
A loop would still be simple. One way:
private SortedLinkedSetNode copy(SortedLinkedSetNode originalNode) {
SortedLinkedSetNode firstNode = null;
SortedLinkedSetNode previousNode = null;
while (originalNode != null) {
SortedLinkedSetNode node = new SortedLinkedSetNode(originalNode.value);
if (firstNode == null) {
firstNode = node;
} else {
previousNode.next = node;
}
previousNode = node;
originalNode = originalNode.next;
}
return firstNode;
}
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.
Update: Thanks a lot to everybody who responded!!! It made me feel that I'm not completely alone in my efforts to learn Java. Please excuse me, but I guess I didn't clarify enough what I don't get about linked lists and the exercise application -
first - how can a class definition contain an object of itself, OK I know that this is recursion but it's still a very strange and alien concept to me.
second - how exactly can a linked list object "link" to another node?
third - if two objects are separated by an equals sign it means what - that the second object disappears and what's left of it is it's "name" that now points to the first object or vice versa?
then - the thing that I don't get about the program I quoted below is the following: after the linkList class is instantiated it's constructor is called and it gives the object of class Link private Link first the value of null, i.e. sets it pointing to nothing. Then, when the first new node is created the method public void insertFirst is called, it gives the object values to its variables and then something absurd happens - the object first that points to nothing is assigned to the new item thus making both objects pointing to nothing and with the first = newLink; I'm completely lost...
I'm doing a college course on Algorithms and Data structures and since the professor is really mean and his explanations are useless I'm trying to learn on my own from a book called Algorithms and data structures by Robert Lafore.
Now I'm learning Linked lists and there is the following code example for a linked list implementation in the book:
Link.java:
class Link
{
public int iData; // data item
public double dData; // data item
public Link next; // next link in list
public Link(int id, double dd) { // constructor
iData = id; // initialize data
dData = dd; // ('next' is automatically
} // set to null)
public void displayLink() { // display ourself
System.out.print("{" + iData + ", " + dData + "} ");
}
}
LinkList.java:
class LinkList {
private Link first; // ref to first link on list
public LinkList() { // constructor
first = null; // no links on list yet
}
public boolean isEmpty() { // true if list is empty
return (first==null);
}
// insert at start of list
public void insertFirst(int id, double dd) { // make new link
Link newLink = new Link(id, dd);
newLink.next = first; // newLink --> old first
first = newLink; // first --> newLink
}
public Link deleteFirst() { // delete first item
// (assumes list not empty)
Link temp = first; // save reference to link
first = first.next; // delete it: first-->old next
return temp; // return deleted link
}
public void displayList() {
System.out.print("List (first-->last): ");
Link current = first; // start at beginning of list
while(current != null) // until end of list,
{
current.displayLink(); // print data
current = current.next; // move to next link
}
System.out.println("");
}
}
LinkListApp.java:
class LinkListApp {
public static void main(String[] args) {
LinkList theList = new LinkList(); // make new list
theList.insertFirst(22, 2.99); // insert four items
theList.insertFirst(44, 4.99);
theList.insertFirst(66, 6.99);
theList.insertFirst(88, 8.99);
theList.displayList(); // display list
while( !theList.isEmpty() ) { // until it's empty,
Link aLink = theList.deleteFirst(); // delete link
System.out.print("Deleted "); // display it
aLink.displayLink();
System.out.println("");
}
theList.displayList(); // display list
}
}
I just CANNOT understand the code that inserts and displays items in the linked list class.
How can it be that newLink.next = first; and first = newLink; after the new object is created?
Please help!
Each Link holds a reference .next to the next Link element (except the last element, having .next = null.
A LinkList holds a reference (.first) to the first Link object it contains.
In order to insert a new Link at the front of the LinkList, we need to do the following:
Create a new Link object to insert in front (newLink).
Let the newly created Link point to the previous first Link object as its .next
Reset the .first reference of the LinkList to the newLinkobject, effectively overwriting the previous reference (marked with a cross below).
This is exacly what's going on:
public void insertFirst(int id, double dd) {
Link newLink = new Link(id, dd);
newLink.next = first;
first = newLink;
}
What may have confused you is that this list implementation is LIFO (Last In First Out), so the last element inserted is the first one returned when traversing.
newLink.next = first; puts the former first element as the new element's next (so second)
first = newLink; puts the new element at the top of the list
There are many possible ways for linked lists to behave differently, it depends on what kind of collection you want them to be (a queue, a stack) or different patterns (single or double linked, circular) and so on.
Assume we have a linked list like this:
first -> Link("monday")
Link("monday").next -> Link("tuesday")
Link("tuesday").next -> Link("wednesday")
Now we want to have the week starting with "sunday".
First we create a new link for "sunday":
Link("sunday") # newLink = new Link(id,dd)
and tell it, that it's follower is "monday"
first -> Link("monday")
Link("sunday").next -> Link("monday") # newLink.next = first
Link("monday").next -> Link("tuesday")
Link("tuesday").next -> Link("wednesday")
Finally we correct the start of the week
first -> Link("sunday") # first = newLink
Link("sunday").next -> Link("monday")
Link("monday").next -> Link("tuesday")
Link("tuesday").next -> Link("wednesday")
You add the new Link to the head of the LinkList object by setting head = newLink;
You append the existing list to the new element's next by setting newLink.next = first;
As your new node is being added, it is being added to the start of the LinkedList, so since the pointer First was pointing to the first node in the List, but on the arrival of a newNode to the same list, this Pointer first must point to the newly added node, and the newly added node must point to the previously established first node, so that it can become the first node of the Linked List.
Hopefully this diagram can explain a bit further :
That's why you have to write newLink.next = first; and first = newLink;