1

I am trying to implement a shallow copy for a Linked Stack, but I am failing the J-unit test provided by my instructor.

I have tried to implement a for loop that will cycle through the stack top to bottom and create a reference for each node to the new list on the pass through. I've added a print statement and the data references seem to match up,but my test are still failing.

public class LinkedStack<E> implements Stack<E>{

private int size = 0;

// Unlike the book, we'll use an inner class for our Node.
// Its two data members can be accessed directly by the Stack
// code, so we don't need setters and getters.
protected class Node{

    E data; 
    Node next;
}

protected Node top; // not public, but can still be seen by other classes in the
                    // csci211 package.

/** Create an empty stack.
 * 
 */
public LinkedStack(){

    top = null;
}

@Override // see interface for comments.
public void push(E e){
    //TODO 75
    Node temp = new Node();
    temp.data = e;
    temp.next = top;
    top = temp;
}

@Override // see interface for comments.
public E pop(){
    if (top==null) {
        throw new NoSuchElementException("Cannout pop an Empty Stack.");
    }
    E topvar;
    topvar = top.data;
    top = top.next;
    return topvar;
}

@Override // see interface for comments.
public E peek() {
    if (top == null) {
        throw new NoSuchElementException("Cannout peek an Empty Stack.");
    }
    //E topvar;
    //topvar = top.data;
    return top.data;
}

/** Retrieve the number of elements on this stack.
 * 
 * @return an int containing the number of elements
 */ 
public int size() {

    return this.size;

}

/** An Iterator for our LinkedStack.
 * 
 * @author rhodes
 *
 */
 class LinkedStackIterator implements Iterator<E> {

    LinkedStack<E>.Node next;  // the book calls this "current"

    public LinkedStackIterator(LinkedStack<E> s){

        next = s.top;
    }

    @Override
    public boolean hasNext() {
        return top != null;
        //TODO 100
        //return false;
    }

    @Override
    public E next() {

        if (!hasNext()) throw new NoSuchElementException();
        E data = top.data;
        top = top.next; 
        return data;

        //TODO 100

        //return null;

    }


}


@Override
public void add(E element) {

    push(element);

}

@Override
public void clear() {

    this.top = null;
    this.size = 0;
}
@Override
public List<E> shallowCopy() {

     LinkedStack<E> newstack = new LinkedStack<E>();
     ArrayList<E> Alist = new ArrayList<E>();
    //Iterate through while we haven't hit the end of the stack
    Node newtest = top;
    while (newtest != null) {
        Alist.add(newtest.data);
        newtest = newtest.next;
    //TODO 85
    }
    for(int i = Alist.size()-1;i>=0;i--) {
        newstack.push(Alist.get(i));
    }
    return newstack;
}

@Override
public Iterator<E> iterator() {

    return new LinkedStackIterator(this);
}

}

This is the Junit tests that I am failing

@Test
@SuppressWarnings("deprecation") // for Date.setHours(), Date.getHours()
public void shallowCopy1() {

    // let's use Date, since it's mutable.
    LinkedStack<Date> s = new LinkedStack<Date>();

    Date d = new Date();
    d.setHours(17);

    s.push(d);

    LinkedStack<Date> s2 =(LinkedStack<Date>) s.shallowCopy();

    Date d2=s2.pop();

    // The shallow copy should contain references to the same objects
    // as the original.
    assertTrue(d == d2);

    // So, we can change the Date in the original list using the Date that
    // came from the shallow copy.
    d2.setHours(14);
    assertTrue(d.getHours() == 14);
    // I don't usually put two asserts in one test, but this seems like 
    // an instructive example.
}

@Test(expected=NoSuchElementException.class)
public void shallowCopy2() {


    LinkedStack<Integer> s1 = new LinkedStack<Integer>();

    for(int i=0; i<10; i++) {

        s1.push(i);
    }       

    LinkedStack<Integer> s2 =(LinkedStack<Integer>) s1.shallowCopy();

    s2.push(10); // supposed to only affect s2
    s2.push(11); // supposed to only affect s2

    for(int i=0; i<10; i++) {

        s1.pop();
    }       

    int last = s1.pop(); // should throw

}


@Test
public void shallowCopy3() {

    LinkedStack<Integer> q1 = new LinkedStack<Integer>();

    for(int i=0; i<10; i++) {

        q1.push(i);
    }       

    LinkedStack<Integer> q2 =(LinkedStack<Integer>) q1.shallowCopy();

    //Let's check that the order of elements is correct in the copy.
    for(int i=0; i<10; i++) {

        int v1=q1.pop();
        int v2=q2.pop();

        assertEquals(v1, v2);
    }               
}

If anyone could point me in the right direction I would appreciate it. This is a Homework Problem.

  • Hint: how many `Node` objects are you creating in `shallowCopy()`? The answer may surprise you! – Kayaman Sep 24 '19 at 17:01
  • @Kayaman Would I not create a new node referencing every existing node? It looks as if I am currently only creating a single node and rewriting the reference for it. If so would that look something like this. Node s = new Node(top) <- in my while loop. – Billathekilla Sep 24 '19 at 18:38
  • Exactly. You're iterating the list to be copied with `top = top.next`, but the copy of your list only has 1 node, and you keep reassigning the `s.data`, so your copy will be a single element list, containing the data in the last node of the list you were trying to copy. – Kayaman Sep 25 '19 at 06:24

2 Answers2

0

Shallow copies duplicate as little as possible. A shallow copy of a collection is a copy of the collection structure, not the elements. With a shallow copy, two collections now share the individual elements.

enter image description here

Deep copies duplicate everything. A deep copy of a collection is two collections with all of the elements in the original collection duplicated.

enter image description here

protected class Node{

    E data; 
    Node next;

    Node(Node node){
        this.next = node.next;
        this.data = node.data;
    }
}


@Override
public List<E> shallowCopy() {

    // LinkedStack<E> newStack = new LinkedStack<E>();
    //Iterate through while we haven't hit the end of the stack
    Node s = new Node(top);

     while (top.next != null) {
          s.next = new Node(top.next);
          top = top.next;
          s = s.next;
     }
     System.out.println("FINSHED!");
     return (List<E>) s;
 }


@Override
public List<E> shallowCopyWithoutUpdatingNodeClass() {

    // LinkedStack<E> newStack = new LinkedStack<E>();
    //Iterate through while we haven't hit the end of the stack
    Node s = new Node(top);

     while (top.next != null) {
          s.next = new Node();
          s.next.next = top.next;
          s.next.data = top.data;
          top = top.next;
          s = s.next;
     }
     System.out.println("FINSHED!");
     return (List<E>) s;
 }

Answer Inspired by :- What is the difference between a deep copy and a shallow copy?

SSP
  • 2,650
  • 5
  • 31
  • 49
  • That won't quite work. You've just created a new top node for the new list, but you need to create all new nodes. The contents' references are then copied. Otherwise they would be able to corrupt each other, when a node is removed for example. – Kayaman Sep 24 '19 at 17:10
  • Why would we need to copy all reference. When we are processing stack, top will be good enough for shallow copy. Its my understanding. – SSP Sep 24 '19 at 17:13
  • Is that wrong? because by the help of we can traverse whole list. and if any changes happen. it will reflect on both head. – SSP Sep 24 '19 at 17:14
  • Because when you make a shallow copy of `stack1`, and pop it, you don't want the original stack to get popped. That's why the whole structure of the stack needs to be copied. It's the contents in the nodes that are just reference copies. – Kayaman Sep 24 '19 at 17:14
  • would not that be a function of deep copy? shallow copy is like pass by reference. right? any changes happen anywhere, It should reflect on all reference variable. – SSP Sep 24 '19 at 17:16
  • @Kayaman just trying to get my concept straight. don't take it other wise. I am really confused about it . – SSP Sep 24 '19 at 17:18
  • No. It even says in your answer "is a copy of the collection structure". But your code doesn't copy the collection structure. In fact your code creates a new `Node`, then throws the just created node away by assigning `s = top`, then returns `s` (i.e. `top`). Your code is all wrong, and you need to re-read about shallow copy. – Kayaman Sep 24 '19 at 17:18
  • Your so called shallow copy can be simplified to `return (List) top;`. That's not shallow copy, that's a copy of the reference. No structure copied, only 1 object existing. – Kayaman Sep 24 '19 at 17:20
  • My earlier understanding was based on geeksforgeek site. they got it wrong. so do i . – SSP Sep 24 '19 at 17:40
  • Implementing the Node constructor as you have mentioned would require changing of my push method. Is there another way or is this the proper way? – Billathekilla Sep 24 '19 at 18:27
  • You can do in while loop. but that not good practice and prone to error. – SSP Sep 24 '19 at 18:48
  • This does not work with my current implementation. I do not believe that my Prof wants us to modify the Node class. – Billathekilla Sep 24 '19 at 19:37
  • I have found a solution that passes two of my three test. @SSP your solution did not work for me. – Billathekilla Sep 25 '19 at 19:50
0

The original problem was the node data was just being overwritten not creating a new node. Then the stack was backwards. Finally I implement and array to reverse the stack.

@Override
public List<E> shallowCopy() {

     LinkedStack<E> newstack = new LinkedStack<E>();
     ArrayList<E> Alist = new ArrayList<E>();
    //Iterate through while we haven't hit the end of the stack
    Node newtest = top;
    while (newtest != null) {
        Alist.add(newtest.data);
        newtest = newtest.next;
    //TODO 85
    }
    for(int i = Alist.size()-1;i>=0;i--) {
        newstack.push(Alist.get(i));
    }
    //System.out.println("FINSHED!");
    return newstack;
}