500 likes | 655 Views
Chapter 2. The stack. Stack and Queue. Stack : Last-In-First-Out ( LIFO ) Last-Come-First-Serve (LCFS) only one end Queue : First-In-First-Out ( FIFO ) First-Come-First-Serve (FCFS) 2 ends one for entering one for leaving.
E N D
Chapter 2 The stack
Stack and Queue Stack: Last-In-First-Out (LIFO) Last-Come-First-Serve (LCFS) only one end Queue: First-In-First-Out (FIFO) First-Come-First-Serve (FCFS) 2 ends one for entering one for leaving top Bottom of stack Stack
A motion picture of a stack Push(S, K) Push(S, G) Pop(S) Push(S, I) Pop(S) top (a) (b) (c) (d) (e) (f) (g) (h) (i) (j) (k) (l) (m) (n) (o)
Operations of a stack push(S, i): add item i into the top of stack S. i = pop(S): remove the top of stack S and assign its value to i. empty(S) : check whether a stack S is empty or not. underflow: pop or access an item from an empty stack. i=stacktop(S): return the top of stack S. can be written as: i = pop(S) Push(S, i)
Checking parentheses • Check whether the parantheses are nested correctly. 7 - ( ( X * ( ( X + Y ) / ( J – 3 ) ) + Y ) / ( 4 - 2.5 ) ) ** ( ( A + B ) ) A + B ( 檢查方法: **
Checking various parentheses . • Check whether one left parenthesis matches the corresponding right parenthesis {x + (y - [a+b]) * c – [(d+e)]} / (h-j) ** 檢查方法: **
Pseudo code for parenthesis (1) vaild = true;/* assume the string is valid */ s = the empty stack; while (we have not read the entire string) { read the next symbol (symb) of the string; if (symb == ’(’ || symb == ’[’ || symb == ’{’)// 左括號 push(s, symb); if (symb == ’)’ || symb == ’]’ || symb == ’}’)// 右括號 if (empty(s)) valid = false; else{ i = pop(s); if (i is not the matching opener of symb) valid = false;// 括號形狀不同 } /* end else */ } /* end while */
Pseudo code for parenthesis (2) if (!empty(s))// 最後須為空的 valid = false; if (valid) printf(”%s”, ”the string is valid”); else printf(”%s”, ”the string is invalid”);
Representing a stack as an abstract data type abstract typedef <<eltype>> STACK (eltype); abstract empty(s) STACK(eltype) s; postcondition empty == (len(s) == 0); abstract eltype pop(s) STACK(eltype) s,s’; precondition empty(s) == FALSE; postcondition pop == first(s); s’==s; s == sub(s’, 1, len(s’)-1); abstract push(s, elt) STACK(eltype) s,s’; eltype elt; postcondition s’=s; s == <elt> + s’;
Representing stacks with C • A stack is an order collection of items. #define STACKSIZE 100 struct stack { int top; int items[STACKSIZE]; }; struct stack s;
Different data types in a stack (1) #define STACKSIZE 100 #define INT 1 #define FLOAT 2 #define STRING 3 struct stackelement { int etype; /* etype equals INT, FLOAT, or STRING */ /* depending on the type of the */ /* corresponding element */ union{ int ival; float fval; char *pval; /* pointer to a string */ } element; }; struct stack { int top; struct stacklement items[STACKSIZE]; };
Different data types in a stack (2) struct stack s; struct stackelement se; ... se = s.items[s.top]; switch (se.etype) { case INT : printf(”%d \n”, se.element.ival); case FLOAT : printf(”%f \n”, se.element.fval); case STRING: printf(”%s \n”, se.element.pval); } /* end switch */
Individual functions are isolated into low-level modules. • int empty(struct stack *ps) • { • if (ps->top == -1) • return(TRUE); • else • return(FALSE); • } /* empty */ • How to call empty() in the calling program? • if (empty (&s)) • /* stack is empty */ • else • /* stack is not empty */ return (ps->top == -1) Modulization (1)
Modulization (2) • int pop(struct stack *ps) • { • if (empty(ps)){ • printf(”%s”, “stack underflow”); • exit(1); • } /* end if */ • return(ps->item[ps->top--]); • } /* end pop */ • How to call pop() in the calling program? • x = pop (&s);
Modulization (3) void popandtest(struct stack *ps, int *px, int *pund) • { // pop及測試是否underflow • if (empty(ps)){ • *pund = TRUE; • return; • } /* end if */ • *pund = FALSE; • *px = ps->items[ps->top--]; • return; • } /* end popandtest */ • calling program: • popandtest(&s, &x, &und); • if (und) • /* take corrective action */ • else • /* use value of x */
Push of a stack void push(struct stack *ps, int x){ ps->items[++(ps->top)] = x; return; } /* end push */ • overflow: put an item onto a full stack void push(struct stack *ps, int x) { if (ps->top == STACKSIZE-1){ printf(”%s”, ”stack overflow”); exit(1); } else ps->items[++(ps->top)] = x; return; } /* end push */
Pop of a stack int stacktop(struct stack *ps) { if (empty(ps)){ printf(”%s”, ”stack underflow”); exit(1); } else return(ps->items[ps->top]); } /*end stacktop */
Infix, postfix, prefix expressions • infix A+B /* A, B: operands, +: operator */ • postfix AB+ • (reverse Polish notation) • prefix +AB • (Polish notation) • Conversion from infix to postfix: • e.g. A + (B*C) infix(inorder) • A + (BC*) • A(BC*)+ • ABC * + postfix(postorder)
inorder traversal: 1. left subtree 2. root 3. right subtree preorder traversal: 1. root 2. left subtree 3. right subtree postorder traversal: 1. left subtree 2. right subtree 3. root Expression tree (1) + infix : A + (B*C) Prefix : + A * B C Postfix: A B C * + * A B C
Expression tree (2) e.g. (A+B) * C infix (AB+) * C (AB+)C * AB+C * postfix * infix : (A+B) * C prefix : * + A B C postfix: A B + C * + C A B
Expression tree (3) e.g. infix A$B*C-D+E/F/(G+H) /* $: exponentation, 次方 */ expression tree: + - / * / + D C E F G H $ A B postfix :prefix : **
precedence: (, ) > $ > *, / > +, - • left associative : A+B+C = (A+B)+C • right associative: A$B$C = A$(B$C) Evaluating a postfix expression e.g. 6 2 3 + - 3 8 2 / + * 2 $ 3 + infix form: ((6 - (2+3)) * (3 + 8/2)) $ 2 + 3 = 52 5 4 1 7 7 49 52
Evaluation with a stack symb opnd1 opnd2 value opndstk 6 6 2 6, 2 3 6, 2, 3 + 2 3 5 6, 5 - 6 5 1 1 3 6 5 1 1, 3 8 6 5 1 1, 3, 8 2 6 5 1 1, 3, 8, 2 / 8 2 4 1, 3, 4 + 3 4 7 1, 7 * 1 7 7 7 2 1 7 7 7, 2 $ 7 2 49 49 3 7 2 49 49, 3 + 49 3 52 52
Algorithm (演算法) ** opndstk = the empty stack; /* scan the input string reading one */ /* element at a time into symb */ while (not end of input){ symb = next input character; if (symb is an operand) push(opndstk, symb); else{ /* symb is an operator */ opnd2 = pop(opndstk); opnd1 = pop(opndstk); value = result of applying symb to opnd1 and opnd2; push (opndstk, value); } /* end else */ } /* end while */ return(pop(opndstk));
How to verify a postfix expression? ** 方法一: 方法二:
Evaluating a postfix expression with C #include <stdio.h> #include <stdlib.h> #include <math.h> #define MAXCOLS 80 #define TRUE 1 #define FALSE 0 double eval(char[]); double pop(struct stack *); void push(struct stack *,double); int empty(struct stack *); int isdigit(char); double oper(int, double, double);
void main() { char expr[MAXCOLS]; int position = 0; while ((expr[position++] = getchar()) != ’\n’); expr[--position] = ’\0’; printf (”%s%s”, ”the original postfix expression is”, expr); printf(”\n%f”, eval(expr)); } /* end main */ struct stack{ int top; double items[MAXCOLS]; };
double eval(char expr[]) { int c, position; double opnd1, opnd2, value; struct stack opndstk; opndstk.top = -1; for (position = 0; (c = expr[position]) != ’\0’; position++) if (isdigit(c)) /* operand– convert the character representation */ /* of the digit into double and push it onto */ /* the stack */ push(&opndstk, (double) (c - ’0’); else{ /* operator */ opnd2 = pop(&opndstk); opnd1 = pop(&opndstk); value = oper(c, opnd1, opnd2); push(&opndstk, value); } /*end else */ return(pop(&opndstk)); } /*end eval */
int isdigit(char symb) • { • return(symb >= ’0’ && symb <= ’9’); • } • double oper(int symb, double op1, double op2) • { • switch(symb){ • case ’+’ : return (op1 + op2); • case ’-’ : return (op1 – op2); • case ’*’ : return (op1 * op2); • case ’/’ : return (op1 / op2); • case ’$’ : return (pow(op1, op2)); // 計算次方 • default : printf(”%s”, ”illegal operation”); • exit(1); • } /* end switch */ • } /* end oper */ • 此程式無法處理 2-digit number 及 minus sign
e.g. A+B*C ABC*+ symb postfix string opstk 1 A A 2 + A + 3 B AB + 4 * AB + * 5 C ABC + * 6 ABC * + 7 ABC * + e.g. A*B+C AB*C+ Conversion from infix to postfix
e.g. ((A-(B+C))*D)$(E+F) ABC+-D*EF+$ symb postfix string opstk ( ( ( (( A A (( - A ((- ( A ((-( B AB ((-( + AB ((-(+ C ABC ((-(+ ) ABC+ ((- ) ABC+- ( * ABC+- (* D ABC+-D (* ) ABC+-D* $ ABC+-D* $ ( ABC+-D* $( E ABC+-D*E $( + ABC+-D*E $(+ F ABC+-D*EF $(+ ) ABC+-D*F+ $ ABC+-D*EF+$
Algorithm for conversion 1)遇 operand, 直接 output 2)遇 operator (a) 若此 operator 之 precedence 比 top of stack 高 ==> 此 operator 放入 stack. (b) 否則, 將所有比此 operator 之precedence 還 高之 operator 全 pop 並 output, 再將比 operator 放入 stack. ** 3) 4) 5)
C program for conversion #include <stdio.h> #include <stdlib.h> #define MAXCOLS 80 #define TRUE 1 #define FALSE 0 void postfix(char *, char *); int isoperand(char); void popandtest(struct stack *, char *, int *); int prcd(char, char); void push(struct stack *, char); char pop(struct stack *);
struct stack { int top; char items[MAXCOLS]; } postfix(char infix[], char postr[]) { int position, und; int outpos = 0; char topsymb = ’+’; char symb; struct stack opstk; opstk.top = -1; /* the empty stack */ for (position = 0; (symb = infix[position])!= ’\0’; position++) if (isoperand(symb)) postr[outpos++] = symb; else{ popandtest(&opstk, &topsymb, &und); while (!und && prcd(topsymb, symb)){ postr[outpos++] = topsymb; popandtest(&opsatk, &topsymb, &und); } /* end while */
if (!und) push(&opstk, topsymb); if (und || (symb != ’)’) ) push(&opstk, symb); else topsymb = pop(&opstk); } /* end else */ while (!empty(&opstk)) postr[outpos++] = pop(&opstk); postr[outpos] = ’\0’; return; } /* end postfix */
Evaluation and conversion evaluation algorithm 比 conversion algorithm容易, 因為conversion 必須考慮各種operator 之precedence, 而 evaluation 則在看到一個operator時, 即可計算 (沒有 precedence 問題) 如何檢查是否為 valid infix expression? **
Stacks in C++ using template template <class T> // T is a parameter // T is of ordinal type // undetermined type class Stack { private: int top; T *nodes; public: Stack(); // default constructor int empty(void); void push(T &); T pop(void); T pop(int &);// example of overloading pop // to handle the functions // of popandtest default ~Stack(); // destructor };
Constructor for stack template <class T> Stack<T>::Stack() { top = -1; nodes = new T[STACKSIZE]; }; • Destructor for stack template <class T> Stack<T>::~Stack() { delete nodes; }; Stack implementation with templates
template <class T> int Stack<T>::empty (void) { return top < 0; }; template <class T> void Stack<T>::push(T & j) { if (top == STACKSIZE){ cout << “Stack overflow” << endl; return; } nodes[++top] = j; }; template <class T> T Stack<T>::pop(void) { T p; if (empty()){ cout << “Stack underflow” << endl; return p; } p = nodes[top--]; return p; };
// The tasks of this function were formerly // performedby popandtest template <class T> T Stack<T>::pop(int & und) { T p; if (empty()){ und = 1; return p; } und = 0; p = nodes[top--]; return p; };
To make use of the stack, include all of the prototype definitions • // stackt.h • #ifndef STACKT_H • #define STACKT_H • #include <stdio.h> • #include <stdlib.h> • #include <alloc.h> • #include <mem.h> • #include <iostream.h> • #define STACKSIZE 100 • #endif
Evaluating infix expression with stack void postfix(char *infix, char *postr); int prcd(char op1, char op2); int isoperand(char op); int isoperator(char op); long double eval(char *postr); long double oper(int symb, long double op1, long double op2); int prcd(char op1, char op2) // body of prcd goes here int isoperator(char op) // body of isoperator goes here int isoperand(char op) // body of isoperand goes here
void postfix(char *infix, char *postr) { int position, und; int outpos = 0; char topsymb = ’+’; char symb; Stack<char> opstk; for (position = 0; (symb = infix[position])!= ’\0’; position++) { if (isoperand(symb)) postr[outpos++] = symb; else{ topsymb = opstk.pop(und); while (!und && prcd(topsymb, symb)){ postr[outpos++] = topsymb; topsymb = opstk.pop(und); }
if (!und) opstk.push(topsymb); if (und || (symb != ’)’) ) opstk.push(symb); else topsymb = opstk.pop(); } } /* end for */ while (!opstk.empty()) postr[outpos++] = opstk.pop(); postr[outpos] = ’\0’; } /* end postfix */
longdouble oper(int symb,longdouble op1,longdouble op2) // body of oper goes here longdouble eval(char *postr) { int c, position; long double opnd1, opnd2, value; Stack<long double> opndstk; for (position = 0; (c = postr[position]) != ’\0’; position++) if (isoperand(c)) opndstk.push((float) (c-’0’)); else{ opnd2 = opndstk.pop(); opnd1 = opndstk.pop(); value = oper(c, opnd1, opnd2); opndstk.push(value); } return (opndstk.pop()); } /* end eval */
void main(void) { char in[250], post[250]; long double res; cin >> in; cout << in << endl; postfix(in, post); res = eval(post); cout << res << endl; }