Stacks The unorganized persons data structure stacks 1

  • Slides: 34
Download presentation
Stacks The unorganized person’s data structure stacks 1

Stacks The unorganized person’s data structure stacks 1

Stack characteristics • Entries are ordered in terms of access -both insertion and removal

Stack characteristics • Entries are ordered in terms of access -both insertion and removal take place at same spot (top of stack) • Specialized type of container class; defining characteristic is insertion/removal order • LIFO = last in, first out; entries are removed in reverse order of insertion stacks 2

Stack operations • Push -- insert item on stack • Pop -- remove item

Stack operations • Push -- insert item on stack • Pop -- remove item from stack • Peek -- examine, but don’t remove item stacks 3

Stack operations • Important to know if stack is empty -attempt to remove an

Stack operations • Important to know if stack is empty -attempt to remove an item from an empty stack is an underflow error • Depending on implementation, may be necessary to check if stack is full -- attempt to add item to a full stack is an overflow error stacks 4

Implementation of Stack ADT • Stacks can be array based (static or dynamic) or

Implementation of Stack ADT • Stacks can be array based (static or dynamic) or linked list based • Invariant for static array implementation: – The number of items stored in the stack is found in member variable used – Items are stored in member variable data, a static array with the stack bottom at data[0] and the stack top at data[used - 1] stacks 5

Stack class -- static array version template <class Item> class Stack { public: enum

Stack class -- static array version template <class Item> class Stack { public: enum {CAPACITY = 64}; Stack ( ); // default constructor Item pop ( ); // removes top Item peek ( ) const; // reveals top Item. . . stacks 6

Stack ADT continued void push (const Item & entry); // adds Item to stack

Stack ADT continued void push (const Item & entry); // adds Item to stack size_t size ( ) const {return used; } bool is_empty ( ) const {return used == 0; } private: Item data[CAPACITY]; // the stack itself size_t used; // # of items stored in stack }; stacks 7

Stack function implementations: constructor // Postcondition: empty stack is created template <class Item> Stack<Item>:

Stack function implementations: constructor // Postcondition: empty stack is created template <class Item> Stack<Item>: : Stack( ) { used = 0; } stacks 8

Pop function // Precondition: stack is not empty // Postcondition: top item is removed

Pop function // Precondition: stack is not empty // Postcondition: top item is removed template <class Item> Item Stack<Item>: : pop ( ) { assert (!is_empty( )); used--; return data[used]; } stacks 9

Peek function // Precondition: stack is not empty // Postcondition: top item is revealed

Peek function // Precondition: stack is not empty // Postcondition: top item is revealed template <class Item> Item Stack<Item>: : peek ( ) const { assert (!is_empty( )); return data[used - 1]; } stacks 10

Push function // Precondition: stack is not full // Postcondition: an item is inserted

Push function // Precondition: stack is not full // Postcondition: an item is inserted on stack template <class Item> void Stack<Item>: : push(const Item& entry) { assert (size() < CAPACITY); data[used] = entry; used++; stacks } 11

Stack application examples • Compilers use stacks for a variety of purposes: – syntax

Stack application examples • Compilers use stacks for a variety of purposes: – syntax analysis: matching brackets, parentheses, etc. – activation records: structures associated with functions, keeping track of local variables, return address, etc. stacks 12

Example application: balanced parentheses • Pseudocode algorithm: – scan string left to right –

Example application: balanced parentheses • Pseudocode algorithm: – scan string left to right – if ‘(‘ is encountered, push on stack – if ‘)’ is encountered, and stack is not empty, pop one ‘(‘ -- if stack is empty, expression is unbalanced – if stack is empty when entire string has been scanned analyzed, expression is balanced stacks 13

A program to test for balanced parentheses int main( ) { String user_input; //

A program to test for balanced parentheses int main( ) { String user_input; // uses String data type defined in ch. 4 - based on array cout << "Type a string with some parentheses and no white space: n"; cin >> user_input; if (balanced_parentheses(user_input)) cout << "Those parentheses are balanced. n"; else cout << "Those parentheses are not balanced. n"; cout << "That ends this balancing act. n"; return EXIT_SUCCESS; } stacks 14

balanced_parentheses function bool balanced_parentheses(const String& expression) // Library facilities used: assert. h, stack 1.

balanced_parentheses function bool balanced_parentheses(const String& expression) // Library facilities used: assert. h, stack 1. h, stdlib. h, mystring. h. { // Meaningful names for constants const char LEFT_PARENTHESIS = '('; const char RIGHT_PARENTHESIS = ')'; Stack<char> store; size_t i; char next; char discard; bool failed = false; . . . // Stack to store the left parentheses as they occur // An index into the String // The next character from the String // A char popped off the stack and thrown away // Becomes true if a needed parenthesis is not found stacks 15

balanced_parentheses continued for (i = 0; !failed && (i < expression. length( )); i++)

balanced_parentheses continued for (i = 0; !failed && (i < expression. length( )); i++) { next = expression[i]; if (next == LEFT_PARENTHESIS) { if (store. size( ) < store. CAPACITY); store. push(next); } else if ((next == RIGHT_PARENTHESIS) && (!store. is_empty( ))) discard = store. pop( ); else if ((next == RIGHT_PARENTHESIS) && (store. is_empty( ))) failed = true; } return (store. is_empty( ) && !failed); } stacks 16

Stack ADT as linked list • Can make use of toolkit functions to simplify

Stack ADT as linked list • Can make use of toolkit functions to simplify task • Stack can grow & shrink as needed to accommodate data -- no fixed size • Invariant: – stack items are stored in a linked list – member variable top is head pointer to list stacks 17

Class definition for new Stack template <class Item> class Stack { public: Stack( )

Class definition for new Stack template <class Item> class Stack { public: Stack( ) { top = NULL; } Stack(const Stack& source); ~Stack( ) { list_clear(top); } stacks. . . 18

Stack definition continued void push(const Item& entry); Item pop( ); void operator =(const Stack&

Stack definition continued void push(const Item& entry); Item pop( ); void operator =(const Stack& source); size_t size( ) const {return list_length(top); } bool is_empty( ) const {return top == NULL; } Item peek( ) const; private: Node<Item> *top; // Points to top of stacks 19 };

Push function template <class Item> void Stack<Item>: : push(const Item& entry) { list_head_insert(top, entry);

Push function template <class Item> void Stack<Item>: : push(const Item& entry) { list_head_insert(top, entry); } stacks 20

Pop function template <class Item> Item Stack<Item>: : pop( ) { assert(!is_empty( )); Item

Pop function template <class Item> Item Stack<Item>: : pop( ) { assert(!is_empty( )); Item answer = top->data; list_head_remove(top); return answer; } stacks 21

Peek function template <class Item> Item Stack<Item>: : peek( ) const { assert(!is_empty( ));

Peek function template <class Item> Item Stack<Item>: : peek( ) const { assert(!is_empty( )); return top->data; } stacks 22

Copy constructor template <class Item> Stack<Item>: : Stack(const Stack<Item>& source) { list_copy(source. top, top);

Copy constructor template <class Item> Stack<Item>: : Stack(const Stack<Item>& source) { list_copy(source. top, top); } stacks 23

Assignment operator template <class Item> void Stack<Item>: : operator =(const Stack<Item>& source) { if

Assignment operator template <class Item> void Stack<Item>: : operator =(const Stack<Item>& source) { if (source. top== top) // Handle self-assignment return; list_clear(top); list_copy(source. top, top); } stacks 24

A stack-based calculator • Input to program is a fully-parenthesized expression -- examples: ((5.

A stack-based calculator • Input to program is a fully-parenthesized expression -- examples: ((5. 3 * 1. 2) / 3. 1) (4 - 3) • Two stacks are used -- one for operators, one for operands • Right parenthesis is signal to pop the stacks and evaluate the expression stacks 25

Algorithm for expression evaluation • Evaluate leftmost, innermost expression; continue evaluating, left to right

Algorithm for expression evaluation • Evaluate leftmost, innermost expression; continue evaluating, left to right – Read each part of expression – Push numbers on operand stack, operators on operator stack – When right parenthesis is encountered, pop the stacks, evaluate, and push result on operand stacks 26

Code for stack calculator int main( ) { double answer; cout << "Type a

Code for stack calculator int main( ) { double answer; cout << "Type a fully parenthesized arithmetic expression: " << endl; answer = read_and_evaluate(cin); cout << "That evaluates to " << answer << endl; return EXIT_SUCCESS; } stacks 27

Code for stack calculator double read_and_evaluate(istream& ins) { const char DECIMAL = '. ';

Code for stack calculator double read_and_evaluate(istream& ins) { const char DECIMAL = '. '; const char RIGHT_PARENTHESIS = ')'; Stack<double> numbers; Stack<char> operations; double number; char symbol; . . . stacks 28

Code for stack calculator while (!ins. eof( ) && ins. peek( ) != 'n')

Code for stack calculator while (!ins. eof( ) && ins. peek( ) != 'n') { if (isdigit(ins. peek( )) || (ins. peek( ) == DECIMAL)) { ins >> number; numbers. push(number); } … stacks 29

Code for stack calculator else if (strchr("+-*/", ins. peek( )) != NULL) { ins

Code for stack calculator else if (strchr("+-*/", ins. peek( )) != NULL) { ins >> symbol; operations. push(symbol); } stacks 30

Code for stack calculator else if (ins. peek( ) == RIGHT_PARENTHESIS) { cin. ignore(

Code for stack calculator else if (ins. peek( ) == RIGHT_PARENTHESIS) { cin. ignore( ); evaluate_stack_tops(numbers, operations); } else cin. ignore( ); } // end of while loop return numbers. pop( ); } stacks 31

Code for stack calculator void evaluate_stack_tops(Stack<double>& numbers, Stack<char>& operations) { double operand 1, operand

Code for stack calculator void evaluate_stack_tops(Stack<double>& numbers, Stack<char>& operations) { double operand 1, operand 2; operand 2 = numbers. pop( ); operand 1 = numbers. pop( ); . . . stacks 32

Code for stack calculator switch (operations. pop( )) { case '+': numbers. push(operand 1

Code for stack calculator switch (operations. pop( )) { case '+': numbers. push(operand 1 + operand 2); break; case '-': numbers. push(operand 1 - operand 2); break; stacks. . . 33

Code for stack calculator case '*': numbers. push(operand 1 * operand 2); break; case

Code for stack calculator case '*': numbers. push(operand 1 * operand 2); break; case '/': numbers. push(operand 1 / operand 2); break; } // end switch statement } // end function stacks 34