//====================================================================== // 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 //---------------------------------------------------------------------- // class list // arbitrary size lists of elements // permits insertion and removal only // from the front of the list //---------------------------------------------------------------------- template class link; 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(); protected: // data field link * ptrToFirstLink; // friends friend class listIterator; }; //---------------------------------------------------------------------- // class link // facilitator for operations on lists // maintains a single element for the linked list class //---------------------------------------------------------------------- template class link { public: // insert a new element following the current value link * insert(T val); private: // constructor link(T linkValue, link * nextPtr); link(const link &); // duplicate link * duplicate() const; // data areas T value; link * 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); protected: // data areas link * currentLink; link * 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 link * 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 link(val, ptrToFirstLink); assert(ptrToFirstLink != 0); } template void list::deleteAllValues() { // clear all items from the list link * next; for (link * 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 { link * firstLink = source.ptrToFirstLink; ptrToFirstLink = firstLink->duplicate(); } } template T list::firstElement() const { // return first value in list assert(ptrToFirstLink != 0); return ptrToFirstLink->value; } template int list::includes(T v) const { // loop to test each element for (link * 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 link * p = ptrToFirstLink; // reassign the ptrToFirstLink node ptrToFirstLink = p->ptrToNextLink; // recover memory used by the first element delete p; } //---------------------------------------------------------------------- // class link implementation //---------------------------------------------------------------------- template link * link::insert(T val) { // insert a new link after current node ptrToNextLink = new link(val, ptrToNextLink); // check that allocation was successful assert(ptrToNextLink != 0); return ptrToNextLink; } template link::link(T val, link * nxt) : value(val), ptrToNextLink(nxt) { // create and initialize a new link field } template link::link(const link & source) : value(source.value), ptrToNextLink(source.ptrToNextLink) { } template link * link::duplicate() const { link * newlink; // if there is a next field. copy remainder of list if (ptrToNextLink != 0) newlink = new link(value, ptrToNextLink->duplicate()); else newlink = new link(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) { // a 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); } //---------------------------------------------------------------------- // 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 # endif # ifndef __GNUG__ # include template void listInsertionSort(vector & v); # endif #endif