# More on Stacks and Queues. As we mentioned before, two common introductory Abstract Data Type (ADT) that worth studying are Stack and Queue Many problems.

## Presentation on theme: "More on Stacks and Queues. As we mentioned before, two common introductory Abstract Data Type (ADT) that worth studying are Stack and Queue Many problems."— Presentation transcript:

More on Stacks and Queues

As we mentioned before, two common introductory Abstract Data Type (ADT) that worth studying are Stack and Queue Many problems (or parts of problems) can be thought of as stack problems, queue problems, or other problems that can be solved with the help of another (perhaps user-defined) ADT You need to decide what ADTs you need, build them, test them, then tackle your larger problem

Stack ADT A stack is an ADT with specific properties and operations Stack properties are: Only one item can be accessed at a time Always the last item inserted is the first to come out (LIFO) New items must be inserted at the top The size of the stack is dynamic The stack must be able to grow and shrink Normally, items stored on the stack are homogeneous (i. e. they are all integers or all are string, etc

Stack Operations Stack operations are: Push: Puts a new item on the top of the stack. Can’t push into a full stack Pop: Removes the top item from stack. Can’t pop an empty stack Top: Examine top item without modifying stack. Can’t top an empty stack Init: Set existing stack to empty Full: Returns true if the stack is full Empty: Returns true if the stack is empty

Problem Solving Using Stack: Bracket Checking Many problems can be solved using stacks Given a mathematical expression with 3 types of “brackets” ( ) [ ] { }, we want to determine if the brackets are properly matched For example, bracketing in the following expression is CORRECT { 5 * (8-2) } / { [4 * (3+2)] + [5 * 6] } However, the bracketing in the following two expressions are INCORRECT { (A+C) * D [A + {B+C} )

This problem is easily solved with a stack Algorithm: Scan expression from left to right Each time a left bracket is encountered, push it onto the stack When a right bracket is encountered, compare it to the top item on the stack If it’s a match, pop the stack If not, report illegal bracketing If the stack is prematurely empty, report illegal bracketing If there are items left on the stack after the expression has been scanned, report illegal bracketing

bool BracketMaching (string expression) { char curr, temp; Stack bracket_stack; for (int i=0; i< stg.size(); i++) { curr = stg[i]; if (curr == ‘(’ || curr == ‘[’ || curr == ‘{’) bracket_stack.push (curr); else if (curr == ‘)’ || curr == ‘]’ || curr == ‘}’) if (bracket_stack.empty() ) then return false; else if (bracket_stack.pop() does not match with curr) return false; end if } // for loop return true; } This program assumes that we have the following routines available bool empty (); push (item); char top ();

Problem Solving Using Stack: Evaluation of An Expression Consider the problem of evaluating an arithmetic expression using a stack Traditionally, when we write an arithmetic expression as follows: 2 + 3 * (6 - 5) This is known as infix notation Operators are in-between the operands When computing arithmetic expressions, it’s sometimes useful to represent them using postfix (operator after) or prefix (operator before) notation

PrefixInfixPostfix - 6 1 * + 4 3 2 / + 2 3 - 9 4 6 - 1 (4 + 3) * 2 (2 + 3) / (9 - 4) 6 1 - 4 3 + 2 * 2 3 + 9 4 - / It’s easy to evaluate postfix and prefix expressions using a stack in part because no brackets are necessary

prefix postfix * + 4 3 2 432432 4 3 + 2 * 3434 evaluate 14 7272 + * + 2727 * Push 2 Push 3 Push 4 Pop 4 Pop 3 Apply + and get 7 Push 7 Pop 7 Pop 2 Apply * and get 14 Push 14 push 4 push 3 Pop 3 Pop 4 Apply addition and get 7 Push 7 Push 2 Pop 2 Pop 7 Apply * and get 14 Push 14

Algorithm for evaluating postfix: Parse expression from left to right When an operand is encountered, push it onto the stack When an operator is encountered, pop the top two operands, apply the operator, and push the result onto the stack When the expression is completely scanned, the final result will be on the stack What if we want to convert an expression from infix to postfix? For example: 2 + 3 * [(5 - 6) / 2] becomes 2 3 5 6 - 2 / * +

Use the following algorithm to change infix to postfix: Scan infix string from left to right Each time an operand is encountered, copy it to the output When a bracket is encountered, check its orientation. Push left brackets onto the stack If it’s a right bracket, pop all operators out of the stack and copy them to output until a matching left bracket is encountered. Discard the left bracket. When an operator is encountered, check the top item of the stack. If the priority is >= the current operator, pop the top operator and copy it to output Continue until an operator of lesser priority is encountered or until stack is empty Assume left brackets have lowest priority Finally, push current operator onto the stack When the end of the expression is reached, copy the remaining stack contents to output in the order popped

Consider the following example that is scanned from left to right Expression: 2 + 3 * [ ( 5 – 6 ) / 2 ] Stack Output: 2 is placed on the output line because it is an operand Expression: 2 + 3 * [ ( 5 – 6 ) / 2 ] Stack Output: + is an operator and it is placed in the stack. Note there is no operator on the top of the stack with priority >= the + operator + 2 2

Expression: 2 + 3 * [ ( 5 – 6 ) / 2 ] Stack Output: 3 is placed on the output line because it is an operand + 2 3 Expression: 2 + 3 * [ ( 5 – 6 ) / 2 ] Stack Output: * is an operator and it is placed in the stack without taking anything out of the stack. Note that * has higher priority than + * 2 3 +

Expression: 2 + 3 * [ ( 5 – 6 ) / 2 ] Stack Output: Left brackets, no matter what type of bracket it is, it is placed in the stack * 2 3 + [ Expression: 2 + 3 * [ ( 5 – 6 ) / 2 ] Stack Output: Again another left encountered and it is placed in the stack * 2 3 + [ (

Expression: 2 + 3 * [ ( 5 – 6 ) / 2 ] Stack Output: 5 is placed on the output line because it is an operand * 2 3 5 + [ ( Expression: 2 + 3 * [ ( 5 – 6 ) / 2 ] Stack Output: Minus sign (-) is placed in the stack. Note that the top of the stack is not an operator to compare minus sign with it * 2 3 5 + [ ( -

Expression: 2 + 3 * [ ( 5 – 6 ) / 2 ] Stack Output: 6 is placed on the output line because it is an operand * 2 3 5 6 + [ ( - Expression: 2 + 3 * [ ( 5 – 6 ) / 2 ] Stack Output: “(” is a closing round bracket. Keep on popping from the stack till we you find the matching opening round bracket. DO NOT COPY THE OPEN ROUND BRACKET TO THE OUTPUT * 2 3 5 6 - + [

Expression: 2 + 3 * [ ( 5 – 6 ) / 2 ] Stack Output: Division (/) is placed in the stack. Note that the top of the stack is not an operator to compare division sign with it * 2 3 5 6 - + [ / Expression: 2 + 3 * [ ( 5 – 6 ) / 2 ] Stack Output: 2 is placed on the output line because it is an operand * 2 3 5 6 - 2 + [ /

Expression: 2 + 3 * [ ( 5 – 6 ) / 2 ] Stack Output: “]” is a closing square bracket. Keep on popping from the stack till we you find the matching opening square bracket. DO NOT COPY THE OPEN SQUARE BRACKET TO THE OUTPUT * 2 3 5 6 - 2 / + Expression: 2 + 3 * [ ( 5 – 6 ) / 2 ] Stack Output: We are done. So keep popping from the stack and place the characters to the output line 2 3 5 6 – 2 / * + What we have on the output line is the corresponding postfix expression

Problem Solving Using Stack: Adding large numbers using stack Another example of stack application is adding two large numbers together. Note that the largest magnitude of integers are limited so we are not able to normally add numbers like: 243678489505654679857465758598595950949463535 + 462668435748955758056548577946 Since the integer variables cannot hold such a big numbers we can use other tools to add these numbers together The next slide shows the algorithm of adding two numbers together using stack

Algorithm for adding two numbers Read the numerals of the first number and store the numbers corresponding to them on the stack; Read the numerals of the second number and store them in another stack; Let R = 0; While at least one stack is not empty Pop a number from each stack and add them to R; Push the unit part of R on the result stack; Store carry part of R in R overwriting the old value; Push R on the result stack if it is not zero Pop numbers from the result stack and display them

592 + 3784 4376 295295 48734873 2 + 4 6 9 + 8 17 1 5 + 7 13 9595 873873 6 5 7373 7676 3 376376 Stack 1 Stack 2 Result Stack 43764376 + =6 + =17 + =13 + =4 1 + 3 4

Problem Solving Using Stack: Exiting A Maze Consider the problem of a trapped mouse that tries to find its way to an exit in a maze The mouse systematically moves and if it hits a wall, it backtracks and tries another path. The maze is implemented as a two dimensional character array in which passages are marked with “o” and walls are marked with “1”. When a cell is visited, it is marked with “.” so that the mouse does not try that again. In general, the mouse always takes right cell first, if it cannot succeed, it takes left and if it still fails, it takes down and finally it tries the upper cell to reach its destination. As long as it finds a space it moves in that path and tries its best to find the exit door. We represent the mouse with M and exit door with E

In order to ensure that the mouse does not fall off the maze, we create a wall around the maze. Thus the mouse will be trapped in the maze until it finds the door. If the mouse tries all the possible solutions and still cannot find the exit door, we report a failure; otherwise, we report a success. The algorithm is: Initialize stack, exitCell, entryCell, currentCell = entryCell; Create a wall of 1’s around the maze While currentCell is not exitCell Mark currentCell as visited; Push onto the stack the unvisited neighbors of current Cell in the order of up, down left and right If stack is empty Report failure Else Pop off a cell from the stack and make it currentCell success

1 1 E o 1 11111 1Moo1 1ooo1 1o111 11111 0123401234 0 1 2 3 4 5 (3, 2) (2, 3) Push the Up and Left cell into stack Start with the following maze where the mouse is at position (3, 3) and the exit door is at (2, 4) 1 1 E o 1 11111 1Moo1 1ooo1 1o111 11111 0123401234 0 1 2 3 4 5 Make the current position visited (“.”) Pop the first element of the stack Move the mouse to that position

Push the Up cell into stack 1 1 E o 1 11111 1..M1 1ooo1 1o111 11111 0123401234 0 1 2 3 4 5 Make the current position visited (“.”) Pop the first element of the stack Move the mouse to that position (3, 1) (2, 2) (2, 3) Push the Up and Left cells into stack 1 1 E o 1 11111 1.Mo1 1ooo1 1o111 11111 0123401234 0 1 2 3 4 5 Make the current position visited (“.”) Pop the first element of the stack Move the mouse to that position (2, 1) (2, 2) (2, 3)

Push the Right cell into stack 1 1 E o 1 11111 1...1 1oM.1 1o111 11111 0123401234 0 1 2 3 4 5 Make the current position visited (“.”) Pop the first element of the stack Move the mouse to that position (2, 2) (2, 3) Push the Right cell into stack 1 1 E o 1 11111 1...1 1ooM1 1o111 11111 0123401234 0 1 2 3 4 5 Make the current position visited (“.”) Pop the first element of the stack Move the mouse to that position (2, 3) (2, 2) (2, 3)

Push the UP cell into stack 1 1 E/M o 1 11111 1...1 1...1 1o111 11111 0123401234 0 1 2 3 4 5 The exit door is found (2, 4) (1, 3) (2, 2) (2, 3) Push the UP and Right cell into stack 1 1 E o 1 11111 1...1 1M..1 1o111 11111 0123401234 0 1 2 3 4 5 Make the current position visited (“.”) Pop the first element of the stack Move the mouse to that position (1, 3) (2, 2) (2, 3)

Queue A queue is an ADT with the following specific properties A queue contains zero or more, normally homogenous, items Data items are added to the tail (back) of the queue and are removed from the head (front) of the queue The items in the queue are maintained in FIFO (first-in- first out) order The first item placed on the queue is always the first one removed

Possible operations Init: Initializes a queue so as to be empty Insert: Adds a new item to the tail of the queue Remove: Removes the item at the head of the queue Empty: Tests to see if the queue is empty Full: Tests to see if the queue is full Data In Data Out Queue tailhead..

Queues are common in computing Scheduling queues Operating systems support multi-tasking by sharing scarce resources such as CPU time Each task that requests CPU resources might be put in a queue Tasks are given cycles of time If task finishes …. good -- if not, task goes to the back of queue for additional cycles Lets discuss some implementations of Queue

Implementing Queue with Array One possible queue implementation is array Elements are added to the end of he queue, and removed from the beginning of the queue Suppose we insert some element to the bottom of the queue and remove other elements from the head of the queue. Now if we reach to the end of the queue, we cannot insert anymore element to the bottom even if we have some elements remove from the head of the queue. Therefore, to optimize space, we can turn our queue into a circular queue so that when we reach the end of the queue, we can still insert some element if there is empty space in the head

Thus, the circular queue is full under when one of the following conditions are true: The head is at position 0 and tail is at position n-1 (last position) The head is at position of “tail+1” in the queue The first case is shown in the following example. Suppose, the queue has 4 positions and we insert 10, 20, 30, and 40 without removing any element 10 20 10 20 30 10 20 30 40 head tail head tail head tail head tail

Now suppose after inserting 30 we pop 10 and we insert 40 and 50. Again the queue is full and head is tail+1 10 20 10 20 30 10 20 30 head tail head tail head tail head tail 40 10 20 30 head tail 40 50 20 30 head tail enqueue 10 enqueue 20 enqueue 30 dequeue 10 enqueue 40 enqueue 50

The queue is initially empty. The initial value of head and tail is -1 and if during the operation we pop one element from the queue and we find out that the head and tail becomes equal class Queue { public: Queue(){last = first = -1, size =4;} void enqueue(int); int dequeue(); bool isFull() { return ( (first==0 && last == size-1) || (first==last+1) ); } bool isEmpty(){return first==-1;} private: int first, last, size; int storage[4]; }; void Queue::enqueue(int e1) { if (! isFull()) { if (last == size -1 || last == -1) { storage[0] = e1; last = 0; if (first == -1) first = 0; } else { last++; storage[last] = e1; } else cout <<“Queue is full" << endl; } int Queue::dequeue() { int tmp; if (isEmpty()) { cout << "Queue is empty " << endl; return 0; } tmp = storage[first]; if (first==last) last = first = -1; else if (first==size-1) first = 0; else first++; return tmp; } See: example 1

Here is the same example with template template class Queue { public: Queue(){last = first = -1;} void enqueue(T); T dequeue(); bool isFull() { return ( (first==0 && last == size-1) || (first==last+1) ); } bool isEmpty(){return first==-1;} private: int first, last; T storage[size]; }; The default size is 100 if the size is not determined

Here is the same example with template See: example 2 template void Queue ::enqueue(T e1) { if (! isFull()) { if (last == size -1 || last == -1) { storage[0] = e1; last = 0; if (first == -1) first = 0; } else { last++; storage[last] = e1; } else cout << "Queue is full" << endl; } template T Queue ::dequeue() { T tmp; if (isEmpty()) { cout << "Queue is empty " << endl; return tmp; } tmp = storage[first]; if (first==last) last = first = -1; else if (first==size-1) first = 0; else first++; return tmp; }

Download ppt "More on Stacks and Queues. As we mentioned before, two common introductory Abstract Data Type (ADT) that worth studying are Stack and Queue Many problems."

Similar presentations