CSC312 -- Lecture 3a
CSC312 -- Lecture 3a
Authors
Michael T. Goodrich, Roberto Tamassia, and David M. Mount.
2
Lecture Objective
3
Lecture Outline
▪ Introduction
▪ The Stack Abstract Data Type
▪ The Stack ADT Operations
▪ The STL Stack
▪ Stack Interface (using C++)
▪ A Simple Array-Based Stack Implementation
▪ Case Study Example
▪ Browser Back Navigation
4
Introduction
5
Introduction
6
Introduction
▪ Stacks are a fundamental data structure. They are used in many
applications, including the following:
▪ Direct applications
▪ Page-visited history in a Web browser
▪ Undo sequence in a text editor
▪ Chain of method calls in the C++ run-time system
▪ Indirect applications
▪ Auxiliary data structure for algorithms
▪ Component of other data structures
7
The Stack Abstract Data Type
▪ Formally, a stack is an abstract data type (ADT) that supports the following operations:
Operation Description
push(𝑒) Insert element 𝑒 at the top of the stack.
pop() Remove the top element from the stack; an error occurs if the stack is
empty.
top() Return a reference to the top element on the stack, without removing
it; an error occurs if the stack is empty.
size() Return the number of elements in the stack.
empty() Return true if the stack is empty and false otherwise.
10
The STL Stack
▪ List the principal member functions. Let 𝒔 be declared to be an STL vector, and let 𝒆
denote a single object whose type is the same as the base type of the stack.
▪ For example, 𝒔 is a vector of integers, and 𝒆 is an integer.
Operation Description
size() Return the number of elements in the
stack.
#include <stack> empty() Return true if the stack is empty and
using std::stack; // make stack accessible false otherwise.
stack<int> myStack; // a stack of integers push(𝑒) Push e onto the top of the stack.
pop() Pop the element at the top of the stack.
top() Return a reference to the element at
the top of the stack.
11
Stack Interface (using C++ )
▪ This entails specifying the Application Programming Interface (API), or
simply interface,
▪ which describes the names of the public members that the ADT must support and how
they are to be declared and used.
▪ The C++ programming language does not provide a simple method for
defining interfaces.
▪ The informal interface for the stack ADT is given in Code Fragment (See
Next Slide)
12
template <typename E> //The element type is indicated by E
class Stack { // an interface for a stack
public:
int size() const; // number of items in stack
bool empty() const; // is the stack empty?
const E& top() const throw(StackEmpty); // the top element
void push(const E& 𝑒); // push 𝑒 onto the stack
void pop() throw(StackEmpty); // remove the top element
};
15
A Simple Array-Based Stack Implementation
▪ This is simple way of implementing the
Stack ADT
▪ Elements are added from left to right
▪ A variable keeps track of the index of the
top element
▪ The array storing the stack elements may
become full
▪ A push operation will then throw a
StackFull exception
16
A C++ Implementation of a Array-based Stack
template <typename E> // member data
// default stack capacity private:
class ArrayStack { // array of stack elements
enum { DEF_CAPACITY = 100 }; E* S;
public: // stack capacity
// constructor from capacity int capacity;
ArrayStack(int cap = DEF_CAPACITY);
// index of the top of the stack
// number of items in the stack
int t;
int size() const;
};
// is the stack empty?
bool empty() const;
// get the top element
const E& top() const throw(StackEmpty);
// push element onto stack
void push(const E& e) throw(StackFull);
// pop the stack
void pop() throw(StackEmpty);
17
A Simple Array-Based Stack Implementation
Limitations
▪ The maximum size of the stack must be defined a priori and cannot be
changed.
▪ Trying to push a new element into a full stack causes an
implementation-specific exception.
18
A C++ Implementation of a Array-based Stack
Explanation (1 of 2)
21
A Simple Array-Based Stack Implementation
Example One
ArrayStack<int> A; // A = [ ], size = 0 * indicates top
A.push(7); // A = [7*], size = 1
A.push(13); // A = [7, 13*], size = 2
cout << A.top() << endl; A.pop(); // A = [7*], outputs: 13
A.push(9); // A = [7, 9*], size = 2
cout << A.top() << endl; // A = [7, 9*], outputs: 9
cout << A.top() << endl; A.pop(); // A = [7*], outputs: 9
ArrayStack<string> B(10); // B = [ ], size = 0
B.push("Bob"); // B = [Bob*], size = 1
B.push("Alice"); // B = [Bob, Alice*], size = 2
cout << B.top() << endl; B.pop(); // B = [Bob*], outputs: Alice
B.push("Eve"); // B = [Bob, Eve*], size = 2
22
A Simple Array-Based Stack Implementation:
Example one: Explanation
▪ In example one, we chose the default capacity value 𝑁 = 100 more or less
arbitrarily
▪ Although the user can set the capacity in the constructor.
▪ An application may actually need much less space than the given initial size,
and this would be wasteful of memory.
▪ Alternatively, an application may need more space than this, in which case our
stack implementation might “crash” if too many elements are pushed onto the
stack.
▪ Fortunately, there are other implementations (e.g. STL stack class) that do not
impose an arbitrary size limitation.
▪ It offers the advantage that it is automatically expanded when the stack
overflows its current storage limits.
23
Class Exercise 1
24
Class Exercise 1: Solution
Operation Output Stack Contents (Cont’d)
push(5) - (5) push(7) - (5,9,7)
push(3) - (5,3) push(6) - (5,9,7,6)
pop() - (5) pop() - (5,9,7)
push(2) - (5,2) pop() - (5,9)
push(8) - (5,2,8) push(4) - (5,9,4)
pop() - (5,2) pop() - (5,9)
pop() - (5) pop() - (5)
push(9) - (5,9) Size() 1 (5)
push(1) - (5,9,1)
pop() - (5,9)
25
Class Exercise 2
▪ Consider a stack and the following sequence of 20 operations.
Determine the output of each operation and the final state of the
stack.
pop(), push(A), push(B), push(C), size(), top(), pop(), push(D), top(),
pop(), empty(), push(E), push(F), size(), pop(), top(), push(G), push(H),
size(), empty()
26
Class Exercise 2: Solution
(Cont’d)
Operation Output Stack Contents
empty() False (A,B)
pop() “error” ()
push(E) - (A,B,E)
push(A) - (A)
push(F) - (A,B,E,F)
push(B) - (A,B)
size() 4 (A,B,E,F)
push(C) - (A,B,C)
pop() - (A,B,E)
size() 3 (A,B,C)
top() E (A,B,E)
top() C (A,B,C)
push(G) - (A,B,E,G)
pop() - (A,B)
Push(H) - (A,B,E,G,H)
push(D) - (A,B,D)
size() 5 (A,B,E,G,H)
top() D (A,B,D)
empty() False (A,B,E,G,H)
pop() - (A,B)
27
Class Exercise 3
▪ Consider the following sequence of operations on an ArrayStack of type string with a maximum
size of 10. Provide the corresponding output for each statement in the form of a comment.
ArrayStack<string> B(10);
B.push("David");
B.push("Mary");
cout << B.top() << endl; B.pop();
B.push("Moses");
B.push("Ruth");
cout << B.top() << endl; B.pop();
B.push("Esther");
B.push("Joshua");
cout << B.top() << endl;
B.pop();
B.push("Naomi");
cout << B.top() << endl; B.pop();
28
Class Exercise 3: Solution
ArrayStack<string> B(10); // B = [ ], size = 0
B.push("David"); // B = [David*], size = 1
B.push("Mary"); // B = [David, Mary*], size = 2
cout << B.top() << endl; B.pop(); // B = [David*], outputs: Mary
B.push("Moses"); // B = [David, Moses*], size = 2
B.push("Ruth"); // B = [David, Moses, Ruth*], size = 3
cout << B.top() << endl; B.pop(); // B = [David, Moses*], outputs: Ruth
B.push("Esther"); // B = [David, Moses, Esther*], size = 3
B.push("Joshua"); // B = [David, Moses, Esther, Joshua*], size = 4
cout << B.top() << endl; // B = [David, Moses, Esther, Joshua*], outputs: Joshua
B.pop(); // B = [David, Moses, Esther*], size = 3
B.push("Naomi"); // B = [David, Moses, Esther, Naomi*], size = 4
cout << B.top() << endl; B.pop(); // B = [David, Moses, Esther*], outputs: Naomi
29
Case Study Example:
Browser Back Navigation
▪ When using a web browser, users often navigate through multiple web pages.
▪ Browsers implement a "Back" button that allows users to return to previously
visited pages in the reverse order they were visited.
▪ This functionality is an excellent example of a stack data structure.
▪ In this case, each page a user visits is "pushed" onto a stack, and
▪ each time the user presses the "Back" button, the current page is "popped" from the
stack, revealing the previous page.
▪ This Last-In, First-Out (LIFO) order makes stacks an ideal choice for implementing
browser back navigation.
30
Case Study Example:
Browser Back Navigation
Push Operation Pop Operation Empty Operation Top Operation
(Navigating to a New (Displaying the
Page) (Back Button) (Check First Page)
Current Page)
When a user visits a When the "Back" If the stack is empty The current page can
new page, the button is pressed, the when the user presses be accessed by looking
current page (if browser removes "Back," it means there at the "top" of the
any) is stored on (pops) the most are no previous pages stack.
the stack. recent page from the to return to.
stack
31
Case Study Example:
Browser Back Navigation: push operation
▪ Here is the sequence of stack operations when the user navigates from the homepage to
page 1, then to page 2, and finally to page 3.
32
Case Study Example:
Browser Back Navigation: pop operation
▪ After the push operations, the final state of the stack is (homepage, page1, page2,
page3). Therefore, if the user carries out the back navigation action, we have:
33
#include <iostream>
#include <stack>
#include <string>
using namespace std;
int main() {
stack<string> backStack; // Stack to hold previously visited pages
string currentPage = "Homepage"; // Starting page
if (!backStack.empty()) {
currentPage = backStack.top(); // Go back to the previous page
backStack.pop(); // Remove the top page from the stack
cout << "Back to: " << currentPage << endl;
} else {
cout << "No previous pages to go back to.\n";
}
C++ Implementation of the Browser Back Navigation (Cont’d) 35
if (!backStack.empty()) {
currentPage = backStack.top(); // Go back to the previous page
backStack.pop(); // Remove the top page from the stack
cout << "Back to: " << currentPage << endl;
} else {
cout << "No previous pages to go back to.\n";
IMPLEMENTATION OUTPUT:
} Current page: Homepage
Navigated to: Page1
return 0; Navigated to: Page2
} Navigated to: Page3
37
EXERCISES
Exercise 1
▪ You are tasked with developing a library application that manages the books currently being read by
users. The library staff needs a system to keep track of the books that users have checked out. When a
user checks out a book, it is added to the collection of currently checked-out books. The most recently
checked-out book should be the first one that is returned. Write a C++ program that fulfills the
following requirements:
▪ Add a new book to the data structure when it is checked out (push operation).
▪ Each book should have a title and a unique ISBN number.
▪ Remove the book that is currently at the top of the data structure when it is returned (pop
operation).
▪ Display the details of the book currently at the top of the stack.
▪ Show the total number of books currently checked out.
▪ Provide a method to check if there are any books currently checked out (i.e., if the data structure
is empty)
39
Exercise 2
40
Exercise 3
▪ You are developing a simple customer service application for a bank. In this system,
customer requests are processed on a "Last In, First Out" (LIFO) basis. This is because
some urgent requests may override the older requests temporarily. Each customer request
is added to a stack, and the bank staff will handle the most recent requests first, removing
them as they are resolved. Write a C++ program that simulates this functionality using an
array-based stack.Your program should allow the following operations:
▪ Add a new request
▪ Resolve the most recent request
▪ Check the most recent request without removing it
▪ Check if the stack is empty
▪ Check if the stack is full
41
Exercise 4
▪ Identify and explain five (5) application areas where the stack data
structure is used. For each application area, provide a relevant
example or scenario to illustrate its use.
▪ Discuss the benefits and drawbacks of using the stack data structure.
42