Abstract Data Type (ADT) &List (Part II) Lecture Objectives Implement linked list using pointers Concept of iterators STL's list class Other variations.

Slides:



Advertisements
Similar presentations
DATA STRUCTURES USING C++ Chapter 5
Advertisements

Chapter 3 – Lists A list is just what the name implies, a finite, ordered sequence of items. Order indicates each item has a position. A list of size 0.
CSE Lecture 12 – Linked Lists …
Introduction to Linked Lists In your previous programming course, you saw how data is organized and processed sequentially using an array. You probably.
Review of Stacks and Queues Dr. Yingwu Zhu. Our Focus Only link-list based implementation of Stack class Won’t talk about different implementations of.
Copyright © 2008 Pearson Education, Inc. Publishing as Pearson Addison-Wesley Starting Out with C++ Early Objects Sixth Edition Chapter 17: Linked Lists.
C++ Programming: Program Design Including Data Structures, Third Edition Chapter 17: Linked Lists.
1 Data Structures Data Structures Topic #2. 2 Today’s Agenda Data Abstraction –Given what we talked about last time, we need to step through an example.
Data Structures Topic #3. Today’s Agenda Ordered List ADTs –What are they –Discuss two different interpretations of an “ordered list” –Are manipulated.
Starting Out with C++: Early Objects 5/e © 2006 Pearson Education. All Rights Reserved Starting Out with C++: Early Objects 5 th Edition Chapter 17 Linked.
Chapter 4 Linked Lists. © 2005 Pearson Addison-Wesley. All rights reserved4-2 Preliminaries Options for implementing an ADT List –Array has a fixed size.
Chapter 4 Linked Lists. © 2005 Pearson Addison-Wesley. All rights reserved4-2 Preliminaries Options for implementing an ADT List –Array has a fixed size.
2 Preliminaries Options for implementing an ADT List Array has a fixed size Data must be shifted during insertions and deletions Linked list is able to.
Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley Starting Out with C++ Early Objects Seventh Edition by Tony Gaddis, Judy.
Copyright © 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley. Ver Chapter 4: Linked Lists Data Abstraction & Problem Solving with.
Copyright © 2008 Pearson Addison-Wesley. All rights reserved. Chapter 13 Pointers and Linked Lists.
1 Chapter 3 Lists, Stacks, and Queues Abstract Data Types, Vectors Sections 3.1, 3.2, 3.3, 3.4 Abstract Data Types (ADT) Iterators Implementation of Vector.
1 CSC 222: Computer Programming II Spring 2004 Pointers and linked lists  human chain analogy  linked lists: adding/deleting/traversing nodes  Node.
Pointers OVERVIEW.
Chapter 1 Object Oriented Programming. OOP revolves around the concept of an objects. Objects are created using the class definition. Programming techniques.
Prof. amr Goneid, AUC1 CSCE 110 PROGRAMMING FUNDAMENTALS WITH C++ Prof. Amr Goneid AUC Part 16. Linked Lists.
Slide 1 Linked Data Structures. Slide 2 Learning Objectives  Nodes and Linked Lists  Creating, searching  Linked List Applications  Stacks, queues.
Review of Stacks and Queues Dr. Yingwu Zhu. How does a Stack Work? Last-in-First-out (LIFO) data structure Adding an item Push operation Removing an item.
1 Working with Pointers An exercise in destroying your computer.
Iterator for linked-list traversal, Template & STL COMP171 Fall 2005.
Lists Chapter 8. 2 Linked Lists As an ADT, a list is –finite sequence (possibly empty) of elements Operations commonly include: ConstructionAllocate &
Starting Out with C++ Early Objects Seventh Edition by Tony Gaddis, Judy Walters, and Godfrey Muganda Chapter 17: Linked Lists.
Copyright © 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley Slide
Copyright © 2012 Pearson Education, Inc. Chapter 17: Linked Lists.
A Doubly Linked List prevnextdata There’s the need to access a list in reverse order header dnode.
1 Today’s Material List ADT –Definition List ADT Implementation: LinkedList.
Chapter 5 Linked Lists. © 2004 Pearson Addison-Wesley. All rights reserved 5 A-2 Preliminaries Options for implementing an ADT –Array Has a fixed size.
Linked lists. Data structures to store a collection of items Data structures to store a collection of items are commonly used Typical operations on such.
Chapter 5 Linked List by Before you learn Linked List 3 rd level of Data Structures Intermediate Level of Understanding for C++ Please.
The List ADT Reading: Sections 3.2, 3.3, 3.5.
1 Chapter 6 Methods for Making Data Structures. 2 Dynamic Arrays in Data Structures In almost every data structure, we want functions for inserting and.
2005MEE Software Engineering Lecture 7 –Stacks, Queues.
Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley Starting Out with C++ Early Objects Seventh Edition by Tony Gaddis, Judy.
1 Chapter 3 Lists, Stacks, and Queues Reading: Sections 3.1, 3.2, 3.3, 3.4 Abstract Data Types (ADT) Iterators Implementation of Vector.
CS162 - Topic #7 Lecture: Dynamic Data Structures –Review of pointers and the new operator –Introduction to Linked Lists –Begin walking thru examples of.
Chapter 17: Linked Lists. Objectives In this chapter, you will: – Learn about linked lists – Learn the basic properties of linked lists – Explore insertion.
1 Linked Lists Assignment What about assignment? –Suppose you have linked lists: List lst1, lst2; lst1.push_front( 35 ); lst1.push_front( 18 ); lst2.push_front(
1 Linked List. Outline Introduction Insertion Description Deletion Description Basic Node Implementation Conclusion.
Copyright © 2011 Pearson Education, Inc. Publishing as Pearson Addison-Wesley Starting Out with C++ Early Objects Seventh Edition by Tony Gaddis, Judy.
Copyright © 2014, 2008 Pearson Education, Inc. Publishing as Pearson Addison-Wesley Starting Out with C++ Early Objects Eighth Edition by Tony Gaddis,
1 CMPT 117 Linked Lists (singly linked). 2 Problems with arrays  When an element is deleted from or inserted into an array, the rest of the array has.
CC 215 DATA STRUCTURES LINKED LISTS Dr. Manal Helal - Fall 2014 Lecture 3 AASTMT Engineering and Technology College 1.
© Oxford University Press All rights reserved. Data Structures Using C, 2e Reema Thareja.
List Structures What is a list? A homogeneous collection of elements with a linear relationship between the elements linear relationship - each element.
Copyright © 2012 Pearson Education, Inc. Chapter 17: Linked Lists.
Prof. Amr Goneid, AUC1 CSCE 210 Data Structures and Algorithms Prof. Amr Goneid AUC Part R2. Elementary Data Structures.
1 Linked List. List vs Arrays Two built-in data structures that can be used to organize data, or to create other data structures: Lists Arrays.
Lecture 6 of Computer Science II
Pointers and Linked Lists
Lectures linked lists Chapter 6 of textbook
Chapter 4 Linked Lists.
A Doubly Linked List There’s the need to access a list in reverse order prev next data dnode header 1.
Chapter 4 Linked Lists
Linked Lists.
Abstract Data Type (ADT)
Object Oriented Programming COP3330 / CGS5409
Chapter 4 Linked Lists.
Chapter 18: Linked Lists.
Node-based storage with arrays
Linked Lists.
Doubly Linked List Implementation
Chapter 4 Linked Lists.
Chapter 17: Linked Lists.
Doubly Linked List Implementation
Chapter 3 Lists, Stacks, and Queues
Presentation transcript:

Abstract Data Type (ADT) &List (Part II)

Lecture Objectives Implement linked list using pointers Concept of iterators STL's list class Other variations of linked list

Review of Pointers #include using namespace std; struct Position { int x; int y; }; int main() { Position pos; Position* p; p = &pos; p->x = 2; p->y = 4; cout << pos.x << " " << pos.y << endl; cout << (*p).x << " " << (*p).y << endl; cout x y << endl; pos.x = 5; pos.y = 7; cout << pos.x << " " << pos.y << endl; cout << (*p).x << " " << (*p).y << endl; cout x y << endl; } output:

#include using namespace std; struct Position { int x; int y; }; int main() { Position* p; p = new Position; p->x = 2; p->y = 4; cout << (*p).x << " " << (*p).y << endl; cout x y << endl; delete p; } 2 4 output:

Review of Array-based Linked List The most basic structure of an array-based implementation of linked list is a LIstNode as represented in the diagram above and implemented as the code shown. Here the field item is the data to be stored in the list and the field next is basically acting as a 'pointer' to the next ListNode. item next ListNode struct ListNode { char item; int next; }; T 4 X M 5 R 7 A 0 I 1 data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] 3 head 1 tail

In the array-based implementation of linked list, the 'pointer' such as head, tail, cur, prev etc. are not really C++ pointers, they are actually an integer value indicating the index to the array used to store all the nodes. In the example above, cur has a value of 0, that means this 'pointer' is now pointing at data[0] which contain a LIstNode. The item stored there is data[cur].item which is 'A'. data[cur].next would give us the 'pointer' to the next node. A pointer that is not pointing to anything is represented as having value -1. B 0 data[1] A 3 data[0] R 5 data[4] T 4 data[3] X data[5] M 1 data[2] 2 head 0 cur 3 data[cur].next 5 tail

Therefore, if I want to move the cur 'pointer' to 'point' to the next node, all I need to do is the statement below : cur = data[cur].next; B 0 data[1] A 3 data[0] R 5 data[4] T 4 data[3] X data[5] M 1 data[2] 2 head 0 cur 3 data[cur].next 5 tail

Likewise, in some function such as insert() and remove(), we will normally make the 'pointer' prev to 'point' to the node before the node at which we wanted to erase or insert. Therefore, given prev 'pointer', we would be able to find the cur 'pointer' with the statement below : cur = data[prev].next; B 0 data[1] A 3 data[0] R 5 data[4] T 4 data[3] X data[5] M 1 data[2] 2 head 0 prev 3 cur 5 tail

To erase the node pointed by cur, we will do the following : 1. Mark the array location as free slot by : data[cur].item = '\0'; 2. Connect the node pointed by prev to the node after the cur node by : data[prev].next = data[cur].next; B 0 data[1] A 4 data[0] R 5 data[4] \0 4 data[3] X data[5] M 1 data[2] 2 head 0 prev 3 cur 5 tail

To insert a node at the node position pointed by cur, we will do the following : 1. Find a free slot, and call the 'pointer' to the free slot as slot : int slot = getFirstEmptySlot(); 2. Assign the item to this slot by : data[slot].item = ch; 3. Connect the node pointed by prev to the new node by : data[prev].next = slot; 4. Connect the new node to the node pointed by cur : data[slot].next = cur; B 0 data[1] A 6 data[0] R 5 data[4] \0 4 data[3] X data[5] M 1 data[2] 2 head 0 prev 3 cur 5 tail Z 3 data[6] 6 slot

For all the cases of inserting a node or erasing a node, we must always make sure we handle 2 special cases : 1. When the node to be erased or inserted is at the head of the linked list. 1. When the node to be erased or inserted is at the tail of the linked list. For these cases, we need to ensure : 1. Nodes are connected properly 2. the 'pointer' head and tail are updated correctly.

Linked List : Pointer-based Implementation In the pointer-based implementation of linked list, there are THREE major differences as compared with array-based implementation : 1. The pointer such as head, tail, cur, prev etc. are REAL C++ pointers, they are actually pointer to the structure LIstNode, i.e. type is LIstNode* as declared above. 2. There are no internal array within the list class to store the LIstNodes, instead all nodes are stored in the heap memory using the statement : ListNode* slot = new ListNode; Note : slot now is also a REAL C++ pointer. 3. The LIstNode itself is different, the field next is also a REAL C++ pointer (see next slide) ListNode *head, *tail, *prev, *cur;

The most basic structure of an array-based implementation of linked list is a LIstNode as represented in the diagram above and implemented as the code shown. Here the field next is basically a pointer to another ListNode. item next ListNode struct ListNode { char item; ListNode* next; };

In the example above, cur is a pointer to a ListNode containing the item 'A'. The item stored there is cur->item which is 'A'. cur->next would give us the pointer to the next node. A pointer that is not pointing to anything is represented as having value NULL as shown in the last node. B A R T 2104 X null 8692 M head 4650 cur 2104 cur->next 8692 tail Whenever in the array-based linked list you have data[ptr].field, you should have ptr->field in the pointer-based linked list

Therefore, if I want to move the cur pointer to point to the next node, all I need to do is the statement below : cur = cur->next; B A R T 2104 X null 8692 M head 4650 cur 2104 cur->next 8692 tail

B A R T 2104 X null 8692 M head 4650 prev 2104 cur 8692 tail Likewise, in some function such as insert() and remove(), we will normally make the pointer prev to point to the node before the node at which we wanted to erase or insert. Therefore, given prev pointer, we would be able to find the cur pointer with the statement below : cur = prev->next;

B A R X null 8692 M head 4650 prev 2104 cur 8692 tail To erase the node pointed by cur, we will do the following : 1. Connect the node pointed by prev to the node after the cur node by : prev->next = cur->next; 2. Free the memory pointed by cur : delete cur; Make sure the sequence is correct, make sure cur->next is assigned to prev->next before you free memory pointed by cur.

B A R T 2104 X null 8692 M head 4650 prev 2104 cur 8692 tail To insert a node at the node position pointed by cur, we will do the following : 1. Find a free slot, and call the pointer to the free slot as slot : ListNode* slot = new ListNode; 2. Assign the item to this slot by : slot->item = ch; 3. Connect the node pointed by prev to the new node by : prev->next = slot; 4. Connect the new node to the node pointed by cur : slot->next = cur; Z slot

Just as in array-based implementation, for all the cases of inserting a node or erasing a node, we must always make sure we handle 2 special cases : 1. When the node to be erased or inserted is at the head of the linked list. 1. When the node to be erased or inserted is at the tail of the linked list. For these cases, we need to ensure : 1. Nodes are connected properly 2. the 'pointer' head and tail are updated correctly.

class MyCharListPtr { public: MyCharListPtr(); ~MyCharListPtr(); MyCharListPtr(const MyCharListPtr& list); MyCharListPtr& operator= (const MyCharListPtr& list); void push_front(char ch); void pop_front(); void push_back(char ch); void pop_back(); char& at(int index); char& operator[](int index); char& front(); char& back(); int size() const; bool empty() const; void clear(); void display(); void erase(int index); void insert(int index, char ch); private:.... }; Class Declaration : If you notice, this class interface is EXACTLY the SAME with the earlier array-based linked list class. This is a GOOD example of data abstraction, the interface of a ADT is independent of its implementation !!

class MyCharListPtr { public:... private: //OLD// int getFirstEmptySlot(); //OLD// void increaseCapacity(); //OLD// ListNode* data; //OLD// int Capacity; struct ListNode { char item; //OLD// int next; /*NEW*/ ListNode* next; }; //OLD// int getDataIndexOfNode(int nodeNo); /*NEW*/ ListNode* getPointerToNode(int nodeNo); int Size; //OLD// int head, tail, cur, prev; /*NEW*/ ListNode *head, *tail, *cur, *prev; }; Private data and member functions : Lines begin with //OLD// are lines from earlier array-based implementation, they are now NOT used and commented. These lines are shown here for comparison purposes. Lines begin with /*NEW*/ are new lines as compared with earlier array-based implementation More explanation next slide... These lines are same with array-based implementation.

class MyCharListPtr { public:... private: //OLD// int getFirstEmptySlot(); //OLD// void increaseCapacity(); //OLD// ListNode* data; //OLD// int Capacity; struct ListNode { char item; //OLD// int next; /*NEW*/ ListNode* next; }; //OLD// int getDataIndexOfNode(int nodeNo); /*NEW*/ ListNode* getPointerToNode(int nodeNo); int Size; //OLD// int head, tail, cur, prev; /*NEW*/ ListNode *head, *tail, *cur, *prev; }; Implementation is now very different from earlier array-based implementation. Do not need this anymore as memory allocation is now done with new operator and stored at the heap memory. these pointers are now REAL C++ pointer of type LIstNode*.

MyCharListPtr::MyCharListPtr() //OLD// : Capacity(8), Size(0) /*NEW*/ : Size(0) { //OLD// head = tail = cur = prev = -1; /*NEW*/ head = tail = cur = prev = NULL; //OLD// data = new ListNode[Capacity]; //OLD// for (int i=0; i<Capacity; i++) //OLD// { //OLD// data[i].item = '\0'; //OLD// data[i].next = -1; //OLD// } } MyCharListPtr::~MyCharListPtr() { //OLD// delete[] data; /*NEW*/ while ( !empty() ) /*NEW*/ pop_front(); } Default Constructor / Destructor : NULL means the pointers are not pointing to anything yet. remove (pop out) all the nodes.

MyCharListPtr& MyCharListPtr::operator= (const MyCharListPtr& list) { if (this==&list) return *this; Size = list.Size; //OLD// Capacity = list.Capacity; //OLD// head = list.head; tail = list.tail; //OLD// cur = list.cur; prev = list.prev; //OLD// delete[] data; //OLD// data = new ListNode[Capacity]; //OLD// for (int i=0; i<Capacity; i++) //OLD// { //OLD// data[i].item = list.data[i].item; //OLD// data[i].next = list.data[i].next; //OLD// } /*NEW*/ clear(); /*NEW*/ head = tail = NULL; /*NEW*/ cur = list.head; /*NEW*/ while (cur != NULL) { /*NEW*/ push_back( cur->item ); /*NEW*/ cur = cur->next; /*NEW*/ } return *this; } Assignment operator : Start with a empty list push all the items from the source list to the current list.

MyCharListPtr::MyCharListPtr(const MyCharListPtr& list) //OLD// : Capacity(list.Capacity), Size(list.Size) { //OLD// data = new ListNode[Capacity]; //OLD// for (int i=0; i<Capacity; i++) //OLD// { //OLD// data[i].item = list.data[i].item; //OLD// data[i].next = list.data[i].next; //OLD// } /*NEW*/ *this = list; } Copy Constructor : Making use of the assignment operator

capacity / size functions : remove (pop out) items until the list is empty int MyCharListPtr::size() const { return Size; } bool MyCharListPtr::empty() const { //OLD// if (head == -1) return true; /*NEW*/ if (head == NULL) return true; } void MyCharListPtr::clear() { //OLD// Size = 0; //OLD// head = tail = cur = prev = -1; //OLD// for (int i=0; i<Capacity; i++) //OLD// data[i].item = '\0'; /*NEW*/ while ( !empty() ) /*NEW*/ pop_front(); } NOTE : there are no functions regarding capacity since this issues does not arise.

slot points to newly allocated LIstNode in the heap memory void MyCharListPtr::push_front(char ch) { if ( empty() ) { //OLD// data[0].item = ch; //OLD// data[0].next = -1; //OLD// head = tail = 0; /*NEW*/ head = new ListNode; /*NEW*/ head->item = ch; /*NEW*/ head->next = NULL; /*NEW*/ tail = head; } else { //OLD// int slot = getFirstEmptySlot(); //OLD// data[slot].item = ch; //OLD// data[slot].next = head; /*NEW*/ ListNode* slot = new ListNode; /*NEW*/ slot->item = ch; /*NEW*/ slot->next = head; head = slot; } Size++; } Push data to front of the list :

void MyCharListPtr::push_back(char ch) { if ( empty() ) { //OLD// data[0].item = ch; //OLD// data[0].next = -1; //OLD// head = tail = 0; /*NEW*/ head = new ListNode; /*NEW*/ head->item = ch; /*NEW*/ head->next = NULL; /*NEW*/ tail = head; } else { //OLD// int slot = getFirstEmptySlot(); //OLD// data[slot].item = ch; //OLD// data[slot].next = -1; /*NEW*/ ListNode* slot = new ListNode; /*NEW*/ slot->item = ch; /*NEW*/ slot->next = NULL; //OLD// data[tail].next = slot; /*NEW*/ tail->next = slot; tail = slot; } Size++; } Push data to back of the list :

void MyCharListPtr::display() { cout << "["; cur = head; //OLD// while (cur != -1) /*NEW*/ while (cur != NULL) { //OLD// cout << data[cur].item; //OLD// cur = data[cur].next; /*NEW*/ cout item; /*NEW*/ cur = cur->next; } cout << "]" << endl; } Displaying the content of the list :

//OLD// int MyCharList::getDataIndexOfNode(int nodeNo) { /*NEW*/ ListNode* MyCharListPtr::getPointerToNode(int nodeNo) { if ( empty() ) { cout << "Error : empty list" << endl; exit(1); } if (nodeNo >= Size) { cout << "Error : past the end" << endl; exit(1); } cur = head; int i = 0; while (i < nodeNo) { //OLD// cur = data[cur].next; /*NEW*/ cur = cur->next; i++; } return cur; } char& MyCharListPtr::at(int nodeNo) { //OLD// int i = getDataIndexOfNode(nodeNo); //OLD// return data[i].item; /*NEW*/ ListNode* p = getPointerToNode(nodeNo); /*NEW*/ return p->item; } char& MyCharListPtr::operator[](int nodeNo) { //OLD// int i = getDataIndexOfNode(nodeNo); //OLD// return data[i].item; /*NEW*/ ListNode* p = getPointerToNode(nodeNo); /*NEW*/ return p->item; } Index operation :

void MyCharListPtr::erase(int nodeNo) { if ( empty() ) { cout << "Error : empty list" << endl; exit(1); } if (nodeNo==0) { //OLD// data[head].item = '\0'; //OLD// head = data[head].next; /*NEW*/ ListNode* oldhead = head; /*NEW*/ head = head->next; /*NEW*/ delete oldhead; } else { //OLD// prev = getDataIndexOfNode(nodeNo-1); //OLD// cur = data[prev].next; //OLD// data[prev].next = data[cur].next; //OLD// data[cur].item = '\0'; /*NEW*/ prev = getPointerToNode(nodeNo-1); /*NEW*/ cur = prev->next; /*NEW*/ prev->next = cur->next; /*NEW*/ delete cur; } Size--; } Erasing a node :

void MyCharListPtr::insert(int nodeNo, char ch) { //OLD// int slot = getFirstEmptySlot(); //OLD// data[slot].item = ch; /*NEW*/ ListNode* slot = new ListNode; /*NEW*/ slot->item = ch; if (nodeNo==0) { //OLD// data[slot].next = head; /*NEW*/ slot->next = head; head = slot; } else { //OLD// prev = getDataIndexOfNode(nodeNo-1); //OLD// cur = data[prev].next; //-1 if at end of list //OLD// data[prev].next = slot; //OLD// data[slot].next = cur; //-1 if at end of list //OLD// if (cur == -1) /*NEW*/ prev = getPointerToNode(nodeNo-1); /*NEW*/ cur = prev->next; /*NEW*/ prev->next = slot; /*NEW*/ slot->next = cur; /*NEW*/ if (cur == NULL) tail = slot; } Size++; } inserting a node :

void MyCharListPtr::pop_front() { if ( empty() ) { cout << "Error : pop empty list" << endl; exit(1); } //OLD// data[head].item = '\0'; //OLD// head = data[head].next; /*NEW*/ ListNode* oldhead = head; /*NEW*/ head = head->next; /*NEW*/ delete oldhead; Size--; } void MyCharListPtr::pop_back() { if ( empty() ) { cout << "Error : pop empty list" << endl; exit(1); } if ( Size == 1 ) pop_front(); //OLD// prev = getDataIndexOfNode(Size-2); //OLD// cur = data[prev].next; //OLD// data[cur].item = '\0'; //OLD// data[prev].next = -1; /*NEW*/ prev = getPointerToNode(Size-2); /*NEW*/ cur = prev->next; /*NEW*/ delete cur; /*NEW*/ prev->next = NULL; tail = prev; Size--; } Other functions :

char& MyCharListPtr::front() { if ( empty() ) { cout << "Error : empty list in front()" << endl; exit(1); } //OLD// return data[head].item; /*NEW*/ return head->item; } char& MyCharListPtr::back() { if ( empty() ) { cout << "Error : empty list in back()" << endl; exit(1); } //OLD// return data[tail].item; /*NEW*/ return tail->item; }

Linked List : Concept of Iterator MyCharListPtr list;... for (int i=0; i<list.size(); i++) cout << list[i] << endl; Given our pointer-based linked list, what is the weakness of the following code?

MyCharListPtr list;... for (int i=0; i<list.size(); i++) cout << list[i] << endl; The main weakness of this code is that each time the operator[] is called, internally, the linked list will search for the node i starting from the head node (node 0) It will be good if we can have some kind of mechanism that allows us to iterate through the list one node after another.

char data[] = { 'H', 'E', 'L', 'L', 'O', '\0' }; char* begin = &data[0]; char* end = &data[5]; char* itr; for (itr=begin; itr!=end; ++itr) cout << *itr << endl; Before we continue, let's consider the code below : Here the pointer itr is acting as an 'locator' of the elements stored in data. It starts at address as given by the value begin which happened to be the first element of the array. This pointer itr will iterate through each element of the array, the way it iterates through is by moving one element forward as given by the ++itr. In each iteration, we can access the items stored by using the dereferencing operator *itr. This process will continue until it reaches the address as given by the value end which is the address passed the last element. HELLOHELLO output:

MyCharListPtr list;... MyIterator itr; for (itr=list.begin(); itr!=list.end(); ++itr) cout << *itr << endl; It will be nice if we could iterate through our linked list in similar way as shown in the program below : From the code above, we can see that we will need to define some kind of class called MyIterator which contain the following operation : 1. operator *()2. operator operator ==4. operator != As for the MyCharListPtr class, it will need to implement the begin() and end() function which returns object of type MyIterator. begin() return an iterator at the head position of the list and end() return a iterator indicating position passed the end of the list. some data type, yet to be defined Of course, we will need to call some kind of function of list to know where the first item is and where the last item is.

class MyCharListPtr { public: struct iterator { char& operator *() { return ptr->item; } void operator ++() //prefix { ptr = ptr->next; } void operator ++(int) //postfix { ptr = ptr->next; } bool operator == (const iterator& itr) { return (ptr == itr.ptr); } bool operator != (const iterator& itr) { return (ptr != itr.ptr); } ListNode* ptr; }; iterator begin() { iterator i; i.ptr = head; return i; } iterator end() { iterator i; i.ptr = NULL; return i; }... }; we define a class called iterator within our linked list itself. This iterator class is basically very simple, it just keep track of a pointer which point to one node of the linked list. The operator ++ simple advance the pointer to the next listnode. This simply set the iterator to point to head node In our linked list, a pointer passed the end of list is assigned a value of NULL.

int main() { MyCharListPtr list; list.push_back('L'); list.push_back('I'); list.push_back('N'); list.push_back('K'); list.push_back('E'); list.push_back('D'); MyCharListPtr::iterator itr; for (itr= list.begin(); itr!=list.end(); ++itr) cout << *itr << endl; } LINKEDLINKED output: The iterator class is defined within the MyCharListPtr class.

Linked List : STL's list class The STL's list class is very much similar to the MyCharListPtr class that we have implemented, the major differences are : 1. list class is based on template, which means it can be used as container to store any kind of data. 2. list class does not have the operator [], meaning it is not a random access container but rather sequential container 3. Since list class does not have the operator [], it does not have the notion of list index, that means for erasing and inserting data, we can not specify the index to insert or erase. to insert or erase data, we must have an iterator to iterate to the point of deletion or insertion. (examples later) 4. list is a doubly linked list (more on this later). In our MyCharListPtr class, it is efficient to iterate through the nodes from head to tail (using the iterator) but not the other way round. However, for the list class, we can iterate through the list using a forward iterator or reverse iterator. 5. list class does not have the display() function. 6. Of course, list class has many more other functions.

STL's list : Sample Runs #include using namespace std; int main() { list lst; list ::iterator itr; lst.push_back('s'); lst.push_back('t'); lst.push_back('r'); lst.push_back('u'); lst.push_front('a'); lst.push_front('t'); lst.push_front('a'); lst.push_front('d'); lst.push_back('a'); lst.push_back('l'); lst.push_back('g'); lst.push_back('o'); for (itr=lst.begin(); itr!=lst.end(); ++itr) cout << *itr << endl; } datastrualgodatastrualgo output: must have this iterator iterate through the list

#include using namespace std; int main() { list lst; list ::iterator itr; lst.push_back('s'); lst.push_back('t'); lst.push_back('r'); lst.push_back('u'); cout << lst.front() << endl; cout << lst.back() << endl; lst.pop_front(); lst.pop_back(); for (itr=lst.begin(); itr!=lst.end(); ++itr) cout << *itr << endl; } sutrsutr output:

#include using namespace std; int main() { list planetlist; list ::iterator itr; planetlist.push_back("Venus"); planetlist.push_back("Earth"); planetlist.push_back("Sun"); planetlist.push_back("Mars"); itr = planetlist.begin(); itr++; planetlist.erase(itr); for (itr=planetlist.begin(); itr!=planetlist.end(); ++itr) cout << *itr << endl; } Venus Earth Mars output: erase function accept NOT index value, but iterator pointing at point of deletion.

#include using namespace std; int main() { list planetlist; list ::iterator itr; planetlist.push_back("Venus"); planetlist.push_back("Earth"); planetlist.push_back("Sun"); planetlist.push_back("Mars"); itr = find (planetlist.begin(), planetlist.end(), "Sun"); planetlist.erase(itr); for (itr=planetlist.begin(); itr!=planetlist.end(); ++itr) cout << *itr << endl; } Venus Earth Mars output: the STL's find function is an example of the algorithm component of STL.

#include using namespace std; int main() { list planetlist; list ::iterator itr; planetlist.push_back("Venus"); planetlist.push_back("Earth"); planetlist.push_back("Mars"); planetlist.push_back("Uranus"); itr = planetlist.begin(); planetlist.insert(itr,"Mercury"); itr = find (planetlist.begin(), planetlist.end(), "Uranus"); itr = planetlist.insert(itr,"Saturn"); itr = planetlist.insert(itr,"Jupiter"); for (itr=planetlist.begin(); itr!=planetlist.end(); ++itr) cout << *itr << endl; } Mercury Venus Earth Mars Jupiter Saturn Uranus output: insert function accept iterator pointing at point of insertion.

#include using namespace std; int main() { list planetlist; list ::iterator itr; planetlist.push_back("Venus"); planetlist.push_back("Earth"); planetlist.push_back("Mars"); planetlist.push_back("Jupiter"); itr = planetlist.begin(); cout << *itr << endl; itr++; cout << *itr << endl; itr++; cout << *itr << endl; itr--; cout << *itr << endl; } Venus Earth Mars Earth output: This iterator is bi-directional, meaning it can iterate backward

#include using namespace std; int main() { list planetlist; list ::reverse_iterator rItr; planetlist.push_back("Venus"); planetlist.push_back("Earth"); planetlist.push_back("Mars"); planetlist.push_back("Jupiter"); rItr = planetlist.rbegin(); cout << *rItr << endl; rItr++; cout << *rItr << endl; rItr++; cout << *rItr << endl; rItr--; cout << *rItr << endl; cout << "-----" << endl; for (rItr=planetlist.rbegin(); rItr!=planetlist.rend(); ++rItr) cout << *rItr << endl; } Jupiter Mars Earth Mars Jupiter Mars Earth Venus output: this is a reverse iterator, its beginning is the tail of the list, forward means going from tail to head.

The STL's list class vs. STL's vector class, which one to use? 1. vector class is an array-based list while list class is based on linked list. 2. vector class suitable for random access while list class is more for sequential access. Therefore, if you have large set of data and the size of your data may shrink or grow from time to time and you constantly need to add or remove data from the list, then list class will be a good choice for you. Bear in mind that for the same amount of data, the list class will use more memory as compare with vector class. If your data set is small, vector class may be a better choice since whatever resizing may not be a big problem as compare with the ease of use (the random access nature).

Linked List Variation : Doubly LInked List If we compare the STL's list class with our MyCharListPtr class, one major different is that the iterator of the STL's list class can go forward or backward (bi-directional) while the iterator of our MyCharListPtr class can only go forward. For our MyCharListPtr class, if the iterator is currently pointing to a node and we want to retrieve the node before it, we will have to go all the way to the beginning of the list and iterate through the list again. This is very inefficient. The list class does not suffer this limitation, this is because it is implemented as a doubly linked list.

Doubly linked list : The most basic structure of a doubly linked list is represented in the diagram above and implemented as the code shown. Here there is an extra field called previous which will be used to connect to the node before the current node. item next ListNode struct ListNode { char item; ListNode* previous; ListNode* next; }; previous

S headcur cur->next tail null T R U As before, if we want to get the pointer of the next node, all I need to do is the statement below : nextnode = cur->next; On top of that, we are also able to get the pointer to the previous node, then we can use the following statement below : prevnode = cur->previous; cur->previous

S headcur nextnode tail null R U To erase the node pointed by cur, we will do the following : 1. Identify the previous node and next node : prevnode = cur->previous; nextnode = cur->next; 1. Connect the node pointed by prevnode to node pointed by nextnode : prevnode->next = nextnode; nextnode->previous = prevnode; 2. Free the memory pointed by cur : delete cur; prevnode

S headcur nextnode tail null T R U prevnode To insert a node at node position pointed by cur, we will do the following : 1. Identify the previous node : prevnode = cur->previous; 2. Find a free slot, and call the pointer to the free slot as slot : ListNode* slot = new ListNode; 3. Assign the item to this slot by : slot->item = ch; 4. Connect the node pointed by prevnode to the new node by : prevnode->next = slot; slot->previous = prevnode; 5. Connect new node to node pointed by cur : slot->next = cur;cur->previous = slot; Z slot

As usual, for all the cases of inserting a node or erasing a node, we must always make sure we handle 2 special cases : 1. When the node to be erased or inserted is at the head of the linked list. 1. When the node to be erased or inserted is at the tail of the linked list. For these cases, we need to ensure : 1. Nodes are connected properly 2. the pointer head and tail are updated correctly.

Advantage of Doubly Linked List : 1. You may have noticed that for node deletion or insertion, the previous node can be directly obtained based on the current node, without having to search through the list starting from the head node. 2. The iterator became bi-directional as it can now iterate forward as well as backward to the previous node.

Linked List Variation : Circular LInked List B A R T 2104 X M ptr S T R U A circular list is basically a linked list of which the the next pointer of the last node points back to the first node (node 0). For doubly linked list, the previous pointer of first node points to the last node. There is no head or tail pointer, but we still need a pointer to one of the node in order to access the list. Application : Implementing a queue

Note about STL There are still a lot of things you can use in STL. In real life application, it is unlikely you would ever need to develop your own vector classes and linked list classes, you are strongly recommended to use STL's vector and list class instead. Even if you would program in Java, there are Java Collection Classes which contains classes for list and linked list as well. Then why do we ever need to learn to do our own list and linked list?

There are still a lot of things you can use in STL. In real life application, it is unlikely you would ever need to develop your own vector classes and linked list classes, you are strongly recommended to use STL's vector and list class instead. Even if you would program in Java, there are Java Collection Classes which contains classes for list and linked list as well. Then why do we ever need to learn to do our own list and linked list? ANSWER : 1. In the future, you may need to program in a different programming language that may not have build-in list and linked list classes 2. Understand how list and linked list are constructed will enable you to make wiser decision on what to use based on your need. 3. Understand how to constructed these classes will enable you to construct other type of user-defined ADT.