chapter 7: the list adt

98
Chapter 7: The List ADT

Upload: corin

Post on 24-Feb-2016

66 views

Category:

Documents


6 download

DESCRIPTION

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. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Chapter 7: The List ADT

Chapter 7: The List ADT

Page 2: Chapter 7: The List ADT

• Chapter 7

– Lists• Overview

– The List ADT and its uses; dynamic memory allocation; programming with linked lists.

Page 3: Chapter 7: The List ADT

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.

Page 4: Chapter 7: The List ADT

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.

Page 5: Chapter 7: The List ADT

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: true if and only if there is at least one element in L.

Page 6: Chapter 7: The List ADT

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: true if and only if there is a next item.

Page 7: Chapter 7: The List ADT

A useful exercise

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

Page 8: Chapter 7: The 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

Page 9: Chapter 7: The List ADT

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

Page 10: Chapter 7: The List ADT

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

Page 11: Chapter 7: The List ADT

List();

• Is the list copy constructor• With no parameters or body it is a

‘default constructor’

Page 12: Chapter 7: The List ADT

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

Page 13: Chapter 7: The List ADT

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

Page 14: Chapter 7: The List ADT

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;

Page 15: Chapter 7: The List ADT

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

Page 16: Chapter 7: The List ADT

Array List Constructor• // cx7-3.cpp• #include "cx7-2.h"

• List::List()• {• // initialize to an empty list• numberOfElements = 0;• currentPosition = -1;• }

Page 17: Chapter 7: The List ADT

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

Page 18: Chapter 7: The List ADT

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

Page 19: Chapter 7: The List ADT

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

Page 20: Chapter 7: The List ADT

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

Page 21: Chapter 7: The List ADT

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

Page 22: Chapter 7: The List ADT

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.

Page 23: Chapter 7: The List ADT

Figure 7-1

2 4 5 8 11 13 6

2 4 5 8 11 13 61

insert 1 here

0 1 2 3 4 5 6 7 8 9 10111213indices

Page 24: Chapter 7: The List ADT

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

Page 25: Chapter 7: The List ADT

Figure 7-2

7 12 5

Page 26: Chapter 7: The List ADT

Figure 7-3

7 12 5

head

Page 27: Chapter 7: The List ADT

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

Page 28: Chapter 7: The List ADT

Figure 7-4

7 12 5

9

head

Page 29: Chapter 7: The List ADT

Figure 7-5

7 12 5

9

head

Page 30: Chapter 7: The List ADT

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

Page 31: Chapter 7: The List ADT

Figure 7-6

7 12 5

9

headtail

Page 32: Chapter 7: The List ADT

Figure 7-7

7 12 5

9

head

tail

Page 33: Chapter 7: The List ADT

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

Page 34: Chapter 7: The List ADT

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

Page 35: Chapter 7: The List ADT

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.

Page 36: Chapter 7: The List ADT

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.

Page 37: Chapter 7: The List ADT

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

Page 38: Chapter 7: The List ADT

Linked list constructor

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

Page 39: Chapter 7: The List ADT

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

Page 40: Chapter 7: The List ADT

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

Page 41: Chapter 7: The List ADT

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

Page 42: Chapter 7: The List ADT

Linked list implementation

• List::List()• {• // Initialize an empty List• head = 0;• tail = 0;• current = 0;• }

Page 43: Chapter 7: The List ADT

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

Page 44: Chapter 7: The List ADT

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

Page 45: Chapter 7: The List ADT

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

Page 46: Chapter 7: The List ADT

Figure 7-8

7 12 5

7 12 5

head

head

current

currentelem next

elem next

Page 47: Chapter 7: The List ADT

The Inorder List ADT• Many applications require that lists

be maintained in some order– Address books– File names– County records– Student records– Dictionary

Page 48: Chapter 7: The List ADT

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.

Page 49: Chapter 7: The List ADT

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.

Page 50: Chapter 7: The List ADT

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

Page 51: Chapter 7: The List ADT

First() method

• bool L.first(ListElementType &elem)• Precondition: None• Postcondition: If the list is empty, none.

Otherwise, the variable elem contains the smallest item in L; the “next” item to be returned is the second in L.

• Return: true if and only if there is at least one element in L.

Page 52: Chapter 7: The List ADT

Next() method• bool L.next(ListElementType &elem)• Precondition: The “first” operation has

been called at least once.• Postcondition:Variable elem contains the

next item in L, in order, if there is one.• Return: true if and only if there is a next

item.

Page 53: Chapter 7: The List ADT

Inorder invariant

u vinvariant: u < v

Page 54: Chapter 7: The List ADT

Insertion (before)

7 12

9

Page 55: Chapter 7: The List ADT

Insertion (after)

7 12

9

Page 56: Chapter 7: The List ADT

Required insertion pointers

7 12

9predaddedNode

Page 57: Chapter 7: The List ADT

Assertions (before insertion)

7 12

9predaddedNode

pred->elem pred->next pred->next->elem

addedNode->elem

Assertion: pred->elem <= addedNode->elem && addedNode->elem <= pred->next->elem

Page 58: Chapter 7: The List ADT

Assertion (considering end-of-list)

• (pred->elem <= addedNode->elem) &&

• (addedNode->elem <= pred->next->elem || pred->next == 0).

Page 59: Chapter 7: The List ADT

Assertion(after insertion)

7 12

9pred

pred->elem pred->next pred->next->next->elem

pred->next->elem

Assertion: pred->elem <= pred->next->elem <= pred->next->next->elem

pred->next->next

Page 60: Chapter 7: The List ADT

Assertions for continued advancing

• 7-2 addedNode->elem > pred->next->elem

• 7-3 pred->next != 0

Page 61: Chapter 7: The List ADT

Insert for Inorder List ADT• // cx7-9.cpp• // cx7-8.cpp• // implementation file, linked list implementation

of List ADT• #include "cx7-5.h"• void List::insert(const ListElementType & elem)• {• // precondition: list is in order• Link addedNode(new Node);

Page 62: Chapter 7: The List ADT

Code Example 7-9• assert(addedNode);• addedNode->elem = elem;• // Special case: if existing list is empty, or if the new data• // is less than smallest item in the list, new node is added• // to the front of the list• if (head == 0 || elem <= head->elem) {• addedNode->next = head;• head = addedNode;• }• else {• // find the pointer to the node that is the predecessor• // to the new node in the in-order list

Page 63: Chapter 7: The List ADT

Code Example 7-9• Link pred(head);• // assertion: pred->elem <= addedNode->elem• while (pred->next != 0 && pred->next->elem <= addedNode-

>elem)• // invariant: pred->next != 0 && pred->next->elem <= elem• pred = pred->next;• // assertion 7-1: (pred->elem <= addedNode->elem) &&• //(addedNode->elem <= pred->next->elem || pred->next == 0)• addedNode->next = pred->next;• pred->next = addedNode;• // assertion: pred->elem <= pred->next->elem &&• // (pred->next->elem <= pred->next->next->elem || pred-

>next->next == 0)• // postcondition: list is in order, with elem added

Page 64: Chapter 7: The List ADT

Variations on linked lists• Dummy head nodes

– Eliminates special case surrounding first node in list

– Never insert or delete a first node• Circular linked lists• Doubly linked lists

Page 65: Chapter 7: The List ADT

Empty linked lists

(head == 0)

(dummy)

Page 66: Chapter 7: The List ADT

List comparisons

(dummy)

7 4

7 4

Page 67: Chapter 7: The List ADT

List classfor list with dummy node• 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

Page 68: Chapter 7: The List ADT

List operations (first)• bool first(ListElementType & elem);• // Precondition: None• // Postcondition: If the list empty, none.

Otherwise, variable elem contains first item in L; the "next" item to be returned is the second in L.

• // Returns: true if and only if there is at least one element in L

Page 69: Chapter 7: The List ADT

List operations (next, remove)

• bool next(ListElementType & elem);• // Precondition: The "first" operation has been called at

least once.• // Postcondition: elem contains next item in L, if there is

one, and next counter advances by one; if no next element,none.

• // Returns: true if and only if there was a next item.• void remove(const ListElementType & target);• // Precondition: None• // Postcondition: Lpost = Lpre with one instance of target

removed

Page 70: Chapter 7: The List ADT

Data members• 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 current;• };

Page 71: Chapter 7: The List ADT

Modifications (constructor)• // cx7-11.cpp• #include "cx7-10.h"

• List::List()• {• // Initialize an empty list• head = new Node;• assert(head); // What is the reason for this?• head->next = 0;• current = 0;• }

Page 72: Chapter 7: The List ADT

Modification to insert()• void List::insert(const ListElementType & elem)• { // precondition: list is in order• Link addedNode(new Node);• assert(addedNode);• addedNode->elem = elem;• // find pointer to predecessor in the in-order list• Link pred(head);• // loop invariant: pred>elem <= elem• while (pred->next != 0 && (pred->next->elem <=

addedNode->elem))• pred = pred->next;

Page 73: Chapter 7: The List ADT

Insertion (con’t)• // assertion: (pred>elem <= addedNode>elem) &&• //(addedNode->elem <= pred->next->elem • // || pred->next == 0)• addedNode->next = pred->next;• pred->next = addedNode;• // postcondition: list is in order• }

Page 74: Chapter 7: The List ADT

Modification of first• bool List::first(ListElementType &elem)• { // After first(), current points to first item in list• assert(head); // if no head, something is wrong! • if (head->next == 0)• return false;• else {• current = head->next;• elem = current->elem;• return true;• }• }

Page 75: Chapter 7: The List ADT

Modification of next()• bool List::next(ListElementType & elem)• { // With proper use, current should be nonzero• assert(current);• // After each call, current points to item returned.• if (current->next == 0)• return false; // no next element available• else {• current = current->next;• elem = current->elem;• return true;• }• }

Page 76: Chapter 7: The List ADT

Modification of remove()• void List::remove(const ListElementType & target)• { assert(head);• Link pred, delNode;• // pred starts out pointing at the dummy head• for (pred = head; pred->next != 0 && pred->next->elem <

target;pred = pred->next);• // at this point, check to see if we've found target --• // if so, remove it. Check to avoid dereferencing null pointer!• if (pred && (pred->next) && (pred->next->elem == target))

{ // remove the next node in the list• delNode = pred->next;• pred->next = delNode->next;• delete delNode; // return node to memory}• }

Page 77: Chapter 7: The List ADT

List before removal

7 12

9pred

delNode

Page 78: Chapter 7: The List ADT

List after removal

7 12

9pred

delNode

Page 79: Chapter 7: The List ADT

Circular linked lists• No ‘0’ pointer at end• Last link points to first node• If external pointer is assigned to tail

of list, it is easy to reference both the tail and the head

Page 80: Chapter 7: The List ADT

Circular linked list

7 12 5

Page 81: Chapter 7: The List ADT

Doubly linked lists• Allow traversal in either direction• Require two links for each node

– Next– Predecessor

Page 82: Chapter 7: The List ADT

A doubly linked list

7 12 5

head

Page 83: Chapter 7: The List ADT

Header file for doubly linked list

• typedef int ListElementType;• class List {• public:• List();• void insert(const ListElementType & elem); • bool first(ListElementType & elem);• bool next(ListElementType & elem);• bool previous(ListElementType & elem);

Page 84: Chapter 7: The List ADT

Data members• private:• struct Node; // declaration without definition• typedef Node *Link;• struct Node {• ListElementType elem;• Link next;• Link prev;• };• Link head;• Link current;• };

Page 85: Chapter 7: The List ADT

Insertion into DLL (front)• void List::insert(const ListElementType & elem)• { Link addedNode = new Node;• assert(addedNode);• addedNode->elem = elem;• addedNode->next = head;• if (head) // test to see if a node exists• head->prev = addedNode; // if so, it needs to

point back to the new node• addedNode->prev = 0;• head = addedNode;• }

Page 86: Chapter 7: The List ADT

Previous for DLL• bool List::previous(ListElementType &elem)• {• assert(current); • if (current->prev == 0)• return false;• else {• current = current->prev;• elem = current->elem;• return true;• }• }

Page 87: Chapter 7: The List ADT

Dynamic Linear Lists• Arrays (conventional linear lists) are

dimensioned in the program code and space allocated at compile time.

• Dynamic arrays (dynamic linear lists) have space allocated for them at run-time.

• This makes them more versatile than static linear lists and easier to code than linked lists.

Page 88: Chapter 7: The List ADT

Dynamic linear list class• typedef int ListElementType;• class List {• public:• List(int lSize);• void insert(const ListElementType & elem);• bool first(ListElementType & elem);• bool next(ListElementType & elem);• int size(); • private:• ListElementType * listArray;• int numberOfElements;• int currentPosition;• int listSize;• };

Page 89: Chapter 7: The List ADT

Constructor and size accessor

• List::List(int lSize)• {• assert(lSize > 0);• listSize = lSize;• listArray = new ListElementType[listSize];• assert(listArray); // memory was successfully allocated• numberOfElements = 0;• currentPosition = -1;• }• List::size()• {• return listSize;• }

Page 90: Chapter 7: The List ADT

Dynamic list client• int main()• {• int list1size, list2size;• cout << "Enter size of the first list: ";• cin >> list1size;• List list1(list1size);• cout << "Enter size of the second list: ";• cin >> list2size;• List list2(list2size);• // . . . and so on . . .• }

Page 91: Chapter 7: The List ADT

The use of const• If a const could possibly be passed to a

function, then the function must be able to accept it.

• Const is generally the proper way to implement accessors

• It avoid client code blowing up when it sends a const actual argument into a function with non-const formal arguments

Page 92: Chapter 7: The List ADT

Example of use of const• #include <string>• class ClubMember {• public:• ClubMember();• void setName(const string & fn, const string & ln);• void setAddress(const string & ad1, const string & ad2);• void setTelnum(const string & tn); • void setGradYear(const int gy);• void setClubMemberData(const string & fn, const string & ln, const string & ad1,

const string & ad2, const string & tn, const int gy);• string getFirstName() const;• string getLastName() const;• string getAddrOne() const;• string getAddrTwo() const;• string getTelnum() const;• int getGradYear() const;

Page 93: Chapter 7: The List ADT

Private section of class• private:• string firstName;• string lastName;• string addrOne;• string addrTwo;• string telNum;• int gradYear;• };

Page 94: Chapter 7: The List ADT

Const problem situation• Void printMember(const ClubMember &member)• {• cout << member.GetFirstName()

• If GetFirstName is not const the compiler will assume it may change any involved parameters and disallow this for a printMember where the parameter was const.

• string getFirstName() const; // is OK• string getFirstName(); // is dangerous

Page 95: Chapter 7: The List ADT

Operator overloading• This is important when using class

objects (derived types)• Standard operators are designed

only to work with native types.• If you invent a class and intend to

use operators, you must overload them for your class objects.

Page 96: Chapter 7: The List ADT

<= operator overloading• // We'll use the names lhs -- short for left hand side -- as the• // name for the argument on the left of an operator, • // and rhs -- right hand side -- for the argument on the right.

• int operator<= (const ClubMember & lhs, const ClubMember & rhs)

• {• if (lhs.getLastName() == rhs.getLastName())• return lhs.getFirstName() <= rhs.getFirstName();• else• return lhs.getLastName() <= rhs.getLastName();• }

Page 97: Chapter 7: The List ADT

Chapter Summary• A List ADT represents items that can be retrieved in

some order.• Linear lists implement the List ADT using an array.• Iterator functions can be used to retrieve items in a

List.• Linked list provide greater flexibility by breaking

the connection between the logical idea of a list and its implementations.

• Dynamic memory allocation allows a program to allocate memory at runtime.

Page 98: Chapter 7: The List ADT

Chapter Summary• The Inorder List ADT maintains items in a specified

order.• Dummy head-nodes, circular linked lists, and

doubly-linked lists provide alternative approaches to the implementation of a linked list.

• Client applications may need to implement particular functions for classes stored within another class.

• Operator overloading provides a way to make built-in operators meaningful for user-defined classes.