> n; int* A = new int[n]; initialize(A, n, 0); print(A, n); A = addEnd(A,n,5); print(A, n); A = addHead(A,n,5); print(A, n); A = deleteFirst(A,n); print(A, n); selectionSort(A, n); print(A, n); delete [] A; } How to use a list? int A[10000]; int n; Nothing compulsory in programming, only style matters!"> > n; int* A = new int[n]; initialize(A, n, 0); print(A, n); A = addEnd(A,n,5); print(A, n); A = addHead(A,n,5); print(A, n); A = deleteFirst(A,n); print(A, n); selectionSort(A, n); print(A, n); delete [] A; } How to use a list? int A[10000]; int n; Nothing compulsory in programming, only style matters!">
Download presentation
Presentation is loading. Please wait.
Published byHarriet Atkinson Modified over 9 years ago
1
List, (dynamic) linked list Let’s first forget about ‘classes’, but only a dynamic list. We make lists with ‘classes’ afterwards.
2
A simple list Example: using a dynamic array * concept of a list, e.g. a list of integers n Print out info n Empty test n Search an element n Insertion (at head, at end, any position) n Deletion n … * implemented n by a static array (over-sized if necessary) int list[1000]; int size; n by a dynamic array int list[size]; int size; n by a linked list and more …
3
int main() { cout << "Enter list size: "; int n; cin >> n; int* A = new int[n]; initialize(A, n, 0); print(A, n); A = addEnd(A,n,5); print(A, n); A = addHead(A,n,5); print(A, n); A = deleteFirst(A,n); print(A, n); selectionSort(A, n); print(A, n); delete [] A; } How to use a list? int A[10000]; int n; Nothing compulsory in programming, only style matters!
4
Initialize void initialize(int list[], int size, int value){ for(int i=0; i<size; i++) list[i] = value; }
5
void print(int list[], int size) { cout << "[ "; for(int i=0; i<size; i++) cout << list[i] << " "; cout << "]" << endl; } Print out a list
6
Delete the first element // for deleting the first element of the array int* deleteFirst(int list[], int& size){ int* newList; newList = new int[size-1]; // make new array if(size){// copy and delete old array for(int i=0; i<size-1; i++) newList[i] = list[i+1]; delete [] list; } size--; return newList; }
7
Instead of A = deleteFirst(A,n) we can also just deleteFirst(A,n) if we define as a void type function: void deleteFirst(int*& A, int& size) { … A = newList; } Remark: We can also B = deleteFirst(A,n) if we keep the original intact
8
Adding Elements // for adding a new element to end of array int* addEnd(int list[], int& size, int value){ int* newList; newList = new int [size+1]; // make new array if(size){// copy and delete old array for(int i=0; i<size; i++) newList[i] = list[i]; delete [] list; } newList[size] = value; size++; return newList; }
9
// for adding a new element at the beginning of the array int* addHead(int list[], int& size, int value){ int* newList; newList = new int [size+1]; // make new array if(size){// copy and delete old array for(int i=0; i<size; i++) newList[i+1] = list[i]; delete [] list; } newList[0] = value; size++; return newList; } Add at the beginning:
10
Linked list: a dynamic list
11
Motivation * list using static array int myArray[1000]; int n; We have to decide (to oversize) in advance the size of the array (list) * list using dynamic array int* myArray; int n; cin >> n; myArray = new int[n]; We allocate an array (list) of any specified size while the program is running * linked-list (dynamic size) size = ?? The list is dynamic. It can grow and shrink to any size.
12
Array naturally represents a (ordered) list, the link is implicit, consecutive and contiguous! Now the link is explicit, any places! 2045 7585 Data Link 20 45 75 85 Data Link 20457585 Data Link 0 1 2 array linked list
13
Linked Lists: Basic Idea * A linked list is an ordered collection of data * Each element of the linked list has n Some data n A link to the next element * The link is used to chain the data Example: A linked list of integers: 20457585 Data Link
14
* The list can grow and shrink Linked Lists: Basic Ideas 20457585 2045 addEnd(75), addEnd(85) deleteEnd(85), deleteHead(20), deleteHead(45) 75
15
* Original linked list of integers: * Insertion (in the middle): * Deletion (in the middle) Linked Lists: Operations 20457585 20457585 20457585 60 old value deleted item
16
struct Node{ int data; Node* next; }; We can also: typedef Node* NodePtr; Definition of linked list type:
17
Linked List Structure * Node : Data + Link n Definition struct Node { int data;//contains useful information Node* next;//points to next element or NULL }; n Create a Node Node* p; p = new Node;//points to newly allocated memory n Delete a Node delete p;
18
n Access fields in a node (*p).data;//access the data field (*p).next;//access the pointer field Or it can be accessed this way p->data//access the data field p->next//access the pointer field
19
Representing and accessing linked lists * We define a pointer Node* head; that points to the first node of the linked list. When the linked list is empty then head is NULL. 20457585 Head
20
Passing a Linked List to a Function When passing a linked list to a function it should suffice to pass the value of head. Using the value of head the function can access the entire list. Problem: If a function changes the beginning of a list by inserting or deleting a node, then head will no longer point to the beginning of the list. Solution: When passing head always pass it by reference (not good!) or using a function to return a new pointer value It is roughly the same as for an array!!!
21
Implementation of an (Unsorted) Linked List
22
Start the first node from scratch Node* newPtr; newPtr = new Node; newPtr->data = 20; newPtr->next = NULL; head = newPtr; Head newPtr 20 Head head = NULL;
23
Inserting a Node at the Beginning newPtr = new Node; newPtr->data = 13; newPtr->next = Head; head = newPtr; Head newPtr 13 20
24
Keep going … Head newPtr 50401320
25
void addHead(Node*& head, int newdata){ Node* newPtr = new Node; newPtr->data = newdata; newPtr->next = Head; head = newPtr; } Adding an element to the head: Call by reference, scaring!!! NodePtr&
26
Node* addHead(Node* head, int newdata){ Node* newPtr = new Node; newPtr->data = newdata; newPtr->next = Head; return newPtr; } Also written (more functionally) as: Compare it with ‘addHead’ with a dynamic array implementation
27
(to delete) Deleting the Head Node Node* p; p = head; head = head->next; delete p; head p 50401320
28
void deleteHead(Node*& head){ if(head != NULL){ NodePtr p = head; head = head->next; delete p; } Node* deleteHead(Node* head){ if(head != NULL){ NodePtr p = head; head = head->next; delete p; } return head; } As a function:
29
Displaying a Linked List p = head; p = p->next; 2045 head p 2045 head p
30
void displayList(Node* head){ NodePtr p; p = head; while(p != NULL){ cout data << endl; p = p->next; } A linked list is displayed by walking through its nodes one by one, and displaying their data fields (similar to an array!). void displayArray(int data[], int size) { int n=0; while ( n<size ) { cout << data[i] << endl; n++; } For an array:
31
//return the pointer of the node that has data=item //return NULL if item does not exist Node* searchNode(Node* head, int item){ NodePtr p = head; NodePtr result = NULL; bool found=false; while((p != NULL) && (!found)){ if(p->data == item) { found = true; result = p;} p = p->next; } return result; } Searching for a node (look at array searching first!)
32
void main() { const int size=8; int data[size] = { 10, 7, 9, 1, 17, 30, 5, 6 }; int value; cout << "Enter search element: "; cin >> value; int n=0; int position=-1; bool found=false; while ( (n<size) && (!found) ) { if(data[n] == value) { found=true; position=n;} n++; } if(position==-1) cout << "Not found!!\n"; else cout << "Found at: " << position << endl; } Remember array searching algorithm: It is essentially the same!
33
Variations of linked lists * Unsorted linked lists * Sorted linked lists * Circular linked lists * Doubly linked lists * …
34
Further considerations for the unsorted lists: * Physical copy of list for operators like ‘deleteHead’ and ‘addHead’ * ‘deleteHead’ should be understood as a decomposition into a sub-list …
35
Node* deleteHead(Node* head){ // physically copy head into a new one, newhead // so to keep the original list intact! Node* newhead=NULL; Node* temp=head; while(temp!=NULL) { newhead=addEnd(newhead,temp->data); temp=temp->next; } if(newhead != NULL){ Node* p = newhead; newhead = newhead->next; delete p; } return newhead; } B = deleteHead(A);
36
* Original linked list of integers: * Add to the end (insert at the end): More operation: adding to the end 50401320 50401320 60 Last element The key is how to locate the last element or node of the list!
37
void addEnd(NodePtr& head, int newdata){ NodePtr newPtr = new Node; newPtr->data = newdata; newPtr->next = NULL; NodePtr last = head; if(last != NULL){ // general non-empty list case while(last->next != NULL) last=last->next; last->next = newPtr; } else// deal with the case of empty list head = newPtr; } Add to the end: Link new object to last->next Link a new object to empty list
38
NodePtr addEnd(NodePtr head, int newdata){ NodePtr newPtr = new Node; newPtr->data = newdata; newPtr->next = NULL; NodePtr last = head; if(last != NULL){ // general non-empty list case while(last->next != NULL) last=last->next; last->next = newPtr; } else// deal with the case of empty list head = newPtr; return head; } Add to the end as a function:
39
Implementation of a Sorted Linked List
40
Inserting a Node Head cur 20 33 4575 prev... newPtr 1.(a) Create a new node using: NodePtr newPtr = new node; (b) Fill in the data field correctly. 2. Find “prev” and “cur” such that the new node should be inserted between *prev and *cur. 3. Connect the new node to the list by using: (a) newPtr->next = cur; (b) prev->next = newPtr;
41
Finding prev and cur Suppose that we want to insert or delete a node with data value newValue. Then the following code successfully finds prev and cur such that prev->data data
42
prev = NULL; cur = head; found=false; while( (cur!=NULL) && (!found) ) { if (newValue > cur->data) { prev=cur; cur=cur->next; } else found = true; } Prev is necessary as we can’t go back! It’s a kind of search algo,
43
prev = NULL; cur = head; while( (cur!=NULL) && (newValue>cur->data) ) { prev=cur; cur=cur->next; } Logical AND (&&) is short-circuited, sequential, i.e. if the first part is false, the second part will not be executed. Finally, it is equivalent to:
44
//insert item into linked list according to ascending order Node* insertNode(Node* head, int item){ NodePtr newp, cur, pre; newp = new Node; newp->data = item; pre = NULL; cur = head; while( (cur != NULL) && (item>cur->data)){ pre = cur; cur = cur->next; } if(pre == NULL){//insert to head of linked list newp->next = head; head = newp; } else { pre->next = newp; new->next = cur; } return head; } If the position happens to be the head General case
45
// not recommended void type function void insertNode(NodePtr& head, int item){ NodePtr newp, cur, pre; newp = new Node; newp->data = item; pre = NULL; cur = head; while( (cur != NULL) && (item>cur->data)){ pre = cur; cur = cur->next; } if(pre == NULL){//insert to head of linked list newp->next = head; head = newp; } else { pre->next = newp; new->next = cur; }
46
(to delete) Deleting a Node * To delete a node from the list 1. Locate the node to be deleted (a) cur points to the node. (b) prev points to its predecessor 2. Disconnect node from list using: prev->next = cur->next; 3. Return deleted node to system: delete cur; Head cur 20457585 prev...
47
Node* deleteNode(Node* head, int item){ NodePtr prev=NULL, cur = head; while( (cur!=NULL) && (item > cur->data)){ prev = cur; cur = cur->next; } if ( cur!==NULL && cur->data==item) { if(cur==head) head = head->next; else prev->next = cur->next; delete cur; } return head; } Delete an element in a sorted linked list: If the element is at the head General case We can delete only if the element is present! If (cur==NULL || cur->data!=item) Item is not in the list! Get the location
48
void deleteNode(NodePtr& head, int item){ NodePtr prev=NULL, cur = head; while( (cur!=NULL) && (item > cur->data)){ prev = cur; cur = cur->next; } if ( cur!==NULL && cur->data==item) { if(cur==Head) Head = Head->next; else prev->next = cur->next; delete cur; } // in a void function, not recommended If the element is at the head General case We can delete only if the element is present! If (cur==NULL || cur->data!=item) Item is not in the list! Get the location
49
Classes with dynamic objects List as a (dynamic) class
50
int x; void f() { x=10; } main() { x=0; f(); } ‘Class’ matters! int x; void f() { int x; x=10; } main() { x=0; f(); } class A { public int x; void f(); } main() { A a; a.x = 0; a.f(); } localglobalpublic
51
class A { public: void f(); int x; private: int y; } void A::f() { x=10; y=100; } int main() { A a; a.f(); cout << a.x << endl; cout << a.y << endl; // no!!! a.x = 1000; a.y = 10000; // no!!! } Public or private?
52
class A { public: A(); int f(); private: int x; } A::A() { x=0; } int A::f() { return x; } int main() { A a; cout << a.f(); // not a.x!!! A b(a); A c; c = a; // member-wise copy } Objects are calling member funtions (public interface) Member functions are using member variables (private data) Objects are not directly dependent on implementation (private data) Abstract Data Type: public function, private data
53
Static variables (objects)Dynamic variables (objects) A (direct) named memory locationA static part (pointer) + (indirect) nameless memory location (dynamic part) int a; a = 20; int* pa; pa = new int; *pa = 20; 20 a pa static dynamic Static and dynamic
54
Only static member variables At least one pointer variable (I.e. dynamic variable) class A { public: A(); private: int x; } class B { public: B(); B(const B& b); ~B(); private: int* px; } (Must) a defaut value constructor A() for ‘copy constructor’ automatically privided No destructor ‘assignment’ automatically provided (Must) a defaut value constructor for (Must) redefine ‘copy constructor’ (Must) the destructor (Must) redefine ‘assignment’ (do later) initialisation Creation by new + initialiation classes
55
class B { public: B(); B(const B& b); ~B(); private: int* px; } B::B() { px = new int; *px = 0; } B::B(const B& b) { px = new int; (*px) = *(b.px); } B::~B() { delete px; }
56
All constructors/destructor have automatic behavior, they are called ‘implicitly’!!! (that’s why they have standard names!) Constructors are called when creating variables and other occasions: Destructors are called when the variables go out of scope A a; // implicitly call the default value constructor A::A(); A b(a); // implicitly call the copy constructor A::A(const A& a); Automatic behavior of constructors/destructor void somefunction() { B b; };
57
Example of a (dynamic) class: linked list class
58
bool listEmpty(NodePtr head) { } int getHead(NodePtr head) { } NodePtr getRest(NodePtr head) { } NodePtr addHead(NodePtr head, int newdata) { } void delHead(NodePtr& Head){ } linked lists: definition struct Node{ int data; Node* next; }; typedef Node* NodePtr; NodePtr head;
59
void main(){ NodePtr Head1=NULL, Head2 = NULL, Head; addHead(Head1, 50); addHead(Head1, 40); addHead(Head1, 30); addHead(Head1, 20); cout << "List 1: " << endl; DisplayList(Head1); cout << "Length of Head1 list: " << length(Head1) << endl; cout << "Recursive length of Head1 list: " << lengthRec(Head1) << endl; if(isPalindrome(Head1)) cout << "Head1 list is palindrome" << endl; else cout << "Head1 list is not palindrome" << endl; addHead(Head2, 25); addHead(Head2, 35); addHead(Head2, 45); addHead(Head2, 35); addHead(Head2, 25); cout << "List 2: " << endl; DisplayList(Head2); cout << "Length of Head2 list: " << length(Head2) << endl; cout << "Recursive length of Head2 list: " << lengthRec(Head2) << endl; if(isPalindrome(Head2)) cout << "Head2 list is palindrome" << endl; else cout << "Head2 list is not palindrome" << endl; Head = mergeLists(Head1, Head2); cout << "Merged List: " << endl; DisplayList(Head); cout << "Length of Merged list: " << length(Head) << endl; cout << "Recursive length of Merged list: " << lengthRec(Head) << endl; if(isPalindromeRec(Head)) cout << "Merged list is palindrome" << endl; else cout << "Merged list is not palindrome" << endl; cout << "check the list again:" << endl; DisplayList(Head); } Usage:
60
Make an Abstract Data Type l One more example of ADT: l integer linked list using class l A class with dynamic objects: l Copy constructor l Destructor
61
struct Node{ public: int data; Node* next; }; typedef Node* Nodeptr; class list { public: list(); // constructor list(const list& list1); // copy constructor ~list(); // destructor bool empty() const; // boolean function int headElement() const; // access functions void addHead(int newdata); // add to the head void deleteHead(); // delete the head int length() const; // utility function void print() const; // output private: Nodeptr head; }; ‘old’ operations ‘new’ member functions
62
void main(){ list L; // constructor called automatically here for L L.print(); { } L.addHead(30); L.print(); { 30 } L.addHead(13); L.print(); { 13 30 } L.addHead(40); L.print(); { 40 13 30 } L.addHead(50); L.print(); { 50 40 13 30 } list N(L); N.print(); { 50 40 13 30 } list R; R.print(); { } if(R.empty()) cout << "List R empty" << endl; L.deleteHead(); L.print(); { 40 13 30 } L.deleteHead(); L.print(); { 13 30 } if(L.empty()) cout << "List L empty" << endl; else{ cout << "List L contains " << L.length() << " nodes" << endl; cout << "Head element of list L is: " << L.headElement() << endl; } } // destructor called automatically here for L How to use it
63
list::list(){ head = NULL; } bool list::empty() const{ if(head==NULL) return true; else return false; } int list::headElement() const { if(head != NULL) return head->data; else{ cout << "error: trying to find head of empty list" << endl; exit(1); } Some simple member functions: Implementation
64
list::list(const list& list1) { head = NULL; Nodeptr cur = list1.head; while(cur != NULL) { // addEnd(cur->data); addHead(cur->data); // inverse list order cur = cur->next; } (explicitly defined) copy constructor:
65
Destructor: deallocation function list::~list(){ Nodeptr cur; while(head!=NULL){ cur = head; head = head->next; delete cur; }
66
void list::addHead(int newdata){ Nodeptr newPtr = new Node; newPtr->data = newdata; newPtr->next = head; head = newPtr; } Adding an element to the head:
67
void list::deleteHead(){ if(head != NULL){ Nodeptr cur = head; head = head->next; delete cur; } Deleting the head:
68
void list::print() const{ cout << "{"; Nodeptr cur = head; while(cur != NULL){ cout data << " "; cur = cur->next; } cout << "}" << endl; } Print the list:
69
int list::length() const{ int n=0; Nodeptr cur = head; while(cur != NULL){ n++; cur = cur->next; } return n; } Computing the number of elements of a given list:
70
struct Node{ public: int data; Node* next; }; typedef Node* Nodeptr; class list { public: list(); // constructor list(const list& list1); // copy constructor const list& operator=(const list& list1); // assigment, l = l1; ~list(); // destructor bool empty() const; // boolean function int head() const; // access functions list remaining() const; // the list with the head removed void insert(int d); // insertion void delete(int d); // deletion int length() const; // utility function void print() const; // private: Nodeptr head; }; Interface functions An almost ideal list class
71
list::list(const listClass& list1) { head = NULL; Nodeptr cur = list1.head; while(cur != NULL) { // addEnd(cur->data); addHead(cur->data); // inverse list order cur = cur->next; } copy constructor: Const list& operator=(const list& list1) { if (this != &list1) { head = NULL; Nodeptr cur = list1.head; while(cur != NULL) { // addEnd(cur->data); addHead(cur->data); // inverse list order cur = cur->next; } return *this; } Operator assignment, ‘deep copy’ Delete[] head; Big three: copy constructor, operator=, destructor
72
list l1, l2; l1.addEnd(5); list l3(l1); l3 = l2; node* head1, head2; head1 = NULL; head2 = NULL addEnd(head1,5); node* head3 = NULL; copylist(head1, head3); head3 = head2; Usage difference
73
Doubly Linked List
74
Motivation * Doubly linked lists are useful for playing video and sound files with “rewind” and instant “replay” * They are also useful for other linked data where “require” a “fast forward” of the data as needed
75
* list using an array: n Knowledge of list size n Access is easy (get the ith element) n Insertion/Deletion is harder * list using ‘singly’ linked lists: n Insertion/Deletion is easy n Access is harder n But, can not ‘go back’!
76
Doubly Linked Lists In a Doubly Linked-List each item points to both its predecessor and successor n prev points to the predecessor n next points to the successor 1070205540 Head Cur Cur->nextCur->prev
77
struct Node{ int data; Node* next; Node* prev; }; typedef Node* NodePtr; Doubly Linked List Definition
78
Doubly Linked List Operations * insertNode(NodePtr& Head, int item) //add new node to ordered doubly linked //list * deleteNode(NodePtr& Head, int item) //remove a node from doubly linked list * SearchNode(NodePtr Head, int item) * Print(nodePtr Head, int item)
79
Deleting a Node Delete a node Cur (not at front or rear) (Cur->prev)->next = Cur->next; (Cur->next)->prev = Cur->prev; delete Cur; 1070205540 Head Cur
80
void deleteNode(NodePtr& head, int item) { NodePtr cur; cur = searchNode(head, item); if (head==NULL) { … } else if (cur->prev == NULL) { … } else if (cur->next==NULL) { … } else { (cur->prev)->next = cur->next; (cur->next)->prev = cur->prev; delete cur; } Empty case At-the-beginning case At-the-end case General case A systematic way is to start from all these cases, then try to simply the codes, …
81
Inserting a Node Insert a node New before Cur (not at front or rear) 1070205540 Head New Cur New->next = Cur; New->prev = Cur->prev; Cur->prev = New; (New->prev)->next = New;
82
void insertNode(NodePtr& head, int item) { NodePtr cur; cur = searchNode(head, item); if (head==NULL) { … } else if (cur->prev == NULL) { … } else if (cur->next==NULL) { … } else { blablabla … } } Many special cases to consider.
83
Many different linked lists … * singly linked lists n Without ‘dummy’ n With dummy n circular * doubly linked lists n Without ‘dummy’ n With dummy Using ‘dummy’ is a matter of personal preference! + simplify codes (not that much - Less logically sounds
84
20 Head 1020407055 Rear 1020407055 70205540 Head 10 70205540 Head 10 Dummy singly linked list (singly) circular linked list (regular) doubly linked list doubly circular linked list with dummy
85
Doubly Linked Lists with Dummy Head Node * To simplify insertion and deletion by avoiding special cases of deletion and insertion at front and rear, a dummy head node is added at the head of the list * The last node also points to the dummy head node as its successor
86
Idea of ‘dummy’ object l Instead of pointing to NULL, point to the ‘dummy’!!! l Skip over the dummy for the real list 70205540 Head 10 Dummy Head Node ‘dummy object’ is also called a ‘sentinel’, it allows the simplification of special cases, but confuses the emptyness NULL!
87
Head Dummy Head Node Empty list: Head->next = head; compared with head=NULL;
88
void createHead(NodePtr& head){ head = new Node; head->next = head; head->prev = head; } NodePtr head; createHead(head); NodePtr cur=head; cur=cur->next; cur=head; // dummy head NodePtr head=NULL; NodePtr cur=head; cur=head; cur=NULL; // or head=NULL; operationsDoubly linked with dummySingly linked creation Empty test Start from reference
89
void print(NodePtr head){ NodePtr cur=head->next; while(cur != head){ cout data << " "; cur = cur->next; } Print the whole list:
90
NodePtr searchNode(NodePtr head, int item){ NodePtr cur = head->next; while ((cur != head) && (item != cur->data)) cur=cur->next; if (cur == head) cur = NULL; // we didn ’ t find return cur; } Searching a node (returning NULL if not found the element): End of the list, empty
91
Deleting a Node Delete a node Cur at front 70205540 Head 10 Dummy Head Node Cur (Cur->prev)->next = Cur->next; (Cur->next)->prev = Cur->prev; delete Cur;
92
Delete a node Cur in the middle (Cur->prev)->next = Cur->next; (Cur->next)->prev = Cur->prev; delete Cur;// same as delete front! 70 Head 10 Dummy Head Node 205540 Cur
93
Delete a node Cur at rear (Cur->prev)->next = Cur->next; (Cur->next)->prev = Cur->prev; delete Cur;// same as delete front and middle! 70205540 Head 10 Dummy Head Node Cur
94
void deleteNode(NodePtr head, int item){ NodePtr cur; cur = searchNode(head, item); if(cur != NULL){ cur->prev->next = cur->next; cur->next->prev = cur->prev; delete cur; } If we found the element, it does not mean any emptyness!
95
Inserting a Node Insert a Node New after dummy node and before Cur Head Dummy Head Node Cur 20 New->next = Cur; New->prev = Cur->prev; Cur->prev = New; (New->prev)->next = New; 10 New
96
Insert a Node New at Rear (with Cur pointing to dummy head) New->next = Cur; New->prev = Cur->prev; Cur->prev = New; (New->prev)->next = New; 70205540 Head 10 Dummy Head Node Cur New
97
Insert a Node New in the middle and before Cur New->next = Cur; New->prev = Cur->prev; Cur->prev = New; (New->prev)->next = New; 55 Head 10 Dummy Head Node 20 Cur 40 New
98
Insert a Node New to Empty List (with Cur pointing to dummy head node) Head Dummy Head Node New 20 New->next = Cur; New->prev = Cur->prev; Cur->prev = New; (New->prev)->next = New; Cur
99
void insertNode(NodePtr head, int item){ NodePtr newp, cur; newp = new Node; newp->data = item; cur = head->next; while ((cur != head)&&(!(item data))) cur = cur->next; newp->next = cur; newp->prev = cur->prev; cur->prev = newp; (newp->prev)->next = newp; } It is similar to, but different from SearchNode! (it returns NULL if no element) creation location insertion
100
void main(){ NodePtr Head, temp; createHead(Head); insertNode(Head, 3); insertNode(Head, 5); insertNode(Head, 2); print(Head); insertNode(Head, 7); insertNode(Head, 1); insertNode(Head, 8); print(Head); deleteNode(Head, 7); deleteNode(Head, 0); print(Head); temp = searchNode(Head, 5); if(temp !=NULL) cout<<" Data is contained in the list"<<endl; else cout<<" Data is NOT contained in the list"<<endl; } Result is 2 3 5 1 2 3 5 7 8 1 2 3 5 8 Data is contained in the list
101
Stacks and Queues
102
struct Node{ double data; Node* next; }; class List { public: List(); // constructor List(const List& list); // copy constructor ~List(); // destructor List& operator=(const List& list); // assignment operator bool empty() const; // boolean function void addHead(double x); // add to the head double deleteHead(); // delete the head and get the head element // List& rest(); // get the rest of the list with the head removed // double headElement() const; // get the head element void addEnd(double x); // add to the end double deleteEnd(); // delete the end and get the end element // double endElement(); // get the element at the end bool searchNode(double x); // search for a given x void insertNode(double x); // insert x in a sorted list void deleteNode(double x); // delete x in a sorted list … void print() const; // output int length() const; // count the number of elements private: Node* head; }; More complete list ADT
103
Stack Overview * Stack ADT * Basic operations of stack n Pushing, popping etc. * Implementations of stacks using n array n linked list
104
Stack * A stack is a list in which insertion and deletion take place at the same end n This end is called top n The other end is called bottom * Stacks are known as LIFO (Last In, First Out) lists. n The last element inserted will be the first to be retrieved
105
Push and Pop * Primary operations: Push and Pop * Push n Add an element to the top of the stack * Pop n Remove the element at the top of the stack top empty stack A top push an element top push another A B top pop A
106
Implementation of Stacks * Any list implementation could be used to implement a stack n Arrays (static: the size of stack is given initially) n Linked lists (dynamic: never become full) * We will explore implementations based on array and linked list
107
class Stack { public: Stack(); // constructor Stack(const Stack& stack); // copy constructor ~Stack(); // destructor bool empty() const; void push(const double x); double pop(); // change the stack double top() const; // keep the stack unchanged // bool full(); // optional // void print() const; private: … }; Stack ADT Compare with List, see that it’s ‘operations’ that define the type! inspection, access
108
Using Stack int main(void) { Stack stack; stack.push(5.0); stack.push(6.5); stack.push(-3.0); stack.push(-8.0); stack.print(); cout << "Top: " << stack.top() << endl; stack.pop(); cout << "Top: " << stack.top() << endl; while (!stack.empty()) stack.pop(); stack.print(); return 0; } result
109
struct Node{ public: double data; Node* next; }; class Stack { public: Stack(); // constructor Stack(const Stack& stack); // copy constructor ~Stack(); // destructor bool empty() const; void push(const double x); double pop(); // change the stack bool full(); // unnecessary for linked lists double top() const; // keep the stack unchanged void print() const; private: Node* top; }; Stack using linked lists
110
void List::addHead(int newdata){ Nodeptr newPtr = new Node; newPtr->data = newdata; newPtr->next = head; head = newPtr; } void Stack::push(double x){ Node* newPtr = new Node; newPtr->data = x; newPtr->next = top; top = newPtr; } From ‘addHead’ to ‘push’ Push (addHead), Pop (deleteHead)
111
Implementation based on ‘existing’ linked lists * Optional to learn * Good to see that we may ‘re-use’ linked lists
112
* Now let’s implement a stack based on a linked list To make the best out of the code of List, we implement Stack by inheriting the List To let Stack access private member head, we make Stack as a friend of List class List { public: List() { head = NULL; }// constructor ~List();// destructor bool empty() { return head == NULL; } Node* insertNode(int index, double x); int deleteNode(double x); int searchNode(double x); void printList(void); private: Node* head; friend class Stack; };
113
class Stack : public List { public: Stack() {} ~Stack() {} double top() { if (head == NULL) { cout << "Error: the stack is empty." << endl; return -1; } else return head->data; } void push(const double x) { InsertNode(0, x); } double pop() { if (head == NULL) { cout << "Error: the stack is empty." << endl; return -1; } else { double val = head->data; DeleteNode(val); return val; } void printStack() { printList(); } }; Note: the stack implementation based on a linked list will never be full. from List
114
Stack using arrays class Stack { public: Stack(int size = 10);// constructor ~Stack() { delete [] values; }// destructor bool empty() { return top == -1; } void push(const double x); double pop(); bool full() { return top == maxTop; } double top(); void print(); private: int maxTop;// max stack size = size - 1 int top;// current top of stack double* values;// element array };
115
Attributes of Stack maxTop : the max size of stack top : the index of the top element of stack values : point to an array which stores elements of stack Operations of Stack empty : return true if stack is empty, return false otherwise full : return true if stack is full, return false otherwise top : return the element at the top of stack push : add an element to the top of stack pop : delete the element at the top of stack print : print all the data in the stack
116
Allocate a stack array of size. By default, size = 10. Initially top is set to -1. It means the stack is empty. When the stack is full, top will have its maximum value, i.e. size – 1. Stack::Stack(int size /*= 10*/) { values=new double[size]; top=-1; maxTop=size - 1; } Although the constructor dynamically allocates the stack array, the stack is still static. The size is fixed after the initialization. Stack constructor
117
* void push(const double x); n Push an element onto the stack n Note top always represents the index of the top element. After pushing an element, increment top. void Stack::push(const double x) { if (full()) // if stack is full, print error cout << "Error: the stack is full." << endl; else values[++top] = x; }
118
* double pop() n Pop and return the element at the top of the stack n Don’t forgot to decrement top double Stack::pop() { if (empty()) { //if stack is empty, print error cout << "Error: the stack is empty." << endl; return -1; } else { return values[top--]; }
119
* double top() n Return the top element of the stack n Unlike p op, this function does not remove the top element double Stack::top() { if (empty()) { cout << "Error: the stack is empty." << endl; return -1; } else return values[top]; }
120
* void print() n Print all the elements void Stack::print() { cout "; for (int i = top; i >= 0; i--) cout << "\t|\t" << values[i] << "\t|" << endl; cout << "\t|---------------|" << endl; }
121
Stack Application: Balancing Symbols * To check that every right brace, bracket, and parentheses must correspond to its left counterpart n e.g. [( )] is legal, but [( ] ) is illegal * How? n Need to memorize n Use a counter, several counters, each for a type of parenthesis …
122
Balancing Symbols using a stack * Algorithm (1) Make an empty stack. (2) Read characters until end of file i. If the character is an opening symbol, push it onto the stack ii. If it is a closing symbol, then if the stack is empty, report an error iii. Otherwise, pop the stack. If the symbol popped is not the corresponding opening symbol, then report an error (3) At end of file, if the stack is not empty, report an error
123
Stack Application: postfix, infix expressions and calculator * Postfix expressions n a b c * + d e * f + g * + n Operands are in a stack * Convert infix to postfix n a+b*c+(d*e+f)*g a b c * + d e * f + g * + n Operators are in a stack * Calculator n Adding more operators …
124
Stack Application: function calls and recursion * Take the example of factorial! And run it. #include using namespace std; int fac(int n){ int product; if(n <= 1) product = 1; else product = n * fac(n-1); return product; } void main(){ int number; cout << "Enter a positive integer : " << endl;; cin >> number; cout << fac(number) << endl; }
125
Stack Application: function calls and recursion * Take the example of factorial! And run it. #include using namespace std; int fac(int n){ int product; if(n <= 1) product = 1; else product = n * fac(n-1); return product; } void main(){ int number; cout << "Enter a positive integer : " << endl;; cin >> number; cout << fac(number) << endl; }
126
Assume the number typed is 3. fac(3): has the final returned value 6 3<=1 ? No. product 3 = 3*fac(2) product 3 =3*2=6, return 6, fac(2): 2<=1 ? No. product 2 = 2*fac(1) product 2 =2*1=2, return 2, fac(1): 1<=1 ? Yes. return 1 Tracing the program …
127
fac(3)prod3=3*fac(2) prod2=2*fac(1)fac(2) fac(1)prod1=1 Call is to ‘push’ and return is to ‘pop’! top
128
Static (non-dynamic) and dynamic objects * ‘static variables’ reside in the system Stack * ‘dynamic variables’ reside in the system Heap (seen later …)
129
Array versus linked list implementations * push, pop, top are all constant-time operations in both array and linked list implementation Caveat: insertNode and deleteNode have to be done at the beginning of the list! n For array implementation, the operations are performed in very fast constant time
130
Queue Overview * Queue ADT * Basic operations of queue n Enqueuing, dequeuing etc. * Implementation of queue n Linked list n Array
131
Queue * A queue is also a list. However, insertion is done at one end, while deletion is performed at the other end. * It is “First In, First Out (FIFO)” order. n Like customers standing in a check-out line in a store, the first customer in is the first customer served.
132
Enqueue and Dequeue * Primary queue operations: Enqueue and Dequeue * Like check-out lines in a store, a queue has a front and a rear. * Enqueue – insert an element at the rear of the queue * Dequeue – remove an element from the front of the queue Insert (Enqueue) Remove (Dequeue) rearfront
133
Implementation of Queue * Just as stacks can be implemented as arrays or linked lists, so with queues. * Dynamic queues have the same advantages over static queues as dynamic stacks have over static stacks * (“static” should be interpreted as “non-dynamic” here!)
134
class Queue { public: Queue(); Queue(Queue& queue); ~Queue(); bool empty(); void enqueue(double x); double dequeue(); void print(void); // bool full(); // optional private: … }; Queue ADT ‘physical’ constructor/destructor ‘logical’ constructor/destructor
135
Using Queue int main(void) { Queue queue; cout << "Enqueue 5 items." << endl; for (int x = 0; x < 5; x++) queue.enqueue(x); cout << "Now attempting to enqueue again..." << endl; queue.enqueue(5); queue.print(); double value; value=queue.dequeue(); cout << "Retrieved element = " << value << endl; queue.print(); queue.enqueue(7); queue.print(); return 0; }
136
Struct Node { double data; Node* next; } class Queue { public: Queue(); Queue(Queue& queue); ~Queue(); bool empty(); void enqueue(double x); double dequeue(); // bool full(); // optional void print(void); private: Node* front;// pointer to front node Node* rear;// pointer to last node int counter;// number of elements }; Queue using linked lists
137
class Queue { public: Queue() {// constructor front = rear = NULL; counter= 0; } ~Queue() {// destructor double value; while (!empty()) dequeue(value); } bool empty() { if (counter) return false; else return true; } void enqueue(double x); double dequeue(); // bool full() {return false;}; void print(void); private: Node* front;// pointer to front node Node* rear;// pointer to last node int counter;// number of elements, not compulsary }; Implementation of some online member functions …
138
Enqueue (addEnd) void Queue::enqueue(double x) { Node* newNode = new Node; newNode->data = x; newNode->next = NULL; if (empty()) { front= newNode; } else { rear->next =newNode; } rear = newNode; counter++; } 8 rear newNode 5 58
139
Dequeue (deleteHead) double Queue::dequeue() { double x; if (empty()) { cout << "Error: the queue is empty." << endl; exit(1); // return false; } else { x = front->data; Node* nextNode = front->next; delete front; front= nextNode; counter--; } return x; } front 583 8 5
140
Printing all the elements void Queue::print() { cout "; Node* currNode=front; for (int i = 0; i < counter; i++) { if (i == 0) cout << "\t"; elsecout << "\t\t"; cout data; if (i != counter - 1) cout << endl; else cout << "\t<-- rear" << endl; currNode=currNode->next; }
141
Queue using Arrays * There are several different algorithms to implement Enqueue and Dequeue * Naïve way n When enqueuing, the front index is always fixed and the rear index moves forward in the array. front rear Enqueue(3) 3 front rear Enqueue(6) 3 6 front rear Enqueue(9) 3 6 9
142
* Naïve way (cont’d) n When dequeuing, the front index is fixed, and the element at the front the queue is removed. Move all the elements after it by one position. (Inefficient!!!) Dequeue() front rear 6 9 Dequeue() front rear 9 rear = -1 front
143
* A better way n When enqueued, the rear index moves forward. n When dequeued, the front index also moves forward by one element XXXXOOOOO (rear) OXXXXOOOO (after 1 dequeue, and 1 enqueue) OOXXXXXOO (after another dequeue, and 2 enqueues) OOOOXXXXX (after 2 more dequeues, and 2 enqueues) (front) The problem here is that the rear index cannot move beyond the last element in the array.
144
Using Circular Arrays * Using a circular array * When an element moves past the end of a circular array, it wraps around to the beginning, e.g. n OOOOO7963 4OOOO7963 (after Enqueue(4)) * How to detect an empty or full queue, using a circular array algorithm? n Use a counter of the number of elements in the queue.
145
class Queue { public: Queue(int size = 10);// constructor Queue(const Queue& queue); ~Queue() { delete [] values; }// destructor bool empty(void); void enqueue(double x); // or bool enqueue(); double dequeue(); bool full(); void print(void); private: int front;// front index int rear;// rear index int counter;// number of elements int maxSize;// size of array queue double* values;// element array }; full() is not essential, can be embedded
146
Attributes of Queue front/rear : front/rear index counter : number of elements in the queue maxSize : capacity of the queue values : point to an array which stores elements of the queue Operations of Queue empty : return true if queue is empty, return false otherwise full : return true if queue is full, return false otherwise enqueue : add an element to the rear of queue dequeue : delete the element at the front of queue print : print all the data
147
Queue constructor * Queue(int size = 10) n Allocate a queue array of size. By default, size = 10. n front is set to 0, pointing to the first element of the array n rear is set to -1. The queue is empty initially. Queue::Queue(int size /* = 10 */) { values=new double[size]; maxSize=size; front=0; rear=-1; counter=0; }
148
Empty & Full Since we keep track of the number of elements that are actually in the queue: counter, it is easy to check if the queue is empty or full. bool Queue::empty() { if (counter==0)return true; elsereturn false; } bool Queue::full() { if (counter < maxSize)return false; elsereturn true; }
149
Enqueue void Queue::enqueue(double x) { if (full()) { cout << "Error: the queue is full." << endl; exit(1); // return false; } else { // calculate the new rear position (circular) rear = (rear + 1) % maxSize; // insert new item values[rear]= x; // update counter counter++; // return true; } Or ‘bool’ if you want
150
Dequeue double Queue::dequeue() { double x; if (empty()) { cout << "Error: the queue is empty." << endl; exit(1); // return false; } else { // retrieve the front item x= values[front]; // move front front= (front + 1) % maxSize; // update counter counter--; // return true; } return x; }
151
Printing the elements void Queue::print() { cout "; for (int i = 0; i < counter; i++) { if (i == 0) cout << "\t"; elsecout << "\t\t"; cout << values[(front + i) % maxSize]; if (i != counter - 1) cout << endl; else cout << "\t<-- rear" << endl; }
152
Using Queue int main(void) { Queue queue; cout << "Enqueue 5 items." << endl; for (int x = 0; x < 5; x++) queue.enqueue(x); cout << "Now attempting to enqueue again..." << endl; queue.enqueue(5); queue.print(); double value; value=queue.dequeue(); cout << "Retrieved element = " << value << endl; queue.print(); queue.enqueue(7); queue.print(); return 0; }
153
Results Queue implemented using linked list will be never full! based on array based on linked list
154
Queue applications * When jobs are sent to a printer, in order of arrival, a queue. * Customers at ticket counters …
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.