//====================================================================== // File: list.h // Author: Timothy A. Budd // Description: This file contains the interface of the list // classes. // // Copyright (c) 1992 by Timothy A. Budd. All Rights Reserved. // may be reproduced for any non-commercial purpose //====================================================================== #ifndef LIST_H #define LIST_H #include #include "iterator.h" #include //---------------------------------------------------------------------- // class list // arbitrary size lists of elements // permits insertion and removal only // from the front of the list //---------------------------------------------------------------------- template class BuddLink; template class listIterator; template class list { public: // constructors list(); list(const list & source); virtual ~list(); // operations void add(T value); virtual void deleteAllValues(); list * duplicate() const; T & firstElement() const; virtual int includes(T value) const; int isEmpty() const; virtual void removeFirst(); unsigned int length() const; void reverse(); T & operator [](unsigned int); T pop(); int operator == (const list & other) const; list & operator = (const list & right); protected: // data field BuddLink * ptrToFirstLink; // friends friend class listIterator; }; //---------------------------------------------------------------------- // class BuddLink // facilitator for operations on lists // maintains a single element for the linked list class //---------------------------------------------------------------------- template class BuddLink { public: // insert a new element following the current value BuddLink * insert(T val); private: // constructor BuddLink(T linkValue, BuddLink * nextPtr); BuddLink(const BuddLink &); // duplicate BuddLink * duplicate() const; // data areas T value; BuddLink * ptrToNextLink; // friends friend class list; friend class listIterator; }; //---------------------------------------------------------------------- // class listIterator // implements iterator protocol for linked lists // also permits removal and addition of elements //---------------------------------------------------------------------- template class listIterator : public iterator { public: // constructor listIterator(list & aList); listIterator(const listIterator &); // iterator protocol virtual int init(); virtual T & operator ()(); virtual int operator !(); virtual int operator ++(); virtual void operator =(T value); // new methods specific to list iterators void removeCurrent(); void addBefore(T newValue); void addAfter(T newValue); void cloneFrom(listIterator &); int nextExists() { return (currentLink != 0 && currentLink->ptrToNextLink != 0); } T & nextItem() { assert(nextExists()); return currentLink->ptrToNextLink->value; } protected: // data areas BuddLink * currentLink; BuddLink * previousLink; list & theList; }; //---------------------------------------------------------------------- // class orderedList // a list structure where each element // is maintained in sequence based on the // less-than comparison operator //---------------------------------------------------------------------- template class orderedList : public list { public: // change the addition method void add(T value); }; //---------------------------------------------------------------------- // class doubleEndedList // a variation on lists - can add elements to end // as well as to front //---------------------------------------------------------------------- template class doubleEndedList : public list { public: // constructors doubleEndedList (); doubleEndedList (const doubleEndedList &); // override the following methods from class list virtual void add (T value); virtual void deleteAllValues (); virtual void removeFirst (); // add a new element to the end of the list void addToEnd (T value); protected: // data area -- link to end BuddLink * ptrToLastLink; }; //---------------------------------------------------------------------- // class list implementation //---------------------------------------------------------------------- template list::list() : ptrToFirstLink(0) { // no further initialization } template list::~list() { // empty all elements from the list deleteAllValues(); } template void list::add(T val) { // add a new value to the front of a linked list ptrToFirstLink = new BuddLink(val, ptrToFirstLink); assert(ptrToFirstLink != 0); } template void list::deleteAllValues() { // clear all items from the list BuddLink * next; for (BuddLink * p = ptrToFirstLink; p != 0; p = next) { // delete the element pointed to by p next = p->ptrToNextLink; p->ptrToNextLink = 0; delete p; } // mark that the list contains no elements ptrToFirstLink = 0; } template list * list::duplicate() const { list * newlist = new list; assert(newlist != 0); // copy list if (ptrToFirstLink) newlist->ptrToFirstLink = ptrToFirstLink->duplicate(); // return the new list return newlist; } template list::list(const list & source) { // duplicate elements from source list if (source.isEmpty()) ptrToFirstLink = 0; else { BuddLink * firstLink = source.ptrToFirstLink; ptrToFirstLink = firstLink->duplicate(); } } template T & list::firstElement() const { // return first value in list assert(ptrToFirstLink != 0); return ptrToFirstLink->value; } template T list::pop() { T answer = firstElement(); removeFirst(); return answer; } template int list::includes(T v) const { // loop to test each element for (BuddLink * p = ptrToFirstLink; p; p = p->ptrToNextLink) if (v == p->value) return 1; // not found return 0; } template int list::isEmpty() const { // test to see if the list is empty // list is empty if the pointer to the first link is null return ptrToFirstLink == 0; } template void list::removeFirst() { // make sure there is a first element assert(ptrToFirstLink != 0); // save pointer to the removed node BuddLink * p = ptrToFirstLink; // reassign the ptrToFirstLink node ptrToFirstLink = p->ptrToNextLink; // recover memory used by the first element delete p; } template void list::reverse() { // reverse the list. We do this by popping each element off of the // list and pushing it onto the result list. Finally, the result is // assigned back to be the original list. BuddLink * result = 0; BuddLink * current; while (ptrToFirstLink) { // pop first element into current current = ptrToFirstLink; ptrToFirstLink = current->ptrToNextLink; // push current onto result current->ptrToNextLink = result; result = current; } ptrToFirstLink = result; } template unsigned int list::length() const { // compute the length of the list unsigned int answer = 0; BuddLink * ptr = ptrToFirstLink; while (ptr) { answer++; ptr = ptr->ptrToNextLink; } return answer; } template T & list::operator [] (unsigned int index) { // return the nth element of a list, treating the list as an indexable structure. // returning a reference allows assignment to the value. BuddLink * ptr = ptrToFirstLink; while (ptr && (index > 0)) { index--; ptr = ptr->ptrToNextLink; } assert(ptr); return ptr->value; } template int list::operator == (const list & other) const { // two lists are equal if all of their elements are equal BuddLink * ourptr = ptrToFirstLink; BuddLink * otherptr = other.ptrToFirstLink; for (; ourptr && otherptr; ourptr = ourptr->ptrToNextLink, otherptr = otherptr->ptrToNextLink) { if (!(ourptr->value == otherptr->value)) return 0; } // both lists should have ended at the same time. return (!ourptr && !otherptr); } template list & list::operator = (const list & other) { if (this == &other) { // self-assignment, do nothing return *this; } else { // Deep copy on assignment // first, release any old list. if (ptrToFirstLink) { deleteAllValues(); } if (other.ptrToFirstLink) { ptrToFirstLink = other.ptrToFirstLink->duplicate(); } else { ptrToFirstLink = 0; } } return *this; } //---------------------------------------------------------------------- // class link implementation //---------------------------------------------------------------------- template BuddLink * BuddLink::insert(T val) { // insert a new link after current node ptrToNextLink = new BuddLink(val, ptrToNextLink); // check that allocation was successful assert(ptrToNextLink != 0); return ptrToNextLink; } template BuddLink::BuddLink(T val, BuddLink * nxt) : value(val), ptrToNextLink(nxt) { // create and initialize a new link field } template BuddLink::BuddLink(const BuddLink & source) : value(source.value), ptrToNextLink(source.ptrToNextLink) { } template BuddLink * BuddLink::duplicate() const { BuddLink * newlink; // if there is a next field. copy remainder of list if (ptrToNextLink != 0) newlink = new BuddLink(value, ptrToNextLink->duplicate()); else newlink = new BuddLink(value, 0); // check that allocation was successful //assert(newlink != 0); return newlink; } //---------------------------------------------------------------------- // class listIterator implementation //---------------------------------------------------------------------- template listIterator::listIterator(list & aList) : theList(aList) { // create and initialize a new list init(); } template listIterator::listIterator(const listIterator & x) : theList(x.theList) { init(); } template int listIterator::init() { // set the iterator to the first element in the list previousLink = 0; currentLink = theList.ptrToFirstLink; return currentLink != 0; } template T & listIterator::operator ()() { // return value of current element // check to see if there is a current element assert(currentLink != 0); // return value associated with current element return currentLink->value; } template int listIterator::operator !() { // test for termination of the iterator // if current link references a removed value, // update current to point to next position if (currentLink == 0) if (previousLink != 0) currentLink = previousLink->ptrToNextLink; // now see if currentLink is valid return currentLink != 0; } template int listIterator::operator ++() { // move current pointer to nect element // special processing if current link is deleted if (currentLink == 0) { if (previousLink == 0) currentLink = theList.ptrToFirstLink; else currentLink = previousLink->ptrToNextLink; } else { // advance pointer previousLink = currentLink; currentLink = currentLink->ptrToNextLink; } // return true if we have a valid current element return currentLink != 0; } template void listIterator::operator =(T val) { // modify value of current element assert(currentLink != 0); // modify value of the current link currentLink->value = val; } template void listIterator::removeCurrent() { // remove the current element from a list // make sure there is a current element assert(currentLink != 0); // case 1, removing first element if (previousLink == 0) theList.ptrToFirstLink = currentLink->ptrToNextLink; // case 2, not removing the first element else previousLink->ptrToNextLink = currentLink->ptrToNextLink; // delete current node delete currentLink; // and set current pointer to null currentLink = 0; } template void listIterator::addBefore(T val) { // add a new element to list before current value // case 1, not at start if (previousLink) previousLink = previousLink->insert(val); // case 2, at start of list else { //theList.list::add(val); // g++ change theList.add(val); previousLink = theList.ptrToFirstLink; currentLink = previousLink->ptrToNextLink; } } template void listIterator::addAfter(T val) { // a a new element to list after current value // case 1, not at start if (currentLink != 0) currentLink->insert(val); // case 2, at end of list else if (previousLink != 0) currentLink = previousLink->insert(val); // case 3, start of list else //theList.list::add(val); // g++ change theList.add(val); } template void listIterator::cloneFrom (listIterator & old) { // old is another iterator of the same type. // make it point to the same spot as self assert (&theList == &old.theList); // copy the values of the pointers from old currentLink = old.currentLink; previousLink = old.previousLink; } //---------------------------------------------------------------------- // class orderedList implementation //---------------------------------------------------------------------- template void orderedList::add(T val) { // add a new value to an ordered list // loop over values smaller than current listIterator itr(*this); for (itr.init(); !itr; ++itr) if (val < itr()) { // found location to insert value itr.addBefore(val); return; } // add to end of list if not yet inserted itr.addBefore(val); } //---------------------------------------------------------------------- // class doubleEndedList implementation //---------------------------------------------------------------------- template doubleEndedList::doubleEndedList() : list() { ptrToLastLink = 0; } template doubleEndedList:: doubleEndedList(const doubleEndedList & x) : list(x), ptrToLastLink(x.ptrToLastLink) { } template void doubleEndedList::add(T val) { // add an element to the front of a double ended list // only need to handle addition to empty list if (isEmpty()) { list::add(val); ptrToLastLink = ptrToFirstLink; } else list::add(val); } template void doubleEndedList::addToEnd(T val) { // add a new element to the end of a double ended list // if there is an end, add to it if (ptrToLastLink != 0) ptrToLastLink = ptrToLastLink->insert(val); // otherwise, just add to front else add(val); } template void doubleEndedList::deleteAllValues() { // delete all values from collection // invoke the list method to do the actual work list::deleteAllValues(); // then set the pointer to the last element to zero ptrToLastLink = 0; } template void doubleEndedList::removeFirst() { // remove the first element from double ended list // invoke the method from list to do the work list::removeFirst(); // only do something different if we removed last element if (isEmpty()) ptrToLastLink = 0; } // // ==========insertion sort -- this is done differently by // cfront and g++ #ifdef __GNUG__ #include "list.C" #endif #ifndef __GNUG__ #include "vector.h" template void listInsertionSort(vector & v); template ostream & operator << (ostream & ostr, list & target); template istream & operator >> (istream & istr, list & target); #endif #endif