Presentation is loading. Please wait.

Presentation is loading. Please wait.

Abstract Data Type (ADT)

Similar presentations


Presentation on theme: "Abstract Data Type (ADT)"— Presentation transcript:

1 Abstract Data Type (ADT)
& List (Part I)

2 Lecture Objectives What is Abstract Data Type (ADT)?
What is Containers? What is List? How to implement a simple Linked List?

3 What is Abstract Data Types?
Suppose someone has implemented a class with the declaration shown here, even though we have no idea how this class is implemented, we still can write a function as shown to use the class that has been implemented. By just looking at the class declaration (interface), we have NO information how the data within it is stored, how the functions are being implemented. class StudentList { public: StudentList(); ~StudentList() void add(int ID,string Name,float Mark); void changeMark(int ID,float Mark); void sortAccordingToIDs(); void display(); }; int main() { StudentList studlist(5); studlist.add(101,"John",0); studlist.add(102,"Chong",60); studlist.add(113,"Zul",50); studlist.add(121,"Ali",100); studlist.changeMark(101,80); studlist.sortAccordingToIDs(); studlist.display(); }

4 Abstract Data Type (ADT)
Data Abstraction - WHAT we can do to a collection of data INDEPENTANTLY of HOW you can do it. Abstract Data Type (ADT) - A collection of DATA together with a set of OPERATIONS on that data. Data Structure - A construct within a programming language that stored a collection of data ADT interface of ADT Program add sortAccordingToIDs display changeMark Data Structure

5 A collection of elements of the same type Operations :
What is ADT List A collection of elements of the same type Operations : Create the list; initialized to an empty state Determine whether the list is empty Determine whether the list is full Find the size of the list Destroy, or clear, the list Determine whether an item is the same as a given list element Insert an item in the list at the specified location Remove an item from the list at the specified location Replace an item at the specified location with another item Retrieve an item from the list at the specified location Search the list for a given item

6 vector #include <iostream> #include <vector>
using namespace std; int main () { unsigned int i; vector<int> first; // empty vector of ints vector<int> second (4,100); // four ints with value 100 vector<int> third (second.begin(),second.end()); // iterating through second vector<int> fourth (third); // a copy of third // the iterator constructor can also be used to construct from arrays: int myints[] = {16,2,77,29}; vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) ); // or vector<int> fifth (myints, myints+4 );; cout << "\n The contents of first are:"; for (i=0; i < first.size(); i++) cout << " " << first[i]; cout << "\n The contents of second are:"; for (i=0; i < second.size(); i++) cout << " " << second[i]; cout << "\n The contents of third are:"; for (i=0; i < third.size(); i++) cout << " " << third[i]; vector cout << "\n The contents of fourth are:"; for (i=0; i < fourth.size(); i++) cout << " " << fourth[i]; cout << "\n The contents of myints are:"; for (i=0; i < 4; i++) cout << " " << myints[i]; cout << "\n The contents of fifth are:"; for (i=0; i < fifth.size(); i++) cout << " " << fifth[i]; cout << endl; system("pause"); return 0;}

7 Major operations of STL's vector class :
push_back add an item to the end of the container pop_back remove an item from the end of the container at return the item given a position operator[] front return the first item in the container back return the last item in the container size return the size of the container capacity return the capacity of the container empty check if the container is empty resize resize the container clear clear all the items in the container

8 output: Introducing the vector class : must include this
The vector class is parameterized class (generic class) using template, you need to specify the type of data to be stored. #include <iostream> #include <vector> using namespace std; int main() { vector<int> v; v.push_back(4); v.push_back(2); v.push_back(1); v.push_back(6); v.push_back(8); v.push_back(3); for (int i=0;i<6;i++) cout << v[i] << " "; } output: push the item to the end of the array The items are accessed just as if they are array elements

9 Demonstrate that you do not need to worry about memory allocating for it :
#include <iostream> #include <vector> using namespace std; int main() { vector<int> v; int n; do { cout << "=> "; cin >> n; if (n!=-1) v.push_back(n); } while (n!=-1); for (int i=0;i<v.size();i++) cout << v[i] << " "; } output: => 1 => 5 => 3 => 2 => -1 return the size

10 Demonstrate that the vector class will automatically increase its internal storage capacity when required : int main() { vector<int> v; v.push_back(5); v.push_back(1); cout << "size = " << v.size() << " cap = " << v.capacity() << endl; v.push_back(3); v.push_back(7); v.push_back(4); << " cap = " << v.capacity() << endl; v.pop_back(); v.pop_back(); for (int i=0;i<v.size();i++) cout << v[i] << " "; cout << endl; } output: size = 2 cap = 2 size = 5 cap = 8 size = 3 cap = 8 5 1 3 remove item from end

11 Demonstrate that the vector class can be used with any data type :
int main() { vector<string> v; string name; do { cout << "=> "; cin >> name; if (name!="quit") v.push_back(name); } while (name!="quit"); for (int i=0;i<v.size();i++) cout << v[i] << endl; } output: => faten => Yousef => Ahmad => bllaw => norhana => azzyati => quit faten Yousef Ahmad bllaw norhana azzyati There are many more operation you can perform using the vector class, you need to refer to the STL documentation for more details.

12 Array-based List : Implementation
class MyFloatVector { public: MyFloatVector(); ~MyFloatVector(); MyFloatVector (const MyFloatVector& v); MyFloatVector& operator= (const MyFloatVector& v); void push_back(float f); void pop_back(); float& at(int index); float& operator[](int index); float& front(); float& back(); int size() const; int capacity() const; bool empty() const; void resize (int num,float elem=0); void clear(); private: void resizeCapacity(int num); float* data; int Size, Capacity; }; The example here shows the class declaration of our own vector class which can be used as dynamic array of floating points values. We will show how these operations are implemented in the next few slides.

13 Constructors / Destructors / Assignment Operator :
MyFloatVector::MyFloatVector() : Capacity(4), Size(0) { data = new float[Capacity]; } MyFloatVector::~MyFloatVector() { delete[] data; MyFloatVector::MyFloatVector(const MyFloatVector& v) : Capacity(v.Capacity), Size(v.Size) { for (int i=0; i<Size; i++) data[i] = v.data[i]; MyFloatVector& MyFloatVector::operator= (const MyFloatVector& v) { if (this==&v) return *this; Capacity = v.Capacity; Size = v.Size; return *this; As you can see from the constructor, this container class is Implemented as a dynamic array. Just as discussed in Lecture1, you must also implement the destructor, copy constructor and assignment operator.

14 capacity / size operations :
void MyFloatVector::resize(int num,float elem) { resizeCapacity(num); if (Capacity > Size) for (int i=Size;i<Capacity;i++) data[i] = elem; Size = num;} void MyFloatVector::resizeCapacity(int num) { Capacity = num; float* newdata = new float[Capacity]; if (Size > Capacity) Size = Capacity; for (int i=0;i<Size;i++) newdata[i] = data[i]; delete[] data; data = newdata; } void MyFloatVector::clear() { Size = 0; } int MyFloatVector::size() const { return Size; } int MyFloatVector::capacity() const { return Capacity; } bool MyFloatVector::empty() const { if (Size==0) return true; return false; } resize and fill added items with the value of elem. to clear the array, simply set the size to zero, the actual internal array is still allocated.

15 other operations : void MyFloatVector::push_back(float f) { if (Size==Capacity) resizeCapacity(Capacity*2); data[Size] = f; Size++; } void MyFloatVector::pop_back() { if (Size!=0) Size--; float& MyFloatVector::at(int index) { return data[index]; float& MyFloatVector::operator[](int index) { float& MyFloatVector::front() { return data[0]; float& MyFloatVector::back() { return data[Size-1]; As item is added to the end of the list, it will automatically resize itself when the size has reached its internal storage capacity. To remove one item from the end of the list, we do not really remove the item or destroy anything, we simply set the size to be one item less.

16 insert operations : void MyFloatVector::insert(int index, float f) { if (Size==Capacity) resizeCapacity(Capacity*2); for (int i=Size; i > index; i--) data[i] = data[i-1]; data[index] = f; Size++; } To insert an item into a particular index position, you need to move a whole block of items one position towards the end of the array. Size = 5 Capacity = 8 1.1 2.3 7.1 3.6 8.2 data 1.1 2.3 7.1 3.6 8.2 data v.insert(1, 9.3) Size = 6 Capacity = 8 1.1 9.3 2.3 7.1 3.6 8.2 data

17 erase operations : Likewise, to erase an item in the container, you need to move a whole block of items one position towards the beginning of the array to fill the erased gap. void MyFloatVector::erase(int index) { for (int i=index; i < Size-1; i++) data[i] = data[i+1]; Size--; } Size = 6 Capacity = 8 1.1 9.3 2.3 7.1 3.6 8.2 data 1.1 9.3 2.3 7.1 3.6 8.2 data v.erase(2) Size = 5 Capacity = 8 1.1 9.3 7.1 3.6 8.2 data

18 Array-based List : Advantage and Disadvantage
Array-based list is efficient for : - random access - bi-directional sequential access - inserting / erasing item to the end of the list Array-based list is NOT efficient for : - inserting erasing items far away from the end of the list - for use of data which the size changes frequently

19 Linked List : Introduction
item next ListNode The most basic component of a Linked List is the ListNode as shown above. It contains 2 fields : item is the data to be stored, it can be simple data type such as int or char data, or it can be a more complex structure or class such as a Student class to store the information about a student. next is a value which tell us where to find the next data item in the sequence. In the STL's vector class, the next item would be stored in the memory just next to the current item. However, for linked list, we would like to be able to store the data wherever it is convenience in the memory. USUALLY this next value is simply the address of where the next item is found, that means next is actually a pointer. However, other implementation is also possible.

20 Therefore, a linked list is simply a storage structure which consist of a group of ListNodes that are linked together by the value next of each of the ListNode. The actual data are stored in the field item of each of the the ListNode. = information indicating there is no more node to be connected, if pointer is used, this is usually set to NULL.

21 MyLinkedList head tail Obviously, if all the ListNodes are stored somewhere in the memory and they are all linked / chained up together, in order for us to retrieve the information of the whole chain, all we need is the information of where the first node is, we call this the head of the linked list. Sometime, as we shall see, it is good to keep track of the information on where the last node is, we call this information tail of the linked list.

22 MyLinkedList head tail
new link MyLinkedList head tail The main advantage of such a setup is that whenever we want to erase an item from the list, we simply delete the node and re-route the next field of the affected node as shown above.

23 MyLinkedList head tail Likewise, if a new node is inserted, we can do the same as shown in the diagram above.

24 Linked List : Array-based Implementation
class MyCharList { public: MyCharList(); ~MyCharList(); MyCharList(const MyCharList& list); MyCharList& operator= (const MyCharList& 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: }; Here we define the interface of a list for use to store a list of character values. This is almost similar to the MyFloatVector class in the earlier slides, each of the functions / operations declared here has the same meaning as that in MyFloatVector. However, what we are about to implement is very different.

25 We now consider a possible implementation of the Linked List without using pointers. Instead of storing each items in the free memory space (heap memory), we first allocate one huge array of ListNodes and try to store all our items within that array itself. On the left is an example of the representation of our implementation of such linked list. data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] T 4 X -1 3 head We first allocate a huge array of ListNodes and name this array as data. Take note that the next value of each ListNode is not a pointer but it is simply an integer number given us the information of where the next character is stored in the data array. M 5 1 tail R 7 A I 1

26 To try to figure out what is stored in this linked list, we always start with the head information. We proceed as follows : 1. Since head has a value of 3, therefore the first listnode is at index 3 of the data array. In another word, the first node is data[head] = data[3]. 2. Therefore, the first item is data[3].item which is the character 'M'. data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] T 4 X -1 3 head 3. Where is the next listnode? This information is store in data[3].next which has the value of 5, in another word, the next listnode is stored at data[5]. 4. The next item is therefore data[5].item which is the character 'A' 5. You can keep tracing till the next value is -1 indicating the end of the list, you will find that the data stored here is the word "MATRIX'. M 5 1 tail R 7 A I 1

27 T 4 X -1 3 M 5 1 R 7 A I 1 Advantage : erasing data
In our MyFloatVector class earlier, whenever we want to erase a data, we need to move the whole block of memory to fill the gap. This is not necessary for our linked list here. data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] T 4 Suppose we want to erase the character 'I' from the list, this is what we should do : 1. Determine the 2 nodes connecting this node, in the example here, the node before 'I' is data[4] and the node after 'I' is data[1]. X -1 3 head M 5 1 tail R 7 A I 1

28 data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] T 4 2. Connect the 2 nodes identified above so that the link now bypass the node containing 'I'. this is done by changing the value of data[4].next from 7 to 1. 3. We should now mark data[7] as free memory. X -1 3 head M 5 1 tail R 1 A I 1

29 T 4 X -1 3 D M 5 1 R 7 A I 1 Advantage : inserting data
In our MyFloatVector class earlier, whenever we want to insert a data, we need to move the whole block of memory to allow the data to be inserted. This is not necessary for our linked list here. data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] T 4 Suppose now we want to insert a character 'D' in between 'A' and 'T'. this is what we should do : 1. Determine the 2 nodes between which we would like to insert the character. in the example here, the 2 nodes are data[5] and data[0]. 2. Find the first free slot in the array and put the 'D' there. This node is data[2]. X -1 3 head D M 5 1 tail R 7 A I 1

30 data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] T 4 3. Make node data[5] link up with data[2], this is done by changing data[5].next to 2. 4. Set data[2].next to 0 to link up with data[0]. X -1 3 head D M 5 1 tail R 7 A 2 I 1

31 Private data and member functions :
class MyCharList { public: . . . private: int getFirstEmptySlot(); void increaseCapacity(); int getDataIndexOfNode(int index); struct ListNode { char item; int next; }; ListNode* data; int Size, Capacity; int head, tail, cur, prev; Explain later Definition of ListNode, here the next data is actually just an integer value and the item is character. All the ListNodes are to be stored in this dynamic array, this dynamic array will be resized automatically if required. Capacity is the actual size of the array data. Size is the number of items stored so far. keeping track the first (head) and last (tail) node To be used by some of the member functions

32 Constructors / Destructor :
a value of -1 means the value is not set. In another word, it is not pointing to anything yet. MyCharList::MyCharList() : Capacity(8), Size(0) { head = tail = cur = prev = -1; data = new ListNode[Capacity]; for (int i=0; i<Capacity; i++) { data[i].next = -1; data[i].item = '\0'; } MyCharList::~MyCharList() { delete[] data; MyCharList::MyCharList(const MyCharList& list) : Capacity(list.Capacity), Size(list.Size), head(list.head), tail(list.tail), cur(list.cur), prev(list.prev) { data[i].item = list.data[i].item; data[i].next = list.data[i].next; The null character '\0' is used to indicate this is available memory and no data is stored here yet. You may choose to use any other character to indicate available memory, just make sure this character is not used in your data. a typical copy constructor

33 this is a very typical assignment operator
MyCharList& MyCharList::operator= (const MyCharList& list) { if (this==&list) return *this; Capacity = list.Capacity; Size = list.Size; head = list.head; tail = list.tail; cur = list.cur; prev = list.prev; delete[] data; data = new ListNode[Capacity]; for (int i=0; i<Capacity; i++) { data[i].item = list.data[i].item; data[i].next = list.data[i].next; } return *this; this is a very typical assignment operator

34 capacity / size functions :
remember to mark all the additional items as available by setting items as '\0'. void MyCharList::increaseCapacity() { ListNode* newdata = new ListNode[ Capacity*2 ]; for (int i=0; i<Capacity; i++) newdata[i] = data[i]; for (int i=Capacity; i<Capacity*2; i++) { newdata[i].item = '\0'; newdata[i].next = -1; } delete[] data; data = newdata; Capacity *= 2; int MyCharList::size() const { return Size; } bool MyCharList::empty() const { if (head == -1) return true; return false; void MyCharList::clear() { Size = 0; head = tail = cur = prev = -1; for (int i=0; i<Capacity; i++) data[i].item = '\0'; if head is not pointing to anything yet, it means the list is empty. to clear the list, mark every items as '\0' to indicate empty available memory.

35 function to search for empty slot :
int MyCharList::getFirstEmptySlot() { for (int i=0;i<Capacity;i++) if (data[i].item == '\0') return i; int firstempty = Capacity; increaseCapacity(); return firstempty; } Iterate through the whole array and find the index of the first available slot. If none is found, the array's capacity is increased and the empty slot is the first node in the newly allocated array of empty nodes.

36 -1 -1 Push data to front of the list :
void MyCharList::push_front(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = head; head = slot; } Size++; . . . list.push_front('A'); list.push_front('B'); list.push_front('M'); -1 head -1 tail We want to push one character 'A' to the empty linked list. list is empty when head is -1

37 if list is empty, item is always push to the index 0 of the array
data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A void MyCharList::push_front(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = head; head = slot; } Size++; . . . list.push_front('A'); list.push_front('B'); list.push_front('M'); -1 head -1 tail if list is empty, item is always push to the index 0 of the array

38 Since this is the only node, this node is not linked to any other node
data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A -1 void MyCharList::push_front(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = head; head = slot; } Size++; . . . list.push_front('A'); list.push_front('B'); list.push_front('M'); -1 head -1 tail Since this is the only node, this node is not linked to any other node

39 Set head and tail to 0, meaning they points to index 0 of the array.
data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A -1 void MyCharList::push_front(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = head; head = slot; } Size++; . . . list.push_front('A'); list.push_front('B'); list.push_front('M'); head tail Set head and tail to 0, meaning they points to index 0 of the array.

40 Now we want to push another character the the front of the list.
data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A -1 void MyCharList::push_front(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = head; head = slot; } Size++; . . . list.push_front('A'); list.push_front('B'); list.push_front('M'); head tail Now we want to push another character the the front of the list.

41 The first empty slot is at index 1.
data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A -1 void MyCharList::push_front(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = head; head = slot; } Size++; . . . list.push_front('A'); list.push_front('B'); list.push_front('M'); head tail The first empty slot is at index 1.

42 put the character 'B' at index 1
data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A -1 void MyCharList::push_front(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = head; head = slot; } Size++; . . . list.push_front('A'); list.push_front('B'); list.push_front('M'); B head tail put the character 'B' at index 1

43 data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A -1 void MyCharList::push_front(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = head; head = slot; } Size++; . . . list.push_front('A'); list.push_front('B'); list.push_front('M'); B head tail let this new node point to the location which the current head is pointing (head has a value of 0).

44 let head now point to the new slot.
data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A -1 void MyCharList::push_front(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = head; head = slot; } Size++; . . . list.push_front('A'); list.push_front('B'); list.push_front('M'); B 1 head tail let head now point to the new slot.

45 first empty slot found is at index 2
data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A -1 void MyCharList::push_front(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = head; head = slot; } Size++; . . . list.push_front('A'); list.push_front('B'); list.push_front('M'); B 1 head tail first empty slot found is at index 2

46 A -1 B 1 M stored 'M' at new node data[0] data[1] data[2] head data[3]
void MyCharList::push_front(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = head; head = slot; } Size++; . . . list.push_front('A'); list.push_front('B'); list.push_front('M'); B 1 head M tail stored 'M' at new node

47 data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A -1 void MyCharList::push_front(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = head; head = slot; } Size++; . . . list.push_front('A'); list.push_front('B'); list.push_front('M'); B 1 head M 1 tail current head value is 1. Assign this value to the next field of the new node.

48 The head is now has a value is 2. tail remain unchanged.
data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A -1 void MyCharList::push_front(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = head; head = slot; } Size++; . . . list.push_front('A'); list.push_front('B'); list.push_front('M'); B 2 head M 1 tail The head is now has a value is 2. tail remain unchanged.

49 A -1 B 2 M 1 2 M 1 B A -1 equivalent data[0] data[1] data[2] data[3]
2 head M 1 tail equivalent data[2] data[1] data[0] 2 head M 1 B A -1

50 A -1 B 2 M 1 Push data to back of the list :
void MyCharList::push_back(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = -1; data[tail].next = slot; tail = slot; } Size++; . . . list.push_back('T'); list.push_back('R'); list.push_back('X'); B 2 head M 1 tail We now consider the push_back() operation. If the list is empty, push_back() operation is just the same as push_front() operation

51 Push 'T' to the back of the list. The free slot is at index 3
data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A -1 void MyCharList::push_back(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = -1; data[tail].next = slot; tail = slot; } Size++; . . . list.push_back('T'); list.push_back('R'); list.push_back('X'); B 2 head M 1 tail Push 'T' to the back of the list. The free slot is at index 3

52 data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A -1 void MyCharList::push_back(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = -1; data[tail].next = slot; tail = slot; } Size++; . . . list.push_back('T'); list.push_back('R'); list.push_back('X'); B 2 head M 1 T -1 tail store 'T' at this new node, since this will be the last node of the list, the next field is assigned a value of -1.

53 data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A 3 void MyCharList::push_back(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = -1; data[tail].next = slot; tail = slot; } Size++; . . . list.push_back('T'); list.push_back('R'); list.push_back('X'); B 2 head M 1 T -1 tail The current tail is 0 (meaning the current last node is at index 0), we must now make this node link to the new node.

54 The new tail should point to index 3 now.
data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A 3 void MyCharList::push_back(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = -1; data[tail].next = slot; tail = slot; } Size++; . . . list.push_back('T'); list.push_back('R'); list.push_back('X'); B 2 head M 1 T -1 3 tail The new tail should point to index 3 now.

55 push another character.
data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A 3 void MyCharList::push_back(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = -1; data[tail].next = slot; tail = slot; } Size++; . . . list.push_back('T'); list.push_back('R'); list.push_back('X'); B 2 head M 1 T 4 4 tail R -1 push another character.

56 A 3 B 2 M 1 T 4 5 R 5 X -1 push one more. data[0] data[1] data[2] head
void MyCharList::push_back(char ch) { if ( empty() ) { data[0].item = ch; data[0].next = -1; head = tail = 0; } else { int slot = getFirstEmptySlot(); data[slot].item = ch; data[slot].next = -1; data[tail].next = slot; tail = slot; } Size++; . . . list.push_back('T'); list.push_back('R'); list.push_back('X'); B 2 head M 1 T 4 5 tail R 5 X -1 push one more.

57 Displaying the internal data of the list (for debugging purpose only) :
void MyCharList::displayInternalData() { cout << "BEGIN list internal" << endl; for (int i=0; i<Capacity; i++) { cout << setw(3) << i << " " << data[i].item << " " << data[i].next << endl; } cout << "head = " << head << " tail = " << tail << endl; cout << "size = " << Size << " capacity = " << Capacity << endl; cout << "END list internal" << endl; This function is not really part of the ADT list operations, it is included for debugging purposes only, what it does is simply dump the internal array to the output screen.

58 Set the cur to have the same value of head.
Displaying the content of the list : 2 head data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A 3 void MyCharList::display() { cout << "["; int cur = head; while (cur != -1) { cout << data[cur].item; cur = data[cur].next; } cout << "]" << endl; B M 1 5 tail T 4 R 5 2 cur X -1 output: [ Set the cur to have the same value of head.

59 Displaying the content of the list :
2 head data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A 3 void MyCharList::display() { cout << "["; int cur = head; while (cur != -1) { cout << data[cur].item; cur = data[cur].next; } cout << "]" << endl; B M 1 5 tail T 4 R 5 2 cur X -1 output: [M cur is 2, therefore : data[cur].item is 'M'

60 cur is 2, data[cur].next is 1, therefore,
Displaying the content of the list : 2 head data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A 3 void MyCharList::display() { cout << "["; int cur = head; while (cur != -1) { cout << data[cur].item; cur = data[cur].next; } cout << "]" << endl; B M 1 5 tail T 4 R 5 1 cur X -1 output: [M cur is 2, data[cur].next is 1, therefore, the new cur value is 1.

61 cur is 1, data[cur].item is 'B'.
Displaying the content of the list : 2 head data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A 3 void MyCharList::display() { cout << "["; int cur = head; while (cur != -1) { cout << data[cur].item; cur = data[cur].next; } cout << "]" << endl; B M 1 5 tail T 4 R 5 1 cur X -1 output: [M B cur is 1, data[cur].item is 'B'.

62 cur is 1, data[cur].next is 0, therefore,
Displaying the content of the list : 2 head data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A 3 void MyCharList::display() { cout << "["; int cur = head; while (cur != -1) { cout << data[cur].item; cur = data[cur].next; } cout << "]" << endl; B M 1 5 tail T 4 R 5 cur X -1 output: [M B cur is 1, data[cur].next is 0, therefore, the new cur value is 0.

63 ....and so on until cur is -1, where the end of list is found.
Displaying the content of the list : 2 head data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A 3 void MyCharList::display() { cout << "["; int cur = head; while (cur != -1) { cout << data[cur].item; cur = data[cur].next; } cout << "]" << endl; B M 1 5 tail T 4 R 5 -1 cur X -1 output: [M B A T R X] ....and so on until cur is -1, where the end of list is found.

64 data[0] data[1] data[2] data[3] data[4] data[5] data[6] data[7] A 3 B indexing the content of the list, make possible by the operator [] : 2 head M 1 T 4 5 tail R 5 equivalent X -1 2 head X -1 data[5] M 1 data[2] B data[1] A 3 data[0] T 4 data[3] R 5 data[4] list[5] list[0] list[1] list[4] list[2] list[3]

65 simply make cur to point to the next node of the list
int MyCharList::getDataIndexOfNode(int nodeNo) { if ( empty() ) { cout << "Error : empty list"; exit(1); } cur = head; int i = 0; while (i < nodeNo) { cur = data[cur].next; if (cur == -1) { cout << "Error : past end of list"; i++; return cur; char& MyCharList::at(int nodeNo) { int i = getDataIndexOfNode(nodeNo); return data[i].item; char& MyCharList::operator[](int nodeNo) { given the node number of the list, we want to find out what is the index number of this node in the internal array. data[0] data[3] A 3 T 4 data[cur].next cur The statement : cur = data[cur].next simply make cur to point to the next node of the list

66 erasing a node at the beginning of the list
void MyCharList::erase(int nodeNo) { if ( empty() ) { cout << "Error : empty list"; exit(1); } if (nodeNo==0) { data[head].item = '\0'; head = data[head].next; if (head == -1) tail = -1; } else { prev = getDataIndexOfNode(nodeNo-1) cur = data[prev].next; if (data[cur].next == -1) tail = prev; data[prev].next = data[cur].next; data[cur].item = '\0'; Size--; erasing a node at the beginning of the list erasing a node in the middle of the list decrease the size (number of nodes) by 1. we will explain each one in the following slides

67 2 Erasing a node at the beginning of the list : 1 3 4 5 -1 head
M 1 data[2] A 3 data[0] T 4 data[3] R 5 data[4] X -1 data[5] B data[1] 2 head void MyCharList::erase(int nodeNo) { . . . if (nodeNo==0) { data[head].item = '\0'; head = data[head].next; }

68 2 1 3 4 5 -1 head M data[2] B data[1] A data[0] T data[3] R data[4] X
data[1] A 3 data[0] T 4 data[3] R 5 data[4] X -1 data[5] 2 head void MyCharList::erase(int nodeNo) { . . . if (nodeNo==0) { data[head].item = '\0'; head = data[head].next; }

69 1 1 3 4 5 -1 head data[4] data[5] data[2] data[1] data[0] data[3] R X
B data[1] A 3 data[0] T 4 data[3] R 5 data[4] X -1 data[5] 1 head void MyCharList::erase(int nodeNo) { . . . if (nodeNo==0) { data[head].item = '\0'; head = data[head].next; }

70 2 Erasing a node in the middle of the list : 1 3 4 5 -1
data[2] A 3 data[0] T 4 data[3] R 5 data[4] X -1 data[5] B data[1] 2 head Let's say we want to erase node 3 (nodeNo is 3). void MyCharList::erase(int nodeNo) { . . . prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; data[prev].next = data[cur].next; data[cur].item = '\0'; }

71 T 4 data[3] R 5 data[4] X -1 data[5] M 1 data[2] B data[1] A 3 data[0] 2 head prev void MyCharList::erase(int nodeNo) { . . . prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; data[prev].next = data[cur].next; data[cur].item = '\0'; } First thing to do is to find node number 2 (i.e. nodeNo -1), the internal array index of this node is assigned into prev.

72 X -1 data[5] M 1 data[2] B data[1] A 3 data[0] T 4 data[3] R 5 data[4] 2 head prev 3 cur void MyCharList::erase(int nodeNo) { . . . prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; data[prev].next = data[cur].next; data[cur].item = '\0'; } therefore, we can find the array index of the node to be erased. This index is assigned to cur.

73 X -1 data[5] M 1 data[2] B data[1] A 4 data[0] T 4 data[3] R 5 data[4] 2 head prev 3 cur void MyCharList::erase(int nodeNo) { . . . prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; data[prev].next = data[cur].next; data[cur].item = '\0'; } make the node pointed by prev link to the node after the cur node.

74 2 3 -1 1 4 4 5 mark the cur node as empty.
X -1 data[5] M 1 data[2] B data[1] A 4 data[0] 4 data[3] R 5 data[4] 2 head prev 3 cur void MyCharList::erase(int nodeNo) { . . . prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; data[prev].next = data[cur].next; data[cur].item = '\0'; } mark the cur node as empty. As a result, the cur node is erased.

75 inserting a node at the beginning of the list
void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { data[slot].next = head; head = slot; } else { prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; //-1 if at end data[prev].next = slot; data[slot].next = cur; //-1 if at end if (cur == -1) tail = slot; } Size++; inserting a node at the beginning of the list Inserting a node in the middle or end of the list increase the size (number of nodes) by 1. we will explain each one in the following slides

76 2 Inserting a node at the beginning of the list : 4 5 -1 1 3 head T
data[3] R 5 data[4] X -1 data[5] M 1 data[2] B data[1] A 3 data[0] 2 head void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { data[slot].next = head; head = slot; } else . . .

77 T 4 data[3] R 5 data[4] X -1 data[5] M 1 data[2] B data[1] A 3 data[0] 2 head Z data[6] void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { data[slot].next = head; head = slot; } else . . . Free slot found at index 6 of array data. (slot number is 6) Assign the character to be inserted into the item field of this node.

78 2 -1 1 3 4 5 2 Connect this new node to the old head node. head X
data[5] M 1 data[2] B data[1] A 3 data[0] T 4 data[3] R 5 data[4] 2 head data[6] Z 2 void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { data[slot].next = head; head = slot; } else . . . Connect this new node to the old head node.

79 X -1 data[5] M 1 data[2] B data[1] A 3 data[0] T 4 data[3] R 5 data[4] 6 head data[6] Z 2 void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { data[slot].next = head; head = slot; } else . . . The new node is now the head node, therefore assign head to point to this node.

80 2 Inserting a node in the middle of the list : 4 5 -1 1 3
data[3] R 5 data[4] X -1 data[5] M 1 data[2] B data[1] A 3 data[0] 2 head void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { . . . } else { prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; //-1 if at end data[prev].next = slot; data[slot].next = cur; //-1 if at end if (cur == -1) tail = slot; } Let's say we want to insert a new node here at node 3, in another word, inserting between node 2 and node 3.

81 M 1 data[2] B data[1] A 3 data[0] T 4 data[3] R 5 data[4] X -1 data[5] 2 head H data[6] void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { . . . } else { prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; //-1 if at end data[prev].next = slot; data[slot].next = cur; //-1 if at end if (cur == -1) tail = slot; } Free slot found at index 6 of array data. (slot number is 6) Assign the character to be inserted into the item field of this node.

82 prev cur 3 X -1 data[5] M 1 data[2] B data[1] A 3 data[0] T 4 data[3] R 5 data[4] 2 head H data[6] void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { . . . } else { prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; //-1 if at end data[prev].next = slot; data[slot].next = cur; //-1 if at end if (cur == -1) tail = slot; } First thing to do is to find node number 2 (i.e. nodeNo -1), the internal array index of this node is assigned into prev. therefore, we can find the array index of the node of insertion. This index is assigned to cur.

83 3 2 -1 1 6 4 5 connect previous node the new node. prev cur head X
3 X -1 data[5] M 1 data[2] B data[1] A 6 data[0] T 4 data[3] R 5 data[4] 2 head H data[6] void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { . . . } else { prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; //-1 if at end data[prev].next = slot; data[slot].next = cur; //-1 if at end if (cur == -1) tail = slot; } connect previous node the new node.

84 3 2 1 6 4 5 -1 3 connect the new node to the cur node prev cur head M
3 M 1 data[2] B data[1] A 6 data[0] T 4 data[3] R 5 data[4] X -1 data[5] 2 head data[6] H 3 void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { . . . } else { prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; //-1 if at end data[prev].next = slot; data[slot].next = cur; //-1 if at end if (cur == -1) tail = slot; } connect the new node to the cur node

85 5 2 5 Inserting a node to the end of the list : 1 3 4 5 -1
prev Inserting a node to the end of the list : 5 M 1 data[2] B data[1] A 3 data[0] T 4 data[3] R 5 data[4] X -1 data[5] 2 head 5 tail data[6] H void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { . . . } else { prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; //-1 if at end data[prev].next = slot; data[slot].next = cur; //-1 if at end if (cur == -1) tail = slot; } If it happen that the point of insertion is at the end of the list (nodeNo is 6 in the example here), prev will points to the last node of the list (node number 5).

86 5 -1 2 5 1 3 4 5 -1 now cur will have a value of -1. prev cur head
M 1 data[2] B data[1] A 3 data[0] T 4 data[3] R 5 data[4] X -1 data[5] 2 head 5 tail data[6] H void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { . . . } else { prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; //-1 if at end data[prev].next = slot; data[slot].next = cur; //-1 if at end if (cur == -1) tail = slot; } now cur will have a value of -1.

87 5 -1 2 5 1 3 4 5 6 prev cur head tail M data[2] B data[1] A data[0] T
data[1] A 3 data[0] T 4 data[3] R 5 data[4] X 6 data[5] 2 head 5 tail data[6] H void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { . . . } else { prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; //-1 if at end data[prev].next = slot; data[slot].next = cur; //-1 if at end if (cur == -1) tail = slot; }

88 prev cur 5 -1 M 1 data[2] B data[1] A 3 data[0] T 4 data[3] R 5 data[4] X 6 data[5] 2 head 5 tail data[6] H -1 void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { . . . } else { prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; //-1 if at end data[prev].next = slot; data[slot].next = cur; //-1 if at end if (cur == -1) tail = slot; } the next field of this node is assigned the value of cur which is -1 (that means this node is the last node)

89 prev cur 5 -1 M 1 data[2] B data[1] A 3 data[0] T 4 data[3] R 5 data[4] X 6 data[5] 2 head 6 tail data[6] H -1 void MyCharList::insert(int nodeNo, char ch) { int slot = getFirstEmptySlot(); data[slot].item = ch; if (nodeNo==0) { . . . } else { prev = getDataIndexOfNode(nodeNo-1); cur = data[prev].next; //-1 if at end data[prev].next = slot; data[slot].next = cur; //-1 if at end if (cur == -1) tail = slot; } point the tail pointer to the new node, since the new node is now the last node.

90 Other functions : void MyCharList::pop_front() { if ( empty() ) { cout << "Error : empty list"; exit(1); } data[head].item = '\0'; head = data[head].next; Size--; void MyCharList::pop_back() { cur = getDataIndexOfNode(Size-2); int nxt = data[cur].next; data[nxt].item = '\0'; data[cur].next = -1; tail = cur; char& MyCharList::front() { if ( empty() ) { cout << "Error : empty list"; exit(1); } return data[head].item; char& MyCharList::back() { return data[tail].item; These functions are straight forward and will be left for you to figure out.

91 Linked List : Advantage and Disadvantage
Linked list is efficient for : - forward sequential access - inserting / erasing items near the head of the list - for use of data which the size changes frequently Linked list is NOT efficient for : - random access - inserting / erasing items far away from the head of the list [inserting / erasing at the last node is also efficient with the help of the tail variable] NOTE : The above statements are true for the implementation as discussed here, we will discuss different types of linked list which may solved some of the disadvantage mentioned above.

92 Linked List : Sample Runs
output: [datastrualgo] BEGIN list internal 0 s 1 1 t 2 2 r 3 3 u 8 4 a 0 5 t 4 6 a 5 7 d 6 8 a 9 9 l 10 10 g 11 11 o -1 head = 7 tail = 11 size = 12 capacity = 16 END list internal int main() { MyCharList list; list.push_back('s'); list.push_back('t'); list.push_back('r'); list.push_back('u'); list.push_front('a'); list.push_front('t'); list.push_front('d'); list.push_back('a'); list.push_back('l'); list.push_back('g'); list.push_back('o'); list.display(); list.displayInternalData(); }

93 output: int main() { MyCharList list; list.push_back('A'); [HGFEDCAB]
list.push_back('B'); list.push_front('C'); list.push_front('D'); list.push_front('E'); list.push_front('F'); list.push_front('G'); list.push_front('H'); list.display(); list.displayInternalData(); list.erase(1); list.erase(3); list.pop_front(); list.pop_back(); } [HGFEDCAB] BEGIN list internal 0 A 1 1 B -1 2 C 0 3 D 2 4 E 3 5 F 4 6 G 5 7 H 6 head = 7 tail = 1 size = 8 capacity = 8 END list internal [FECA] 0 A -1 1 -1 3 2 4 E 2 6 5 7 5 head = 5 tail = 0 size = 4 capacity = 8

94 output: int main() { MyCharList list; list.push_back('A');
list.push_back('B'); list.push_front('C'); list.push_front('D'); list.push_front('E'); list.push_front('F'); list.push_front('G'); list.push_front('H'); list.display(); list.displayInternalData(); list.erase(1); list.erase(3); list.pop_front(); list.pop_back(); list.push_back('I'); list.insert(1,'J'); list.front() = 'K'; list.back() = 'L'; list[1] = 'M'; list.at(3) = 'N'; } [HGFEDCAB] BEGIN list internal 0 A 1 1 B -1 2 C 0 3 D 2 4 E 3 5 F 4 6 G 5 7 H 6 head = 7 tail = 1 size = 8 capacity = 8 END list internal [KMENAL] 1 L -1 2 N 0 3 M 4 4 E 2 5 K 3 6 5 7 5 head = 5 tail = 1 size = 6 capacity = 8

95 Next Lecture In the next lecture, we will cover :
- implementing linked list using pointers and heap memory - various types of linked list (doubly linked list, circular linked list etc.) - the STL's list class The next lecture is LINKED from this lecture !!! :)


Download ppt "Abstract Data Type (ADT)"

Similar presentations


Ads by Google