Circular Linked List

Chapter: Circular Linked List

My implementation of a Circular Linked List uses a plain linked structure inside of it.

Here is the code I used for the linked structure:

    /** class List < T > can be an inner class inside of CircularList 
     *  -- basic linked list node
     * 
     * @author Rhys Price Jones
     * @version 15x07
     */
    class List < T > {
        private T data;
        private List < T > next;
        public List(T stuff, List < T > next) {
            data = stuff;
            this.next = next;
        }
        public T getData() {
            return data;
        }
        public List < T > getNext() {
            return next;
        }
        public void setNext(List < T > n) {
            next = n;
        }
    }

All you have to do to get it to compile is to close up the spaces I had to insert around the angle brackets for the generic type T. As I mention in the documentation, you may want to hide this class by defining it as an inner class inside the CircularList class that's coming soon.

The picture shows a circular linked list with two handles, one called head to the "first" node (whatever "first" may mean) and another called tail directly referring to the "last" (whatever "last" may mean) node.

Q. 3
Do we really need two handles?


The fewer handles we have, the less work will be involved in any of our operations. We do not need both tail and head.

Q. 4
So which shall we keep?


Here is my code for CircularList, except that you have to write your own rotate() method.


/**
 * CircularList.
 * 
 * @author rpj 
 * @version 15x07
 */
public class CircularList < T >  
{
    
    protected List < T >  tail;
    /*  
     * We maintain a pointer to the tail which, in turn, points to the head
     * If we ever need the head, it is simply tail.getNext()
     *   head                                  tail
     *    1   ->   2  ->  3   ->   ...      -> 42   -|
     *   ^                                           |
     *   |-------------------------------------------|
     */


    public CircularList()
    {
        tail = null;
    }

    /**
     * add
     * 
     * @param  stuff   to be added
     */
    public void add(T stuff)
    {
        if (tail == null) {
            tail = new List < T > (stuff, null);
            tail.setNext(tail);
        }
        else {
            tail.setNext(new List < T > (stuff, tail.getNext()));
            tail = tail.getNext();
        }
    }
    
    /**
     * peek
     * 
     * @return  thing at head
     */ 
    public T peek()
    {
        return (tail == null) ? null : tail.getNext().getData();
    }
    
    /**
     * rotate
     * 
     * advance to point to next item
     */
    public void rotate() 
    {
        // be careful of the empty list
    }
    
    /**
     * removeFromHead
     * remove item at head of list
     */
    public void removeFromHead() {
        if (tail.getNext() == tail) tail = null; // removed last item
        else {
            List < T >  head = tail.getNext();
            tail.setNext(head.getNext());
        }
    }
}

Notice that it is all pretty straightforward. The only tricky thing is dealing with the empty list. Remember also to close the spaces around the generic type arguments.


Exercise 1

Finish the code by writing the rotate() method. Here is a class for testing your resulting circular list:

/**
 * TestList
 * 
 * @author rpj
 * @version15x07
 */
public class TestList
{
        
        public static void main(String[] args) 
        {
                CircularList < String > cl = new CircularList < String > ();
                int i;
                for (String s : args) cl.add(s);
                for (i=0; i < args.length*3; i++) {
                    System.out.println(cl.peek());
                    cl.rotate();
                }
        }
}

As usual, close the spaces. If all is well, this program should print three sets of your commandline args, one per line.


rhyspj@gwu.edu