Chapter 5 ADTs Stack and Queue
Stacks of Coins and Bills
Stacks of Boxes and Books TOP OF THE STACK
Definition of Stack Logical (or ADT) level: A stack is an ordered group of homogeneous items (elements), in which the removal and addition of stack items can take place only at the top of the stack. A stack is a LIFO “last in, first out” structure.
Stack ADT Operations MakeEmpty -- Sets stack to an empty state. IsEmpty -- Determines whether the stack is currently empty. IsFull -- Determines whether the stack is currently full. Push (ItemType newItem) -- Throws exception if stack is full; otherwise adds newItem to the top of the stack. Pop -- Throws exception if stack is empty; otherwise removes the item at the top of the stack. ItemType Top -- Throws exception if stack is empty; otherwise returns a copy of the top item
ADT Stack Operations Transformers Push Pop Observers IsEmpty IsFull change state observe state
class StackType { public: StackType( ); bool IsFull () const; bool IsEmpty() const; void Push( ItemType item ); void Pop(); private: ItemType Top(); private: int top; ItemType items[MAX_ITEMS]; }; What are the pre and post conditions?
// File: StackType.cpp #include "StackType.h" #include StackType::StackType( ) { top = -1; } bool StackType::IsEmpty() const { return(top == -1); } bool StackType::IsFull() const { return (top = = MAX_ITEMS-1); }
void StackType::Push(ItemType newItem) { if( IsFull() ) throw FullStack(): top++; items[top] = newItem; } void StackType::Pop() { if( IsEmpty() ) throw EmptyStack(); top--; } ItemType StackType::Top() { if (IsEmpty()) throw EmptyStack(); return items[top]; }
Class Interface Diagram (Memory reversed to better illustrate concept) StackType class StackType Pop Push IsFull IsEmpty Private data: top [MAX_ITEMS-1]. [ 2 ] [ 1 ] items [ 0 ] Top
charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)} Tracing Client Code Private data: top [ MAX_ITEMS-1 ]. [ 2 ] [ 1 ] items [ 0 ] letter ‘V’‘V’
Tracing Client Code letter ‘V’‘V’ Private data: top -1 [ MAX_ITEMS-1 ]. [ 2 ] [ 1 ] items [ 0 ] charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
Tracing Client Code letter ‘V’‘V’ Private data: top 0 [ MAX_ITEMS-1 ]. [ 2 ] [ 1 ] items [ 0 ] ‘V’ charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
Tracing Client Code letter ‘V’‘V’ Private data: top 1 [ MAX_ITEMS-1 ]. [ 2 ] [ 1 ] ‘C’ items [ 0 ] ‘V’ charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
Tracing Client Code letter ‘V’‘V’ Private data: top 2 [ MAX_ITEMS-1 ]. [ 2 ] ‘S’ [ 1 ] ‘C’ items [ 0 ] ‘V’ charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
Tracing Client Code letter ‘V’‘V’ Private data: top 2 [ MAX_ITEMS-1 ]. [ 2 ] ‘S’ [ 1 ] ‘C’ items [ 0 ] ‘V’ charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
Tracing Client Code letter ‘V’‘V’ Private data: top 1 [ MAX_ITEMS-1 ]. [ 2 ] ‘S’ [ 1 ] ‘C’ items [ 0 ] ‘V’0 charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
Tracing Client Code letter ‘V’‘V’ Private data: top 2 [ MAX_ITEMS-1 ]. [ 2 ] ‘K’ [ 1 ] ‘C’ items [ 0 ] ‘V’ charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
Tracing Client Code letter ‘V’‘V’ Private data: top 2 [ MAX_ITEMS-1 ]. [ 2 ] ‘K’ [ 1 ] ‘C’ items [ 0 ] ‘V’ charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
Tracing Client Code letter ‘K’‘K’ Private data: top 2 [ MAX_ITEMS-1 ]. [ 2 ] ‘K’ [ 1 ] ‘C’ items [ 0 ] ‘V’ charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
Tracing Client Code letter ‘K’‘K’ Private data: top 1 [ MAX_ITEMS-1 ]. [ 2 ] ‘K’ [ 1 ] ‘C’ items [ 0 ] ‘V’ charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
Tracing Client Code letter ‘K’‘K’ Private data: top 1 [ MAX_ITEMS-1 ]. [ 2 ] ‘K’ [ 1 ] ‘C’ items [ 0 ] ‘V’ charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
Tracing Client Code letter ‘C’‘C’ Private data: top 0 [ MAX_ITEMS-1 ]. [ 2 ] ‘K’ [ 1 ] ‘C’ items [ 0 ] ‘V’ charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
Tracing Client Code letter ‘C’‘C’ Private data: top 0 [ MAX_ITEMS-1 ]. [ 2 ] ‘K’ [ 1 ] ‘C’ items [ 0 ] ‘V’ charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
Tracing Client Code letter ‘V’‘V’ Private data: top -1 [ MAX_ITEMS-1 ]. [ 2 ] ‘K’ [ 1 ] ‘C’ items [ 0 ] ‘V’ charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
End of Trace letter ‘V’‘V’ Private data: top -1 [ MAX_ITEMS-1 ]. [ 2 ] ‘K’ [ 1 ] ‘C’ items [ 0 ] ‘V’ charletter = ‘V’; StackType charStack; charStack.Push(letter); charStack.Push(‘C’); charStack.Push(‘S’); if ( !charStack.IsEmpty( )) charStack.Pop( ); charStack.Push(‘K’); while (!charStack.IsEmpty( )) { letter = charStack.Top(); charStack.Pop(0)}
Another Stack Implementation One advantage of an ADT is that the implementation can be changed without the program using it knowing about it. The dynamic array implementation of the stack has a weakness -- the maximum size of the stack is passed to the constructor as parameter. Instead we can dynamically allocate the space for each stack element as it is pushed onto the stack.
ItemType is char class StackType StackType Top Pop Push IsFull IsEmpty Private data: topPtr ~StackType ‘C’ ‘V’
class StackType StackType Top Pop Push IsFull IsEmpty Private data: topPtr ~StackType ItemType is float
ItemType is string class StackType StackType Top Pop Push IsFull IsEmpty Private data: topPtr ~StackType cat dog
Tracing Client Code letter ‘V’‘V’ charletter = ‘V’; StackType myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); If (!myStack.IsEmpty() ) { letter = myStack.Top( ); myStack.Pop(); } myStack.Push(‘K’);
Tracing Client Code letter ‘V’‘V’ Private data: topPtr NULL charletter = ‘V’; StackType myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); If (!myStack.IsEmpty() ) { letter = myStack.Top( ); myStack.Pop(); } myStack.Push(‘K’);
Tracing Client Code letter Private data: topPtr ‘V’‘V’ ‘V’‘V’ charletter = ‘V’; StackType myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); If (!myStack.IsEmpty() ) { letter = myStack.Top( ); myStack.Pop(); } myStack.Push(‘K’);
Tracing Client Code letter Private data: topPtr ‘C’ ‘V’ ‘V’‘V’ charletter = ‘V’; StackType myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); If (!myStack.IsEmpty() ) { letter = myStack.Top( ); myStack.Pop(); } myStack.Push(‘K’);
Tracing Client Code letter Private data: topPtr ‘S’ ‘ C’ ‘ V’ ‘V’‘V’ charletter = ‘V’; StackType myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); If (!myStack.IsEmpty() ) { letter = myStack.Top( ); myStack.Pop(); } myStack.Push(‘K’);
Tracing Client Code letter Private data: topPtr ‘S’ ‘ C’ ‘V’ ‘V’‘V’ charletter = ‘V’; StackType myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); If (!myStack.IsEmpty() ) { letter = myStack.Top( ); myStack.Pop(); } myStack.Push(‘K’);
Tracing Client Code letter Private data: topPtr ‘C’ ‘V’ ‘S’‘S’ charletter = ‘V’; StackType myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); If (!myStack.IsEmpty() ) { letter = myStack.Top( ); myStack.Pop(); } myStack.Push(‘K’);
Tracing Client Code letter Private data: topPtr ‘C’ ‘V’ ‘S’‘S’ charletter = ‘V’; StackType myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); If (!myStack.IsEmpty() ) { letter = myStack.Top( ); myStack.Pop(); } myStack.Push(‘K’);
Tracing Client Code letter Private data: topPtr ‘V’‘V’ ‘C’‘C’ charletter = ‘V’; StackType myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); If (!myStack.IsEmpty() ) { letter = myStack.Top( ); myStack.Pop(); } myStack.Push(‘K’);
Tracing Client Code letter Private data: topPtr ‘V’‘V’ ‘C’‘C’ charletter = ‘V’; StackType myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); If (!myStack.IsEmpty() ) { letter = myStack.Top( ); myStack.Pop(); } myStack.Push(‘K’);
Tracing Client Code letter Private data: topPtr ‘V’‘V’ charletter = ‘V’; StackType myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); If (!myStack.IsEmpty() ) { letter = myStack.Top( ); myStack.Pop(); } myStack.Push(‘K’);
Tracing Client Code letter Private data: topPtr ‘V’‘V’ charletter = ‘V’; StackType myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); If (!myStack.IsEmpty() ) { letter = myStack.Top( ); myStack.Pop(); } myStack.Push(‘K’);
Tracing Client Code letter Private data: topPtr ‘K’‘K’ ‘V’‘V’ charletter = ‘V’; StackType myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); If (!myStack.IsEmpty() ) { letter = myStack.Top( ); myStack.Pop(); } myStack.Push(‘K’);
// DYNAMICALLY LINKED IMPLEMENTATION OF STACK Struct NodeType; //Forward declaration class StackType { public: //Identical to previous implementation private: NodeType* topPtr; };. Struct NodeType { ItemType info; NodeType* next; };
Adding newItem to the stack newItem = ‘B’; NodeType* location; location = new NodeType ; location->info = newItem; location->next = topPtr; topPtr = location; topPtr ‘X’ ‘C’ ‘L’ ‘B’‘B’ newItem
Adding newItem to the stack newItem = ‘B’; NodeType* location; location = new NodeType ; location->info = newItem; location->next = topPtr; topPtr = location; topPtr ‘X’ ‘C’ ‘L’ ‘B’‘B’ newItem location
Adding newItem to the stack newItem = ‘B’; NodeType* location; location = new NodeType ; location->info = newItem; location->next = topPtr; topPtr = location; topPtr ‘X’ ‘C’ ‘L’ ‘B’‘B’ newItem location
Adding newItem to the stack newItem = ‘B’; NodeType* location; location = new NodeType ; location->info = newItem; location->next = topPtr; topPtr = location; topPtr ‘X’ ‘C’ ‘L’ ‘B’‘B’ newItem location ‘B’‘B’
Adding newItem to the stack newItem = ‘B’; NodeType* location; location = new NodeType ; location->info = newItem; location->next = topPtr; topPtr = location; topPtr ‘X’ ‘C’ ‘L’ ‘B’‘B’ newItem location ‘B’‘B’
Adding newItem to the stack newItem = ‘B’; NodeType* location; location = new NodeType ; location->info = newItem; location->next = topPtr; topPtr = location; topPtr ‘X’ ‘C’ ‘L’ ‘B’‘B’ newItem location ‘B’‘B’
void StackType::Push ( ItemType newItem ) // Adds newItem to the top of the stack. { if (IsFull()) throw FullStack(); NodeType* location; location = new NodeType ; location->info = newItem; location->next = topPtr; topPtr = location; } Implementing Push Do we need IsFull?
Deleting item from the stack NodeType* tempPtr; item = topPtr->info; tempPtr = topPtr; topPtr = topPtr->next; delete tempPtr; topPtr ‘B’ ‘X’ ‘C’ ‘L’ tempPtr item
Deleting item from the stack NodeType* tempPtr; item = topPtr->info; tempPtr = topPtr; topPtr = topPtr->next; delete tempPtr; topPtr item ‘B’ ‘X’ ‘C’ ‘L’ tempPtr ‘B’‘B’
Deleting item from the stack NodeType* tempPtr; item = topPtr->info; tempPtr = topPtr; topPtr = topPtr->next; delete tempPtr; topPtr item ‘B’ ‘X’ ‘C’ ‘L’ tempPtr ‘B’‘B’
Deleting item from the stack NodeType* tempPtr; item = topPtr->info; tempPtr = topPtr; topPtr = topPtr->next; delete tempPtr; topPtr item ‘B’ ‘X’ ‘C’ ‘L’ tempPtr ‘B’‘B’
Deleting item from the stack NodeType * tempPtr; item = topPtr->info; tempPtr = topPtr; topPtr = topPtr->next; delete tempPtr; topPtr item ‘X’ ‘C’ ‘L’ tempPtr ‘B’‘B’
void StackType::Pop()// Remove top item from Stack. { if (IsEmpty()) throw EmptyStack(); else { NodeType* tempPtr; tempPtr = topPtr; topPtr = topPtr ->next; delete tempPtr; } ItemType StackType::Top() // Returns a copy of the top item in the stack. { if (IsEmpty()) throw EmptyStack(); else return topPtr->info; } Implementing Pop / Top
Implementing IsFull bool StackType::IsFull() const // Returns true if there is no room for another // ItemType on the free store; false otherwise { NodeType* location; try { location = new NodeType; delete location; return false; } catch(std::bad_alloc exception) { return true; }
Example of a Queue
What is a Queue? Logical (or ADT) level: A queue is an ordered group of homogeneous items (elements), in which new elements are added at one end (the rear), and elements are removed from the other end (the front). A queue is a FIFO “first in, first out” structure.
Queue ADT Operations MakeEmpty -- Sets queue to an empty state. IsEmpty -- Determines whether the queue is currently empty. IsFull -- Determines whether the queue is currently full. Enqueue (ItemType newItem) -- Adds newItem to the rear of the queue. Dequeue (ItemType& item) -- Removes the item at the front of the queue and returns it in item.
ADT Queue Operations Transformers MakeEmpty Enqueue Dequeue Observers IsEmpty IsFull change state observe state
typedef char ItemType; class QueType { public: QueType(int max); // max is the size of the queue. QueType(); // Default size of 500. ~QueType(); void MakeEmpty(); bool IsEmpty() const; bool IsFull() const; void Enqueue(ItemType item); void Dequeue(ItemType& item); Public Interface of QueType
SIMPLE ARRAY IMPLEMENTATION QueType ~QueType Enqueue Dequeue. class QueType Private Data: front 1 rear 4 maxQue 5 items ‘ C’ ‘X’ ‘J’ items [0] [1] [2] [3] [4] RESERVED
What is the private part of class QueType for this design? What troubles do we encounter?
DYNAMIC ARRAY IMPLEMENTATION QueType ~QueType Enqueue Dequeue. class QueType Private Data: front 1 rear 4 maxQue 5 items ‘C’ ‘X’ ‘J’ items [0] [1] [2] [3] [4] RESERVED
What is the private part of class QueType for this design? Does this design have the same problems as the previous design?
class QueType QueType ~QueType Enqueue Dequeue. Private Data: qFront qRear ‘C’‘C’‘Z’ ‘T’
What is the private part of class QueType for this design?
CountedQueType inherits from QueType // DERIVE CLASS CountedQueType FROM BASE CLASS QueType class CountedQueType : QueType; { public: CountedQueType( ); void Enqueue( ItemType newItem ); void Dequeue( ItemType& item ); int GetLength( ) const; // Returns number of items on the counted queue. private: int length; };
What additional fields does CountedQueType need? What functions must be changed?
Comparing Queue Implementations 80-byte string Array: (80 bytes * 101 slots) + (2 bytes * 2 indexes) = 8084 bytes Linked queue: 8 bytes for 2 queue pointers, plus (80 bytes + 4 bytes) = 84 bytes / node Array requires same amount of memory, regardless of slots used. When elements > 96, queue requires more memory. 2-byte integer Array: (2 bytes * 101 slots) + (2 bytes * 2 indexes) = 206 bytes Lined queue: 8 bytes for 2 queue pointers, plus 2 bytes + 4 bytes = 6 bytes / node When elements > 33, queue requires more memory than array
Big-O Comparison of Queue Operations Dynamic ArrayLinked List Class Constructor O(1) MakeEmpty O(1)O(N) IsFull O(1) IsEmpty O(1) Enqueue O(1) Dequeue O(1) Destructor O(1)O(N)