560 likes | 733 Views
Stacks. (Walls & Mirrors - Chapter 6). Overview. The ADT Stack Array Implementation of a Stack Linked-List Implementation of a Stack Application Domain: Algebraic Expressions Application Domain: Search. IN. OUT. The ADT Stack.
E N D
Stacks (Walls & Mirrors - Chapter 6)
Overview • The ADT Stack • Array Implementation of a Stack • Linked-List Implementation of a Stack • Application Domain: Algebraic Expressions • Application Domain: Search
IN OUT The ADT Stack • A stack is a linear list, for which all insertions and deletions occur at one end of the list. Stacks exhibit a Last In First Out (LIFO) property. • This is like a cafeteria tray (or plate) dispenser.
The ADT Stack (Cont’d.) Recall, that an abstract data type(ADT) is a type of data, defined by the programmer, where the implementation details are hidden from the user, and access to the data is provided through an interface to a specific set of operations.
The ADT Stack (Cont’d.) • For an ADT stack, these operations include: • Create an empty stack • Destroy a stack • Determine whether a stack is empty • Add a new item to the stack • Remove the item added most recently • Retrieve a copy of the item added most recently • As long as these operations are supported, you don’t need to be concerned with whether the stack is implemented as an array, a linked list, or something else.
ADT Stack: Public Member Functions Stack( ); is the default constructor, which creates a new, empty stack. Stack( const Stack &oStack ); is the copy constructor, which makes a copy of oStack. ~Stack( ); is the destructor, which destroys a stack. bool isEmpty( ) const; returns true if the stack is empty, otherwise returns false.
ADT Stack: Public Member Functions bool push( StackItemType newItem ); adds newItem to the top of a stack. Returns true if push succeeds, otherwise returns false. bool pop( ); removes the item at the top of a stack. Returns true if pop succeeds, otherwise returns false. bool pop( StackItemType &stackTop ); removes the item at the top of a stack and returns it in stackTop. Returns true if pop succeeds, otherwise returns false.
ADT Stack: Public Member Functions bool getTop( StackItemType &stackTop ) const; retrieves a copy of the item at the top of a stack, leaving the stack unchanged. Returns true if getTop succeeds, otherwise returns false.
ADT Stack: Array Implementation const int MAX_STACK = 20; // maximum Stack size typedef int StackItemType; // items in Stack are int’s class Stack { public: // declarations of public member functions private: StackItemType items[MAX_STACK]; // array of Stack items int top; // index to top of Stack };
ADT Stack: Member Function Definitions Stack::Stack( ) : top( -1 ) { } // default constructor, which // creates a new Stack and // initializes top to -1 Stack::Stack( const Stack &oStack ) // copy constructor, : top( oStack.top ) // which copies oStack { // to a new Stack for( int i = 0; i <= oStack.top; i++ ) items[i] = oStack.items[i]; }
ADT Stack: Member Function Definitions // destructor Stack::~Stack( ) { } // returns true if Stack is empty, otherwise returns false bool Stack::isEmpty( ) const { return top < 0; }
ADT Stack: Member Function Definitions // adds newItem to the top of a Stack. Returns true if // add succeeds, otherwise returns false. bool Stack::push( StackItemType newItem ) { if( top >= MAX_STACK - 1 ) return false; items[ ++top ] = newItem; return true; }
ADT Stack: Member Function Definitions // removes the item at the top of a Stack. Returns true if // removal succeeds, otherwise returns false. bool Stack::pop( ) { if( isEmpty( ) ) return false; top--; return true; }
ADT Stack: Member Function Definitions // removes the item at the top of a Stack and returns it in // stackTop. Returns true if removal succeeds, otherwise // returns false. bool Stack::pop( StackItemType &stackTop ) { if( isEmpty( ) ) return false; stackTop = items[top]; top--; return true; }
ADT Stack: Member Function Definitions // retrieves a copy of the item at the top of a Stack and returns // it in stackTop. Returns true if retrieval succeeds // otherwise returns false. bool Stack::getTop( StackItemType &stackTop ) const { if( isEmpty( ) ) return false; stackTop = items[top]; return true; }
ADT Stack: Linked-List Implementation typedef int StackItemType; // items in Stack are int’s class Stack { public: // declarations of public member functions - same as for array! private: struct StackNode // linked-list of items in Stack { StackItemType item; StackNode *next; }; StackNode *topPtr; // pointer to top of Stack };
ADT Stack: Member Function Definitions // default constructor, which creates a new Stack and // initializes topPtr to NULL Stack::Stack( ) : topPtr( NULL ) { }
ADT Stack: Member Function Definitions Stack::Stack( const Stack &oStack ) // copy constructor, { // which copies oStack if( oStack.topPtr = = NULL ) // to a new Stack topPtr = NULL; else { // copy top of Stack topPtr = new StackNode; // assert is true if assert( topPtr != NULL ); // allocation succeeds topPtr -> item = oStack.topPtr -> item; // copy rest of Stack } }
ADT Stack: Member Function Definitions // copy rest of Stack StackNode *pnew = topPtr; for( StackNode *porig = oStack.topPtr -> next; porig != NULL; porig = porig -> next ) { pnew -> next = new StackNode; assert( pnew -> next != NULL ); // assert is true if pnew = pnew -> next; // allocation succeeds pnew -> item = porig -> item; } pnew -> next = NULL;
ADT Stack: Member Function Definitions // destructor pops Stack until empty Stack::~Stack( ) { while( pop( ) ); } // returns true if Stack is empty, otherwise returns false bool Stack::isEmpty( ) const { return topPtr = = NULL; }
ADT Stack: Member Function Definitions // adds newItem to the top of a Stack. Returns true if // add succeeds, otherwise returns false. bool Stack::push( StackItemType newItem ) { StackNode *pnode = new StackNode; if( pnode = = NULL ) return false; pnode -> item = newItem; pnode -> next = topPtr; topPtr = pnode; return true; }
ADT Stack: Member Function Definitions // removes the item at the top of a Stack. Returns true if // removal succeeds, otherwise returns false. bool Stack::pop( ) { if( isEmpty( ) ) return false; StackNode *pnode = topPtr; topPtr = topPtr -> next; pnode -> next = NULL; delete pnode; // removed node is deallocated return true; }
ADT Stack: Member Function Definitions // removes the item at the top of a Stack and returns it in // stackTop. Returns true if removal succeeds, otherwise // returns false. bool Stack::pop( StackItemType &stackTop ) { if( isEmpty( ) ) return false; stackTop = topPtr -> item; StackNode *pnode = topPtr; topPtr = topPtr -> next; pnode -> next = NULL; delete pnode; // removed node is deallocated return true; }
ADT Stack: Member Function Definitions // retrieves the item at the top of a Stack and returns it in // stackTop. Returns true if retrieval succeeds, otherwise // returns false. bool Stack::getTop( StackItemType &stackTop ) const { if( isEmpty( ) ) return false; stackTop = topPtr -> item; return true; }
Application: Recognizing Balanced Parentheses Problem: Determine whether the parentheses in a given string are balanced. Examples:
Recognizing Balanced Parentheses Strategy: • Scan a string, pushing each “(” onto a stack. • When a “)” is found, pop one “(” from the stack. • The parentheses are balanced if • “(” can be popped from the stack for every “)” found, and • the stack is empty when the entire string has been processed.
Recognizing Balanced Parentheses typedef char StackItemType; // returns true if str[ ] has bool isBalanced( const char str[ ] ) // balanced parentheses, { // else returns false Stack parendStack; bool match = true; for( char *pstr = str; match && *pstr != ‘\0’; pstr++ ) { if( *pstr = = ‘(’ ) parendStack.push( ‘(’ ); else if( *pstr = = ‘)’ ) { match = parendStack.pop( ); } } return match && parendStack.isEmpty( ); }
Application: Recognizing Strings in a Language Problem: Define a recognizer for the following language: { w$wR : w is a string of characters that does not contain ‘$’, wR is the reverse of w } Examples:
Recognizing Strings in a Language Strategy: • Scan a string, pushing each character onto a stack until ‘$’ is found. • When ‘$’ is found, skip it. For each character remaining in the string, pop a character from the stack and compare. • The string is in { w$wR } if • each character remaining in the string matches, in order, a character popped from the stack, and • the stack is empty when the entire string has been processed.
Recognizing Strings in a Language typedef char StackItemType; bool inLanguage( const char str[ ] ) { Stack charStack; // push chars from str[ ] onto charStack until ‘$’ is found // skip over ‘$’ // match remaining chars in str[ ] with those on charStack return charStack.isEmpty( ); }
Recognizing Strings in a Language // push chars from str[ ] onto charStack until ‘$’ is found char *pstr; for( pstr = str; *pstr != ‘$’; pstr++ ) { if( *pstr = = ‘\0’ ) return false; charStack.push( *pstr ); } // skip over ‘$’ pstr++; // match remaining chars in str[ ] with those on charStack for( char stackTop; *pstr != ‘\0’; pstr++ ) { if( !charStack.pop( stackTop ) ) return false; if( stackTop != *pstr ) return false; }
Application: EvaluatingPostfix Expressions Problem: Compute the value of a given postfix expression. Examples:
Evaluating Postfix Expressions Strategy: • Scan a string, pushing each number onto a stack. • When an operator is found • pop two numbers from the stack, • apply the operator, and • push the result back onto the stack. • When the entire string has been processed, the result will be the only thing left on the stack.
Scan Process Stack (top is leftmost) Evaluating Postfix Expressions Evaluating 2 3 + 4 * :
Evaluating Postfix Expressions In the C++ program segment that follows, we make the following simplifying assumptions: • All input is syntactically correct (no error checking) • The only operators are +, –, *, / • No unary operators • Input operands are non-negative, single-digit integers • However, the value of the processed expression is an integer that may be either positive or negative and contain multiple digits.
Evaluating Postfix Expressions We also assume that the following functions are available: • bool isDigit( char chr ) returns true if character chr is a member of the set { ‘0’, ‘1, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’ }, otherwise returns false. • int Value( char digit )returns an integer representing the value of the character digit. • int Eval( int arg1, char op, int arg2 )returns an integer representing the value of arg1 op arg2.
Evaluating Postfix Expressions // value of postfix expression in str[ ] is placed on top of intStack typedef int StackItemType; Stack intStack; char *pstr; int arg1, arg2; for( pstr = str; *pstr != ‘\0’; pstr++ ) { if( isDigit( *pstr ) ) intStack.push( Value( *pstr ) ); else // *pstr is an operator { intStack.pop( arg2 ); intStack.pop( arg1 ); intStack.push( Eval( arg1, *pstr, arg2 ) ); } }
Converting Infix to Postfix: Strategy Strategy (5 rules): 1) Initialize char postfixExpr[ ] to the empty string. When an operand is found in the input, append it to the end of postfixExpr[ ]. 2) When a ‘(’ is found in the input, push it onto a Stack. 3) When a ‘)’ is found in the input, pop operators off the Stack and append them, in order, to the end of postfixExpr[ ],until a matching ‘(’ is popped from the Stack.
Converting Infix to Postfix: Strategy Strategy (cont’d.): 4) When an operator is found in the input: a) If the Stack is empty, push the operator onto the Stack. b) Otherwise, pop operators of greater or equal precedence from the Stack and append them to postfixExpr[ ], stopping when: • the Stack is empty, or • a ‘(’ is found on the Stack, or • an operator of lower precedence is found on the Stack. Then, push the operator onto the Stack.
Converting Infix to Postfix: Strategy Strategy (cont’d.): 5) When the end of the input is reached, pop all operators from the Stack and append them, in order, to the end of postfixExpr[ ]. Example: Use the preceding algorithm to convert the following to postfix: A – (B + C * D) / E
Infix to Postfix: Observations • Operands stay in the same order: A + B becomes A B + not B A + • An operator will move only to the right relative to its operands: A + B becomes A B + not + A B • Parentheses are removed (A + B) * C becomes A B + C * See Chapter 6 of Walls & Mirrors for detailed pseudocode corresponding to this algorithm
Y Z W S T Q X R P Search for a Path Between Two Cities Problem: Given the origin and destination of each flight made by an airline, determine whether a sequence of these flights will allow one to travel from a desired origin to a desired destination. Example:
Search for a Path Between Two Cities 3 Files Are Provided As Input: • Cityfile – names of the cities served by the airline. • Flightfile – pairs of city names, representing the origin and destination of each airline flight. • Requestfile – one pair of city names, representing a request to fly from some origin to some destination. Output Either: • “Desired path exists” or • “Desired path does not exist”
Search for a Path: Strategy Strategy: Use backtracking to perform an exhaustive search of all (non-looping) sequences of flights that originate from the desired origin. We explore the basic idea behind this strategy on the next slide. Let O denote the desired origin and D denote the desired destination.
Search for a Path: Basic Idea 1) Select a flight (O C1) originating from O. 2) If C1 = D, we are done: there is a direct flight O D. Otherwise, select a flight (C1 C2). 3) If C2 = D, we are done: there is a path O C1 D. Otherwise, select a flight (C2 C3). 4) Continue in this manner until a city Ck is reached with no departing flights. Backtrack to the city Ck-1 from which we departed to arrive at Ck. 5) Now, select a flight (Ck-1 Cm) originating from Ck-1 that is different from (Ck-1 Ck). If Cm = D, we are done: there is a path O C1 C2 . . . Ck-1 D. Otherwise, select a flight (Cm Cm+1), and continue as above.
Y Z W S T Q X R P Search for a Path: Loop Avoidance How do we avoid looping (or cycling) through the same cities? In the given example, how do we avoid a path such as W S T W S T . . . ?
Y Z W S T Q X R P Search for a Path: Loop Avoidance Mark a city when it is visited. When choosing the next city to visit, restrict consideration to unmarked cities. W S T backtrack to S backtrack to W Y
Search for a Path: Backtracking How do we implement an exhaustive search with backtracking? Consider two approaches: 1) Use a stack to hold the path under consideration from the desired origin, O, to the most recently visited city. After step (5) of our “Basic Idea” the stack would contain O C1 C2 . . . Cm Cm+1 2) Alternatively, implement a recursive solution, where the nested recursive calls to a search function store the path implicitly. Let’s focus first on the stack-based solution.