330 likes | 610 Views
Stacks. Ordered list with property: Insertions and deletions always occur at the same end. INSERT. DELETE. A3. A3. TOP. A2. A2. A2. TOP. TOP. A1. A1. A1. A0. A0. A0. Stacks Implementation. Implementation with arrays: Declare an array of size maxSize
E N D
Stacks Ordered list with property: Insertions and deletions always occur at the same end. INSERT DELETE A3 A3 TOP A2 A2 A2 TOP TOP A1 A1 A1 A0 A0 A0
Stacks Implementation Implementation with arrays: • Declare an array of size maxSize • Have a reference to the current top spot in the array. Private data members: KeyType *stack; // array of KeyType int maxSize; // max elements int top; // current top index
Linked Stacks • There are problems with implementing stacks on top of arrays • Sizing problems (bounds, clumsy resizing, …) • Given concepts of list nodes, can take advantage of to represent stacks. • Need to determine appropriate way of: • Representing top • Facilitating node addition and deletion at the top of the stack
HAT CAT MAT RAT TOP After 2nd Add TOP (Null initially) TOP After 3rd Add TOP After 4th Add TOP After 1st Delete Linked Stacks Add HAT Add CAT Add MAT Add RAT Delete
Linked Stacks • Need to represent StackNodes • Data element • Pointer to node beneath it in the stack • Need to represent Stack • Pointer to a StackNode top that indicates the top of the stack
Linked Stack Definition Class StackNode{ friend class Stack; public: StackNode(int d, StackNode * l); private: int data; StackNode *link; };
Linked Stack Definition class Stack { public: Stack(); void Add(const int); int* Delete(int&); bool isEmpty(); private: StackNode* top; }
Linked Stack Implementation Stack::Stack() { top = 0; } bool Stack::isEmpty() { return (top == 0); }
Linked Stack Implementation void Stack::Add(const int y) { // create a new node that contains data y // and points to the old top // assign top to point to the new node top = new StackNode(y, top); }
Linked Stack Implementation int * Stack::Delete(int & retValue) { // handle empty case if (isEmpty()) return 0; // return value, delete top element if not empty StackNode* toPop = top; retValue = toPop.data; top = toPop->link; delete toPop; return &retValue; }
Stack Examples Consider a railroad switching network as drawn below: 1 2 3 … N What are possible permutations of cars one could have using this system? Stack
Stack Examples Total possible permutations with n = 3 1,2,3 Add 1, Delete 1 Add 2, Delete 2 Add 3, Delete 3 1 2 3 2,3,1 Add 1, Add 2 Delete 2, Add 3 Add 3, Delete 1 1,3,2 Add 1, Delete 1 Add 2, Add 3 Delete 3, Delete 2 2,1,3 Add 1, Add 2 Delete 2, Delete 1 Add 3, Delete 3 3,2,1 Add 1, Add 2 Add 3, Delete 3 Delete 2, Delete 1 3,1,2 – Not possible Either one moves out first or two has to be on top of one
Stacks: Expression Evaluation Expression: Combination of operators and operands Evaluates to some value X = A/B – C + D * E – A * C Many different interpretations: A/(B-C) + D *E – A * C (A/B) – (C + D) * (E-A) * c A/(B-C+D*E) – (A*C) …
Expression Evaluation Defining order of operations provides the appropriate semantics for evaluating such an expression Equivalent level – go left to right X = A/B – C + D * E – A * C = ((((A/B) – C) + (D*E)) – (A*C))
Expression Evaluation How might a compiler ensure correct code? Converts infix notation to postfix notation: Infix: Operators appear between operands 3 + 5 * 4 Postfix: Operators appear after operands 3 5 4 * +
Expression Evaluation Infix: A / B – C + D * E – A * C Postfix: A B / C - D E * + A C * - Postfix Evaluation: T1 = A/B T1C-DE*+AC*- T2 = T1 – C T2DE*+AC*- T3 = D*E T2T3+AC*- T4 = T2+T3 T4AC*- T5 = A * C T4T5- T6 = T4-T5 T6
Expression Evaluation • Why use postfix? No need for parentheses Priority is no longer important (explicit in the ordering) Simple to evaluate using a stack, storing temporary values after computation
Expression Evaluation Evaluating postfix expressions: // Assume last token is # (a stop symbol), alternative implementations would also work void eval(expression e) { Stack<token> stack; // initialize stack for (token x = NextToken(e); x != ‘#’, x = NextToken(e)) { if (operand(x)) stack.Add(x); else { // x is an operation a = *stack.Delete(a); b = *stack.Delete(b); stack.Add(perform(operation, a, b)); } } }
Evaluating Expressions Postfix: A B / C - D E * + A C * - / - + * - * E C B C D T3 A T5 A A T1 T1 T2 T2 T2 T4 T4 T4 T6
Expression Evaluation How to translate between infix/postfix? Infix: Operators appear between operands 3 + 5 * 4 Postfix: Operators appear after operands 3 5 4 * +
Expression Evaluation Converting infix to postfix (conceptually): 1) Fully parenthesize the expression 2) Move all operators so they replace corresponding right parentheses 3) Delete all parentheses Operands remain in same order, so once we encounter one, we can print it directly out, need to determine when to print operators
Expression Evaluation Start State: Infix Notation Expression: A+B * C Fully Parenthesize by OrderOfOp: (A+(B*C)) Move Operators To Right Parentheses: (A(BC*+ Remove Parentheses: ABC*+ Evaluate: A B C * + => A T1 + => T2 (Answer)
Expression Evaluation Rule for what to unstack: Let operator priority be as in table to right Let in-stack priority of ‘(‘ be 8 Let incoming priority of ‘(‘ be 0 Operators are taken out of the stack as long as their in-stack priority is numerically less than or equal to the incoming priority of the new operator. Clears on end of tokens Clears up to left-parentheses on ) Forces onto stack when have (
Expression Evaluation A + B * C => A B C * + Next token Stack Output None Empty None A Empty A + + A B + AB Do we place * on top of stack or pop + off? * is higher priority so it goes on stack * +* AB C +* ABC No more tokens, output all operators off stack ABC*+
Expression Evaluation A*(B+C)*D => ABC+*D* Next token Stack Output None Empty None A Empty A * * A ( *( A B *( AB + *(+ AB C *(+ ABC // unstack to left parentheses ) * ABC+ * * ABC+* D * ABC+*D Done Empty ABC+*D*
Expression Evaluation void toPostfix(Expression e) { Stack<token> stack; token y; for (token x = NextToken(e); x!= ‘#”; x = NextToken(e)) { if (operand(x)) cout << operand; else if (x == ‘(‘) { stack.Add(x); } else if (x == ‘)’) { for (y = *stack.Delete(y); y != ‘(‘; y = *stack.Delete(y)) cout << y; } else { // x is an operator for (y = *stack.Delete(y); isp(y) <= icp(x); y = *stackDelete(y)) {cout << y;} stack.Add(y); stack.Add(x); } } while (!(stack.IsEmpty()) cout << *stack.Delete(y); }
Expression Evaluation Big O Analysis: Look at each operand at most once: O(1) Each operator is stacked/unstacked usually one time: [every once in a while more than that if it’s an operator that is checked as whether or not should remain on stack and it should]: O(1) N total operands: O(N)
Maze Search 0 1 0 0 0 1 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 0 1 1 1 0 1 1 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 1 1 1 1 0 1 1 0 1 1 0 0 1 1 0 1 0 0 1 0 1 1 1 1 1 1 1 0 0 1 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 1 0 1 1 1 0 1 0 0 1 0 1 0 1 1 1 1 0 0 1 1 1 1 1 1 1 1 0 0 1 1 0 1 1 0 1 1 1 1 1 0 1 1 1 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 0 0 1 0 0 1 1 1 1 1 0 1 1 1 1 0
Maze Search 0 1 0 0 0 1 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 0 1 1 1 0 1 1 0 0 0 0 1 1 1 1 0 0 1 1 1 1 0 1 1 1 1 0 1 1 0 1 1 0 0 1 1 0 1 0 0 1 0 1 1 1 1 1 1 1 0 0 1 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 1 0 1 1 1 0 1 0 0 1 0 1 0 1 1 1 1 0 0 1 1 1 1 1 1 1 1 0 0 1 1 0 1 1 0 1 1 1 1 1 0 1 1 1 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 0 0 1 0 0 1 1 1 1 1 0 1 1 1 1 0
Maze Search Maze has two dimensions: m rows, p columns Natural representation: 2-dimensional array maze[i][j] Can move in any of eight directions: -1 to +1 rows -1 to +1 cols
Maze Search Basic algorithmic idea: Maintain current successful path Pick one of 8 possible directions [start with East] If not open, select next direction [clockwise] Else, move in new direction When fail, return [backtrack] to last successful state which has directions left to try
Maze Search Implementation: Stack maintains current path: Add and delete new locations Maximum size needed for stack array? Longest possible path through maze = rows * columns Equivalent to recursion? 2,3,SW 1,3,S 1,2,E 1,1,E 0,0,SE
Maze Search Mark array: 2-D, same size as maze, Update visited locations with a 1 indicating unsuccessful so don’t repeatedly try a route that is known to fail.