0

hello there i did the deep copy and the shallow copy is suggested by the user AndyMan and now i did the JUnit and im having a slight problem making those tests:

1.deep copy method

   public ListNode<E> deep_clone() {
           first = deep_clone(first);
           ListNode<E> copy = new ListNode<>(first);
     return copy;
    } 

    private static Node deep_clone(Node head) {
        if (head == null) {
            return null;
        }

        Node temp = new Node(head.getData());
        temp.setNext(deep_clone(head.getNext()));

        return temp;
    }

Edit

many thanks for AndyMan for suggesting this shallow copy method:

private static Node shallow_clone(Node head) {
   if (head == null)
      return null;

   Node temp = new Node(head.getData());
   temp.setNext(head.getNext());  // Just copy the reference

return temp;
}

but one question though how to Junit both the deep and shallow copy methods?

i did the following and i got a failed Junit test:

@Test
public void test_shallow_clone(){
    ListNode<Integer> list =new ListNode<>();
    for (int i = 0; i < 10; i++)
        list.insert(i);

    ListNode<Integer>cloned =list.shallow_clone();
    //assertSame(cloned,list); //failed i dont know why
    //assertEquals(cloned, list);//Even though its shallow copy i get that they are  not equal!
    assertSame(list.getFirst(), cloned.getFirst());
    assertTrue(cloned.equals(list));
}

and the test for the deep copy:

@Test
public void test_depp_clone(){
    ListNode<Integer> list =new ListNode<>();
    for (int i = 0; i < 10; i++)
        list.insert(i);

    ListNode<Integer>cloned =list.depp_clone();

    assertSame(cloned.getFirst(),list.getFirst());//check for same val..
    //assertEquals(cloned, list);//this make the test fail..
    assertFalse(cloned.equals(list));//okay the are not equal lists this means its deep copy...no implemented equal method :)
}

class ListNode

public class ListNode<E> implements Iterable<E>{

private Node<E> first;
//private Node<E> last;

public ListNode() {
    first = null;
    //last = null;
}

public ListNode(Node head) {
    this.first = head;
    //this.last = this.first;
}

public ListNode(E data) {
    Node head = new Node(data);
    this.first = head;
    //this.last = this.first;
}

@Override
public Iterator<E> iterator() {
    return new LL_Iterator<>(first);
}

private static class Node<E> {

    private E data;
    private Node next;

    public Node() {
        this.data = null;
        this.next = null;
    }

    public Node(E data) {
        this.data = data;
        next = null;
    }

    public Node(E data, Node next) {
        this.data = data;
        this.next = null;
    }

    public E getData() {
        return data;
    }

    public void setData(E val) {
        this.data = val;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }

    @Override
    public String toString() {
        return "Node{" + "data=" + data + ", next=" + next + '}';
    }

}

private static class LL_Iterator<E> implements Iterator<E> {

    private Node<E> curr;//we have to specify the E here because if we dont we have to cast the curr.getData()

    public LL_Iterator(Node head) {
        curr = head;
    }

    @Override
    public boolean hasNext() {
        return curr != null;
    }

    @Override
    public E next() {
        if (hasNext()) {
            E data = curr.getData();
            curr = curr.getNext();
            return data;
        }
        return null;
    }

}

public E getFirst(){
    if(first==null)
        return null;

    return first.getData();
}

public boolean addFirst (E data) {
    if(data==null)
        return false;

    Node t= new Node (data);
    t.setNext(first);
    first=t;
    return true;
}

public E getLast() {
    if (first==null)
        return null;
    return getLast(first).getData();
}

private static<E> Node<E> getLast(Node<E> head) {
    if (head == null) {
        return null;
    }

    Node temp = head;
    if (temp.getNext() != null) {
        temp = getLast(temp.getNext());
    }

    return temp;
}

//insertion....Wie setLast
public boolean insert(E data) {
    if(data==null)
        return false;

    first = insert(first, data);
    //last = getLast();
    return true;
}

private static <E> Node insert(Node head, E data) {
    if (head == null) {
        return new Node(data);
    } else {
        head.setNext(insert(head.getNext(), data));
    }
    return head;
}

public void printList(){
    LL_Iterator it= new LL_Iterator(first);
    printUsingIterator(it,it.next());

}

private static<E> void printUsingIterator (LL_Iterator it, E data){

    //VERDAMMT MAL RHEINFOLGE DER ANWEISUNGEN MACHT UNTERSCHIED
    System.out.print(data+"->");

    if (!it.hasNext()) {
        System.out.print(it.next()+"\n");//THIS WILL PRINT NULL!!!
        return;
    }
    printUsingIterator(it,it.next());
}

public int size() {
    return size(first);
}

private static int size(Node head) {
    if (head == null) {
        return 0;
    } else {
        return 1 + size(head.getNext());
    }
}

public boolean contains(E data) {
    return contains(first, data);
}

public static <E> boolean contains(Node head, E data) {
    if (head == null || data == null) {
        return false;
    }
    if (head.getData().equals(data)) {
        return true;
    }
    return contains(head.getNext(), data);
}

public int countIf(E t) {
    return countIf(first, t);
}

private static <E> int countIf(Node head, E t) {
    if (head == null ||t ==null) {
        return 0;
    }
    if (head.getData().equals(t)) {
        return 1 + countIf(head.getNext(), t);
    }

    return countIf(head.getNext(), t);
}


//TODO: WHY IM GETTING HERE AN OVERRIDE REQUEST FROM THE COMPILER??
//answer because im overriding the damn clone() of the list class which is shallow clone
public ListNode<E> depp_clone() {
    first = depp_clone(first);
    ListNode<E> copy = new ListNode<>(first);
    return copy;
}

private static Node depp_clone(Node head) {
    if (head == null) {
        return null;
    }

    Node temp = new Node(head.getData());
    temp.setNext(depp_clone(head.getNext()));

    return temp;
}

public ListNode shallow_clone (){
    ListNode<E> cloned=new ListNode<>(shallow_clone(first));
    return cloned;
}
private static Node shallow_clone(Node head) {
    if (head == null)
        return null;

    Node temp = new Node(head.getData());
    temp.setNext(head.getNext());  // Just copy the reference

    return temp;
}
StudentAccount4
  • 186
  • 1
  • 11
  • Does ListNode have a setNext() method? Can you provide a link to the class? It seems unclear this is a linked list. Could you write a method that prints the list using getNext() for iterating. This would clarify what is happening. – AndyMan Dec 01 '19 at 12:59
  • @AndyMan, thanks for replying again. I just edited the post pls take another look. and before you tell me that some method could be done iteratively its a homework and I must use recursion... – StudentAccount4 Dec 01 '19 at 13:08
  • I added equals() to the answer for both ListNode and Node. This should help with your unittests. – AndyMan Dec 01 '19 at 17:46

1 Answers1

0

Say head points to node0 which points to node1: head = node0 => node1

In a deep copy, create two new nodes 7 and 8: deepCopy = node7 => node6

In a shallow copy, create one new node 7 and copy reference to original node: shallowCopy = node7 => node1

private static Node shallow_clone(Node head) {
if (head == null) {
    return null;
}

Node temp = new Node(head.getData());
temp.setNext(head.getNext());  // Just copy the reference

return temp;

}

If the original node1 is changed, it will affect both the original and the shallow copy. it will not affect the deep copy.

Now for the terminology. What has been described is how to deep copy or shallow copy a node. It does not really make sense to shallow copy a linked list, because you are really just shallow coping a single node. Of course you can deep copy the list.

If it were an array, rather than a linked list, then you could shallow or deep copy.

To test these, override equals() and hashCode(). I would consider two lists equal if they have the same values. For two nodes to be equal, they should have the same value, and the rest of the list should be equal. If you don't override equals(), the implementation in Object is used. Object uses a bitwise comparison requiring the same references. You may want to look this up.

Also when overriding equals(), hashCode() needs to be overriden too. This is not directly related to the question, so you may want to look it after.

ListNode equals() and hashCode():

@Override
public boolean equals(Object otherObject) {
    // Objects are equal if they have the same value, and next has the same value
    if (otherObject instanceof ListNode) {
        ListNode other = (ListNode)otherObject;
        return first.equals(other.first);
    }
    else {
        return false;
    }
}
@Override
public int hashCode() {
    return first.hashCode();
}

Node equals() and hashCode():

@Override
    public boolean equals(Object otherObject) {
        // Objects are equal if they have the same value, && next has the same value
        if (otherObject instanceof Node) {
            Node other = (Node)otherObject;
            return data.equals(other.data) && ((next == null && ((Node) otherObject).getNext() == null) || next.equals(((Node) otherObject).next));
        }
        else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return data.hashCode();
    }
AndyMan
  • 397
  • 1
  • 7