1 / 98

Chapter 7: The List ADT

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.

corin
Download Presentation

Chapter 7: The List ADT

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 7: The List ADT

  2. Chapter 7 • Lists • Overview • The List ADT and its uses; dynamic memory allocation; programming with linked lists.

  3. 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.

  4. 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.

  5. 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.

  6. 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.

  7. A useful exercise • Define some additional operations that might be useful for a List ADT.

  8. 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

  9. 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

  10. 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 • };

  11. List(); • Is the list copy constructor • With no parameters or body it is a ‘default constructor’

  12. 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

  13. 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

  14. 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;

  15. 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; • };

  16. Array List Constructor • // cx7-3.cpp • #include "cx7-2.h" • List::List() • { • // initialize to an empty list • numberOfElements = 0; • currentPosition = -1; • }

  17. Insertion into linear list • void List::insert(const ListElementType & elem) • { • assert(numberOfElements < maxListSize); • listArray[numberOfElements] = elem; • numberOfElements++; }

  18. Iterator function: first • bool List::first(ListElementType & elem) • { • if (numberOfElements == 0) • return false; • else { • currentPosition = 0; • elem = listArray[currentPosition]; • return true; • } • }

  19. 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; } • }

  20. 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; }

  21. 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; • }

  22. 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.

  23. Figure 7-1

  24. 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

  25. Figure 7-2

  26. Figure 7-3

  27. 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

  28. Figure 7-4

  29. Figure 7-5

  30. 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

  31. Figure 7-6

  32. Figure 7-7

  33. 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; • }

  34. 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

  35. 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.

  36. 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.

  37. 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; • };

  38. Linked list constructor • List::List() • { • // Initialize an empty list • head = 0; • tail = 0; • current = 0; • }

  39. 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; • }

  40. 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; • }

  41. 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);

  42. Linked list implementation • List::List() • { • // Initialize an empty List • head = 0; • tail = 0; • current = 0; • }

  43. 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; • }

  44. 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; • } • }

  45. 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; • } • }

  46. Figure 7-8

  47. The Inorder List ADT • Many applications require that lists be maintained in some order • Address books • File names • County records • Student records • Dictionary

  48. 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.

  49. 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.

  50. 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

More Related