Deep Copy Constructor for Linked List in Java - java

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;
}

Related

Remove All Occurrences of a Given Value from a Doubly Linked List

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

Confusion regarding references in implementation of a double linked list

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.

How does ListNodes work in java implementation

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.

java List type variable

I have been breaking my head with below code which I made. The problem is that when I do
tail.child = null;
it is also making my childPoint's child as null.
tail is instance variable with below definition:
public List tail;
public void removeMultiLinkList() {
List headPoint = head;
while (headPoint.next != null) {
List childPoint = headPoint;
while (childPoint.child != null) {
tail.next = childPoint.child;
tail = tail.next;
tail.child=null;
childPoint = childPoint.child;
}
headPoint = headPoint.next;
}
}
I have made this method to solve the problem of multilevel link list and convert it into linear singly link by in non recurssive manner
Examine what you are doing:
tail.next = childPoint.child;
tail = tail.next;
In here, tail is childPoint.child (reference identity)
Then, you do:
tail.child=null;
This means, you actually set childPoint.child.child = null; - because chilePoint.child and tail are different names for the same object.
And then, you assign:
childPoint = childPoint.child;
But you assign childPoint to the same object you just changed - so the new childPoint's child, is null!
A very easy workaround is to copy by value (by creating a copy constructor) the elements from one list to the other.
An alternative might be to keep copying references - but without changing child at all. At the end of your algorithm, do some post-processing and set e.child = null for each element e in your list.

Help making a singly linked list in Java

This is for homework but please know that I have looked online for help (such as http://www.sethi.org/classes/class_stuff/cis435/others/notes-java/data/collections/lists/simple-linked-list.html) and my textbook but I am still having some issues.
Any help would be appreciated...
Right now I'm trying to just insert values in but nothing is working. Whether it's the first item, whether it's being added as the last one, or somewhere in between.
Node header = null; // First element of list.
Node back = null; // Last element of list.
public void insert(int i, double value){ //insert value before i-th element
Node e = new Node();
e.num = value;
Node curr = header;
for(int x=0;x<i;x++) {
if (i == 1) { //we want to insert as first thing
if (size == 0) { //its the FIRST time we add something
header.next = e;
e.next = back;
break;
} else if (size == 1){
e.next = header.next; //i.e. the second thing in the list
header.next = e;
break;
} else {
e.next = header.next.next; //i.e. the second thing in the list
header.next = e;
break;
}
}
else if (x == (i-1)) {
e.next = curr.next;
curr.next = e;
break;
}
curr = curr.next;
}
size = size+1;
}
Not really sure why it isn't working.
Thanks!
For some reason, people who are still learning to program make things far more complicated then they need to be. I did it when I was learning java, I still do it when I am just getting into a new language, and students that I have marked find new and amazing ways to do it. You have more going on in your insert then there needs to be, for example, a method that inserts a value at a specific index should not check if it's the first item to be inserted (not saying it shouldn't check bounds). Here is the pseudo code of what I would do.
insert(index, value)
if index>size
throw null pointer
traverse to index -1 //lets call this nodeI
create newnode and set value
set newnode.next to nodeI.next
set nodeI.next to newnode
increase size.
Couple of handy hints for you, you should have a function to get an element from the link list, something that returns a node? public node elementAt(int index) for example? use that to traverse the linked list. If you want to append to the Linked list, try this
append(value)
insert(size-1,value)
and if you want to insert at the beginning? same idea
insert(value)
insert(0,value)
In the line e.next = header.next.next what would happen if header.next points to a 'null'? Is it possible to get there?
What are the corner cases you have to deal with and have you taken them all into account?
Can you start with the simplest case first, adding either an element to the front or an element to the back? Then use those functions to implement the insert?
A few suggestions:
implement java.util.List
Think about generics
Read this.
Start with "insert at the end" before you think about "insert at i".
I have tried a simple program, which will be useful for you guys, I am also learning Java, please bear with me for any mistakes, but this program works fine.
I am posting a very simple singly linked list program in Java, which I tried out today.
I hope it will help all.
LinkList.java
class LinkList
{
public static void main(String args[])
{
Node node = new Node(1);
node.addAtLast(2);
node.addAtLast(3);
node.addAtLast(4);
node.addAtLast(5);
node.printList();
}
}
Node.java
class Node
{
private int data;
private Node link;
public Node(int mydata)
{
data = mydata;
link = null;
}
public void printList()
{
System.out.print("|"+data+"|"+"->");
if(link != null)
{
//recursive call
link.printList();
}
else
{
//marking end of list as NULL
System.out.print("|NULL|");
}
}
public void addAtLast(int mydata)
{
if(link == null)
{
link = new Node(mydata);
}
else
{
link.addAtLast(mydata);
}
}
}
OUTPUT :
The below is our output
|1|->|2|->|3|->|4|->|5|->|NULL|

Categories