------------------------------------------------------------------------------
MC logo
Linked List Classes
[^] CSc 220 Home
------------------------------------------------------------------------------
[Introduction] [Boolean and Control] [Functions] [Arrays and Pointers] [Dynamic Arrays] [Array Errors] [Command Array] [Standard Containers] [Structs and Classes] [Automatic Pointer] [Multi-File Programs] [Copying Objects] [Templates] [Inheritance] [Plain C I/O] [Type Odds And Ends] [Plain C Strings] [File I/O]
[Bounded Safe Array] [Bounded Safe Array Driver] [PrintMe Class] [PrintMe2 Class] [PrintMeLots Class] [PrintMeLots2 Class] [PrintMe Test Driver] [Linked List Node Classes] [Linked List Classes] [Linked List Implementation] [Linked List Driver] [Expression Calculator]
linkedlist.h
#ifndef _LIST_
#define _LIST_

/*
 * Header file for single and double linked lists of integers.  This defines
 * four classes: OneWayList, TwoWayList, OneWayIter, and TwoWayIter.  The
 * XxxxIter classes are used to access the contents of the lists.  The list
 * classes themselves have minimal public interface, so are not much use
 * without the iterators.
 *
 * The public interface of each list type is the same.  Stated for OneWayList:
 *    OneWayList lis;           // Create a new, empty list.
 *    ~OneWayList()             // Clean up.
 *    lis.Print(ostream&);      // Print the list.
 *    strm << lis               // Calls lis.Print(strm)
 *
 * The iterator classes permit scanning through the list, and adding items.
 * An iterator has a current position, which is at one of the list members,
 * or "before", which is a current position before any list members.
 *    OneWayList slis;
 *    OneWayIter si(slis);      // Construct a new iterator in position
 *                              // "before" of list slis.
 *    si.Add(i);                // Add integer i to the list after current pos.
 *                              // Returns a reference to si.
 *    si << i;                  // Add integer i to the list after current pos,
 *                              // then make current pos at i.  Returns si ref.
 *    si.Val()                  // Value at curr location; zero at "before."
 *    si.Val(i);                // Set curr value to i.  Ignored at "before."
 *    *si                       // Same as si.Val().
 *    si.Rewind();              // Change current position to "before."
 *    si++   ++si               // Advance, return old or new value.
 *    si.Start()                // Tell if the position is "before."
 *    si.First()                // Tell if pos is the first list member.
 *    si.End()                  // Tell if pos is the last member of the list,
 *                              // or "before" if the list is empty.
 * The iterator class TwoWayIter contains the above, except it must be
 * constructed on a TwoWayList.  It then adds prefix and postfix versions of --
 * to move back through the list.  A OneWayIter may be constructed on a
 * TwoWayList, but should not be used to add.  (There is a simple, horrid hack
 * to make such construction illegal, and it should probably be added to the
 * class.  Ask me about it after we have discussed the example.)
 */
#include "linkednode.h"

// Single linked list class.
class OneWayList
{
        friend class OneWayIter;        // Iterator classes need access to
        friend class TwoWayIter;        // the protected Add(), but it should 
                                        // not be public.  They also need the
                                        // field head.
    protected:
        OneWayNode *head;               // Head of the list.

        // Add a node.
        void Add(OneWayNode *curr, OneWayNode *nd);
    public:
        // Construct an empty list.
        OneWayList()
        {
                head = NULL;
        }

        // Get rid of all the list nodes.
        ~OneWayList()
        {
                if(head != NULL)
                        head->Die();
        }

        // Print the list.
        void Print(ostream &o = cout) const;
};

// Doubly-linked list
class TwoWayList: public OneWayList
{
        friend class TwoWayIter;        // Needs the protected Add().
    protected:
        // Used by TwoWayIter to add nodes to the list.
        void Add(TwoWayNode *curr, TwoWayNode *nd);
    public:
        // Create a new, empty double-linked list.
        TwoWayList(): OneWayList() { }
        // Actually, this constructor is provided by default, so we don't
        // really need to give it.  The  :OneWayList()  syntax is used to
        // call a constructor for the base class.
};

// Iterator for the single linked list.
class OneWayIter
{
    protected:
        OneWayList &list;               // List being scanned.
        OneWayNode *curr;               // Current loc, or NULL for "before".
    public:
        // Construct one.  Note: The  :list(lis)  syntax is used to initialize
        // a field which is a reference.
        OneWayIter(OneWayList &lis): list(lis)
        {
                curr = NULL;
        }

        // Add an object to the list, after the current location.  Return the
        // iterator.
        OneWayIter& Add(int i)
        {
                list.Add(curr, new OneWayNode(i));
                return *this;
        }

        // Add, then advance the list.
        OneWayIter& operator <<(int i)
        {
                return ++Add(i);
        }

        // Discover the value at the current position.
        int Val();

        // Set the value at the current location.
        void Val(int i)
        {
                if(curr != NULL)
                        curr->Cont(i);
        }

        // Another way to discover the value at the current location.
        int operator*()
        {
                return Val();
        }

        // Go back to the beginning.
        void Rewind()
        {
                curr = NULL;
        }

        // Advance to next location in list.  If there is no next position,
        // the iterator does not advance.
        OneWayIter& operator++();       // Prefix, ++i.
        OneWayIter operator++(int)      // Postfix, i++.
        {
                OneWayIter retval = *this;
                ++(*this);
                return retval;
        }

        // Are you at the start (before the list)?
        bool Start()
        {
                return curr == NULL;
        }

        // Are you at the first member of the list?
        bool First()
        {
                return list.head != NULL && curr == list.head;
        }

        // Are you at the end?  I.e., is there nothing after?
        bool End()
        {
                return list.head == NULL ||
                                (curr != NULL && curr->Next() == NULL);
        }
};

// Iterator for the double-linked list.
class TwoWayIter: public OneWayIter
{
    public:
        // Construct a TwoWayIter by constructing the base class, then there is
        // no more to do.
        TwoWayIter(OneWayList &ref): OneWayIter(ref) { }

        // Add in the reverse scanning.
        TwoWayIter& operator--();       // Prefix, --i.
        TwoWayIter operator--(int)      // Postfix, i--.
        {
                TwoWayIter retval = *this;
                --(*this);
                return retval;
        }

        // Must change add.  Looks the same to the user, but has different
        // implementation details.
        TwoWayIter& Add(int i)
        {
                ((TwoWayList &)list).Add((TwoWayNode*)curr, new TwoWayNode(i));
                return *this;
        }

        // Another way to add.  
        TwoWayIter& operator <<(int i)
        {
                Add(i);
                return (TwoWayIter&)++(*this);
        }
};

// Printing.
inline ostream &operator<<(ostream &st, const OneWayList& li)
{
        li.Print(st);
        return st;
}


#endif