1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 8 Stacks and Queues Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall
2 Stack ADT Recall that ADT is abstract data type, a set of data and a set of operations that act upon the data In a stack, the set of data is the stack of elements
3 Stack ADT Operations push: places an element onto the top of a stack pop: removes an element from the top of the stack peek: which retrieves (copies) a value from the top of the stack without removing it an operation to determine whether or not the stack is empty an operation to empty out a stack
4 Push Push means place a new data element at the top of the stack
5 Push (cont.) Push means place a new data element at the top of the stack
6 Push (cont.) Push means place a new data element at the top of the stack
7 Push (cont.) Push means place a new data element at the top of the stack
8 Pop Pop means take a data element off the top of the stack
9 Pop (cont.) Pop means take a data element off the top of the stack
10 Pop (cont.) Pop means take a data element off the top of the stack
11 Pop (cont.) Pop means take a data element off the top of the stack
12 Peek Peek means retrieve the top of the stack without removing it
13 Peek (cont.) Peek means retrieve the top of the stack without removing it
14 Peek (cont.) Peek means retrieve the top of the stack without removing it
15 1 #include “Array.h” 2 3 template 4 class Stack 5 { 6 public: 7Stack( ); 8void push( DataType elementToPush ); 9bool pop( DataType & poppedElement ); 10bool peek( DataType & topElement ); 11bool isEmpty( ) const; 12void makeEmpty( ); 13 private: 14Array elements; 15int top; 16 }; #include “Stack.cpp” Stack Class Template
16 1 #include “Array.h” 2 3 template 4 class Stack 5 { 6 public: 7Stack( ); 8void push( DataType elementToPush ); 9bool pop( DataType & poppedElement ); 10bool peek( DataType & topElement ); 11bool isEmpty( ) const; 12void makeEmpty( ); 13 private: 14Array elements; 15int top; 16 }; #include “Stack.cpp” Stack Class Template (cont.)
17 1 #include “Array.h” 2 3 template 4 class Stack 5 { 6 public: 7Stack( ); 8void push( DataType elementToPush ); 9bool pop( DataType & poppedElement ); 10bool peek( DataType & topElement ); 11bool isEmpty( ) const; 12void makeEmpty( ); 13 private: 14Array elements; 15int top; 16 }; #include “Stack.cpp” Stack Class Template (cont.) used as an index to the top of the stack
18 The Actual Pop elements top An element can’t really be removed from an array, as one would think pop would achieve.
19 The Actual Pop (cont.) elements top The element 70 is at the top of the stack, and what really happens during a pop, is that 70 is returned to the client…
20 The Actual Pop (cont.) elements top The element 70 is at the top of the stack, and what really happens during a pop, is that 70 is returned to the client… client
21 The Actual Pop (cont.) elements top and top is decremented… client
22 The Actual Pop (cont.) elements top and top is decremented… client
23 The Actual Pop (cont.) elements top The element 70 is still in the array, but it is no longer accessible. The next push will overwrite it. Say, we would like to push 63… client
24 The Actual Push (cont.) elements top First, top is incremented…
25 The Actual Push (cont.) elements top First, top is incremented…
26 The Actual Push (cont.) elements top Then, 63 is pushed into that position…
27 The Actual Push (cont.) elements top Then, 63 is pushed into that position…
28 1 template 2 Stack ::Stack( ) 3: elements( 2 ), top( -1 ) 4 { 5 } Stack Constructor
29 Shift Operators Shift operators are used in the array implementations of data structures They are appropriate when multiplying or dividing by powers of two They are faster than multiplication and division Assume num is a positive integer. num << n is the same as num * 2 n num >> n is the same as num / 2 n (using integer division)
30 Push Code 6 template 7 void Stack ::push( 8DataType elementToPush ) 9 { 10if ( ++top == elements.length( ) ) 11 elements.changeSize( elements.length( ) << 1 ); 12elements[ top ] = elementToPush; 13 }
31 Pop Recall…to conserve memory, if the number of used elements of an array drops to 25% of the capacity, we want to cut the capacity of the array in half On each pop, it is possible that we may want to reduce the size of the array
32 Reducing Array Size When we call the changeSize function for the Array object, it is possible that there is not enough heap memory to reduce the array size A new, smaller dynamic array needs to be created to copy the elements of the old, larger dynamic array to it If the smaller array cannot be created the pop function should still succeed (stack is still completely functional)
33 Reducing Array Size (cont.) If array size reduction does not succeed, it might succeed later on –Other dynamic memory may be freed –The number of used elements in the stack may drop so low that a small dynamic array can be made Therefore, in the pop function, we should try to reduce the size to the smallest power of 2, which is: –At least twice the number of elements being used –At least 2
34 Example Suppose there are 3 elements being used in a stack. top would be 2, so top + 1 gives the number of elements Suppose also that the capacity of the array is 32. The array’s capacity should be reduced to 8 (one quarter of the capacity instead of one half)
35 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:
36 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:
37 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:32
38 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:32
39 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:32 Number of elements: 3
40 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:32 Number of elements: 3
41 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:32 Number of elements: 3 trysize / 4 : 8
42 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:32 Number of elements: 3 trysize / 4 : 8 TRUE
43 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:32 Number of elements: 3 trysize / 4 : 8 TRUE
44 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:32 Number of elements: 3 trysize / 4 : 8 TRUE
45 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:32
46 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:16
47 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:16
48 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:16 3 <= 4 : TRUE
49 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:16 3 <= 4 : TRUE
50 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:16 3 <= 4 : TRUE TRUE
51 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:16
52 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:8
53 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:8
54 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:8 3 <= 2 : FALSE
55 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:8
56 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:8 trysize will be the new capacity that we attempt to use (might be out of heap memory)
57 Example (cont.) int trysize = elements.length( ); while ( ( top + 1 > 2 ) && trysize > 2 ) trysize >>= 1; top:2 capacity:32 trysize:8 If trysize would become 2, this part would be false, causing 2 to be the smallest possible capacity
58 14 template 15 bool Stack ::pop( 16DataType & poppedElement ) 17 { 18if ( top == -1 ) 19return false; 20poppedElement = elements[ top ]; 21top--; 22int trysize = elements.length( ); 23while ( ( top + 1 > 2 ) && trysize > 2 ) 24trysize >>= 1; Pop Code Pop code continued…
59 Pop Code (cont.) 25if ( trysize < elements.length( ) ) { 26try { 27elements.changeSize( trysize ); 28} 29catch( … ) { } 30} 31 32return true; 33 }
60 Peek 34 // returns the element at the top of the stack in 35 // topElement without removing it. Returns false if 36 // called on an empty stack; otherwise, returns true 37 template 38 bool Stack ::peek( 39 DataType & topElement ) 40 { 41if ( top == -1 ) 42return false; 43topElement = elements[ top ]; 44return true; 45 }
61 46 template 47 bool Stack ::isEmpty( ) const 48 { 49return top == -1; 50 } isEmpty
62 makeEmpty 51 template 52 void Stack ::makeEmpty( ) 53 { 54top = -1; 55try { 56elements.changeSize( 2 ); 57} 58catch( … ) { } 59 }
63 Linked-List Stack Stacks can also be implemented with a linked list The front node is the top of the stack
64 Linked-List Stack (cont.) top To pop, we remove the node at the front of the linked list, and return the element to the client…
65 Linked-List Stack (cont.) top To pop, we remove the node at the front of the linked list, and return the element to the client…
66 Linked-List Stack (cont.) top To push, we place the new element in a node and insert it at the front of the linked list…
67 Linked-List Stack (cont.) To push, we place a new element in a node and insert it at the front of the linked list… top
68 The Queue ADT The queue is a data structure that is like a line of people, except that it is a line of elements The line of elements is the data upon which operations are performed
69 Queue ADT Operations enqueue: add an element to the end of the line dequeue: take an element from the front of the line peek: retrieve (copy) the element at the front of the line without removing it an operation to determine whether or not the queue is empty an operation that will empty out the queue
70 Queue A queue is like a line of people When people join the line, they go at the end When people are served, they come off the front of the line A queue is a FIFO (first-in, first-out) data structure It is used in situations where a fair first- come, first-serve basis is called for, like a print queue
71 Queue (cont.) In addition to a pointer at the beginning of the linked list (called front), a pointer to the end of the linked list (called back) is also maintained in the private section The back pointer makes it fast to add new elements to the end of the queue – you don’t have to use a loop to go all the way through the queue to find the last node
72 Header Node A header node can simplify the code for a linked-list queue We make use of a header node in the queue implementation
73 Dequeue Operation front back header
74 Dequeue Operation (cont.) front back header
75 Enqueue Operation front back header
76 Enqueue Operation (cont.) front back header
77 1 // queue.h -- class template for the linked list 2 // implementation of a queue 3 // note: use of the copy constructor, overloaded 4 // assignment operator, or enqueue function can cause an 5 // exception to be thrown when heap memory is exhausted 6 7 template 8 struct Node { 9DataType info; 10Node *next; 11 }; Queue Specification File Specification File continued…
78 Queue Specification File (cont.) 12 template 13 class Queue 14 { 15 public: 16Queue( ); 17Queue( const Queue & apqueue ); 18~Queue( ); 19Queue & operator =( 20 const Queue & rqueue ); public section of Queue continued…
79 Queue Specification File (cont.) 21void enqueue( const DataType & element ); 22bool dequeue( DataType & deqElement ); 23bool peek( DataType & frontElement ); 24bool isEmpty( ) const; 25void makeEmpty( ); private section of Queue is next…
80 Queue Specification File (cont.) 26 private: 27Node *front; 28Node *back; 29Node header; 30inline void deepCopy( 31const Queue & original ); 32 }; #include "queue.cpp"
81 1 // queue.cpp 2 3 template 4 Queue ::Queue( ) 5 { 6front = back = &header; 7 } Queue Constructor
82 Queue Copy Constructor and Destructor 8 template 9 Queue ::Queue( 10const Queue & apqueue ) 11 { 12deepCopy( apqueue ); 13 } template 16 Queue ::~Queue( ) 17 { 18makeEmpty( ); 19 }
83 Queue Overloaded Assignment Operator 20 template 21 Queue & Queue :: 22 operator =( const Queue & rqueue ) 23 { 24if ( this == &rqueue ) 25return *this; 26makeEmpty( ); 27deepCopy( rqueue ); 28return *this; 29 }
84 Enqueue 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } This section creates the new node to enqueue and places element within in it…
85 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } This section creates the new node to enqueue and places element within in it… ptr
86 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } Let’s consider a couple of cases with these next two lines. ptr
87 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } Let’s consider a couple of cases with these next two lines. ptr
88 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } Case 1: The queue is initially empty. ptr
89 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } Case 1: The queue is initially empty. front ptr header back
90 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } Case 1: The queue is initially empty. front ptr header back
91 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } Case 1: The queue is initially empty. front ptr header back
92 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } Case 1: The queue is initially empty. front ptr header back
93 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } Case 1: The queue is initially empty. front ptr header back
94 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } Case 2: The queue has nodes. ptr
95 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } Case 2: The queue has nodes. ptr front header back
96 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } Case 2: The queue has nodes. ptr front header back
97 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } Case 2: The queue has nodes. ptr front header back
98 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } Case 2: The queue has nodes. ptr front header back
99 Enqueue (cont.) 30 template 31 void Queue ::enqueue( 32const DataType & element ) 33 { 34Node *ptr = new Node ; 35ptr->info = element; 36back->next = ptr; 37back = ptr; 38 } Case 2: The queue has nodes. ptr front header back
100 Dequeue 39 template 40 bool Queue ::dequeue( 41DataType & deqElement ) 42 { 43if ( front == back ) 44return false; Dequeue continued… Returns false if client tries to dequeue an empty queue.
101 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header
102 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header
103 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr
104 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr
105 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr deqElement: passed in by reference
106 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr deqElement:
107 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr deqElement:
108 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr deqElement:
109 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr deqElement:
110 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr deqElement:
111 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr Let’s consider what happens if only one node is left to dequeue.
112 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header Let’s consider what happens if only one node is left to dequeue.
113 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header
114 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr
115 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr
116 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr deqElement:
117 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr deqElement:
118 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr deqElement:
119 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr deqElement:
120 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front back header ptr deqElement:
121 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front header ptr deqElement: back
122 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front header ptr deqElement: back
123 Dequeue (cont.) 45Node *ptr = front->next; 46deqElement = ptr->info; 47front->next = ptr->next; 48if ( back == ptr ) 49back = front; 50delete ptr; 51 52return true; 53 } front header ptr deqElement: back
124 Peek 54 template 55 bool Queue ::peek( 56DataType & frontElement ) 57 { 58if ( front == back ) 59return false; 60frontElement = front->next->info; 61return true; 62 }
125 isEmpty and makeEmpty 63 template 64 bool Queue ::isEmpty( ) const 65 { 66 return front == back; 67 } template 70 void Queue ::makeEmpty( ) 71 { 72 DataType temp; 73while ( dequeue( temp ) ); 74 }
126 deepCopy 75 template 76 inline void Queue ::deepCopy( 77const Queue & original ) 78 { 79Node *copyptr = front = &header; 80Node *originalptr = original.front; frontback OriginalCopy header
127 deepCopy 75 template 76 inline void Queue ::deepCopy( 77const Queue & original ) 78 { 79Node *copyptr = front = &header; 80Node *originalptr = original.front; frontback OriginalCopy header
128 deepCopy 75 template 76 inline void Queue ::deepCopy( 77const Queue & original ) 78 { 79Node *copyptr = front = &header; 80Node *originalptr = original.front; frontback OriginalCopy header front copyptr
129 deepCopy 75 template 76 inline void Queue ::deepCopy( 77const Queue & original ) 78 { 79Node *copyptr = front = &header; 80Node *originalptr = original.front; frontback OriginalCopy header front copyptr
130 deepCopy 75 template 76 inline void Queue ::deepCopy( 77const Queue & original ) 78 { 79Node *copyptr = front = &header; 80Node *originalptr = original.front; frontback OriginalCopy header front originalptrcopyptr
131 deepCopy 75 template 76 inline void Queue ::deepCopy( 77const Queue & original ) 78 { 79Node *copyptr = front = &header; 80Node *originalptr = original.front; frontback OriginalCopy header front originalptrcopyptr deepCopy function continued…
132 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
133 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
134 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
135 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
136 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
137 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
138 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
139 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
140 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
141 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
142 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
143 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
144 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
145 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
146 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
147 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
148 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
149 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
150 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
151 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
152 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
153 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
154 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
155 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
156 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
157 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
158 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
159 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
160 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr
161 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr back
162 deepCopy (cont.) 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } frontback OriginalCopy header front originalptrcopyptr back Let’s consider the empty case…
163 deepCopy (cont.) 75 template 76 inline void Queue ::deepCopy( 77const Queue & original ) 78 { 79Node *copyptr = front = &header; 80Node *originalptr = original.front; frontback OriginalCopy header
164 deepCopy (cont.) 75 template 76 inline void Queue ::deepCopy( 77const Queue & original ) 78 { 79Node *copyptr = front = &header; 80Node *originalptr = original.front; frontback Original header Copy header front copyptr
165 deepCopy (cont.) 75 template 76 inline void Queue ::deepCopy( 77const Queue & original ) 78 { 79Node *copyptr = front = &header; 80Node *originalptr = original.front; frontback Original header Copy header front copyptr
166 deepCopy (cont.) 75 template 76 inline void Queue ::deepCopy( 77const Queue & original ) 78 { 79Node *copyptr = front = &header; 80Node *originalptr = original.front; frontback Original header Copy header front copyptr originalptr
167 deepCopy (cont.) 75 template 76 inline void Queue ::deepCopy( 77const Queue & original ) 78 { 79Node *copyptr = front = &header; 80Node *originalptr = original.front; frontback Original header Copy header front copyptr originalptr
168 deepCopy (cont.) frontback Original header Copy header front copyptr originalptr 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 }
169 deepCopy (cont.) frontback Original header Copy header front copyptr originalptr 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 }
170 deepCopy (cont.) frontback Original header Copy header front copyptr originalptr 81while ( originalptr != original.back ) { 82originalptr = originalptr->next; 83copyptr->next = new Node ; 84copyptr = copyptr->next; 85copyptr->info = originalptr->info; 86} 87back = copyptr; 88 } back
171 Array Implementation of a Queue Similar to the linked-list queue, there are two data members called front and back, but they are indexes into an Array instead of pointers When enqueuing, the back index is incremented, and when dequeuing, the front index is incremented
172 Enqueue / Dequeue frontback
frontback DEQUEUE Enqueue / Dequeue (cont.)
frontback DEQUEUE Enqueue / Dequeue (cont.)
frontback DEQUEUE Enqueue / Dequeue (cont.)
frontback DEQUEUE Enqueue / Dequeue (cont.)
frontback ENQUEUE Enqueue / Dequeue (cont.)
frontback ENQUEUE Enqueue / Dequeue (cont.)
frontback ENQUEUE Enqueue / Dequeue (cont.)
frontback ENQUEUE Enqueue / Dequeue (cont.)
frontback DEQUEUE Enqueue / Dequeue (cont.)
frontback DEQUEUE Enqueue / Dequeue (cont.)
frontback DEQUEUE Enqueue / Dequeue (cont.)
frontback DEQUEUE Enqueue / Dequeue (cont.)
frontback ENQUEUE Enqueue / Dequeue (cont.)
frontback ENQUEUE Enqueue / Dequeue (cont.)
frontback DEQUEUE Enqueue / Dequeue (cont.)
frontback DEQUEUE Enqueue / Dequeue (cont.)
frontback DEQUEUE Enqueue / Dequeue (cont.)
frontback ENQUEUE Enqueue / Dequeue (cont.)
frontback ENQUEUE ? Enqueue / Dequeue (cont.)
frontback ENQUEUE Enqueue / Dequeue (cont.) We could double the size of the array here.
frontback ENQUEUE Enqueue / Dequeue (cont.) But if we keep doing this, we may have a million elements in the Array, but only a few at the end are used!
frontback ENQUEUE Enqueue / Dequeue (cont.) We handle this problem by having the back wrap around to the beginning of the array.
frontback ENQUEUE Enqueue / Dequeue (cont.)
frontback The front also wraps to the beginning when it reaches the end of the array Enqueue / Dequeue (cont.)
197 How Do We Know When the Array is Full? We may still need to double the capacity of the array if it gets filled An array will be full when –back + 1 == front –OR –back + 1 == capacity AND front == 0
198 A Full Array frontback
199 A Full Array frontback If the next operation is ENQUEUE, the array capacity will need to be doubled
200 The Queue Class Template 1 #include "Array.h" 2 3 template 4 class Queue 5 { 6 public: 7 Queue( ); 8void enqueue( DataType element ); 9bool dequeue( DataType & deqElement ); 10bool peek( DataType & frontElement ); 11bool isEmpty( ) const; 12void makeEmpty( );
201 The Queue Class Template (cont.) 13 private: 14Array elements; 15int front; 16int back; 17 }; #include "queue.cpp"
202 Queue Constructor 1 // queue.cpp 2 template 3 Queue ::Queue( ) 4 : elements( 2 ), front( -1 ), back( -1 ) 5 { 6 }
203 Enqueue 7 template 8 void Queue ::enqueue( DataType element ) 9 { 10 if ( back + 1 == front || 11( back == elements.length( ) - 1 && !front ) ) { 12 elements.changeSize( elements.length( ) << 1 ); 13 // if front end was last part of array, readjust 14 if ( back < front ) { 15int i = elements.length( ) - 1; 16for ( int j = ((i + 1) >> 1) - 1; j >= front; i--, j-- ) 17elements[ i ] = elements[ j ]; 18front = i + 1; 19} 20} Enqueue continued…
204 Enqueue (cont.) 21if ( back == -1 ) // queue is empty 22front = 0; 23back = (back == elements.length( ) - 1)? 240 : back + 1; 25elements[ back ] = element; 26 }
205 Dequeue 27 template 28 bool Queue ::dequeue( 29DataType & deqElement ) 30 { 31if (front == -1 ) 32return false; Dequeue continued…
206 Dequeue (cont.) 33deqElement = elements[ front ]; 34if ( front == back ) // only one element was in queue 35front = back = -1; 36else 37front = (front == elements.length( ) - 1)? 380 : front + 1; Dequeue continued…
207 Dequeue (cont.) 39// try to reduce the size of the array 40int trysize = elements.length( ); 41int numElements = (front <= back)? 42back - front + 1 : back + trysize - front + 1; 43while ( ( numElements > 2 ) && trysize > 2 ) 44trysize >>= 1; Dequeue continued…
208 Dequeue (cont.) 45if ( trysize < elements.length( ) ) { 46// readjust so we won't lose elements when 47// shrinking the array size 48int i, j; 49if ( front > back ) { If true, we can try to change the size of the array… The code for the “front > back” case is shown next…
209 Dequeue (cont.) 50 for ( i = trysize - 1, j = elements.length( ) - 1; j >= front; i--, j-- ) 51elements[ i ] = elements[ j ]; 52 front = i + 1; 53 try { 54elements.changeSize( trysize ); 55} 56 catch( … ) { 57 for ( i = elements.length( ) - 1, j = trysize - 1; j >= front; i--, j-- ) 58 elements[ i ] = elements[ j ]; 59 front = i + 1; 60 } If we can’t change the size, we’ll have to undo the realignment on lines
210 Dequeue (cont.) 61return true; 62} 63else if ( front = trysize ) { 64for ( i = 0, j = front; j <= back; i++, j++ ) 65elements[ i ] = elements[ j ]; 66front = 0; 67back = i - 1; 68} We need to return for the “front > back” case We won’t need to undo this realignment if we can’t change the size. We’re ready for the changeSize attempt…
211 Dequeue (cont.) 69try { 70elements.changeSize( trysize ); 71 } 72catch( … ) { } 73} 74 75return true; 76 } This changeSize attempt handles the “front = trysize” case AND the case where no realignment is necessary: “front <= back && back < trysize”
212 Peek 77 template 78 bool Queue ::peek( 79DataType & frontElement ) 80 { 81if (front == -1 ) 82return false; 83frontElement = elements[ front ]; 84return true; 85 }
213 isEmpty 86 template 87 bool Queue ::isEmpty( ) const 88 { 89return front == -1; 90 }
214 makeEmpty 91 template 92 void Queue ::makeEmpty( ) 93 { 94front = back = -1; 95try { 96elements.changeSize( 2 ); 97} 98catch( … ) { } 99 }