Stack pop • To pop, decrement the p counter. • To push, increment the p counter, and write in the array position. • Empty stack has p = -1, and a full stack has p = n-1, where n is the size of the array. • Stacks can be implemented with an array and an integer p that stores the array index of the top of the stack. Implementing Stacks: Array push • There are only two basic operations on stacks, the push (insert), and the pop (read and delete). • The only element of a stack that may be accessed is the one that was most recently inserted. • Examples: letter basket, stack of trays, stack of plates. • The operation push(x) places the item x onto the top of the stack. • A Stack is a sequential organization of items in which the last element inserted is the first element removed. They are often referred to as LIFO, which stands for “last in first out.” p -1 0 1 2 1 2 1 0 E0 ? 55 55 55 55 55 55 55 E1 ? ? -7 -7 -7 -7 -7 -7 E2 ? ? ? 16 16 -8 -8 -8 E3 ? ? ? ? ? ? ? ? E4 ? ? ? ? ? ? ? ? 1 1 1 16 1 -8 -7 R • Notice that some values are still in the array, but are no longer considered to be in the stack. In general, elements E[i] are “garbage” if i > p. Why don’t we erase the element (i.e. set it to some default value.)? Operation create push(55) push(-7) push(16) pop push(-8) pop pop • We use an array E[0..4] to store the elements and a variable p to keep track of the top. The last column, labeled “R” is the result of the function call. Example of Array Implementation of Stack • In some cases, we will also have to worry about filling the stack (called overflow). One way to do this is to have push(x) return “1” if it is successful, and “0” if it fails. • We need some way of detecting an empty stack (This is an underfull stack). – In some cases, we can have pop() return some value that couldn’t possibly be on the stack. – Example: If the items on the stack are positive integers, we can return “-1” in case of underflow. – In other cases, we may be better off simply keeping track of the size of the stack. • The operation pop() removes the top item from the stack, and returns that item. Stacks: Push and Pop Stacks () (55) (-7,55) (16,-7,55) (-7,55) (-8,-7,55) (-8,-7,55) (-7,55) (55) () () create push(55) push(-7) push(16) pop push(-8) push(23) pop pop pop pop 1 1 1 16 1 0 -8 -7 55 101 Return • If (! Stack.Empty) report an error • While there is still input: s = next symbol if (s is an opening symbol) push(s) else //s is a closing symbol if (Stack.Empty) report an error else r = pop() if(! Match(s,r)) report an error The following algorithm will do the trick: • If the symbols are balanced correctly, then when a closing symbol is seen, it should match the “most recently seen” unclosed opening symbol. Therefore, a stack will be appropriate. • Example: {()} is legal, as is {()({})}, whereas {((} and {(}) are not (so simply counting symbols does not work). • Stacks can be used to check a program for balanced symbols (such as {},(),[ ]). Example Application of Stacks Stack Contents Operation Assume we have a stack of size 3 which holds integers between -100 and 100. Here is a series of operations, and the results. An Example Stack Operations (This will fail.) (This will fail.) (This will succeed.) A B C • Note: Slight error in pop. What is it? • void push(ItemType x) { node *x; x=new node; x->key = X; insert(x); } • ItemType pop () { ItemType x = head->key; head=head->next; return x; } Head D • Example After push(D), push(C), push(B), push(A), we have: • The head of the list represents the top of the stack. • We can use linked lists to implement stacks. Stack Implementation: C++ Linked Lists 3. Input: { ( ) } ) 2. Input: { ( { } ){ } ( ) } 2. Input: { ( ) ( { ) } } • End of file; stack is empty, so the string is valid. • Read }, so pop; popped item is { which matches }. • Read ), so pop. popped item is ( which matches ). Stack has now {. • Read (, so push (. Stack has { ( • Read {, so push { 1. Input: { ( ) } Examples Which is better? Why? • The maximum size is determined when the stack is created. • Allocate a constant amount of space, some of which may never be used. The amount of wasted memory is the number of unused elements times the size of the item, which could be large in some cases. Arrays • Are unlimited in size. • Use 1 pointer extra memory per item. If an item is an integer, that means twice as much space is used. If an item is a structure/class consisting of many objects, it is only a small price to pay. Linked Lists Stack Implementation: Array or Linked List? class Stack { private: ItemType *stack; int p; public: Stack(int max=100) {stack = new ItemType[max]; p = -1; } ˜Stack() {delete [] stack; } void push(ItemType v) { stack[++p] = v; } ItemType pop() {return stack[p--]; } bool empty() {return (p==-1); } }; • The following is a C++ stack that holds items of type ItemType Stack: C++ Array Implementation • Procedure call and procedure return is similar to matching symbols: – When a procedure returns, it returns to the most recently active procedure. – When a procedure call is made, save current state on the stack. On return, restore the state by popping the stack. • Reversing things is easily done with stacks. • Recursion removal can be done with stacks. Stack Applications char c; Stack acc(50); int x; while (cin.get(c)) { x = 0; while (c == ’ ’ ) cin.get(c); if (c == ’+’) x = acc.pop() + acc.pop(); if (c == ’*’) x = acc.pop() * acc.pop(); while (c>=’0’ && c<=’9’) {x = 10*x + (c-’0’); cin.get(c); } acc.push(x); } cout << acc.pop() << ’\n’; • Then, the following C++ routine uses a stack to perform this evaluation: 598+46∗∗7+∗ • First, we transform it to postfix notation: 5 ∗ (((9 + 8) ∗ (4 ∗ 6)) + 7) • We can use the stack class we just defined to parse and evaluate mathematical expressions like: Operator Precedence Parsing Chapter Objectives • • • • • • • Chapter 7 Stacks Data Structures Using C++ 1 Stacks Learn about stacks Examine various stack operations Learn how to implement a stack as an array Learn how to implement a stack as a linked list Discover stack applications Learn to use a stack to remove recursion Become aware of the STL class stack Data Structures Using C++ 2 Various Types of Stacks • Definition: list of homogeneous elements, wherein the addition and deletion of elements occur only at one end, called the top of the stack • Last In First Out (LIFO) data structure • Used to implement function calls • Used to convert recursive algorithms (especially not tail recursive) into nonrecursive algorithms Data Structures Using C++ 3 LIFO Data Structures Using C++ 4 Empty Stack • Last In First Out (LIFO) data structure – Top element of stack is last element to be added to stack – Elements added and removed from one end (top) – Item added last are removed first Data Structures Using C++ 5 Data Structures Using C++ 6 1 Stack Operations Basic Operations on a Stack • initializeStack: Initializes the stack to an empty state • destroyStack: Removes all the elements from the stack, leaving the stack empty • isEmptyStack: Checks whether the stack is empty. If empty, it returns true; otherwise, it returns false Data Structures Using C++ 7 Basic Operations on a Stack • top: Returns the top element of the stack. Prior to this operation, the stack must exist and must not be empty. • pop: Removes the top element of the stack. Prior to this operation, the stack must exist and must not be empty. – Add new element to the top of the stack – The input consists of the stack and the new element. – Prior to this operation, the stack must exist and must not be full 9 Example of a Stack Data Structures Using C++ 8 Basic Operations on a Stack • isFullStack: Checks whether the stack is full. If full, it returns true; otherwise, it returns false • push: Data Structures Using C++ Data Structures Using C++ Data Structures Using C++ 10 Empty Stack 11 Data Structures Using C++ 12 2 initializeStack and destroyStack emptyStack and fullStack template<class Type> void stackType<Type>::initializeStack() { stackTop = 0; }//end initializeStack template<class Type> bool stackType<Type>::isEmptyStack() { return(stackTop == 0); }//end isEmptyStack template<class Type> void stackType<Type>::destroyStack() { stackTop = 0; }//end destroyStack template<class Type> bool stackType<Type>::isFullStack() { return(stackTop == maxStackSize); }//end isFullStack Data Structures Using C++ 13 Push Data Structures Using C++ 14 Push template<class Type> void stackType<Type>::push(const Type& newItem) { if(!isFullStack()) { list[stackTop] = newItem; //add newItem at the top //of the stack stackTop++; //increment stackTop } else cerr<<"Cannot add to a full stack."<<endl; }//end push Data Structures Using C++ 15 Return Top Element template<class Type> Type stackType<Type>::top() { assert(stackTop != 0); return list[stackTop - 1]; 16 Pop //if the stack is empty, //terminate the program //return the element of the //stack indicated by //stackTop - 1 }//end top Data Structures Using C++ Data Structures Using C++ 17 template<class Type> void stackType<Type>::pop() { if(!isEmptyStack()) stackTop--; //decrement stackTop else cerr<<"Cannot remove from an empty stack."<<endl; }//end pop Data Structures Using C++ 18 3 Pop copyStack template<class Type> void stackType<Type>::copyStack(const stackType<Type>& otherStack) { delete [] list; maxStackSize = otherStack.maxStackSize; stackTop = otherStack.stackTop; list = new Type[maxStackSize]; assert(list != NULL); //copy otherStack into this stack for(int j = 0; j < stackTop; j++) list[j] = otherStack.list[j]; }//end copyStack Data Structures Using C++ 19 20 Overloading the Assignment Operator (=) Copy Constructor template<class Type> stackType<Type>::stackType(const stackType<Type>& otherStack) { list = NULL; copyStack(otherStack); }//end copy constructor Data Structures Using C++ Data Structures Using C++ template<class Type> const stackType<Type>& stackType<Type>::operator= (const stackType<Type>& otherStack) { if(this != &otherStack) //avoid self-copy copyStack(otherStack); return *this; }//end operator= 21 Time-Complexity of Operations of class stackType Data Structures Using C++ 22 Stack Header File //Header file: myStack.h #ifndef H_StackType #define H_StackType #include <iostream> #include <cassert> using namespace std; //Place the definition of the class template stackType, as given //previously in this chapter, here. //Place the definitions of the member functions, as discussed in //this chapter, here. #endif Data Structures Using C++ 23 Data Structures Using C++ 24 4 Programming Example: Highest GPA 1. 2. 3. 4. Declare the variables. Open the input file. If the input file does not exist, exit the program. Set the output of the floating-point numbers to a fixed decimal format with a decimal point and trailing zeroes. Also, set the precision to two decimal places. 5. Read the GPA and student name. 6. highestGPA = GPA; 7. Initialize the stack. Input The program reads an input file consisting of each student’s GPA, followed by the student’s name. Sample data is: 3.8 3.6 3.9 3.7 3.4 3.9 3.4 Lisa John Susan Kathy Jason David Jack Data Structures Using C++ 25 Programming Example: Highest GPA (Algorithm) 27 Input File (Ch7_HighestGPAData.txt) Holt Bolt Colt Tom Ron Mickey Pluto Donald Cindy Dome Andy Fox Minnie Goofy Doc Danny 26 9. Output the highest GPA. 10. Output the names of the students having the highest GPA. Programming Example: Highest GPA (Sample Run) 3.4 3.2 2.5 3.4 3.8 3.8 3.6 3.5 3.8 3.7 3.9 3.8 3.9 2.7 3.9 3.4 Data Structures Using C++ Programming Example: Highest GPA (Algorithm) 8. while (not end of file) { 8.1 if (GPA > highestGPA) { 8.1.1 destroyStack(stack); 8.1.2 push(stack, student name); 8.1.3 highestGPA = GPA; } 8.2 else if(GPA is equal to highestGPA) push(stack, student name); 8.3 Read the GPA and student name; } Data Structures Using C++ Programming Example: Highest GPA (Algorithm) Data Structures Using C++ 28 Programming Example: Highest GPA (Sample Run) Output Highest GPA = 3.90 The students holding the highest GPA are: Doc Minnie Andy Data Structures Using C++ 29 Data Structures Using C++ 30 5 Empty and Nonempty Linked Stack Default Constructor template<class Type> //default constructor linkedStackType<Type>::linkedStackType() { stackTop = NULL; } Empty linked stack Nonempty linked stack Data Structures Using C++ 31 Destroy Stack //while there are elements //in the stack { temp = stackTop; //set temp to point to //the current node stackTop = stackTop->link; //advance stackTop //to the next node delete temp; //deallocate the memory //occupied by temp } }//end destroyStack Data Structures Using C++ 33 template<class Type> void linkedStackType<Type>:: initializeStack() { destroyStack(); } template<class Type> bool linkedStackType<Type>::isEmptyStack() { return(stackTop == NULL); } template<class Type> bool linkedStackType<Type>::isFullStack() { return false; Data Structures Using C++ Push Stack before the push operation 32 initializeStack and isStackEmpty template<class Type> void linkedStackType<Type>::destroyStack() { nodeType<Type> *temp; //pointer to delete the node while(stackTop != NULL) Data Structures Using C++ 34 Push Stack and newNode Stack after the statement newNode->link = stackTop; executes Data Structures Using C++ 35 Stack after the statement stackTop = newNode; executes Data Structures Using C++ 36 6 Pop Return Top Element template<class Type> Type linkedStackType<Type>::top() { assert(stackTop != NULL); return stackTop->info; }//end top //if the stack is empty, //terminate the program //return the top element Stack before the pop operation Data Structures Using C++ 37 Pop Stack after the statements temp = stackTop; and stackTop = stackTop->link; execute Stack after the statement delete temp; executes 39 Application of Stacks: Postfix Expression Calculator Stack after pushing 3 38 Application of Stacks: Postfix Expression Calculator Data Structures Using C++ Stack after pushing 6 Data Structures Using C++ 40 Application of Stacks: Postfix Expression Calculator Stack after retrieving the top two elements and popping twice Stack after pushing the result of op1 + op2, which is 9 Data Structures Using C++ Data Structures Using C++ 41 Stack after pushing the result of op1 * op2, which is 18 Stack after pushing 2 Stack after retrieving the top two elements and popping twice Stack after popping the element Data Structures Using C++ 42 7 Postfix Expression Calculator (Main Algorithm) Nonrecursive Algorithm to reverse linked list current = first; while(current != NULL) { stack.push(current); current = current->link; } llistType, *newfirst = stack.pop(); current = newfirst; while (!stack.empty()) current->link = stack.pop(); current->link = NULL; Data Structures Using C++ 43 List After Execution of Statement current = first; Data Structures Using C++ 45 STL class stack (Stack Container Adapter) Data Structures Using C++ 44 Repeated Execution of: stack.push(current); current = current->link; Data Structures Using C++ 46 Operations on a stack Object • Standard Template Library (STL) provides a class to implement a stack in a program • Name of the class defining a stack is “stack” • Name of the header file containing the definition of the class stack is “stack” Data Structures Using C++ 47 Data Structures Using C++ 48 8