CS 250 Computer Programming and Problem Solving - FALL 1998 |
---|
[ Home | Syllabus | Notes | Glossary | CS250 WEB Version Home Page ]
// A node in a singly linked list. template <class T> class Tnode { friend class Tlist<T>; // why? friend ostream & operator <<(ostream & os, const Tnode<T> & N); // PRE: type T has overloaded the insertion operator // POST: outputs data value in node
public: Tnode(); // POST: create node with next pointer NULL // the value field will use its default constructor Tnode( const T & val ); // PRE: type T has a copy constructor // POST: create node with NULL next pointer // and value set to "val" Tnode<T> * Next() const; // POST: returns pointer to successor node
// why not a get/set of the value field?? private: T value; // data stored in node Tnode * next; // points to next node };
// A singly linked list of Tnode objects. template <class T> class Tlist { public: Tlist(); ~Tlist(); bool Advance(); // Return 0 if current position is already at // the end of the list; otherwise, increment // current and return 1. void Append( const T & nodeVal ); // Add a new node to the end of the list. void Clear(); // Remove all nodes. T Get() const; // Get the data at the current position. void GoLast(); // Set current to the last node in the list. void GoTop(); // Set current to the header node. void InsertAfter( const T & nodeVal ); // Insert new node after current one. int IsEmpty() const; // Return 1 if the list is empty; otherwise, // return 0. void Prepend( const T & nodeVal ); // Insert a node at the beginning of the list. void Replace( const T & newVal ); // Replace the data in the current node. friend ostream & operator <<(ostream &, const Tlist<T> &); private: Tnode<T> * head; // dummy head node Tnode<T> * tail; // dummy tail node Tnode<T> * current; // current position };
Implementation of Tnode
//............Tnode<T> class ............ template <class T> Tnode<T>::Tnode() { next = NULL; }
template <class T> Tnode<T>::Tnode( const T & val ): value(val)// use non-default constructor { next = NULL; }
template <class T> Tnode<T> * Tnode<T>::Next() const // can you parse this? { return next; } template <class T> ostream & operator <<( ostream & os, const Tnode<T> & N ) { os << N.value << ','; return os; }
//............ Tlist<T> class ............ template <class T> Tlist<T>::Tlist() { head = new Tnode<T>; // dummy nodes avoid special cases at the ends tail = new Tnode<T>; head->next = tail; tail->next = head; current = head; } template <class T> Tlist<T>::~Tlist() { Clear(); delete head; delete tail; } template <class T> bool Tlist<T>::Advance() { if( !current ) throw NoCurrentNode(); // we'll explain this later if( current->next != tail ) { current = current->next; return true; } return false; } template <class T> void Tlist<T>::Append( const T & nodeVal ) { GoLast(); InsertAfter( nodeVal ); } template <class T> void Tlist<T>::Clear() { current = head->next; // why not just head? while( current != tail ) { head->next = current->next; // use as temp delete current; current = head->next; } current = head; head->next = tail; // is this necessary? } template <class T> int Tlist<T>::IsEmpty() const { return head->next == tail; // what is being tested here? } template <class T> T Tlist<T>::Get() const { if( !current ) throw NoCurrentNode(); return current->value; } template <class T> void Tlist<T>::GoLast() //PRE: current cannot point to tail or else what? { if( !current ) throw NoCurrentNode(); while( current->next != tail ) current = current->next; } template <class T> void Tlist<T>::GoTop() { current = head; } template <class T> void Tlist<T>::InsertAfter( const T & nodeVal ) { if( !current ) throw NoCurrentNode(); Tnode<T> * p = new Tnode<T>( nodeVal ); p->next = current->next; // normal list insertion current->next = p; current = p; } template <class T> void Tlist<T>::Prepend( const T & nodeVal ) { GoTop(); InsertAfter( nodeVal ); } template <class T> void Tlist<T>::Replace( const T & newVal ) { if( !current ) throw NoCurrentNode(); current->value = newVal; } template <class T> ostream & operator <<( ostream & os, const Tlist<T> & S ) { if( S.IsEmpty()) return os; Tnode<T> * p = S.head->Next(); while( p != S.tail ) { os << *p; p = p->Next(); } os << endl; return os; }