Stacks Objective n In this chapter we will
Stacks
Objective n In this chapter we will learn: q q Stacks Different implementations (arrays and linked list) of both Comparison of implementation Application of Stacks
Stack n A stack is a data structure that works on the principle of Last In First Out (LIFO). n So last item put on the stack is the first item that can be taken off, like a physical stack of books/plates. n In stack new elements are added to and removed from the top of the structure.
Two Implementations of Stack As Array Storing the items contiguously. n As List Storing items noncontiguously. n
Operations of Stack q q q Is. Empty: return true if stack is empty, return false otherwise Is. 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 Display. Stack: print all the data in the stack
Array Implementation n To use an array to implement a stack, you need both the array itself and an integer q The integer tells you either: n n n Which location is currently the top of the stack, or How many elements are in the stack for an empty stack, set To. S to -1
n n n Push q (1) Increment To. S by 1. q (2) Set Stack[To. S] = X Pop q (1) Set return value to Stack[To. S] q (2) Decrement To. S by 1 These operations are performed in very fast constant time
How stack works Empty stack push(5) push(7) tos=1 tos=0 tos= -1 5 pop() 7 5 tos=0 5
Create Stack n Create an empty stack by setting Top of the stack to -1 create. Stack() { TOS=-1; }
Push Stack n void Push(int x); q q q Push an element onto the stack If the stack is full, print the error information. Note top always represents the index of the top element. After pushing an element, increment top. Void push(int x) { if(is. Full()) printf(" Stack overflow"); else { TOS++; Stack[TOS]=x; } }
Pop Stack n int Pop() q q Pop and return the element at the top of the stack If the stack is empty, print the error information. Don’t forgot to decrement TOS pop() { if (is. Empty()) printf( "Stack Underflow"); else { return(Stack[TOS--]); } }
Stack Top n int Top(int Stack[]) q q Return the top element of the stack Unlike Pop, this function does not remove the top element int Top(int Stack[ ]) { if (is. Empty()) { printf("n Stack is empty"); return; } return Stack[TOS]; }
Printing all the elements n void Display. Stack() q Print all the elements Void display. Stack() { int i; printf("Top -->"); for(i=TOS; i>=0; i--) printf("t t%d n" , Stack[i]); }
Linked List Implementation n Advantage of the linked list : using only one pointer per item at a time. n Disadvantage of contiguous vector implementation : using excess space equal to the number of vacant array items.
Linked List Implementation of Stack n The stack class can be implemented as a linked list in which the top of the stack is represented by the first item in the list. top. Of. Stack
Linked List Implementation of Stack n Each stack item stores q q element value pointer to next element
Node Structure of the Stack typedef struct node{ int item; struct node *next; }Node; //Create Empty stack Node *Stack=NULL;
Push operation void Push(int x) { Node *top; top=(Node *)malloc(sizeof(Node)); top->item=x; if(Stack==NULL) {Stack=top; } else top->next=Stack; Stack=top; }
List Stack Example push(6); Stack top 6 void Push(int x) { Node *top; top=(Node *)malloc(sizeof(Node)); top->item=x; if(Stack==NULL) {Stack=top; } else top->next=Stack; Stack=top; }
List Stack Example push(6); push(1); Stac k 1 6
List Stack Example stack 7 1 6 push(6); push(1); push(7);
List Stack Example 8 stack 7 1 6 push(6); push(1); push(7); push(8);
Pop Stack //Pop from a stack int Pop(Node *Stack) {Node *temp; int i; if (Is. Empty(Stack)) printf("Stack empty"); else { temp=Stack; i=temp->item; Stack=Stack->next; free(temp); return i; } }
List Stack Example 8 stack 7 1 6 push(6); push(1); push(7); push(8); pop();
List Stack Example stack 7 1 6 push(6); push(1); push(7); push(8); pop();
Is. Empty - to Check whether the stack is empty int Is. Empty(Node *Stack) { if(Stack->next == NULL) return 1; }
Retrieve the Top element of the stack int Top(Node *S) { if (!Is. Empty(S)) return (S->item); printf("Empty stack"); return 0; }
List Stack Example 8 stack 7 1 push(6); push(1); push(7); push(8); Top() pop(); Top(); 6 Top element retrieved is 8 Top element retrieved is 7
Display the stack void display. Stack(Node *Stack) { Node *temp; temp=Stack; printf("Top--->"); while(temp!=NULL) { printf("tt%dn", temp->item); temp=temp->next; } }
Application of Stack n n Recognizing palindromes Checking balanced expressions Evaluating algebraic expressions is easier. Searching networks, traversing trees (keeping a track where we are).
Stack Applications Converting Decimal to Binary: Consider the following pseudocode n Read (number) 2) Loop (number > 0) 1) digit = number modulo 2 2) print (digit) 3) number = number / 2 // from Data Structures by Gilbert and Forouzan 1) The problem with this code is that it will print the binary number backwards. (ex: 19 becomes 11001000 instead of 00010011. ) To remedy this problem, instead of printing the digit right away, we can push it onto the stack. Then after the number is done being converted, we pop the digit out of the stack and print it.
Simple Applications of the ADT Stack: Checking for Balanced Braces n A stack can be used to verify whether a program contains balanced braces q An example of balanced braces abc{defg{ijk}{l{mn}}op}qr q An example of unbalanced braces abc{def}}{ghij{kl}m abc{def}{ghij{kl}m
Checking for Balanced Braces n Requirements for balanced braces q q Each time you encounter a “}”, it matches an already encountered “{” When you reach the end of the string, you have matched each “{”
Checking for Balanced Braces Figure 7 -3 Traces of the algorithm that checks for balanced braces
Infix, Postfix, & Prefix notation n n There is no reason we can’t place the operator somewhere else. How ? Infix notation : a + b Prefix notation : + a b Postfix notation: a b +
Why ? n Question: Why would anyone ever want to use anything so “unnatural, ” when infix seems to work just fine? n Answer: With postfix and prefix notations, parentheses are no longer needed!
Example infix postfix prefix (a + b) * c a b + c * * + a b c a + (b * c) a b c * + + a * b c Infix form : <identifier> <operator> <identifier> Postfix form : <identifier> <operator> Prefix form : <operator> <identifier>
Building an Arithmetic Expression Evaluator Infix and Postfix Expressions: Assume 1 -digit integer operands and the binary operators + - * / only Infix Expression Properties: Usual precedence and associativity of operators Parentheses used to subvert precedence Postfix Expression Properties: Both operands of binary operators precede operator Parentheses no longer needed Infix Expression 3*4+5 3*(4+5)/2 (3+4)/(5 -2) 7 -(2*3+5)*(8 -4/2) 3 -2+1 Equivalent Postfix Expression 34*5+ 345+*2/ 34+52 -/ 723*5+842/-*32 -1+
Infix to Postfix Expressions n How to convert an infix expression to a postfix expression? Use a stack. Read the infix expression from left-to-right. 1. 2. 3. 4. 5. When an operand (number) is read, output it. If an operator (other than ‘(‘, ‘)’) is read, pop the stack (and output the operator) until a lower precedence operator or ‘(‘ is on the top of stack. Then push the current operator on the stack. If ‘(‘ is read, push it on the stack. If a ‘)‘ is read, pop the stacks (and output the operators), until we meet ‘(’. Pop that ‘(’ (do no output it). Finally, if we read the end of the expression, pop the stack (and output the operators) until the stack is empty. 39 Applications of Stacks
Infix to Postfix Expressions n Example : (1+2*(5+1))*3 postfix expression 1 2 5 1 + * + 3 * Applications of Stacks 40
Infix to postfix conversion infix. Vect ( a + b - c ) * d – ( e + f ) postfix. Vect
Infix to postfix conversion stack. Vect infix. Vect a + b - c ) * d – ( e + f ) postfix. Vect (
Infix to postfix conversion stack. Vect infix. Vect + b - c ) * d – ( e + f ) postfix. Vect a (
Infix to postfix conversion stack. Vect infix. Vect b - c ) * d – ( e + f ) postfix. Vect a + (
Infix to postfix conversion stack. Vect infix. Vect - c ) * d – ( e + f ) postfix. Vect a b + (
Infix to postfix conversion stack. Vect infix. Vect c ) * d – ( e + f ) postfix. Vect a b + (
Infix to postfix conversion stack. Vect infix. Vect ) * d – ( e + f ) postfix. Vect a b + c (
Infix to postfix conversion stack. Vect infix. Vect * d – ( e + f ) postfix. Vect a b + c -
Infix to postfix conversion stack. Vect infix. Vect d – ( e + f ) postfix. Vect a b + c - *
Infix to postfix conversion stack. Vect infix. Vect – ( e + f ) postfix. Vect a b + c - d *
Infix to postfix conversion stack. Vect infix. Vect ( e + f ) postfix. Vect a b + c – d * -
Infix to postfix conversion stack. Vect infix. Vect e + f ) postfix. Vect a b + c – d * ( -
Infix to postfix conversion stack. Vect infix. Vect + f ) postfix. Vect a b + c – d * e ( -
Infix to postfix conversion stack. Vect infix. Vect f ) postfix. Vect + ( - a b + c – d * e
Infix to postfix conversion stack. Vect infix. Vect ) postfix. Vect + ( - a b + c – d * e f
Infix to postfix conversion stack. Vect infix. Vect postfix. Vect a b + c – d * e f + -
Infix to postfix conversion stack. Vect infix. Vect postfix. Vect a b + c – d * e f + -
Infix to Postfix ( ( ( A + B ) * ( C - E ) ) / ( F + G ) ) n n stack: <empty> output: []
Infix to Postfix ( ( A + B ) * ( C - E ) ) / ( F + G ) ) n n stack: ( output: []
Infix to Postfix ( A + B ) * ( C - E ) ) / ( F + G ) ) n n stack: ( ( output: []
Infix to Postfix A + B ) * ( C - E ) ) / ( F + G ) ) n n stack: ( ( ( output: []
Infix to Postfix + B ) * ( C - E ) ) / ( F + G ) ) n n stack: ( ( ( output: [A]
Infix to Postfix B ) * ( C - E ) ) / ( F + G ) ) n n stack: ( ( ( + output: [A]
Infix to Postfix ) * ( C - E ) ) / ( F + G ) ) n n stack: ( ( ( + output: [A B]
Infix to Postfix * ( C - E ) ) / ( F + G ) ) n n stack: ( ( output: [A B + ]
Infix to Postfix ( C - E ) ) / ( F + G ) ) n n stack: ( ( * output: [A B + ]
Infix to Postfix C - E ) ) / ( F + G ) ) n n stack: ( ( * ( output: [A B + ]
Infix to Postfix - E ) ) / ( F + G ) ) n n stack: ( ( * ( output: [A B + C ]
Infix to Postfix E ) ) / ( F + G ) ) n n stack: ( ( * ( output: [A B + C ]
Infix to Postfix ) ) / ( F + G ) ) n n stack: ( ( * ( output: [A B + C E ]
Infix to Postfix ) / ( F + G ) ) n n stack: ( ( * output: [A B + C E - ]
Infix to Postfix / ( F + G ) ) n n stack: ( output: [A B + C E - * ]
Infix to Postfix ( F + G ) ) n n stack: ( / output: [A B + C E - * ]
Infix to Postfix F + G ) ) n n stack: ( / ( output: [A B + C E - * ]
Infix to Postfix + G ) ) n n stack: ( / ( output: [A B + C E - * F ]
Infix to Postfix G ) ) n n stack: ( / ( + output: [A B + C E - * F ]
Infix to Postfix ) ) n n stack: ( / ( + output: [A B + C E - * F G ]
Infix to Postfix ) n n stack: ( / output: [A B + C E - * F G + ]
Infix to Postfix n n stack: <empty> output: [A B + C E - * F G + / ]
Transform postfix to infix: a)Push each operand in the stack until an operation is encountered. b)Pop two operands and wrap them around their operation. c) repeat until done. Transform Prefix to infix: Same as above, but we start parsing from right to left. Example: + B * C D
Evaluating Postfix Expressions n A postfix (reverse Polish logic) calculator q Requires you to enter postfix expressions n q When an operand is entered, the calculator n q Example: 2 3 4 + * Pushes it onto a stack When an operator is entered, the calculator n n n Applies it to the top two operands of the stack Pops the operands from the stack Pushes the result of the operation on the stack
Evaluating Postfix Expressions Figure 7 -8 The action of a postfix calculator when evaluating the expression 2 * (3 + 4)
Postfix Expression Evaluation for each character C in a given string { if C is an operand push C onto stack; else // C is an operator { pop item from stack, and store in Opr 2; pop item from stack, and store in Opr 1; result = Opr 1 C Opr 2, using C as an operator; push result onto stack; } }
Application of Stacks – Contd. .
Stack Activation Frames n the activation record contains the return address for this function call, and also the parameters, and local variables, and space for the function’s return value, if non-void n the activation record for a particular function call is popped off the run-time stack when the final closing brace in the function code is reached, or when a return statement is reached in the function code n at this time the function’s return value, if non -void, is brought back to the calling block return address for use there
- Slides: 85