Chapter 7: The List ADT - PowerPoint PPT Presentation

1 / 98
About This Presentation
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
Learn more at: http://www.d.umn.edu
Category:
Tags: adt | chapter | compiler | list

less

Transcript and Presenter's Notes

Title: Chapter 7: The List ADT


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.
  • PostconditionLpost Lpre with an instance of
    elem added to Lpost.

5
List ADT, first
  • 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
List ADT, next
  • 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
    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 authors 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 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
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-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
    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 (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
  • Link next
  • Link head
  • Link tail
  • Link current

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

39
Insert for linked list
  • void Listinsert(const ListElementType elem)
  • Link addedNode(new Node)
  • assert(addedNode) // check whether node was
    allocated
  • addedNode-gtelem elem
  • if (head 0) // list was empty -- set head
  • head addedNode
  • else
  • tail-gtnext addedNode
  • tail addedNode
  • addedNode-gtnext 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 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.
  • link newNode new Node
  • assert(newNode)

42
Linked list implementation
  • ListList()
  • // Initialize an empty List
  • head 0
  • tail 0
  • current 0

43
Code Example 7-8
  • void Listinsert(const ListElementType elem)
  • Link addedNode new Node
  • assert(addedNode) // check whether node was
    allocated
  • addedNode-gtelem elem
  • if (head 0) // list was empty -- set head
  • head addedNode
  • else
  • tail-gtnext addedNode
  • tail addedNode
  • addedNode-gtnext 0

44
First() method
  • bool Listfirst(ListElementType elem)
  • // After calling first, current points to //
    first item in list
  • if (head 0)
  • return false
  • else
  • elem head-gtelem
  • current head
  • 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
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 lt 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 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
    added to the list

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-gtelem lt addedNode-gtelem)
  • (addedNode-gtelem lt pred-gtnext-gtelem
    pred-gtnext 0).

59
Assertion(after insertion)
60
Assertions for continued advancing
  • 7-2 addedNode-gtelem gt pred-gtnext-gtelem
  • 7-3 pred-gtnext ! 0

61
Insert for Inorder List ADT
  • // cx7-9.cpp
  • // cx7-8.cpp
  • // implementation file, linked list
    implementation of List ADT
  • include "cx7-5.h"
  • void Listinsert(const ListElementType elem)
  • // precondition list is in order
  • Link addedNode(new Node)

62
Code Example 7-9
  • assert(addedNode)
  • addedNode-gtelem 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 lt head-gtelem)
  • addedNode-gtnext head
  • head addedNode
  • 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
  • Link pred(head)
  • // assertion pred-gtelem lt addedNode-gtelem
  • while (pred-gtnext ! 0 pred-gtnext-gtelem
    lt addedNode-gtelem)
  • // invariant pred-gtnext ! 0 pred-gtnext-gtelem
    lt elem
  • pred pred-gtnext
  • // assertion 7-1 (pred-gtelem lt addedNode-gtelem)
  • //(addedNode-gtelem lt pred-gtnext-gtelem
    pred-gtnext 0)
  • addedNode-gtnext pred-gtnext
  • pred-gtnext addedNode
  • // 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
    added

64
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

65
Empty linked lists
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
    of elem added to Lpost

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
  • Link next
  • Link head
  • Link current

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

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

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

74
Modification of first
  • bool Listfirst(ListElementType elem)
  • // After first(), current points to first item
    in list
  • assert(head) // if no head, something is
    wrong!
  • if (head-gtnext 0)
  • return false
  • else
  • current head-gtnext
  • 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)
  • assert(head)
  • Link pred, delNode
  • // 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
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

80
Circular linked list
81
Doubly linked lists
  • Allow traversal in either direction
  • Require two links for each node
  • Next
  • Predecessor

82
A doubly linked list
83
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)

84
Data members
  • private
  • struct Node // declaration without definition
  • typedef Node Link
  • struct Node
  • ListElementType elem
  • Link next
  • Link prev
  • Link head
  • Link current

85
Insertion into DLL (front)
  • void Listinsert(const ListElementType elem)
  • Link addedNode new Node
  • assert(addedNode)
  • addedNode-gtelem elem
  • addedNode-gtnext head
  • if (head) // test to see if a node exists
  • head-gtprev addedNode // if so, it
    needs to point back to the new node
  • addedNode-gtprev 0
  • head addedNode

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

93
Private section of class
  • private
  • string firstName
  • string lastName
  • string addrOne
  • string addrTwo
  • string telNum
  • int gradYear

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

96
lt 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 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.
  • 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.
Write a Comment
User Comments (0)
About PowerShow.com