0% found this document useful (0 votes)
10 views

Stack Implementation

Stack

Uploaded by

salmamoahmmed4
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views

Stack Implementation

Stack

Uploaded by

salmamoahmmed4
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 39

Stack

1
Stack
 A stack is a list of homogenous elements in which the addition and deletion of elements occurs only at one end, called the top of the stack. For
example, to get to your favorite computer science book, which is underneath your math and history books, you must first remove the math and
history books. After removing these books, the computer science book becomes the top book—that is, the top element of the stack. Figure 1
shows some examples of stacks.
 It is a linear data structure that follows the Last-In-First-Out (LIFO) principle. This means that the last element added to the stack is the first
one to be removed. It is also sometimes referred to as First In Last Out (FILO) ordering, as the first element added to the stack is the last one
to be removed.

Some common operations implemented on the stack:


 Pop: add an element to the top of the stack.

 Push: remove the top element from the stack.

 Peek: return the top element of the stack without removing it. (sometimes called top)

 isEmpty: returns true if the stack is empty (i.e., has no elements) and false otherwise.

 isFull: this operation returns true if the stack is full (i.e., has reached its maximum size) and
false otherwise.

Figure 1
2
Stack
 There are two ways we can implement a stack:
Using an array
Using a linked list

Array-based implementation:
Stack is implemented using an array to store the elements. The stack uses a variable to keep track of the index of the top element in the array.

It is fixed size stack has a fixed size and cannot grow or shrink dynamically. If the stack is full and an attempt is made to add an element to it, an
overflow error occurs. If the stack is empty and an attempt is made to remove an element from it, an underflow error occurs.

It can be implemented using (fixed-size array or dynamic array).

Linked-based implementation:
Stack is implemented using a linked list to store the elements. The stack uses a pointer to keep track of the top element in the linked list.

It is a dynamic size stack can grow or shrink dynamically. When the stack is full, it automatically increases its size to accommodate the new
element, and when the stack is empty, it decreases its size. As it is implemented using a linked list, as it allows for easy resizing of the stack.

3
Stack
 Push (ItemType newItem)
Function: Adds newItem to the top of the stack.
Preconditions: Stack has been initialized and is not full.
Postconditions: newItem is at the top of the stack.

 Pop (ItemType& item)


Function: Removes topItem from stack and returns it in item.
Preconditions: Stack has been initialized and is not empty.
Postconditions: Top element has been removed from stack and item is a copy of the removed element.

4
Stack (implementation)

Please write the implementation in the following files


 Stack.h
 Stack.cpp
 Main.cpp

5
Stack (linked-based implementation)

6
Stack (linked-based implementation)
/* Node class for a singly linked list*/
template<class T>
class Node {
public:
T data; /* Data stored in the node*/
Node<T>* next; /* Pointer to the next node in the list*/
};
/* Stack class using a linked list*/
template<class T>
class Stack {
private:
Node<T>* top; /* Pointer to the top node of the stack*/
public:
Stack() ;
T peek() ;
bool isEmpty() ;
bool isFull();
void push(T item);
void pop(T & item);
void peek(T& item) ;
void display();
};

7
Stack (linked-based implementation)
/* Constructor to initialize an empty stack*/
template<class T>
Stack<T> :: Stack() {
top = NULL; /* Set the top pointer to NULL*/
}
/* Function to check if the stack is empty*/
template<class T>
bool Stack<T> :: isEmpty() {
return top == NULL; /* If the top pointer is NULL, the stack is empty*/
}
/* Function to check if the stack is full*/
template<class T>
bool Stack<T> :: isFull() {
return false; } /*stack is always not full*/
}
/* Function to push an element onto the stack*/
template<class T>
void Stack<T> :: push(T item) {
Node<T>* newNode = new Node<T>; /* Create a new node with the given data*/
newNode->data=item;
newNode->next = top; /* Set the new node's next pointer to the current top node*/
top = newNode; /* Set the top pointer to the new node*/
} 8
Stack (linked-based implementation)
/*Function to pop an element from the stack*/ /*Function to peek at the top element of the stack*/
template<class T> template<class T>
void Stack<T> ::pop(T& item) { void Stack<T> ::peek(T& item) {
/* Check if the stack is empty*/ // Check if the stack is empty
if (isEmpty()) { if (isEmpty()) {
cout << "Stack Underflow" << endl; cout << "Stack Underflow" << endl;
} }
else else
{ item= top->data;
/* Get the item of the top node and /* Return the item of the top node*/
the next node*/ }
item = top->data; /*Function to display the elements of the stack*/
Node<T>* temp = top->next; template<class T>
/* Delete the top node and set the top void Stack<T>::display() {
pointer to the next node*/ if (isEmpty()) {
delete top; cout << "Stack is empty" << endl; }
top = temp; else {
} Node<T>* current = top;
} while (current != NULL) {
cout << current->data << " ";
current = current->next;
}
9
cout << endl;} }
Stack (linked-based implementation)
#include <iostream> //Example of stack of char elements
using namespace std; Stack<char> st; // create a stack of integers
#include "stack.h" char item_ch;
// push elements onto the stack
int main() { st.push('A');
//Example of stack of int elements st.push('B');
Stack<int> s; // create a stack of integers st.push('C');
int item; // display the stack
// push elements onto the stack cout << "Stack elements are "; st.display();
s.push(100); // pop an element from the stack
s.push(200); st.pop(item_ch);
s.push(300); cout << "Popped item: " << item_ch << endl;
// display the stack // display the stack
cout << "Stack elements are "; cout << "Stack element after pop operation are ";
s.display(); st.display();
// pop an element from the stack // peek at the top element of the stack
s.pop(item); st.peek(item_ch);
cout << "Popped item: " << item << endl; cout << "Top item is " << item_ch << endl;
// display the stack system("pause");
cout << "Stack element after pop operation are "; return 0;
s.display(); }
// peek at the top element of the stack
s.peek(item);
cout << "Top item is " << item << endl;

10
Stack (array-based implementation)

11
Stack (array-based implementation)
#define maxSize 100 // Maximum number of elements the stack can hold

template<class T>
class Stack {
private:
int top; // Index of the top element in the stack
T arr[maxSize]; // Array that holds the stack elements
public:
Stack(); // Constructor
bool isEmpty(); // Function to check if the stack is empty
bool isFull(); // Function to check if the stack is full
void push(T item); // Function to push an element onto the stack
void pop(T& item); // Function to pop an element from the stack
void peek(T& item); // Function to peek at the top element of the stack
void display(); // Function to display the elements of the stack
};

12
Stack (array-based implementation)
/* Constructor */ /* Function to push an element onto the stack*/
template<class T> template<class T>
Stack<T>::Stack() { void Stack<T>::push(T item) {
top = -1; // Set the top index to -1 to indicate if (isFull()) {// Check if the stack is full
an empty stack cout << "Error: stack overflow" << endl;
} } else {
top++; // Increment the top index
/* Function to check if the stack is empty*/ arr[top] = item; // Add the new element
template<class T> to the top of the stack
bool Stack<T>::isEmpty() { }
return top == -1; // If the top index is -1, the }
stack is empty
} /* Function to pop an element from the stack*/
template<class T>
/* Function to check if the stack is full*/ void Stack<T>::pop(T& item) {
template<class T> if (isEmpty()) {// Check if the stack is empty
bool Stack<T>::isFull() { cout << "Error: stack underflow" << endl;
return top == maxSize - 1; // If the top index is } else {
equal to the maxSize - 1, the stack is full item = arr[top]; // Get the element at the
} top of the stack
top--; // Decrement the top index
}
13
}
Stack (array-based implementation)
/* Function to peek at the top element of the stack*/
template<class T>
void Stack<T>::peek(T& item) {
if (isEmpty()) { // Check if the stack is empty
cout << "Error: stack underflow" << endl;
} else {
item = arr[top]; // Get the element at the top of the stack
}
}

/* Function to display the elements of the stack*/


template<class T>
void Stack<T>::display() {
if (isEmpty()) { // Check if the stack is empty
cout << "Error: stack is empty" << endl;
} else {
for (int i = top; i >= 0; i--) { // Iterate over the elements of the stack
from the top to the bottom
cout << arr[i] << " ";
}
cout << endl;
}
}
14
Stack (array-based implementation)
#include <iostream>
using namespace std;
#include "stack.h"
int main() {
Stack<int> s; // create a stack of integers
int item;
// push elements onto the stack
s.push(100);
s.push(200);
s.push(300);
// display the stack
cout << "Stack elements are "; s.display();
// pop an element from the stack
s.pop(item);
cout << "Popped item: " << item << endl;
// display the stack
cout << "Stack element after pop operation are "; s.display();
// peek at the top element of the stack
s.peek(item);
cout << "Top item is " << item << endl;
// check if the stack is empty
if (s.isEmpty()) cout << "Stack is empty" << endl;
else cout << "Stack is not empty" << endl;
15
return 0;
Stack (array-based implementation) (dynamic array)

16
Stack (array-based implementation) (dynamic array)

template<class T>
class Stack {
private:
int top; // Index of the top element in the stack
int maxSize; // Maximum number of elements the stack can hold
T* arr; // Pointer to the dynamic array that holds the stack elements
public:
Stack(int maxSize); // Constructor to initialize the stack with the given maxSize
~Stack(); // Destructor to free the memory allocated for the dynamic array
bool isEmpty(); // Function to check if the stack is empty
bool isFull(); // Function to check if the stack is full
void push(T item); // Function to push an element onto the stack
void pop(T& item); // Function to pop an element from the stack
void peek(T& item); // Function to peek at the top element of the stack
void display(); // Function to display the elements of the stack
};

17
Stack (array-based implementation) (dynamic array)
/* Function to check if the stack is full*/
/* Constructor to initialize the stack with the
template<class T>
given maxSize*/
bool Stack<T>::isFull() {
template<class T>
return top == maxSize - 1; // If the top index
Stack<T>::Stack(int maxSize) {
is equal to the maxSize - 1, the stack is full
top = -1; // Set the top index
}
to -1 to indicate an empty stack
arr = new T[maxSize]; // Allocate memory
/* Function to push an element onto the stack*/
for the dynamic array
template<class T>
}
void Stack<T>::push(T item) {
/* Destructor to free the memory allocated for the
if (isFull()) { // Check if the
dynamic array*/
stack is full
template<class T>
cout << "Stack Overflow" << endl;
Stack<T>::~Stack() {
} else {
delete[] arr;
top++; // Increment the
}
top index
/* Function to check if the stack is empty*/
arr[top] = item; // Add the new
template<class T>
element to the top of the stack
bool Stack<T>::isEmpty() {
}
return top == -1; // If the top index is -1,
}
the stack is empty
}

18
Stack (array-based implementation) (dynamic array)
/* Function to pop an element from the stack*/ /* Function to display the elements of the stack*/
template<class T> template<class T>
void Stack<T>::pop(T& item) { void Stack<T>::display() {
if (isEmpty()) {// Check if the stack is empty if (isEmpty()) { // Check if the
cout << "Stack Underflow" << endl; stack is empty
} else { cout << "Stack is empty" << endl;
item = arr[top]; // Get the element at the top } else {
of the stack for (int i = top; i >= 0; i--) { //
top--; // Decrement the top index Iterate over the elements of the stack from the
} top to the bottom
} cout << arr[i] << " ";
/* Function to peek at the top element of the stack*/ }
template<class T> cout << endl;
void Stack<T>::peek(T& item) { }
if (isEmpty()) {// Check if the stack is empty }
cout << "Stack Underflow" << endl;
} else {
item = arr[top]; // Get the element at the top
of the stack
}
}

19
Stack (array-based implementation) (dynamic array)
#include <iostream>
using namespace std;
#include "stack.h"
int main() {
Stack<int> s(50); // create a stack of integers
int item;
// push elements onto the stack
s.push(100);
s.push(200);
s.push(300);
cout << "Stack elements are "; s.display(); // display the stack
// pop an element from the stack
s.pop(item);
cout << "Popped item: " << item << endl;
// display the stack
cout << "Stack element after pop operation are "; s.display();
// peek at the top element of the stack
s.peek(item);
cout << "Top item is " << item << endl;
// check if the stack is empty
if (s.isEmpty()) cout << "Stack is empty" << endl;
else cout << "Stack is not empty" << endl;
return 0;
20
}
Stack application

21
Stack application
 Undo/redo functionality.
 Browser history.
 Processing function calls
 Reverse a data
 Delimiter checking
 Evaluation of arithmetic expressions
 Tower of hanoi game
 Recursion

 Browser history: The back and forward buttons in web browsers can be implemented using stacks. Each time a user visits a new web page, it is
added to the stack, and when the user clicks the back button, the most recently visited page is popped off the stack.

 Undo/redo functionality: Many software applications allow users to undo or redo their actions. Stacks can be used to store the state of the
application at each step, so that the user can undo or redo their actions by popping items off the stack.

 Recursion: Recursive algorithms often use stacks to keep track of the function calls. Each time a function is called, its parameters and return
address are pushed onto the stack, and when the function returns, they are popped off the stack.

22
Stack application
Processing function calls
 Stack plays an important role in programs that call several functions in succession. Suppose we have a program containing three functions: A, B,
and C. function A invokes function B, which invokes the function C.
 When we invoke function A, which contains a call to function B, then its processing will not be completed until function B has completed its
execution and returned. Similarly for function B and C. So we observe that function A will only be completed after function B is completed and
function B will only be completed after function C is completed. Therefore, function A is first to be started and last to be completed. To conclude,
the above function activity matches the last in first out behavior and can easily be handled using Stack.
 Consider addrA, addrB, addrC be the addresses of the statements to which control is returned after completing the function A, B, and C,
respectively.

 The following figure shows that return addresses appear in the


Stack in the reverse order in which the functions were called.
After each function is completed, the pop operation is performed,
and execution continues at the address removed from the Stack.
Thus the program that calls several functions in succession can
be handled optimally by the stack data structure. Control returns
to each function at a correct place, which is the reverse order of
the calling sequence.

23
Stack application
Reverse data
To reverse a given set of data, we need to reorder the data so that the first and last elements are exchanged, the second and second last element are
exchanged, and so on for all other elements.
Example: Suppose we have a string Welcome, then on reversing it would be Emoclew.
There are different reversing applications:
 Reversing a string
 Converting Decimal to Binary

Reverse string
 A Stack can be used to reverse the characters of a string. This can be
achieved by simply pushing one by one each character onto the
Stack, which later can be popped from the Stack one by one. Because
of the last in first out property of the Stack, the first character of the
Stack is on the bottom of the Stack and the last character of the
String is on the Top of the Stack and after performing the pop
operation in the Stack, the Stack returns the String in Reverse order.

24
Stack application (reverse string)
#include <iostream>
#include <string>
#include "stack.h"
using namespace std;
void reverseString(string& str) {
Stack<char> s; char c;
// Push each character of the string onto the stack
for (int i = 0; i < str.length(); i++) {
s.push(str[i]); }
// Pop each character from the stack and overwrite the string in reverse order
for (int i = 0; i < str.length(); i++) {
s.pop(c);
str[i] = c;
} }
int main() {
string str;
cout << "Enter a string: ";
getline(cin, str);
reverseString(str);
cout << "Reversed string: " << str << endl;
return 0;
}
25
Stack application
Converting decimal to binary:
 Although decimal numbers are used in most business applications, some scientific and technical applications require numbers in either binary,
octal, or hexadecimal. A stack can be used to convert a number from decimal to binary/octal/hexadecimal form. For converting any decimal
number to a binary number, we repeatedly divide the decimal number by two and push the remainder of each division onto the Stack until the
number is reduced to 0. Then we pop the whole Stack and the result obtained is the binary equivalent of the given decimal number.

 In the following example, on dividing 14 by 2, we get seven


as a quotient and one as the reminder, which is pushed on the
Stack. On again dividing seven by 2, we get three as quotient
and 1 as the reminder, which is again pushed onto the Stack.
This process continues until the given number is not reduced
to 0. When we pop off the Stack completely, we get the
equivalent binary number 1110.

26
Stack application
Delimiter checking
 The common application of Stack is delimiter checking, i.e., parsing that involves analyzing a source program syntactically. It is also called
parenthesis checking. When the compiler translates a source program written in some programming language such as C, C++ to a machine
language, it parses the program into multiple individual parts such as variable names, keywords, etc. By scanning from left to right. The main
problem encountered while translating is the unmatched delimiters. We make use of different types of delimiters include the parenthesis checking
(,), curly braces {,} and square brackets [,], and common delimiters /* and */. Every opening delimiter must match a closing delimiter, i.e., every
opening parenthesis should be followed by a matching closing parenthesis. Also, the delimiter can be nested. The opening delimiter that occurs
later in the source program should be closed before those occurring earlier.

Valid Delimiter Invalid Delimiter

While ( i > 0) While ( i >


/* Data Structure */ /* Data Structure
{ ( a + b) - c } { ( a + b) - c

 To perform a delimiter checking, the compiler makes use of a stack. When a compiler translates a source program, it reads
the characters one at a time, and if it finds an opening delimiter it places it on a stack. When a closing delimiter is found, it
pops up the opening delimiter from the top of the Stack and matches it with the closing delimiter.

27
Stack application
Delimiter checking

On matching, the following cases may arise.


 If the delimiters are of the same type, then the match is
considered successful, and the process continues.
 If the delimiters are not of the same type, then the syntax
error is reported.

 When the end of the program is reached, and the Stack is


empty, then the processing of the source program stops.

 Example: To explain this concept, let's consider the


following expression.
[{a -b) * (c -d)}/f]

28
Stack application (delimiter checking)
#include <iostream>
#include <string>
#include "stack.h"
using namespace std;
// Checks if the delimiters in the string are balanced using a stack
bool checkDelimiters(string str)
{
Stack<char> s; /* Create a stack of characters*/
int len = str.length(); // Get the length of the string*/
/* Loop through each character in the string*/
for (int i = 0; i < len; i++) {
/* If the character is an opening delimiter, push it onto the stack*/
if (str[i] == '(' || str[i] == '[' || str[i] == '{') {
s.push(str[i]);
}
/* If the character is a closing delimiter, pop the top element from the stack
/ and compare it to the current character to see if they match*/
else if (str[i] == ')' || str[i] == ']' || str[i] == '}')
{
/* If the stack is empty, then there is no matching opening delimiter for the closing
delimiter*/
if (s.isEmpty())
return false;
29
Stack application (delimiter checking)
/* Get the top element of the stack without removing it*/
char top;
s.peek(top);
/* Compare the top element of the stack to the current character to see if they match.
If they do match, then pop the top element from the stack
If they don't match, then the delimiters are not balanced*/
if ((str[i] == ')' && top == '(') ||
(str[i] == ']' && top == '[') ||
(str[i] == '}' && top == '{'))
s.pop(top);
else
return false;
}
}
/* If the stack is empty at the end of the loop, then all the delimiters are balanced
/ If the stack is not empty, then there are some opening delimiters that don't have matching
closing delimiters*/
return s.isEmpty();
}

30
Stack application (delimiter checking)
int main() {
char str[100]; // declare a character array to hold the input string
cout << "Enter a string: ";
cin.getline(str, 100); // read the input string from the user
// Check if the delimiters in the string are balanced
if (checkDelimiters(str))
cout << "Delimiters are balanced." << endl;
else
cout << "Delimiters are not balanced." << endl;
return 0;
}

31
Stack application
Evaluation of Arithmetic Expressions
A stack is a very effective data structure for evaluating arithmetic expressions in programming languages. An arithmetic
expression consists of operands and operators.
In addition to operands and operators, the arithmetic expression may also include parenthesis like "left parenthesis" and
"right parenthesis".
Example: A + (B - C)
To evaluate the expressions, one needs to be aware of the standard precedence rules for arithmetic expression. The
precedence rules for the five basic arithmetic operators are:

Operators Associativity Precedence

^ exponentiation Right to left Highest followed by


*Multiplication and /division
*Multiplication, /division Left to right Highest followed by + addition and
- subtraction
+ addition, - subtraction Left to right lowest

32
Stack application
Evaluation of Arithmetic Expressions
Notations for Arithmetic Expression
There are three notations to represent an arithmetic expression:
•Infix Notation
•Prefix Notation
•Postfix Notation

Infix Notation
The infix notation is a convenient way of writing an expression in which each operator is placed between the operands. Infix
expressions can be parenthesized or unparenthesized depending upon the problem requirement.
Example: A + B, (C - D) etc.
All these expressions are in infix notation because the operator comes between the operands.

Prefix Notation
The prefix notation places the operator before the operands. Example: + A B, -CD etc.
All these expressions are in prefix notation because the operator comes before the operands.

Postfix Notation
The postfix notation places the operator after the operands. Example: AB +, CD+, etc.
All these expressions are in postfix notation because the operator comes after the operands.

33
Stack application
Evaluation of Arithmetic Expressions

Conversion of Arithmetic Expression into various Notations:

Infix Notation Prefix Notation Postfix Notation

A*B *AB AB*


(A+B)/C /+ ABC AB+C/
(A*B) + (D-C) +*AB - DC AB*DC-+

Let's take the example of Converting an infix expression into a


postfix expression.

In the above example, the only change from the postfix


expression is that the operator is placed before the operands
rather than between the operands.

34
Stack application
Evaluation of postfix expression
 Stack is the ideal data structure to evaluate the postfix expression because
the top element is always the most recent operand. The next element on
the Stack is the second most recent operand to be operated on.
 Before evaluating the postfix expression, the following conditions must
be checked. If any one of the conditions fails, the postfix expression is
invalid.
 When an operator encounters the scanning process, the Stack must
contain a pair of operands or intermediate results previously calculated.
 When an expression has been completely evaluated, the Stack must
contain exactly one value.
Example:
Now let us consider the following infix expression 2 * (4+3) - 5.
Its equivalent postfix expression is 2 4 3 + * 5.
The following step illustrates how this postfix expression is evaluated.

35
Stack application
Evaluation of postfix expression
Scan the given postfix expression from left to right character by character.
If the character is an operand, push it into the stack.
But if the character is an operator, pop the top two values from stack.
Concatenate this operator with these two values (2nd top value+operator+1st top value) to get a new string.
Now push this resulting string back into the stack.
Repeat this process until the end of postfix expression. Now the value in the stack is the infix expression.

Example: 43*82-+
pop(3) as op2
Empty Then Calculate pop(2) as op2 Calculate pop(6) as op2 Calculate Pop(20)
stack push(4) push(3) (op2*op1) Then (op2-op1) This is the
pop(4) as op1 Then (op2-op1)
push(3*4) push(8) push(2) pop(8) as op1 push(8-2) pop(14) as op1 push(6+14) result

2 2
3 3 8 8 8 6 6
4 4 4 12 12 12 12 12 12 18 18 36
Stack application (postfix evaluation )
#include <iostream>
#include <string>
#include "stack.h"

using namespace std;

/* Function to evaluate a postfix expression */


int evaluatePostfix(string expression) {
/* Create a stack to store the operands */
Stack<int> stack;
int operand1, operand2,digit;
/* Traverse the expression from left to right */
for (int i = 0; i < expression.length(); i++) {
/* If the current character is a digit, push it onto the stack */
char ch = expression[i];
if (isdigit(ch)) {
// stack.push(ch - '0');
/* If the character is a digit, convert it to an integer and push it onto the stack*/
digit = stoi(string(1, expression[i]));
stack.push(digit);
}

37
Stack application (postfix evaluation )
/* If the current character is an operator, pop two operands from the stack, apply the operator, and push
the result onto the stack */
else
{
stack.pop(operand2);
stack.pop(operand1);
switch(ch) {
case '+': stack.push(operand1 + operand2); break;
case '-': stack.push(operand1 - operand2); break;
case '*': stack.push(operand1 * operand2); break;
case '/': stack.push(operand1 / operand2); break;
default: cout << "Invalid operator" << endl;
}} }
/* The final result is the only item remaining on the stack */
int result;
stack.pop(result);
if (!stack.isEmpty()) {
cout << "Invalid expression" << endl;
return 0;
}
return result;
}
38
Stack application (postfix evaluation )
int main() {
// string expression = "234*+5-";
string expression;
// Get the postfix expression from the user
cout << "Enter the postfix expression: ";
cin >> expression; /* Read the postfix expression from the user */

// Evaluate the expression and print the result


int result = evaluatePostfix(expression);
cout << "Result: " << result << endl;
system("Pause");
return 0;
}

39

You might also like