44
A Generic List A Generic List Class Class and Linked Lists and Linked Lists Andy Wang Andy Wang Data Structures, Data Structures, Algorithms, and Generic Algorithms, and Generic Programming Programming

A Generic List Class and Linked Lists Andy Wang Data Structures, Algorithms, and Generic Programming

Embed Size (px)

Citation preview

A Generic List Class A Generic List Class and Linked Listsand Linked Lists

Andy WangAndy Wang

Data Structures, Algorithms, and Data Structures, Algorithms, and Generic ProgrammingGeneric Programming

Lists in Everyday LifeLists in Everyday Life

Shopping listShopping list

To-do listTo-do list

Dave Letterman’s top 10 listDave Letterman’s top 10 list

My cat’s revenge listMy cat’s revenge list

Shopping vector?Shopping vector? What if you want to insert an item? What if you want to insert an item?

List Wish ListList Wish List

Insert an element Insert an element Remove an element Remove an element Remove all items Remove all items Assignment operator Assignment operator Comparison operators Comparison operators Constructors/destructors Constructors/destructors Generic classGeneric classConvenient way to iterate through the listConvenient way to iterate through the list

IteratorIterator

Motivating exampleMotivating examplechar A[10] = { ‘a’, ‘b’, ‘c’, …’j’ };char A[10] = { ‘a’, ‘b’, ‘c’, …’j’ };

char *j;char *j;

for (j = A; j != A + 10; j++) {for (j = A; j != A + 10; j++) {

cout << *j << endl;cout << *j << endl;

}}

IteratorIterator

A generalized modelA generalized model A way to initialize at the front and back of a A way to initialize at the front and back of a

listlist A way to move to the next or previous positionA way to move to the next or previous position A way to detect the end of an iterationA way to detect the end of an iteration A way to retrieve the current valueA way to retrieve the current value A way to compare two iterators at the same A way to compare two iterators at the same

locationlocation

List Iterator Wish ListList Iterator Wish List

Return the first item Return the first item Return the last itemReturn the last itemReturn the current itemReturn the current itemIncrement to the next item Increment to the next item Decrement to previous item Decrement to previous item Detect the end of an iterationDetect the end of an iterationCompare iterators for equalityCompare iterators for equalityGeneric classGeneric class

List Public InterfaceList Public Interface

Read-only accessor functionsRead-only accessor functionsunsigned int Size() const;unsigned int Size() const;

int Empty() const;int Empty() const;

List Public Interface (2)List Public Interface (2)

Locating places on the listLocating places on the listIterator Begin() const;Iterator Begin() const;

Iterator End() const;Iterator End() const;

Accessing values on the listAccessing values on the listT& Front() const;T& Front() const;

T& Back() const;T& Back() const;

List Public Interface (3)List Public Interface (3)

Write functionsWrite functionsint PushFront(const T& t);int PushFront(const T& t);

int PushBack(const T& t);int PushBack(const T& t);

int PopFront();int PopFront();

int PopBack();int PopBack();

int Insert(Iterator& I, const T& t);int Insert(Iterator& I, const T& t);

int Remove(Iterator& I);int Remove(Iterator& I);

unsigned int Remove(const T& t);unsigned int Remove(const T& t);

void Clear();void Clear();

List Public Interface (4)List Public Interface (4)

Constructors and destructorConstructors and destructorTList();TList();

~TList();~TList();

TList<T>& operator=(const TList<T>& L);TList<T>& operator=(const TList<T>& L);

TList(const TList<T>& L);TList(const TList<T>& L);

Terminology supportTerminology supporttypedef T value_type;typedef T value_type;

typedef TListIterator<T> Iterator;typedef TListIterator<T> Iterator;

List Public Interface (5)List Public Interface (5)

Non-member functionsNon-member functionsint operator==(const TList<T>& L1, const TList<T>& L2);int operator==(const TList<T>& L1, const TList<T>& L2);

int operator!=(const TList<T>& L1, const TList<T>& L2);int operator!=(const TList<T>& L1, const TList<T>& L2);

ostream operator<<(ostream& os, const TList<T>& L);ostream operator<<(ostream& os, const TList<T>& L);

List Complexity RequirementsList Complexity Requirements

O(1) Runtime complexity O(1) Runtime complexity Default ConstructorDefault Constructor PushFront(t)PushFront(t), , PushBack(t)PushBack(t), , Insert(I, t)Insert(I, t) PopFront()PopFront(), , PopBack()PopBack(), , Remove(I, t)Remove(I, t) Begin()Begin(), , End()End();; Front()Front(), , Back()Back();; Empty()Empty();;

•Not available for vectors•PushFront(t) for a vector

•Increment size•Copy v[j] to v[j + 1]•Assign v[0] = t(size) (at least size)

List Complexity Requirements (2)List Complexity Requirements (2)

O(Size()) Runtime complexity O(Size()) Runtime complexity Copy constructorCopy constructor Assignment operatorAssignment operator DestructorDestructor Size()Size() Clear()Clear() Remove(t)Remove(t)

The maintenance cost of the size operation is (size) (at least size)

•Incremental computation•On-demand computation

List Iterator Public InterfaceList Iterator Public Interface

Read-only operatorsRead-only operatorsint operator==(const iterator& I2) const;int operator==(const iterator& I2) const;int operator!=(const iterator& I2) const;int operator!=(const iterator& I2) const;T& operator*() const; // return a reference to current valueT& operator*() const; // return a reference to current valueint Valid() const; // Iterator is pointing to a valid elementint Valid() const; // Iterator is pointing to a valid element

Write operatorsWrite operatorsiterator& operator=(const iterator& I);iterator& operator=(const iterator& I);iterator& operator++(); // prefixiterator& operator++(); // prefixiterator operator++(int); // postfixiterator operator++(int); // postfixiterator& operator--(); // prefixiterator& operator--(); // prefixiterator operator--(int); // postfixiterator operator--(int); // postfix

O(1) requirement for space and timeO(1) requirement for space and time

Using ListUsing ListTList<String> KittyVengenceList;TList<String> KittyVengenceList;

KittyVengenceList.PushFront(“toe biting”);KittyVengenceList.PushFront(“toe biting”); ““toe biting”toe biting”

KittyVengenceList.PushBack(“carpet littering”);KittyVengenceList.PushBack(“carpet littering”); ““toe biting”, “carpet littering”toe biting”, “carpet littering”

KittyVengenceList.PushFront(“midnight howling”);KittyVengenceList.PushFront(“midnight howling”); ““midnight howling”, “toe biting”, “carpet littering”midnight howling”, “toe biting”, “carpet littering”

KittyVengenceList.PushBack(“toilet drinking”);KittyVengenceList.PushBack(“toilet drinking”); ““midnight howling”, “toe biting”, “carpet littering”, “toilet midnight howling”, “toe biting”, “carpet littering”, “toilet

drinking”drinking”

TList<String>::Iterator I;TList<String>::Iterator I;

for (I = KittyVengenceList.Begin(); I != KittyVengenceList.End(); ++I) {for (I = KittyVengenceList.Begin(); I != KittyVengenceList.End(); ++I) {// print list with <<// print list with <<

}}

List InsertionList Insertion

Insert “furniture scratching” after “toe biting”Insert “furniture scratching” after “toe biting”

// sequential search// sequential searchfor (I = KittyVengenceList.Begin(); I.Valid(); ++I) {for (I = KittyVengenceList.Begin(); I.Valid(); ++I) {

if (“toe biting” == *I) {if (“toe biting” == *I) {break;break;

}}}}KittyVengenceList.Insert(I, “furniture scratching”);KittyVengenceList.Insert(I, “furniture scratching”);

““midnight howling”, “toe biting”, “furniture midnight howling”, “toe biting”, “furniture scratching”, “carpet littering”, “toilet drinking”scratching”, “carpet littering”, “toilet drinking”

// what happens if “toe biting” is not on the list?// what happens if “toe biting” is not on the list?

Remove all copies of t from ListRemove all copies of t from List

TList<String>::Iterator I;TList<String>::Iterator I;for (I = KittyVengenceList.Begin(); I.Valid();) {for (I = KittyVengenceList.Begin(); I.Valid();) {

if (t == *I) {if (t == *I) {KittyVengenceList.Remove(I);KittyVengenceList.Remove(I);

} else {} else {++I;++I;

}}}}

List and List IteratorList and List Iterator

Conceptual relationshipConceptual relationshipIterator L1Iterator L1

beginbegin currentcurrent endend

List: A, B, C, D, E, FList: A, B, C, D, E, F

beginbegin currentcurrent endend

Iterator L2Iterator L2

List Implementation PlanList Implementation Plan

ListElementListElement Pointers to the previous and next elementPointers to the previous and next element ValueValue

Defined within the List class, with limited scopeDefined within the List class, with limited scopeclass ListElement {class ListElement {

// data// dataListElement *prev;ListElement *prev;ListElement *next;ListElement *next;T value;T value;

// constructor// constructor ListElement(const T& t) : value(t);ListElement(const T& t) : value(t);};};

value

prev

next

value

prev

next

value

prev

next

No need for contiguous memory allocation

List Implementation Plan (2)List Implementation Plan (2)

Protected dataProtected data Pointers to the first and the last element of the listPointers to the first and the last element of the list Number of list elementsNumber of list elementstemplate <typename T>template <typename T>class List {class List {protected:protected:

ListElement* first;ListElement* first;ListElement* last;ListElement* last;unsigned int size;unsigned int size;

public:public:……

};};

Three Perspectives of ListThree Perspectives of List

Client viewClient view List interfaceList interface ListIterator interface ListIterator interface

Implementation viewImplementation view Sequentially ordered list elementsSequentially ordered list elements

System viewSystem view List elements connected by List elements connected by pointerspointers

List Iterator Implementation PlanList Iterator Implementation Plan

Protected dataProtected data Pointer to the current list elementPointer to the current list element

template <typename T>template <typename T>

class ListIterator {class ListIterator {

protected:protected:

ListElement* curr;ListElement* curr;

public:public:

ListIterator& operator++();ListIterator& operator++();

……

};};

Iterator operator++()Iterator operator++()

Set curr to the next list elementSet curr to the next list elementtemplate <typename T>template <typename T>

ListIterator<T>&ListIterator<T>&

ListIterator<T>::operator++() {ListIterator<T>::operator++() {

curr = (*curr).next; curr = (*curr).next; // curr->next// curr->next

return *this;return *this;

}} value

prev

next

value

prev

next

value

prev

next

curr

ListIterator

ListElement

(*curr).next

Common Implementation PitfallsCommon Implementation Pitfalls

Forget to update first, last, and sizeForget to update first, last, and size

Forget to handle special casesForget to handle special cases Empty listEmpty list List with one elementList with one element List with more than one elementsList with more than one elements

Debugging TipsDebugging Tips

Best debugging toolsBest debugging tools YOUR BRAINYOUR BRAIN Careful analysis and designCareful analysis and design Writing code for readability and self-Writing code for readability and self-

documentationdocumentation

Best times to debugBest times to debug DESIGN TIMEDESIGN TIME Coding timeCoding time

Defining Defining class TList<T>class TList<T>template <typename t>template <typename t>class TList {class TList {

friend class TListIterator<T>;friend class TListIterator<T>;public:public:

typedef t value_type;typedef t value_type;typedef TListIterator<T> Iterator;typedef TListIterator<T> Iterator;

// constructors and destructor// constructors and destructorTList();TList();~TList();~TList();TList(const TList<T>& L); TList(const TList<T>& L); TList<T>& operator=(const TList<T>& L);TList<T>& operator=(const TList<T>& L);

// Read-only accessor functions// Read-only accessor functionsunsigned int Size() const;unsigned int Size() const;int Empty() const;int Empty() const;T& Front() const;T& Front() const;T& Back() const;T& Back() const;Iterator Begin() const;Iterator Begin() const;Iterator End() const;Iterator End() const;void Display(ostream os, char ofc = ‘\0’) const;void Display(ostream os, char ofc = ‘\0’) const;

Defining Defining class TList<T>class TList<T> (2) (2)

// Write routines// Write routines

int PushFront(const T& t);int PushFront(const T& t);

int PushBack(const T& t);int PushBack(const T& t);

int PopFront();int PopFront();

int PopBack();int PopBack();

int Insert(Iterator& I, const T& t);int Insert(Iterator& I, const T& t);

int Remove(Iterator& I);int Remove(Iterator& I);

unsigned int Remove(const T& t);unsigned int Remove(const T& t);

void Clear();void Clear();

Defining Defining class TList<T> class TList<T> (3)(3)

protected:protected:

class TListElement {class TListElement {

friend class TList<T>;friend class TList<T>;

friend class TListIterator<T>;friend class TListIterator<T>;

// data// data

T value;T value;

TListElement *prev;TListElement *prev;

TListElement *next;TListElement *next;

TListElement(const T& Tval);TListElement(const T& Tval);

}}

ListElement *first;ListElement *first;

ListElement *last;ListElement *last;

unsigned int size;unsigned int size;

void Clone(const TList<T>& L);void Clone(const TList<T>& L);

};};

Defining Defining class TList<T> class TList<T> (4)(4)// global scope operators and functions// global scope operators and functions

template <typename T>template <typename T>

int operator==(const TList<T>& L1, const TList<T>& L2);int operator==(const TList<T>& L1, const TList<T>& L2);

template <typename T>template <typename T>

int operator!=(const TList<T>& L1, const TList<T>& L2);int operator!=(const TList<T>& L1, const TList<T>& L2);

tempalte <typename T>tempalte <typename T>

ostream& operator<<(ostream& os, const TList<T>& L);ostream& operator<<(ostream& os, const TList<T>& L);

Defining Defining class TListIterator<T>class TListIterator<T>

Template <typename T>Template <typename T>

Class TListIterator {Class TListIterator {

friend class TList<T>;friend class TList<T>;

public:public:

typedef T value_type;typedef T value_type;

// constructors// constructors

TListIterator();TListIterator();

TListIterator(const TList<T>& L);TListIterator(const TList<T>& L);

tListIterator(const TListIterator& I);tListIterator(const TListIterator& I);

void Initialize(const TList<T>& L);void Initialize(const TList<T>& L);

void rInitialize(const TList<T>& L);void rInitialize(const TList<T>& L);

// read-only routines// read-only routines

T& Retrieve() const; // return reference to currT& Retrieve() const; // return reference to curr

int Valid() const; int Valid() const;

Defining Defining class TListIterator<T>class TListIterator<T> (2) (2)

// read-only operators// read-only operators

int operator==(const TListIterator& I2) const;int operator==(const TListIterator& I2) const;

int operator!=(const TListIterator& I2) const;int operator!=(const TListIterator& I2) const;

T& operator*() const; // same as retrieveT& operator*() const; // same as retrieve

// write operators// write operators

TListIterator<T>& operator=(const TListIterator<T>& I);TListIterator<T>& operator=(const TListIterator<T>& I);

TListIterator<T>& operator++(); // prefixTListIterator<T>& operator++(); // prefix

TListIterator<T> operator++(int); // postfixTListIterator<T> operator++(int); // postfix

TListIterator<T>& operator--(); // prefixTListIterator<T>& operator--(); // prefix

TListIterator<T> operator--(int); // postfixTListIterator<T> operator--(int); // postfix

protected:protected:

TList<T>::TListElement *curr;TList<T>::TListElement *curr;

};};

Implementing Implementing class TList<T>class TList<T>

Helper functionsHelper functionstemplate <typename T>template <typename T>

void TList<T>::Clear() {void TList<T>::Clear() {

// deletes all list elements in the TList// deletes all list elements in the TList

// and set data members to 0// and set data members to 0

}}

template <typename T>template <typename T>

void TList<T>::Clone(const TList<T>& L) {void TList<T>::Clone(const TList<T>& L) {

// makes *this a clone of L// makes *this a clone of L

// first copy the static data and initialize the pointers// first copy the static data and initialize the pointers

// then the dynamic data in the non-empty case// then the dynamic data in the non-empty case

}}

Implementing Implementing class TList<T> class TList<T> (2)(2)

ConstructorsConstructorstemplate <typename T>template <typename T>

TList<T>::TListElement::TListElement(const T& t) : value(t), prev(0), TList<T>::TListElement::TListElement(const T& t) : value(t), prev(0), next(0) {next(0) {

}}

template <typename T>template <typename T>

TList<T>::TList() : first(0), last(0), size(0) {TList<T>::TList() : first(0), last(0), size(0) {

}}

template <typename T>template <typename T>

TList<T>::TList(const TList<T>& L) {TList<T>::TList(const TList<T>& L) {

Clone(L);Clone(L);

}}

Implementing Implementing class TList<T> class TList<T> (3)(3)

DestructorDestructortemplate <typename T>template <typename T>

TList<T>::~TList() {TList<T>::~TList() {

Clear();Clear();

}}

Implementing Implementing class TList<T> class TList<T> (4)(4)

Read-only functionsRead-only functionstemplate <typename T> TListIterator<T> TList<T>::Begin() const {template <typename T> TListIterator<T> TList<T>::Begin() const {

Iterator I;Iterator I;

I.curr = first;I.curr = first;

return I;return I;

}}

template <typename T> void TList<T>::Display(ostream &os, char ofc) const {template <typename T> void TList<T>::Display(ostream &os, char ofc) const {

TList<T>::Iterator I;TList<T>::Iterator I;

if (ofc == ‘\0’) {if (ofc == ‘\0’) {

for (I = Begin(); I.Valid(); ++I) {for (I = Begin(); I.Valid(); ++I) {

os << *I;os << *I;

}}

} else {} else {

for (I = Begin(); I.Valid(); ++I) {for (I = Begin(); I.Valid(); ++I) {

os << *I << ofc;os << *I << ofc;

}}

}}

}}

Implementing Implementing class TList<T> class TList<T> (5)(5)

Read-only functionsRead-only functionstemplate <typename T> template <typename T>

ostream& operator<<(ostream& os, const TList<T>& L2) {ostream& operator<<(ostream& os, const TList<T>& L2) {

L2.Display(os);L2.Display(os);

return os;return os;

}}

Implementing Implementing class TList<T> class TList<T> (6)(6)

Read-only functionsRead-only functionstemplate <typename T> template <typename T>

int operator==(const TList<T>& L1, const TList<T>& L2) {int operator==(const TList<T>& L1, const TList<T>& L2) {

if (L1.Size() != L2.Size()) {if (L1.Size() != L2.Size()) {

return 0;return 0;

}}

for (TList<T>::Iterator I1(L1), I2(L2);for (TList<T>::Iterator I1(L1), I2(L2);

I1.Valid() && I2.Valid;I1.Valid() && I2.Valid;

I1++, I2++) {I1++, I2++) {

if (*I1 != *I2) {if (*I1 != *I2) {

return 0;return 0;

}}

}}

return 1;return 1;

}}

Implementing Implementing class TList<T> class TList<T> (7)(7)

Write functionsWrite functionstemplate <typename T> template <typename T>

int operator=(const TList<T>& L) {int operator=(const TList<T>& L) {

if (this != &L) {if (this != &L) {

Clear();Clear();

Clone(L);Clone(L);

}}

return *this;return *this;

}}

Implementing Implementing class TList<T> class TList<T> (8)(8)

InsertInserttemplate <typename T> template <typename T>

int TList<T>::Insert(TListIterator<T>& I, const T& t) {int TList<T>::Insert(TListIterator<T>& I, const T& t) {

// call the Push methods when they apply// call the Push methods when they apply

// Insert at back if iterator is not valid// Insert at back if iterator is not valid

// insert at front if iterator is at front// insert at front if iterator is at front

// iterator is valid and not at front// iterator is valid and not at front

// 1. create a new element// 1. create a new element

// 2. link new element into the list// 2. link new element into the list

// 3. adjust size (if present)// 3. adjust size (if present)

// 4. leave I at new entry and return // 4. leave I at new entry and return

}}

template <typename T>template <typename T>

TListIterator<T> TList<T>::Insert(const T& t) {TListIterator<T> TList<T>::Insert(const T& t) {

TListIterator<T> I = End();TListIterator<T> I = End();

Insert(I, t);Insert(I, t);

return I;return I;

}}

Implementing Implementing class TList<T> class TList<T> (9)(9)

RemoveRemovetemplate <typename T> int TList<T>::Remove(TListIterator<T>& I) {template <typename T> int TList<T>::Remove(TListIterator<T>& I) {

// call the Pop methods when they apply// call the Pop methods when they apply

// make sure of consistent interaction with ends of list// make sure of consistent interaction with ends of list

// first deal with the invalid iterator case// first deal with the invalid iterator case

// for a valid iterator and non-void list// for a valid iterator and non-void list

// deal with cases where I.curr == first or last// deal with cases where I.curr == first or last

// at this point, we are removing a link that’s neither first nor last// at this point, we are removing a link that’s neither first nor last

// 1. remember list element to be removed, and advance iterator// 1. remember list element to be removed, and advance iterator

// 2. unlink old list element from the list// 2. unlink old list element from the list

// 3. delete old list element, adjust size and return// 3. delete old list element, adjust size and return

}}

template <typename T> int TList<T>::Remove(const T& t) {template <typename T> int TList<T>::Remove(const T& t) {

// use iterator I and call Remove(I)// use iterator I and call Remove(I)

// be sure to take into account the similarity of Remove(I) and ++I// be sure to take into account the similarity of Remove(I) and ++I

}}

Implementing Implementing class TListIterator<T>class TListIterator<T>

Helper functionHelper functiontemplate <typename T>template <typename T>

TListIterator<T>::Initialize(const TList<T>& L) {TListIterator<T>::Initialize(const TList<T>& L) {

curr = L.first;curr = L.first;

}}

template <typename T>template <typename T>

TListIterator<T>::rInitialize(const TList<T>& L) {TListIterator<T>::rInitialize(const TList<T>& L) {

curr = L.last;curr = L.last;

}}

Implementing Implementing class TListIterator<T> class TListIterator<T> (2)(2)

ConstructorsConstructorstemplate <typename T>template <typename T>

TListIterator<T>::TListIterator() : curr(0) {TListIterator<T>::TListIterator() : curr(0) {

}}

template <typename T>template <typename T>

TListIterator<T>::TListIterator(const TList<T>& L) {TListIterator<T>::TListIterator(const TList<T>& L) {

Initialize(L);Initialize(L);

}}

template <typename T>template <typename T>

TListIterator<T>::TListIterator(const TListIterator<T>& I) : curr(I.curr) {TListIterator<T>::TListIterator(const TListIterator<T>& I) : curr(I.curr) {

}}

Implementing Implementing class TListIterator<T> class TListIterator<T> (3)(3)

Read-only functionsRead-only functionstemplate <typename T>template <typename T>

int TListIterator<T>::Valid() const {int TListIterator<T>::Valid() const {

return curr != 0;return curr != 0;

}}

template <typename T>template <typename T>

T& TListIterator<T>::Retrieve() const {T& TListIterator<T>::Retrieve() const {

if (curr == 0) {if (curr == 0) {

std:cerr << “TListIterator: invalid dereference” << endl;std:cerr << “TListIterator: invalid dereference” << endl;

exit(EXIT_FAILURE);exit(EXIT_FAILURE);

}}

return curr->value;return curr->value;

}}

Implementing Implementing class TListIterator<T> class TListIterator<T> (4)(4)

Operator functionsOperator functionstemplate <typename T>template <typename T>

T& TListIterator<T>::operator*() const {T& TListIterator<T>::operator*() const {

return curr->value;return curr->value;

}}

template <typename T>template <typename T>

int TListIterator<T>::operator==(const TListIterator<T>& I2) const {int TListIterator<T>::operator==(const TListIterator<T>& I2) const {

if (curr == I2.curr) {if (curr == I2.curr) {

return 1;return 1;

}}

return 0;return 0;

}}