Application of Stack (Backtracking) Think of a labyrinth or maze How do you find a way from an entrance to an exit? Once you reach a dead end, you must backtrack. But backtrack to where? to the previous choice point.
Application: Checking for Balanced Braces A stack can be used to verify whether a program contains balanced braces An example of balanced braces abc{defg{ijk}{l{mn}}op}qr An example of unbalanced braces abc{def}}{ghij{kl}m
Application: A Search Problem Beginning at the origin city, the algorithm will try every possible sequence of flights until either it finds a sequence that gets to the destination city. P is origin city; Z is destination city A Flight Map
Stacks BLG221E
Introduction to the Stack A stack is a data structure that stores and retrieves items in a last-in-first-out (LIFO) manner. 1st element of stack The first element that is pushed on a stack is the last one to be removed.
Stack Push Pop the operation to place a new item at the top of the stack the operation to remove the item from the top of the stack
Stack C R X A push(m) M C R X A item = pop() item = M C R X A Push: the operation to place a new item at the top of the stack Pop: the operation to remove the item from the top of the stack
Stack Operations Create an empty stack Destroy a stack push pop Determine whether a stack is empty Add a new item -- push top Remove the item that was added most recently -- pop Retrieve the item that was added most recently Stack
Applications of Stacks Computer systems use stacks during a program s execution to store function return addresses, local variables, etc. Some calculators use stacks for performing mathematical operations. The simplest application of a stack is to reverse a word. You push a given word to stack - letter by letter - and then pop letters from the stack. Another application is an "undo" mechanism in text editors; this operation is accomplished by keeping all text changes in a stack.
Application of Stack (Backtracking) Think of a labyrinth or maze How do you find a way from an entrance to an exit? Once you reach a dead end, you must backtrack. But backtrack to where? to the previous choice point. Therefore, at each choice point you store on a stack all possible choices. Then backtracking simply means popping a next choice from the stack.
Stack Computer systems use stacks during a program s execution to store function return addresses, local variables, etc. When a function is called, a frame containing local variables and return adress is pushed on the stack When a function returns, its frame is popped from the stack and control is passed to the method on top of the stack main() { int i = 5; foo(i); } foo(int j) { int k; k = j+1; bar(k); } bar(int m) { } bar m = 6 foo j = 5 k = 6 main i = 5 Run-time Stack
Example: Factorial function int fact(int n) { if (n == 0) return (1); else return (n * fact(n-1)); }
Tracing the call fact (N=3) When a function returns, its frame is popped from the stack and control is passed to the item on top of the stack N = 0 if (N==0) true return (1) N = 1 N = 1 if (N==0) false if (N==0) false N = 3 if (N==0) false return (3*fact(2)) After original call N = 2 if (N==0) false return (2*fact(1)) N = 3 if (N==0) false return (3*fact(2)) After 1 st call return (1*fact(0)) N = 2 if (N==0) false return (2*fact(1)) N = 3 if (N==0) false return (3*fact(2)) After 2 nd call return (1*fact(0)) N = 2 if (N==0) false return (2*fact(1)) N = 3 if (N==0) false return (3*fact(2)) After 3rd call
Tracing the call fact (3) When a function returns, its frame is popped from the stack and control is passed to the item on top of the stack N = 1 if (N==0) false return (1* 1) N = 2 if (N==0) false return (2*fact(1)) N = 2 if (N==0) false return (2* 1) N = 3 N = 3 N = 3 if (N==0) false if (N==0) false if (N==0) false return (3*fact(2)) After return from 3rd call return (3*fact(2)) After return from 2nd call return (3* 2) After return from 1st call return 6
Application: Checking for Balanced Braces A stack can be used to verify whether a program contains balanced braces An example of balanced braces abc{defg{ijk}{l{mn}}op}qr An example of unbalanced braces abc{def}}{ghij{kl}m When the algortihm encounters open braces push operation is implemented. Otherwise pop operation is implemented.
Application: A Search Problem Beginning at the origin city, the algorithm will try every possible sequence of flights until either it finds a sequence that gets to the destination city. P is origin city; Z is destination city A Flight Map
Calculating Arithmetic Expression Evaluation of arithmetic expressions ((A/(B*C))+(D*E))-(A*C) operands: A,B,C,D,E operators: /, *, +,-, * Each operation has a certain precedence. The use of parentheses affects the result. Using parentheses, different results could be obtained.
Application: Algebraic Expressions To evaluate an infix expression Convert the infix expression to postfix form Evaluate the postfix expression Infix Expression Postfix Expression 5 + 2 * 3 5 2 3 * + 5 * 2 + 3 5 2 * 3 + 5 * ( 2 + 3 ) - 4 5 2 3 + * 4 - While generating code, compilers first convert the given expression to a representation called postfix. This postfix expression is then processed using the stack structure. In this representation (postfix), the operands are written before the operators (A B +).
Calculating Postfix Expression Infix: (3 + 2) * 10 Postfix: 3 2 + 10 * Scan the postfix expression from left to right : 1) If an operand found, then push it into stack. 2) If an operator found, pop two operands from the stack. 3) Perform the arithmetic operator, then push the result into the stack.
If an operand found push it into stack Postfix expression: If an operator found, pop two operands from the stack. 3 2 + 10 * Empty stack 5 4 3 2 1 0
If an operand found push it into stack Postfix expression: If an operator found, pop two operands from the stack. 3 2 + 10 * Stack Push(3) 5 4 3 2 1 0 3
If an operand found push it into stack Postfix expression: If an operator found, pop two operands from the stack. 3 2 + 10 * Stack Push(2) 5 4 3 2 1 2 0 3
If an operand found push it into stack Postfix expression: If an operator found, pop two operands from the stack. 3 2 + 10 * Stack + operator found. Pop two operands from stack. 5 4 3 2 1 2 0 3
If an operand found push it into stack Postfix expression: If an operator found, pop two operands from the stack. 3 2 + 10 * 5 4 3 Stack 2 1 2 poped 0 3 poped
If an operand found push it into stack Postfix expression: 3 2 + 10 * Stack If an operator found, pop two operands from the stack. Perform the arithmetic operator, then push the result into the stack. Push the result of + operator into stack. 5 4 3 2 1 2+3 = 5 0 5 Push(5)
If an operand found push it into stack Postfix expression: 3 2 + 10 * Stack If an operator found, pop two operands from the stack. Perform the arithmetic operator, then push the result into the stack. Push(10) 5 4 3 2 1 10 0 5
If an operand found push it into stack Postfix expression: 3 2 + 10 * Stack If an operator found, pop two operands from the stack. Perform the arithmetic operator, then push the result into the stack. * operator found. Pop two operands from stack. 5 4 3 2 1 10 0 5
If an operand found push it into stack Postfix expression: 3 2 + 10 * Stack If an operator found, pop two operands from the stack. Perform the arithmetic operator, then push the result into the stack. 5 4 3 2 1 10 poped 0 5 poped
If an operand found push it into stack Postfix expression: 3 2 + 10 * Stack If an operator found, pop two operands from the stack. Perform the arithmetic operator, then push the result into the stack. Push the result of * operator into stack. 5 4 3 2 1 10*5= 50 0 50 Push(50)
Postfix expression: 3 2 + 10 * Stack End of expression. Pop the final result from stack. 5 4 3 2 1 0 50 poped
Static and Dynamic Stacks Static Stacks Fixed size Can be implemented with an array Dynamic Stacks Grow in size as needed Can be implemented with a linked list
Array implementation of stacks To implement a stack, items are inserted and removed at the same end (called the top). To use an array to implement as a stack, you need both the array itself and an integer variable. The integer tells you either: Which location is currently the top of the stack, or How many elements are in the stack
Array implementation of stacks stk: 0 1 2 3 4 5 6 7 8 9 17 23 97 44 top = 3 or count=4 The bottom of the stack is at location top=0, count =1 Empty stack is represented by top = -1 or count = 0 stk: 0 1 2 3 4 5 6 7 8 9 top = -1 or count=0
Pushing 0 1 2 3 4 5 6 7 8 9 stk: 17 23 97 44 To add (push) an element: top = 3 or count=4 Increment top and store the element in stk[top] stk: 0 1 2 3 4 5 6 7 8 9 17 23 97 44 21 top = 4 or count=5
Popping stk: 0 1 2 3 4 5 6 7 8 9 17 23 97 44 To remove (pop) an element: top = 3 or count=4 Get the element from stk[top] and decrement [top] stk: 0 1 2 3 4 5 6 7 8 9 17 23 97 44 top = 2 or count = 3
After popping stk: 0 1 2 3 4 5 6 7 8 9 17 23 97 44 top = 2 or count = 3 When you pop an element, do you leave the deleted element sitting in the array? The surprising answer is, it depends If this is an array of primitives, or if you are programming in C or C++, then doing anything more is just a waste of time If you are programming in Java, and the array contains objects, you should set the deleted array element to null Why? To allow it to be garbage collected!
Stack definition #define SIZE 50 int stk[size]; int top=-1; void init_stack() { // Empty stack is represented by top = -1 } top=-1;
Push and Pop operations void push( int n ) { if( top==size-1) printf("\nstack is full"); else stk[++top]= n; } int pop( ) { if(top== -1) { printf("\nstack is empty"); return -1; } else return stk[top--]; }
Display all elements of stack void display( ) { int i; if(top== -1) printf("\nstack is empty."); else { printf("\nelements are : \n"); for(i=0; i<=top; i++) printf("%5d ",stk[i]); } }
Check int isempty( ) { if ( top== -1 ) return 1; else return 0; } int peek( ) { return stk[top]; }
Array implementation of stacks #include<stdio.h> #include<conio.h> #include <stdlib.h> #define SIZE 50 int stack[size]; int top; void init_stack() { top=-1; } void push( int n ) { if( top==size-1) printf("\nstack is full"); else stack[++top]= n; } int pop( ) { if(top== -1) { printf("\nstack is empty"); return -1; } else return stack[top--]; } void display( ) { int i; if(top== -1) printf("\nstack is empty."); else { printf("\nelements are : \n"); for(i=0;i<=top;i++) printf("%5d ",stack[i]); } } int isempty( ) { if ( top== -1 ) return 1; else return 0; } int peek( ){ return stack[top]; }
Array implementation of stacks(cont.) switch(choice) { case 1:printf("\nEnter the element to push : "); int main() { scanf("%d",&item); int choice,item; push(item); break; init_stack(); case 2:item = pop(); printf("\nelement poped : %d",item); do printf("\npress a key to continue..."); { getche(); break; printf("\n\tmenu\n\t1.push.\n\t2.pop."); case 3:item = peek(); printf("\nelement at top : %d",item); printf("\n\t3.peek.\n\t4.display.\n\t5.exit.\n"); printf("\npress a key to continue..."); printf("\nyour Choice: "); getche(); break; scanf("%d",&choice); case 4:display(); printf("\npress a key to continue..."); getche(); break; case 5:exit(0); } } while(1); } // end of main
Sharing space Of course, the bottom of the stack could be at the other end stk: 0 1 2 3 4 5 6 7 8 9 44 97 23 17 top = 6 or count = 4 Sometimes this is done to allow two stacks to share the same storage area stks: 0 1 2 3 4 5 6 7 8 9 49 57 3 44 97 23 17 topstk1 = 2 topstk2 = 6
Dynamic Stacks Grow in size as needed Can be implemented with a linked list Bottom of stack Top of stack
Empty stack head
Push(50) head 50
Push(30) head Bottom of stack 30 50
Push(70) head Bottom of stack 70 30 50
Pop() head 70 poped Bottom of stack 30 50
Pop() head 30 poped 50
Pop() head 50 poped
Stack definition struct s_node { int data; struct s_node *link; } *stack=null; stack
Push operation //Pushing element in to stack void push(int j) { struct s_node *m; m=new struct s_node ; m->data= j ; m->link=stack; stack=m; return; } Top of stack Bottom of stack Stack Pointer a b c stack = m; m->link = stack; m=new struct s_node ;
Pop operations //Popping element from stack int pop( ) { struct s_node *temp=null; if(stack==null) { printf("\nstack is Empty."); getch(); } else { int i=stack->data; temp = stack ; stack=stack->link; delete temp; return (i); } } Top of stack
Display all elements of stack //Displaying Stack void display() { struct s_node *temp=stack; while(temp!=null) { printf("%d\t", temp->data); temp=temp->link; } }
Linked List implementation of stacks #include<stdio.h> #include<conio.h> #include <stdlib.h> struct s_node { int data; struct s_node *link; } *stack=null; //Pushing element in to stack void push(int j) { struct s_node *m; m=new struct s_node ; m->data= j ; m->link=stack; stack=m; return; } //Popping element from stack int pop( ) { struct s_node *temp=null; if(stack==null) { printf("\nstack is Empty."); getch(); } else { int i=stack->data; temp = stack ; stack=stack->link; delete temp; return (i); } } //Displaying Stack void display() { struct s_node *temp=stack; while(temp!=null) { printf("%d\t",temp->data); temp=temp->link; } } //Calling in main() int main() { int choice,num,i; while(1) { printf("\n\t MENU\n1. Push\n2. Pop\n"); printf("\n3. Elements in Stack\n4. Exit\n"); } } printf("\n\tenter your choice: "); scanf("%d",&choice); switch(choice) { case 1: printf("\nelement to be pushed:"); scanf("%d",&num); push(num); break; case 2: num=pop(); printf("\nelement popped: %d ",num); getch(); break; case 3: printf("\nelements present in stack : " ); display();getch(); break; case 4: exit(1); default: printf("\ninvalid Choice\n"); break; }