# Chapter 7: The List ADT - PowerPoint PPT Presentation

1 / 98
Title:

## Chapter 7: The List ADT

Description:

### Title: Chapter 7: The List ADT Author: Jim Allert Last modified by: Jim Allert Created Date: 3/23/1999 9:39:38 PM Document presentation format: On-screen Show – PowerPoint PPT presentation

Number of Views:122
Avg rating:3.0/5.0
Slides: 99
Provided by: JimA189
Category:
Tags:
Transcript and Presenter's Notes

Title: Chapter 7: The List ADT

1
2
• Chapter 7
• Lists
• Overview
• The List ADT and its uses dynamic memory

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
• Characteristics
• A List L stores items of some type, called
ListElementType.
• Operations
• void L.insert(ListElementType elem)
• Precondition None.
• PostconditionLpost Lpre with an instance of

5
• bool L.first(ListElementType elem)
• Precondition None
• PostconditionIf 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.

6
• bool L.next(ListElementType elem)
• Precondition The first operation has been
called at least once.
• PostconditionVariable 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.

7
A useful exercise
• Define some additional operations that might be

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
• cx7-1.h (on authors web page)
• See next slide
• characteristics
• operations

10
Code Example 7-1
• 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
• // 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 listArraymaxListSize
• int numberOfElements
• int currentPosition

16
Array List Constructor
• // cx7-3.cpp
• include "cx7-2.h"
• ListList()
• // initialize to an empty list
• numberOfElements 0
• currentPosition -1

17
Insertion into linear list
• void Listinsert(const ListElementType elem)
• assert(numberOfElements lt maxListSize)
• listArraynumberOfElements elem
• numberOfElements

18
Iterator function first
• bool Listfirst(ListElementType elem)
• if (numberOfElements 0)
• return false
• else
• currentPosition 0
• elem listArraycurrentPosition
• return true

19
Iterator function next
• bool Listnext(ListElementType elem)
• // currentPosition should always be
• // greater than or equal to zero
• assert(currentPosition gt 0)
• if (currentPosition gt numberOfElements - 1)
• return false
• else
• currentPosition
• elem listArraycurrentPosition
• 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 ltlt "Enter items to add to list, or 0 to
stop "
• cin gtgt i
• while (i ! 0)
• l.insert(i)
• cin gtgt i

21
Client main continued
• cout ltlt "Here are the items in the list.\n"
• ListElementType elem
• bool notEmpty(l.first(elem))
• while (notEmpty)
• cout ltlt elem ltlt 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
• 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
• A four step process
• Add at front of list
• Create new node
• Copy data into it
• Copy node pointer to head

28
Figure 7-4
29
Figure 7-5
30
• A five step process
• Create new node
• Copy data into it
• Assign new node ptr to tail-gtlink
• 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
• while current is not NULL
• process the node current points to
• current the link field of the node current
points to

34
• 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 (cont)
• 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 (cont) private of next
• private
• struct Node // declaration without definition
• typedef Node Link // use declaration of Node
• struct Node // now we define Node
• ListElementType elem

38
• ListList()
• // Initialize an empty list
• tail 0
• current 0

39
• void Listinsert(const ListElementType elem)
• assert(addedNode) // check whether node was
allocated
• else

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 ltlt zero pointer\n
• else
• cout ltlt 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.
• assert(newNode)

42
• ListList()
• // Initialize an empty List
• tail 0
• current 0

43
Code Example 7-8
• void Listinsert(const ListElementType elem)
• assert(addedNode) // check whether node was
allocated
• else

44
First() method
• bool Listfirst(ListElementType elem)
• // After calling first, current points to //
first item in list
• return false
• else
• return true

45
Next() method
• bool Listnext(ListElementType elem)
• // current should always be nonzero
• assert(current)
• // After each call, current points to the item
• // that next has just returned.
• if (current-gtnext 0)
• return false
• else
• current current-gtnext
• elem current-gtelem
• return true

46
Figure 7-8
47
• Many applications require that lists be
maintained in some order
• 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 lt k2
• A total order is any set of keys that obey an
ordering rule.

49
• 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 lt
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 lt
and .
• Operations
• void L.insert(const ListElementType elem)
• Precondition None.
• PostconditionL L with an instance of elem

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

52
Next() method
• bool L.next(ListElementType elem)
• Precondition The first operation has been
called at least once.
• PostconditionVariable elem contains the next
item in L, in order, if there is one.
• Return true if and only if there is a next item.

53
Inorder invariant
54
Insertion (before)
55
Insertion (after)
56
Required insertion pointers
57
Assertions (before insertion)
58
Assertion (considering end-of-list)
pred-gtnext 0).

59
Assertion(after insertion)
60
• 7-3 pred-gtnext ! 0

61
• // cx7-9.cpp
• // cx7-8.cpp
• // implementation file, linked list
• include "cx7-5.h"
• void Listinsert(const ListElementType elem)
• // precondition list is in order

62
Code Example 7-9
• // Special case if existing list is empty, or
if the new data
• // is less than smallest item in the list, new
• // to the front of the list
• else
• // find the pointer to the node that is the
predecessor
• // to the new node in the in-order list

63
Code Example 7-9
• // assertion pred-gtelem lt addedNode-gtelem
• while (pred-gtnext ! 0 pred-gtnext-gtelem
• // invariant pred-gtnext ! 0 pred-gtnext-gtelem
lt elem
• pred pred-gtnext
• // assertion 7-1 (pred-gtelem lt addedNode-gtelem)
pred-gtnext 0)
• // assertion pred-gtelem lt pred-gtnext-gtelem
• // (pred-gtnext-gtelem lt pred-gtnext-gtnext-gtelem
pred-gtnext-gtnext 0)
• // postcondition list is in order, with elem

64
• Eliminates special case surrounding first node in
list
• Never insert or delete a first node

65
66
List comparisons
67
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

68
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

69
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

70
Data members
• private
• struct Node // declaration without definition
• typedef Node Link // use declaration of Node
• struct Node // now we define Node
• ListElementType elem

71
Modifications (constructor)
• // cx7-11.cpp
• include "cx7-10.h"
• ListList()
• // Initialize an empty list
• assert(head) // What is the reason for this?
• current 0

72
Modification to insert()
• void Listinsert(const ListElementType elem)
• // precondition list is in order
• // find pointer to predecessor in the in-order
list
• // loop invariant predgtelem lt elem
• while (pred-gtnext ! 0 (pred-gtnext-gtelem lt
• pred pred-gtnext

73
Insertion (cont)
• // assertion (predgtelem lt addedNodegtelem)
• // pred-gtnext 0)
• // postcondition list is in order

74
Modification of first
• bool Listfirst(ListElementType elem)
• // After first(), current points to first item
in list
wrong!
• return false
• else
• elem current-gtelem
• return true

75
Modification of next()
• bool Listnext(ListElementType elem)
• // With proper use, current should be nonzero
• assert(current)
• // After each call, current points to item
returned.
• if (current-gtnext 0)
• return false // no next element available
• else
• current current-gtnext
• elem current-gtelem
• return true

76
Modification of remove()
• void Listremove(const ListElementType target)
• // pred starts out pointing at the dummy head
• for (pred head pred-gtnext ! 0
pred-gtnext-gtelem lt targetpred pred-gtnext)
• // at this point, check to see if we've found
target --
• // if so, remove it. Check to avoid
dereferencing null pointer!
• if (pred (pred-gtnext) (pred-gtnext-gtelem
target)) //
remove the next node in the list
• delNode pred-gtnext
• pred-gtnext delNode-gtnext
• delete delNode // return node to memory

77
List before removal
78
List after removal
79
• 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

80
81
• Allow traversal in either direction
• Require two links for each node
• Next
• Predecessor

82
83
• typedef int ListElementType
• class List
• public
• List()
• void insert(const ListElementType elem)
• bool first(ListElementType elem)
• bool next(ListElementType elem)
• bool previous(ListElementType elem)

84
Data members
• private
• struct Node // declaration without definition
• struct Node
• ListElementType elem

85
Insertion into DLL (front)
• void Listinsert(const ListElementType elem)
• if (head) // test to see if a node exists
needs to point back to the new node

86
Previous for DLL
• bool Listprevious(ListElementType elem)
• assert(current)
• if (current-gtprev 0)
• return false
• else
• current current-gtprev
• elem current-gtelem
• return true

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

88
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

89
Constructor and size accessor
• ListList(int lSize)
• assert(lSize gt 0)
• listSize lSize
• listArray new ListElementTypelistSize
• assert(listArray) // memory was successfully
allocated
• numberOfElements 0
• currentPosition -1
• Listsize()
• return listSize

90
Dynamic list client
• int main()
• int list1size, list2size
• cout ltlt "Enter size of the first list "
• cin gtgt list1size
• List list1(list1size)
• cout ltlt "Enter size of the second list "
• cin gtgt list2size
• List list2(list2size)
• // . . . and so on . . .

91
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

92
Example of use of const
• include ltstringgt
• class ClubMember
• public
• ClubMember()
• void setName(const string fn, const string
ln)
• void setTelnum(const string tn)
• 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 getTelnum() const

93
Private section of class
• private
• string firstName
• string lastName
• string telNum

94
Const problem situation
• Void printMember(const ClubMember member)
• cout ltlt 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

95
• 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
objects.

96
• // 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 operatorlt (const ClubMember lhs,
const ClubMember rhs)
• if (lhs.getLastName() rhs.getLastName())
• return lhs.getFirstName() lt
rhs.getFirstName()
• else
• return lhs.getLastName() lt
rhs.getLastName()

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

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