990 likes | 1.21k Views
Chapter 7: The List ADT. Chapter 7 Lists Overview The List ADT and its uses; dynamic memory allocation; programming with linked lists. Objectives. 1. Understanding and applying the List ADT. 2. Implementing a List Class using an array. 3. Implementing a List Class using a linked list.
E N D
Chapter 7 • Lists • Overview • The List ADT and its uses; dynamic memory allocation; programming with linked lists.
Objectives • 1. Understanding and applying the List ADT. • 2. Implementing a List Class using an array. • 3. Implementing a List Class using a linked list. • 4. Using dynamic allocation and pointers in C++. • 5. Variations on the linked list. • 6. Creating a class with overloaded operators.
The List ADT • Characteristics: • A List L stores items of some type, called ListElementType. • Operations: • void L.insert(ListElementType elem) • Precondition: None. • Postcondition:Lpost = Lpre with an instance of elem added to Lpost.
List ADT, first • bool L.first(ListElementType &elem) • Precondition: None • Postcondition:If the list is empty, none. Otherwise, the variable elem contains the first item in L; the “next” item to be returned is the second in L. • Return:trueif and only if there is at least one element in L.
List ADT, next • bool L.next(ListElementType &elem) • Precondition: The “first” operation has been called at least once. • Postcondition:Variable elem contains the next item in L, if there is one, and the next counter advances by one; if there is no next element, none. • Return:trueif and only if there is a next item.
A useful exercise • Define some additional operations that might be useful for a List ADT.
List traversal • The process of accessing each item in the list • Can be defined in terms of two other operations • Accessing the first element in a list • Accessing the next element in a list
Implementing lists • A header file for the list ADT • cx7-1.h (on author’s web page) • See next slide • Must include List ADT • characteristics • operations
Code Example 7-1 • // Code Example 7-1: List ADT header file • #include "dslib.h" • // the type of the individual elements in list is defined here • typedef int ListElementType; • // implementation specific stuff here • class List { • public: • List(); • void insert(const ListElementType & elem); • bool first(ListElementType & elem); • bool next(ListElementType & elem); • private: • // implementation specific stuff here • };
List(); • Is the list copy constructor • With no parameters or body it is a ‘default constructor’
void insert(const ListElementType & elem); • & means pass by reference • Value parameters should only be used for simple types (int, char, etc.) which have simple copy constructors. • For more complex data types, avoid the copy constructor by passing it by address • const means the element cannot be modified in this function
Lists using arrays • The simplest method to implement a List ADT is to use an array • “linear list”, “contiguous list” • Characteristics are • Array for storing entries (listArray) • numberOfElements • currentPosition
Header file for array list • // cx7-2.h • #include "dslib.h" • // the type of the individual elements in the list is defined here • typedef int ListElementType; • // the maximum size for lists is defined here • const int maxListSize = 1000;
Code Example 7-2 • class List { • public: • List(); • void insert(const ListElementType & elem); • bool first(ListElementType & elem); • bool next(ListElementType & elem); • private: • ListElementType listArray[maxListSize]; • int numberOfElements; • int currentPosition; • };
Array List Constructor • // cx7-3.cpp • #include "cx7-2.h" • List::List() • { • // initialize to an empty list • numberOfElements = 0; • currentPosition = -1; • }
Insertion into linear list • void List::insert(const ListElementType & elem) • { • assert(numberOfElements < maxListSize); • listArray[numberOfElements] = elem; • numberOfElements++; }
Iterator function: first • bool List::first(ListElementType & elem) • { • if (numberOfElements == 0) • return false; • else { • currentPosition = 0; • elem = listArray[currentPosition]; • return true; • } • }
Iterator function: next • bool List::next(ListElementType & elem) • { • // currentPosition should always be • // greater than or equal to zero • assert(currentPosition >= 0); • if (currentPosition >= numberOfElements - 1) • return false; • else { • currentPosition++; • elem = listArray[currentPosition]; • return true; } • }
Simple List Client • // cx7-4.cpp • #include "cx7-2.h" // header for Linear List; ListElementType is int • int main() • { List l; • ListElementType i; // header defines this as int • cout << "Enter items to add to list, or 0 to stop: "; • cin >> i; • while (i != 0) { • l.insert(i); • cin >> i; }
Client main continued • cout << "Here are the items in the list.\n"; • ListElementType elem; • bool notEmpty(l.first(elem)); • while (notEmpty) { • cout << elem << endl; • notEmpty = l.next(elem); • } • return 0; • }
Problems with arrays • Array implementations of lists use a static data structure. Often defined at compile-time. Cannot be altered while program is running. • This means we usually waste space rather than have program run out. • It also means that data must be added to the end. If inserted in front, others must shuffle down. This is slow and inefficient.
Linked list implementation • Data storage must now contain both item and pointer to next item. • These are called ‘nodes’ • This can be made dynamic • Much more efficient for insertion and deletion
Adding a node (insertion) • A four step process • Add at front of list • Create new node • Copy data into it • Copy head into its link field • Copy node pointer to head
Adding to end of list • A five step process • Create new node • Copy data into it • Assign new node ptr to tail->link • Assign 0 to new node link (not NULL) • Assign new node ptr to tail
Algorithm 7-1: List Traversal • Comment: Assume that “head” is the name of the external link to the list. • current = head; • while current is not NULL { • process the node current points to; • current = the link field of the node current points to; • }
Linked list example • typedef int ListElementType; • class List { • // Use L to mean "this List" • public: • List(); • // Precondition: None • // Postcondition: L is an empty List • void insert(const ListElementType & elem); • // Precondition: None • // Postcondition: Lpost = Lpre with an • // instance of elem added to Lpost
First() • bool first(ListElementType & elem); • // Precondition: None • // Postcondition: If the list is empty, none. • // Otherwise, the variable • // elem contains the first item in L; • // the "next" item returned is the second in L. • // Returns: true, if and only if, • // there is at least one element in L.
List class, public (con’t) • bool next(ListElementType & elem); • // Precondition: The "first" operation has been called at least once. • // Postcondition: Variable elem contains the next item in L, if there is one, and the next counter advances by one; if there is no next element, none. • // Returns: true if and only if there was a next item.
7.5 (con’t) private of next • private: • struct Node; // declaration without definition • typedef Node *Link; // use declaration of Node • struct Node { // now we define Node • ListElementType elem; • Link next; • }; • Link head; • Link tail; • Link current; • };
Linked list constructor • List::List() • { • // Initialize an empty list • head = 0; • tail = 0; • current = 0; • }
Insert for linked list • void List::insert(const ListElementType & elem) • { • Link addedNode(new Node); • assert(addedNode); // check whether node was allocated • addedNode->elem = elem; • if (head == 0) // list was empty -- set head • head = addedNode; • else • tail->next = addedNode; • tail = addedNode; • addedNode->next = 0; • }
An easy mistake to make • //unsafe test of pointer with 0 • int main() { • int * p; //p is a pointer to an int, initialized to 0 • if (p = 0) //obviously, == was intended • cout << “zero pointer\n”; • else • cout << “non-zero pointer\n”; • return 0; • }
Dynamic memory allocation • Use the ‘new’ operator instead of old C calloc, malloc and realloc • This draws from the “free store” • Dynamic allocation occurs at run-time, not compile time • To check on availability of memory use an assertion. • link newNode = new Node; • assert(newNode);
Linked list implementation • List::List() • { • // Initialize an empty List • head = 0; • tail = 0; • current = 0; • }
Code Example 7-8 • void List::insert(const ListElementType & elem) • { • Link addedNode = new Node; • assert(addedNode); // check whether node was allocated • addedNode->elem = elem; • if (head == 0) // list was empty -- set head • head = addedNode; • else • tail->next = addedNode; • tail = addedNode; • addedNode->next = 0; • }
First() method • bool List::first(ListElementType & elem) • { • // After calling first, current points to // first item in list • if (head == 0) • return false; • else { • elem = head->elem; • current = head; • return true; • } • }
Next() method • bool List::next(ListElementType & elem) • { • // current should always be nonzero • assert(current); • // After each call, current points to the item • // that next has just returned. • if (current->next == 0) • return false; • else { • current = current->next; • elem = current->elem; • return true; • } • }
The Inorder List ADT • Many applications require that lists be maintained in some order • Address books • File names • County records • Student records • Dictionary
Inorder List requirements • Some part of the information stored must be a designated key • For any two keys (k1, k2) there must be a way to evaluate them, such as k1 < k2 • A ‘total order’ is any set of keys that obey an ordering rule.
The Inorder List ADT • Characteristics: • An Inorder List L stores items of some type (ListElementType) that is totally ordered. • The items in the List are in order; that is, if a and b are elements of ListElement Type, and a < b, then if a and b are in L, a will be before b.
Inorder List operations • Prerequisite: • ListElementType must work with the operations <= and ==. • Operations: • void L.insert(const ListElementType &elem) • Precondition: None. • Postcondition:L = L with an instance of elem added to the list