Is this linked list implemented circularly?

Noah :

This is my first post on here! I am a CS student, so I'm still learning. If you have any advice or pointers (haha..!) to give as far as structuring my code or general practice, I'd appreciate any feedback!

I was given an assignment to re-implement the Queue class in java (https://docs.oracle.com/javase/7/docs/api/java/util/Queue.html) using a circular linked list. My submission is attached to this question. I received a zero on the assignment -- according to the grader my implementation of the linked list is not circular.

I do not want to come off as egotistical or too self-assured, because I obviously have no idea what I'm doing to some degree, but in lines 155 through 161 I have commented-out a section that prints out the data of the next link in the list. To my knowledge, the nodes in the list are linked circularly, because they continue to print the first node's data even after the last node's data has been printed.

For example (and I know this segment looks messy, I only have it set like this for the purpose of debugging -- this is actually the section I have commented-out my actual code):

System.out.println("next: " + cursor.getNext().getData());
System.out.println("next.next: " + cursor.getNext().getNext().getData());
System.out.println("next.next.next: " + cursor.getNext().getNext().getNext().getData());
System.out.println("next.next.next.next: " + cursor.getNext().getNext().getNext().getNext().getData());

prints:

next: 45

next.next: 71

next.next.next: 3

next.next.next.next: 45

when there are three nodes containing data entered in the list.

Furthermore, the add method starting on line 30 assigns the next node after the tail of the list to the head (as opposed to a null value), thus the list should cycle circularly, correct? Here's a segment:

Node<T> node = new Node<T>(element);
if(isEmpty() == true){
    head = node;
}else{tail.setNext(node);}

tail = node;
node.setNext(head);

I guess my question is: in what way is this not implemented circularly?

Again it totally is possible that I have no idea what I am talking about, but to my knowledge, this is in fact a circular linked list.

Thank you in advance for any help!

Full code (the three classes are CircularLinkedQueue, Node, and CircularLinkedListTest, respectively):

CircularLinkedQueue:

import java.util.NoSuchElementException;

public class CircularLinkedQueue<T> {
int count = 0;
private Node<T> head = null;
private Node<T> tail = head;

public CircularLinkedQueue(){
    Node<T> node = new Node<T>();
    tail = node;
}

/* Inserts the specified element into this queue if it is
 * possible to do so immediately without violating capacity
 * restrictions, returning true upon success and throwing
 * an IllegalStateException if no space is currently available.
 */
public boolean add(T element){
    try{
        Node<T> node = new Node<T>(element);
        if(isEmpty() == true){
            head = node;
        }else{tail.setNext(node);}

        tail = node;
        node.setNext(head);
        count++;
        return true;
    }catch(Exception all){
        Node<T> node = new Node<T>(element);
        if(element == null){throw new NullPointerException("Specified 
element is null.");}
        else if(element.getClass().getName() != 
node.getData().getClass().getName()){
            throw new ClassCastException
            ("Class of specified element prevents it from being added.");
        }
        return false;
    }
}
/* Retrieves, but does not remove, the head of this queue.
 * This method differs from peek only in that it throws
 * an exception if this queue is empty.
 */
public T element(){
    Node<T> cursor;
    if(isEmpty() != true){
        cursor = head;
    }else{throw new NoSuchElementException("No such element exists.");}
    return cursor.getData();

}
/*
Inserts the specified element into this queue if it is possible
to do so immediately without violating capacity restrictions.
When using a capacity-restricted queue, this method is generally
preferable to add(E), which can fail to insert an element only
by throwing an exception.
/*
public boolean offer(T element){
    try{
        Node<T> node = new Node<T>(element);
        if(isEmpty() == true){
            head = node;
        }else{tail.setNext(node);}

        tail = node;
        node.setNext(head);
        count++;
        return true;
    }catch(Exception all){return false;}
}

/* Retrieves, but does not remove, the head of this queue,
 * or returns null if this queue is empty.
 */
public T peek(){
    Node<T> cursor;
    //set cursor to head if not empty, create new null node otherwise
    if(isEmpty() != true){
        cursor = head;
    }else{cursor = new Node<T>(); cursor.setData(null);}
    //return null if no data is stored
    return cursor.getData();
}
/* Retrieves and removes the head of this queue,
 * or returns null if this queue is empty.
 */
public T poll(){
    Node<T> cursor = head;
    if(isEmpty() != true){
        if(count <= 1){
            head.setNext(null);
            head = head.getNext();
            tail = head;
            count--;
            return null;
        }else{
            //cursor = head;
            head = head.getNext();
            tail.setNext(head);
        }
    }else{cursor = new Node<T>(); cursor.setData(null);}
    count--;
    return cursor.getData();
}
/* Retrieves and removes the head of this queue.
 * This method differs from poll only in that it
 * throws an exception if this queue is empty.
 */
public T remove(){
    Node<T> cursor;
    if(isEmpty() != true){
        if(count <= 1){
            head.setNext(null);
            head = head.getNext();
            tail = head;
            count--;
            return null;
        }else{
            cursor = head;
            head = head.getNext();
            tail.setNext(head);
        }
    }
    else{throw new NoSuchElementException("No such element exists.");}
    count--;
    return cursor.getData();
}
//returns whether the list is empty or not
public boolean isEmpty(){return head == null;}

/* This method puts all the values of the circular linked list
 * into a String type for output purposes.
 */
@Override
public String toString(){
    int cycles = count;
    String s = "";
    Node<T> cursor = head;
    while(cycles > 0){
        s = s + cursor.getData() + "\n";
        cursor = cursor.getNext();
        cycles--;
    }
    /*
     * these lines print as expected & exist only for debugging purposes
    System.out.println("next: " + cursor.getNext().getData());
    System.out.println("next.next: " + 
cursor.getNext().getNext().getData());
    System.out.println("next.next.next: " + 
cursor.getNext().getNext().getNext().getData());
    System.out.println("next.next.next.next: " + 
cursor.getNext().getNext().getNext().getNext().getData());
    */
    return s;
}
//returns the length of the list
public int getCount(){return count;}
}

Node:

public class Node<T> {
T data;
Node<T> next;

public Node(){data = null;}

public Node(T data){this.data = data;}

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

public void setNext(Node<T> nextNode){next = nextNode;}

public T getData(){return data;}

public Node<T> getNext(){return next;}
}

CircularLinkedListTest:

public class CircularLinkedListTest<T>{

public static void main(String[] args) {
    /* demonstrates creation of new circular linked lists/linked queues,
     * uses two different data types
     */
    CircularLinkedQueue<Integer> c1 = new CircularLinkedQueue<Integer>();
    CircularLinkedQueue<String> c2 = new CircularLinkedQueue<String>();
    //demonstrate add and offer methods detailed in Queue interface
    c1.add(3);
    c1.offer(45);
    c1.offer(71);
    c2.add("hello");
    c2.offer("good evening");
    c2.offer("how do you do");
    //demonstrates a toString method and prints after data has been added
    System.out.println("c1.toString(): \n" + c1.toString());
    System.out.println("c2.toString(): \n" + c2.toString());
    /* demonstrates the remove and poll methods, prints out the values in 
the list,
     * poll method returns null when implemented, isEmpty method shows the
     * nodes are truly being removed from the list after poll or remove
methods are
     * called
     */
    c1.remove();
    c2.remove();
    c2.remove();
    System.out.println("c1.toString(): \n" + c1.toString());
    System.out.println("c2.poll(): " + c2.poll());
    System.out.println("c2.getCount(): " + c2.getCount());
    System.out.println("c2.isEmpty(): " + c2.isEmpty());
    System.out.println("");
    //re-add data to c2
    c2.offer("howdy");
    c2.offer("hi there");
    //reprint c2, getCount and isEmpty to prove updated data values
    System.out.println("c2.toString(): \n" + c2.toString());
    System.out.println("c2.getCount(): " + c2.getCount());
    System.out.println("c2.isEmpty(): " + c2.isEmpty());
    System.out.println("");
    /* demonstrate peek and element functions by printing out most
     * recent items in the linked queue
     */
    System.out.println("c1.peek(): " + c1.peek());
    System.out.println("c2.element(): " + c2.peek());
    System.out.println("");
    //remove items from c1 to show peek returns null when list is empty
    c1.remove();
    c1.remove();
    System.out.println("c1.peek(): " + c1.peek());
    System.out.println("c1.getCount(): " + c1.getCount());
    System.out.println("c1.isEmpty(): " + c1.isEmpty());

    //all methods in queue interface have been demonstrated
}

}

Thank you again in advance for any help!

janos :

I received a zero on the assignment -- according to the grader my implementation of the linked list is not circular.

I find that assessment a bit harsh. Looking from the outside, your class behaves circular: it is able to add new values in O(1) time, and the "last" value has a link to the "first", closing the loop.

I guess my question is: in what way is this not implemented circularly?

In a truly circular implementation, I wouldn't expect to see notions of "head" and "tail". After all, a circle has no beginning and no end. It may have a current element, with links to next and previous elements. And maybe this is what was required. Looking from the inside, this implementation looks very similar to a run-of-the-mill linked list, with fast access to tail. It would be best to ask the grader!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=102368&siteId=1