230 likes | 240 Views
Explore what stacks are and how they work in programming. Learn about stack operations, applications, and algorithms for efficient coding.
E N D
What Are Stacks ? Overflow MAX PUSH POP 0 -1 Underflow Stacks
The Stack ADT stores arbitrary objects Insertions and deletions follow the last-in first-out scheme Think of a spring-loaded plate dispenser Main stack operations: push(object o): inserts element o pop(): removes and returns the last inserted element Auxiliary stack operations: getTop(): returns a reference to the last inserted element without removing it size(): returns the number of elements stored isEmpty(): returns a Boolean value indicating whether no elements are stored The Stack ADT Stacks
Applications of Stacks • Direct applications • Page-visited history in a Web browser • Undo sequence in a text editor • Saving local variables when one function calls another, and this one calls another, and so on. • Indirect applications • Auxiliary data structure for algorithms • Component of other data structures Stacks
A simple way of implementing the Stack ADT uses an array We add elements from left to right A variable keeps track of the index of the top element Array-based Stack Algorithmsize() returnt +1 Algorithmpop() ifisEmpty()then error(EmptyStack) else tt 1 returnS[t +1] … S 0 1 2 t Stacks
… S 0 1 2 t Array-based Stack (cont.) • The array storing the stack elements may become full • A push operation will then throw a FullStack Error condition • Limitation of the array-based implementation • Not intrinsic to the Stack ADT Algorithmpush(o) if(t=S.length 1)then error (FullStack) else tt +1 S[t] o Stacks
int main( ) { int n; double item; double numbers[n]; printf( " Type in an integer n followed by n decimal numbers.\n"); printf(" The numbers will be printed in reverse order.\n”); scanf(“%d”, &n); for (int i = 0; i < n; i++) { scanf(“%d, &item); push(item); } printf( “\n\n”); while (!empty( )) { printf( “%d ”, getTop( )); item = pop( ); } return 0; } Example: What does this code slice do? Stacks
Stack: Example const int MaxStack = 10;const char EmptyFlag = '\0'; int top; int items[MaxStack]; enum { FullStack = MaxStack, EmptyStack = -1 }; // better enum Err_code {FullStack ...} top = EmtyStack; bool push(int);int pop(); int getTop() bool empty(); bool full(); bool push(int x){ if (full()) return false; items[++top] = x; return true; } int pop(){ if (empty()) return EmptyFlag; return items[top--]; } intgetTop(){ if (empty()) return EmptyStack; return items[top]; } Stacks
Stack: Example bool full(){ if (top + 1 == FullStack) { printf( "Stack Full at %d \n“, MaxStack); return true; } return false; } bool empty(){ if (top == EmptyStack) { printf("Stack empty \n“); return true; } return false; } int main(void){ /* Define stack */ int s1 [ MaxStack ]; /* fill in here the necessary statements that use stack functions */ } Stacks
Exp: Prime Divisors of a Number • Read an integer and print all its prime divisors in descending order. • Note that the smallest divisor greater than 1 of any integer is guaranteed to be a prime • 2100/2 = 1050 + 0 • 1050/2 = 525 + 0 • 525/3 = 175 + 0 • 175/5 = 35 + 0 • 35/5 = 7 + 0 • 7/7= 1 + 0 • 7*5*5*3*2*2 = 2100 Stacks
Reverse Polish Calculator • ? Read an operand push it onto the stack • +,-,*,/ Arithmetic operations • = Print the top of the stack • Examples: • ?a?b+=Read and store a and b, calculate and store their sum, and then print the sum (a+b)= • ?a?b +?c?d+*= do (a+b)*(c+d) and print • ?a?b?c - = * ?d + = do (a*(b-c))+d and print: • Push a, b, c onto the stacks, • Replace the pair b,c by b-c and print its value, • Calculate a*(b-c), • Push d onto the stack. • Finally, calculate and print (a*(b - z)) + d. Stacks
Get command of calculator char get command( ) { char command; bool waiting = true; printf( "Select command and press < Enter > :“); while (waiting) { scanf(“%c”, &command); command = tolower(command); if (command == ‘?’ || command == ‘=’ || command == ‘+’ || command == ‘−’|| command == ‘*’|| command == ‘/’ || command == ‘q’) waiting = false; else { printf( "Please enter a valid command: \n" ); printf(“[?]push to stack [=]print top \n"); printf(“[+] [−] [*] [/] are arithmetic operations \n"); printf(“[Q]uit. \n"); } } return command; } Stacks
Adding and printing ?p?q+= bool do_command(char command) { double p, q; switch (command) { case ‘?’: printf(“Enter a number: "); flush(); scanf(“%d, &p); if (push(p) == false) printf(“Warning: Stack full, lost number \n"); break; case ‘=’: if ( (p = getTop()) == EmptyFlag) printf(“Stack empty \n”); else printf(“%d \n”, p); break; case ‘+’: if ((p = getTop()) == EmptyFlag) printf(“Stack empty \n”); else { p = pop( ); if ((q = getTop()) == EmptyFlag { printf(“Stack has just one entry\n”); push(p); } else { q = pop( ); if (push(q + p) == false) printf(“Warning: Stack full, lost result\n”); } } break; /* Add options for further user commands. */ case ‘q’: printf(“Calculation Finished.\n"; return false; } return true; } Stacks
Exp: Bracket checking int main( ) /* Post: Notice the use of any bracket mismatch in the standard input */ char symbol, match; bool is_matched = true; while (is_matched && (symbol = getchar( )) != “\n”) { if (symbol == ‘{‘ || symbol == ‘(‘ || symbol == ‘[‘) push(symbol); if (symbol == ‘}’ || symbol == ‘)’ || symbol == ‘]’) { if (empty( )) { printf("Unmatched closing bracket %c detected \n“); is_matched = false; } else { match = getTop(); match = pop( ); is_matched = (symbol == ‘}’ && match == ‘{‘) || (symbol == ‘)’ && match == ‘(‘) || (symbol == ‘]’ && match == ‘[‘); if (!is_matched) printf("Bad match %c %c \n“, match, symbol”); } } } if (! empty( )) printf("Unmatched opening bracket(s) detected.\n“); } Stacks
Performance and Limitations • Performance • Let n be the number of elements in the stack • The space used is O(n) • Each operation runs in time O(1) • Limitations • The maximum size of the stack must be defined a priori , and cannot be changed • Trying to push a new element into a full stack causes an implementation-specific exception Stacks
Computing Spans • Given an an array X, the span S[i] of X[i] is the maximum number of consecutive elements X[j] immediately preceding X[i] such that X[j] X[i] • Spans have applications to financial analysis • E.g., stock at 52-week high X S Stacks
Quadratic Algorithm Algorithmspans1(X, n) Inputarray X of n integers Outputarray S of spans of X # S new array of n integers n fori0ton 1do n s 1n while s i X[i - s]X[i]1 + 2 + …+ (n 1) ss+ 11 + 2 + …+ (n 1) S[i]sn returnS 1 Algorithm spans1 runs in O(n2) time Stacks
Computing Spans with a Stack • Keep in a stack the indices of the elements visible when “looking back” • Scan the array from left to right • Let i be the current index • Pop indices from the stack until finding index j such that X[i] X[j] • Set S[i]i - j • Push x onto the stack Stacks
Linear Algorithm • Each index of the array • Is pushed into the stack exactly once • Is popped from the stack at most once • The statements in the while-loop are executed at most n times • Algorithm spans2 runs in O(n) time Algorithmspans2(X, n)# S new array of n integers n A new empty stack 1 fori0ton 1do n while(A.isEmpty() X[top()]X[i] )do n jA.pop()n if A.isEmpty()thenn S[i] i +1 n else S[i]i - j n A.push(i) n returnS 1 Stacks
Growable Array-based Stack Algorithmpush(o) ift=S.length 1then A new array of size … fori0tot do A[i] S[i] S A tt +1 S[t] o • In a push operation, when the array is full, instead of throwing an exception, we can replace the array with a larger one • How large should the new array be? • incremental strategy: increase the size by a constant c • doubling strategy: double the size Stacks
Comparison of the Strategies • We compare the incremental strategy and the doubling strategy by analyzing the total time T(n) needed to perform a series of n push operations • We assume that we start with an empty stack represented by an array of size 1 • We call amortized time of a push operation the average time taken by a push over the series of operations, i.e., T(n)/n Stacks
Incremental Strategy Analysis • We replace the array k = n/c times • The total time T(n) of a series of n push operations is proportional to n + c + 2c + 3c + 4c + … + kc = n + c(1 + 2 + 3 + … + k) = n + ck(k + 1)/2 • Since c is a constant, T(n) is O(n +k2),i.e., O(n2) • The amortized time of a push operation is O(n) Stacks
geometric series 2 4 1 1 8 Doubling Strategy Analysis • We replace the array k = log2n times • The total time T(n) of a series of n push operations is proportional to n + 1 + 2 + 4 + 8 + …+ 2k= n+ 2k + 1-1 = 2n -1 • T(n) is O(n) • The amortized time of a push operation is O(1) Stacks