710 likes | 724 Views
Learn the logical and physical levels of stacks and queues, including array-based and linked implementations. Understand stack and queue operations, usage in algorithms, and common problems they can solve. This educational resource covers stack and queue ADTs, inheritance for advanced queue types, and the transformational effects of stack operations.
E N D
Stack and Queues CS3240
Goals • Describe a stack and its operations at a logical level • Demonstrate the effect of stack operations using a particular implementation of a stack • Implement the Stack ADT, in both an array-based implementation and a linked implementation • Describe the structure of a queue and its operations at a logical level
Goals • Demonstrate the effect of queue operations using a particular implementation of a queue • Implement the Queue ADT, using both a an array-based implementation and a linked implementation • Use inheritance to create a Counted Queue ADT
Stacks of Boxes and Books TOP OF THE STACK TOP OF THE STACK
Stacks • What do these composite objects all have in common?
Stacks Stack An abstract data type in which elements are added and removed from only one end (LIFO – Last In First Out)
Stacks • What operations would be appropriate for a stack? 8
Stacks • Transformers • Push • Pop • Observers • IsEmpty • IsFull • Top change state observe state What about an iterator? 9
Stacks • For what type of problems would stacks be useful?
Stacks Logical Level • class StackType • { • public: • StackType(); • bool IsEmpty() const; • bool IsFull() const; • void Push(ItemType item); • void Pop(); • ItemType Top() const;
Array-Based Implementation private: int top; ItemType items[MAX_ITEMS]; }; [0] [1] [2] …. [M..] stack .items .top Physical Level
Array-Based Implementation Give a series of operations that could produce this situation
Array-Based Implementation To what do we initialize top ? 0 or -1 Do we increment or store first? 0: store and increment -1: increment and store Which is better?
Array-Based Implementation • Before we code, we must consider error conditions • Stack overflow • The condition that results from trying to push an element on to a full stack • Stack underflow • The condition that results from trying to pop an empty stack
Array-Based Implementation StackType::StackType() { top = -1; } bool StackType::IsEmpty() const { return ( top = -1); } bool StackType::IsFull() const { return ( top == MAX_ITEMS); } What does const mean?
Array-Based Implementation void StackType::Push(ItemType newItem) { if (IsFull()) throw FullStack(); top++; items[top] = newItem; } What is FullStack() ?
Array-Based Implementation void StackType::Pop() { if (IsEmpty()) throw EmptyStack(); top- -; } ItemType StackType::Top() const { if (IsEmpty()) throw EmptyStack(); return (items[top]); } What is EmptyStack ?
Array-Based Implementation Which functions have to be changed if we dynamically allocate the array items ? Do we need to add any new functions?
Linked Implementation The logical level (public part of the class declaration) stays the same; the implementation level (private part of the class declaration) changes private: NodeType* topPtr; } Can we “borrow” code from UnsortedType for Push and Pop ?
Linked Implementation void StackType::Push(ItemType newItem) { if (IsFull()) throw FullStack(); else { NodeType* location; location = new NodeType; location->info = newItem; location>next = topPtr; topPtr = location; } }
Linked Implementation void StackType::Pop() { if (IsEmpty()) throw EmptyStack(); else { NodeType* tempPtr; tempPtr = topPtr; topPtr = topPtr->next; delete tempPtr; } } Does this work for stacks of one item? More than one item?
Linked Implementation More than one item
Linked Implementation One item
Linked Implementation What about the constructor, destructor, and observer functions? We can borrow all but Top from class UnsortedType ItemType StackType::Top() { if (IsEmpty()) throw EmptyStack else return topPtr->info; }
What Problems can Stacks Be Used For • Any time you need LIFO functionality
Stack application: Converting Decimal # to Binary # • Starting Algorithm • Read a number • while number > 0 • Find out the remainder after dividing the number by 2 • Print the remainder • Divide the number by 2 • PROBLEM: the number = 23 we get the result as 11101, instead of getting 10111. Number= 23 23/2 = 11 REMAINDER 1 11/2 = 5 REMAINDER 1 5/2 = 2 REMAINDER 1 2/2 = 1 REMAINDER 0 1 / 2 = 0 REMAINDER 1
SOLVE --- USE A STACK • we push the binary digit formed into the stack, instead of printing it directly. • after the entire number has been converted into the binary form, we pop one digit at a time from the stack and print it. • Therefore we get the decimal number converted into its proper binary form.
n= 23 bit = 1 (23 modulo 2) s.push(1) n = floor(n/2) = 11bit = 1 (11 modulo 2) s.push(1) n = floor(n/2) = 5bit = 1 (5 modulo 2) s.push(1) n = floor(n/2) = 2bit = 0 (2 modulo 2) s.push(0) n = floor(n/2) = 1bit = 1 (1 modulo 2) s.push(1) n = floor(n/2) = 0STOP PUSHING s.pop() 1 s.pop() 0 s.pop() 1 s.pop() 1 s.pop() 1 • Fixed STACK Algorithm: • outputInBinary(Integer n) Stack s = new Stack while n > 0 Integer bit = n modulo 2 s.push(bit) if s is fullthenreturn error n = floor(n / 2) while s is not empty output(s.pop())
Stacks and another problem • A famous problem that can be solved with stacks is called the “Tower of Hanoi” • old Brahmin story, the existence of the universe is calculated in terms of the time taken by a number of monks, who are working all the time, to move 64 disks from one pole to another. • RULES • move only one disk at a time. • for temporary storage, a third pole may be used. • a disk of larger diameter may not be placed on a disk of smaller diameter.
Solution –using stacks implicitly in recursion (where are things placed when you recurse—on a STACK!!) • void TowersofHanoi(int n, int a, int b, int c) • { if(n > 0) { • TowersofHanoi(n-1, a, c, b); //recursion • printf("> Move top disk from tower %d to tower %d.\n", a, c); • TowersofHanoi(n-1, b, c, a); //recursion • } • } • TowersofHanoi(3,A,B,C) • Solve problem TowersofHanoi(top n-1 discs) moving to pole b (using c as empty) • Move the top disc (which is now the largest disc by itself) from pole a to pole c • Solve problem of TowersofHanoi( top n-1 discs on pole b) moving to pole c (using a as empty)
What if you have more discs --- a recursion problem using stacks!!! Say have problem of Hanoi(N+1) = Hanoi(N) + 1 disc • RECURSION
So what is the solution using stacks explicitly ---- read • // Global variable , tower [1:3] are three towers • arrayStack<int> tower[4]; • void TowerofHanoi(int n) { • // Preprocessor for moveAndShow. • for (int d = n; d > 0; d--) //initialize • tower[1].push(d); //add disk d to tower 1 • moveAndShow(n, 1, 2, 3); /*move n disks from tower 1 to tower 3 using tower 2 as intermediate tower*/ • } • void moveAndShow(int n, int a, int b, int c) { • // Move the top n disks from tower a to tower b showing states. • // Use tower c for intermediate storage. • if(n > 0) • { moveAndShow(n-1, a, c, b); //recursion • int d = tower[a].top(); //move a disc from top of tower x to top of • tower[a].pop(); //tower y • tower[c].push(d); • showState(); //show state of 3 towers • moveAndShow(n-1, b, a, c); //recursion • } • }
Stacks –another application • Expression evaluation and syntax parsing • Calculators employing reverse Polish notation use a stack structure to hold values
Stacks used in Function calls • Some programming languages use the stack (Call Stack) to store data that is local to a procedure and the procedure calls themselves. • Space for local data items is allocated from the stack when the procedure is entered, and is deallocated when the procedure exits. • C programming language is typically implemented in this way. DrawSquare runs and calls DrawLine which is currently running (abo e is Call stack)
Stacks – use them as you need • A number of programming languages are stack-oriented, meaning they define most basic operations (adding two numbers, printing a character) as taking their arguments from the stack, and placing any return values back on the stack. For example, PostScript has a return stack and an operand stack, and also has a graphics state stack and a dictionary stack. • virtual machines are also stack-oriented, including the p-code machine and the Java Virtual Machine. • Almost all calling conventions – computer runtime memory environments – use a special stack (the "call stack") to hold information about procedure/function calling and nesting in order to switch to the context of the called function and restore to the caller function when the calling finishes.
Queues • What do these composite objects all have in common?
Queues Queue An abstract data type in which elements are added to the rear and removed from the front; a “first in, first out” (FIFO) structure
Queues • What operations would be appropriate for a queue? 44
Queues • Transformers • MakeEmpty • Enqueue • Dequeue • Observers • IsEmpty • IsFull change state observe state What about an iterator? 45
Queues • For what type of problems would stacks be useful?
Queues • class QueType • { • public: • QueType(int max); • QueType(); • ~QueType(); • bool IsEmpty() const; • bool IsFull() const; • void Enqueue(ItemType item); • void Dequeue(ItemType& item); Logical Level
Array-Based Implementation private: ItemType* items; // Dynamically allocated array int maxQue; // Whatever else we need } Implementation level
Array-Based Implementation One data structure: An array with the front of the queue fixed in the first position Enqueue A, B, C, D Dequeue Move elements down What’s wrong with this design?
Array-Based Implementation Another data structure: An array where the front floats What happens if we add X, Y, and Z ?