750 likes | 858 Views
Container Classes. Lesson #12. Note: CIS 601 notes were originally developed by H. Zhu for NJIT DL Program. The notes were subsequently revised by M. Deek. Content. Linked Lists (Template based) Doubly Linked Lists (Objects based) Iterator Class Applications of Linked Lists. Lists.
E N D
Container Classes Lesson #12 Note: CIS 601 notes were originally developed by H. Zhu for NJIT DL Program. The notes were subsequently revised by M. Deek
Content • Linked Lists (Template based) • Doubly Linked Lists (Objects based) • Iterator Class • Applications of Linked Lists
Lists • A list consists of a set of sequentially organized elements. • A specific type of graph, where each node except the first has a single preceding node, and each node except the last has a single following node. • Contains 0-n nodes. • Implementation: array and linked lists.
Linked Lists • Each element in a list is called a node, and a connection between any two nodes is called a link. • Implementation: dynamic memory allocation( saves memory). • Limitation: nodes are accessed sequentially.
Operations on a list • Append: Add a node to the end • Prepend: Add a node at the beginning • Insert: Insert a node in place • Find: Find a specific node • Get: Get a node at the current position • Replace: Replace the contents of a node • IsEmpty: Find out if the list is empty • Remove: Remove a node • Clear: Remove all the nodes
Generic Linked List head tail info next
X Insert Operation head tail A B
X Insert Operation head tail A B
X Append Operation head tail
Remove a node tail head A X B
RemoveHead Operation head tail
RemoveTail Operation head tail
Lists with different types • Using templates • With the same structure, we can have integer, float, or character string as a value of a node. • We can have a list with values in different types with the same base class.
next value Tnode template <class T> class Tnode { friend class Tlist<T>; public: Tnode():next(0){ } Tnode( const T & val ); Tnode<T> * Next() const; friend ostream & operator <<(ostream & os, const Tnode<T> & N); private: T value; // data stored in node Tnode * next; // points to next node };
Tnode template <class T> Tnode<T>::Tnode( const T & val ): value(val) { next = 0;} template <class T> Tnode<T> * Tnode<T>::Next() const { return next;} template <class T> ostream & operator <<( ostream & os, const Tnode<T> & N ) { os << N.value << ','; return os; }
Tlist.h template <class T> class Tlist { public: Tlist(); ~Tlist(); int Advance(); // Return 0 if current is already at the end of the list; //otherwise, current will point to the next node 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.
Tlist.h 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 };
head tail current next next value value Tlist<T> class template <class T> Tlist<T>::Tlist() { head = new Tnode<T>; tail = new Tnode<T>; head->next = tail; tail->next = head; current = head; } template <class T> Tlist<T>::~Tlist() { Clear(); delete head; delete tail; }
Tlist<T> class template <class T> int Tlist<T>::Advance() {if( !current ) throw NoCurrentNode(); if( current->next != tail ) { current = current->next; return 1; } return 0; } template <class T> void Tlist<T>::Append( const T & nodeVal ) { GoLast(); InsertAfter( nodeVal ); }
Tlist<T> class template <class T> void Tlist<T>::Clear() { current = head->next; while( current != tail ) { head->next = current->next; delete current; current = head->next; } current = head; head->next = tail; } template <class T> int Tlist<T>::IsEmpty() const { return head->next == tail; }
Tlist<T> class template <class T> T Tlist<T>::Get() const { if( !current ) throw NoCurrentNode(); return current->value; } template <class T> void Tlist<T>::GoLast() { if( !current ) throw NoCurrentNode(); while( current->next != tail ) current = current->next; }
head X tail current InsertAfter A B
Tlist<T> class 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; current->next = p; current = p; } template <class T> void Tlist<T>::Prepend( const T & nodeVal ) { GoTop(); InsertAfter( nodeVal ); }
Insert Before • It is more difficult to insert a new node before the current. • You must search from the head, and find the node whose next is current, then insert the new node after this node.
Tlist<T> class 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; }
Test Tlist class NoCurrentNode { // exception class public: friend ostream & operator <<( ostream & os, const NoCurrentNode & nc ) { os << "List exception: No current node."; return os; } };
Test Tlist #include <stdlib.h> #include <iostream.h> #include "fstring.h" #include "tlist.h" // Tlist<T> class void CreateRandomScores() { Tlist<int> scores; cout << "Creating a random list of scores:\n"; for(int i = 0; i < 10; i++) { int n = rand() % 100; scores.Append( n ); } cout << scores << endl; scores.GoLast(); cout << "Last item: " << scores.Get() << '\n'; scores.GoTop(); scores.Advance();
Test Tlist cout << "First item: " << scores.Get() << '\n'; cout << "\nReplacing first node with value 101...\n"; scores.Replace( 101 ); cout << scores; cout << "\nClearing the list..."; scores.Clear(); if( scores.IsEmpty()) cout << "the list is now empty.\n"; } void CreateNameList() {Tlist<FString> names; names.Append( "Baker" ); names.Append( "Johnson" ); names.Append( "Chong" ); names.Append( "Hamamoto" ); names.Append( "Kawai" );
Test Tlist names.Append( "Figueroa" ); cout << "current: " << names.Get() << endl; cout << names; names.GoTop(); names.Advance(); names.Replace( "Allton" ); names.GoLast(); names.InsertAfter( "Gonzalez" ); names.Prepend( "Abraham" ); cout << names << endl; cout << "Clearing the list..."; names.Clear(); if( names.IsEmpty()) cout << "the list is empty.\n\n"; }
Test Tlist int main() { try { CreateNameList(); CreateRandomScores(); } catch( const NoCurrentNode & nc ) { cout << nc; } return 0; }//cis601source/ch11/tlist/main.cpp
Results current: Figueroa Baker,Johnson,Chong,Hamamoto,Kawai,Figueroa, Abraham,Allton,Johnson,Chong,Hamamoto,Kawai,Figueroa,Gonzalez, Clearing the list...the list is empty. Creating a random list of scores: 41,67,34,0,69,24,78,58,62,64, Last item: 64 First item: 41 Replacing first node with value 101... 101,67,34,0,69,24,78,58,62,64, Clearing the list...the list is now empty.
data previous next Object-Based Lists • In this section, we will introduce a method to design a list (not based on templates). • Also, we will implement a doubly linked list (every node in the list has links to the previous one and the next one).
Doubly Linked List an administrator a faculty a student . . . . . .
The structure DblNode Administrator . . . . . Faculty Student
DblNode #include <iostream.h> class DblNode { friend class DblList; friend class DblIterator; public: DblNode(); virtual ~DblNode() { } DblNode * Next() const; // Return pointer to next node. DblNode * Prev() const; // Return pointer to previous node. DblNode * Detach(); // Detach node from its neighbors. virtual int operator ==( const DblNode & N ) const = 0; friend ostream & operator << (ostream & os, const DblNode & N ); friend istream & operator >> (istream & inp, DblNode & N );
next 0 prev 0 DblNode private: virtual void printOn( ostream & os ) const = 0; virtual void readFrom( istream & is ) = 0; DblNode * next; // pointer to next node DblNode * prev; // pointer to previous node }; inline DblNode::DblNode() { next = prev = 0;} inline DblNode * DblNode::Next() const { return next;} inline DblNode * DblNode::Prev() const { return prev;}
next next next 0 next next 0 prev prev prev prev prev B C A DblNode::Detach() C A B
DblNode DblNode * DblNode::Detach() // detach from surrounding nodes { if ( next ) // any node in front? next->prev = prev; // let it point to previous node if ( prev ) // any node in back? prev->next = next; // let it point to next node prev = 0; // detach current node next = 0; return this; } ostream & operator << ( ostream & os, const DblNode & N ) { N.printOn( os ); return os; } istream & operator >> (istream & is, DblNode & N ) { N.readFrom( is ); return is; }
DblList class DblList { friend class DblIterator; public: DblList(); // Construct an empty list. ~DblList(); // Destructor: delete all nodes. void Append( DblNode * N ); // Add node to end of the list. void DeleteAll(); // Delete all nodes in the list. DblNode *Find(const DblNode & N) const; // Find a node in the list. DblNode * Remove( DblNode * N ); // Remove a node from the list. int IsEmpty() const; // Return 1 if the list is empty. DblNode * First() const; // Return pointer to first node. DblNode * Last() const; // Return pointer to last node. long GetSize() const; // Return the number of nodes. friend ostream & operator << ( ostream & os, const DblList & L ); private: virtual void printOn( ostream & ) const; DblNode * first; // first node in the list DblNode * last; // last node in the list long size; // number of elements }; first last size
0 0 DblList::Append() first last size=0 size=1 A
0 0 0 0 DblList::Append() first last size=1 size=2 B A
DblList DblList::DblList() { first = 0; last = 0; size = 0;} DblList::~DblList() { DeleteAll(); } void DblList::Append( DblNode * P ) { if( !P ) return; if( last ) // is there a last node? { last->next = P; // yes: attach new node to it P->prev = last; } else first = P; // no: attach new node to first last = P; // last points to appended node size++; // increment size of list } first=0 last =0 size =0
DblList void DblList::DeleteAll() { while( first ) delete Remove( first ); } DblNode * DblList::Find( const DblNode & N ) const { DblNode * P = first; while( P ) { if( N == *P ) return P; // “==“ is an overloaded operator P = P->next; } return 0; } DblNode * DblList::First() const { return first;} long DblList::GetSize() const { return size;}
DblList int DblList::IsEmpty() const { return first == 0;} DblNode * DblList::Last() const { return last; } void DblList::printOn( ostream & os ) const { DblNode * N = first; while( N ) { os << (*N); N = N->next; } }
0 next prev 0 DblList::Remove(p) first last size=3 size=2 C A B 0 0 p
DblList DblNode * DblList::Remove( DblNode * P ) { if( !P ) return 0; if( P == first ) // removing the first node? first = first->next; if( P == last ) // removing the last node? last = last->prev; P->Detach(); // detach node from its neighbors size--; // decrement list size return P; } ostream & operator << (ostream & os, const DblList & aList) { aList.printOn( os ); return os; }
The pointer “current” • You can add a pointer “current” to the DblList class.
Apply DblList #include "dblnode.h" #include "dbllist.h" #include "tlist.h" class Student :public DblNode { public: Student(); Student( long idNum ); void SetId( long idNum ); int operator ==( const DblNode & P2 ) const; friend ostream & operator << (ostream & os, const Student * N ); protected: void printOn( ostream & os ) const { os << id; } void readFrom( istream & is ) { is >> id; } id prev next
Apply DblList private: long id; }; ostream & operator << (ostream & os, const Student * N ) { os<< N->id; return os; } Student::Student() { id = 0;} Student::Student( long idNum ) { id = idNum;} void Student::SetId( long idNum ) { id = idNum;} int Student::operator ==( const DblNode & P2 ) const { return id == ((Student &)P2).id;}
Apply DblList int Register( Tlist<Student *> & classRoll,const DblList & college ) { Student S; long id; cout << "Enter student id: "; cin >> id; if( id == -1 ) return 0; S.SetId( id ); Student * p = (Student *) college.Find( S ); if( p ) { cout << "Adding student to the class roll.\n"; classRoll.Append( p ); } else cout << "Student not found in college list\n"; return 1; }