Unit 5
Unit 5
7.1 INTRODUCTION
A stack is a data structure that works like a stack of plates: you add (push) items on top and remove (pop)
items from the top. It follows a "Last In, First Out" (LIFO) rule, meaning the last item added is the first one to
be removed. Imagine stacking books: you can only take the top book without moving the others. Stacks are
used in many areas of programming, like tracking function calls or undo actions in apps.
1. Push
2. Pop
Description: Removes and returns the item at the top of the stack.
Example:
o Initial Stack: [1, 2, 3, 4]
o Operation: pop()
o Result: Returns 4
o Resulting Stack: [1, 2, 3]
Explanation: The top element 4 is removed and returned.
Description: Retrieves the item at the top of the stack without removing it.
Example:
o Initial Stack: [1, 2, 3, 4]
o Operation: peek()
o Result: Returns 4
o Resulting Stack: [1, 2, 3, 4] (unchanged)
Explanation: The top element 4 is accessed but not removed.
4. isEmpty
5. isFull
Description: Checks if the stack has reached its maximum capacity (only applies to fixed-size stacks).
Example:
o Assume Stack Capacity: 5
o Initial Stack: [1, 2, 3, 4, 5]
o Operation: isFull()
o Result: Returns true
Explanation: Since the stack has 5 elements (its maximum capacity), isFull() returns true.
6. Size
8. Search
Description: Searches for an item in the stack and returns its distance from the top (top element has
distance 1).
Example:
o Initial Stack: [1, 2, 3, 4, 5]
o Operation: search(3)
o Result: Returns 3
Explanation: The element 3 is 3 positions away from the top, so search(3) returns 3. If the item
isn’t found, it returns -1.
Top of the stack: We maintain a variable (often called top) that points to the index of the top element
in the stack.
Array: The stack is represented using an array where the elements are stored in consecutive positions.
1. Push Operation:
o Adds an element to the stack. The element is inserted at the position indicated by the top
index.
o After the insertion, the top index is incremented.
java
Copy code
top++; // Increment top
stack[top] = element; // Place element at the top
2. Pop Operation:
o Removes the element from the top of the stack. The top index is decremented after removing
the element.
java
Copy code
element = stack[top]; // Get the top element
top--; // Decrease top
3. Peek Operation:
o Returns the element at the top of the stack without removing it.
java
Copy code
element = stack[top]; // Get the top element
4. IsEmpty Operation:
o Checks if the top is at -1 (indicating an empty stack).
java
Copy code
if (top == -1) {
// Stack is empty
}
Visualization:
If the stack array is of size 5 and contains elements [1, 2, 3] with top = 2, it would look like this:
Index 0 1 2 3 4
Value 1 2 3 _ _
Top ↑
Index 0 1 2 3 4
Value 1 2 3 4 _
Top ↑
class Stack {
private:
int maxSize;
int top;
int* stackArray;
public:
// Constructor to initialize the stack
Stack(int size) {
maxSize = size;
stackArray = new int[size];
top = -1; // Stack is empty initially
}
// Push operation
void push(int element) {
if (top < maxSize - 1) {
stackArray[++top] = element; // Increment top and add element
} else {
cout << "Stack Overflow" << endl;
}
}
// Pop operation
int pop() {
if (top == -1) {
cout << "Stack Underflow" << endl;
return -1; // Indicating underflow
} else {
return stackArray[top--]; // Return top element and decrement top
}
}
// Peek operation
int peek() {
if (top != -1) {
return stackArray[top]; // Return top element
} else {
cout << "Stack is empty" << endl;
return -1; // Indicating empty stack
}
}
// IsEmpty operation
bool isEmpty() {
return top == -1; // Stack is empty if top is -1
}
};
int main() {
Stack stack(5); // Create stack of size 5
stack.push(10);
stack.push(20);
stack.push(30);
cout << "Top element is " << stack.peek() << endl; // Should output 30
stack.pop(); // Removes 30
cout << "Top element after pop is " << stack.peek() << endl; // Should output 20
return 0;
}
#include <iostream>
using namespace std;
class Stack {
private:
int maxSize;
int top;
int* stackArray;
public:
// Constructor to initialize the stack
Stack(int size) {
maxSize = size;
stackArray = new int[size];
top = -1; // Stack is empty initially
}
int main() {
Stack stack(5); // Create stack with a maximum size of 5
cout << "Top element after pops is: " << stack.peek() << endl; //
Peek after popping
return 0;
}
C++ Program for Stack Operations with Overflow and Underflow Handling:
#include <iostream>
using namespace std;
class Stack {
private:
int top;
int stackArray[MAX_SIZE];
public:
// Constructor to initialize the stack
Stack() {
top = -1; // Stack is empty initially
}
int main() {
Stack stack; // Create a stack object
cout << "Top element is: " << stack.peek() << endl; // Peek at top
element
cout << "Popped element: " << stack.pop() << endl; // Pop an element
cout << "Popped element: " << stack.pop() << endl; // Pop another
element
stack.display(); // Show updated stack contents
cout << "Top element after pops is: " << stack.peek() << endl; //
Peek after popping
return 0;
}
#include <iostream>
using namespace std;
public:
Stack() {
top = nullptr;
}
// Push operation
void push(int value) {
Node* newNode = new Node;
newNode->data = value;
newNode->next = top;
top = newNode;
cout << value << " pushed to stack\n";
}
// Pop operation
int pop() {
if (top == nullptr) {
cout << "Stack is empty\n";
return -1;
}
int poppedValue = top->data;
Node* temp = top;
top = top->next;
delete temp;
return poppedValue;
}
int main() {
Stack stack;
stack.push(10);
stack.push(20);
stack.push(30);
return 0;
}
Here are the basic stack operations in C++ implemented as individual functions. These operations include
push, pop, peek, isEmpty, and a constructor/destructor for managing the stack.
#include <iostream>
using namespace std;
// Peek function to view the top element of the stack without removing it
int peek(Node* top) {
if (top == nullptr) {
cout << "Stack is empty\n";
return -1;
}
return top->data;
}
int main() {
Node* top = nullptr; // Initialize stack
push(top, 10);
push(top, 20);
push(top, 30);
return 0;
}
Expression Evaluation: Used to evaluate mathematical expressions like 2 3 + 5 * (postfix notation) and
convert between infix and postfix expressions.
Function Calls: Manages function calls and keeps track of the execution state (call stack).
Undo/Redo: Keeps a history of actions in apps like text editors, so you can undo or redo actions.
Backtracking: Helps in problems like maze solving or searching, where you backtrack to a previous state.
Balanced Parentheses: Checks if symbols like (), {}, and [] are balanced in code or expressions.
Depth-First Search (DFS): Used in algorithms to explore graphs and trees, by going as deep as possible
before backtracking.
Memory Management: Manages local variable storage in the program, where memory is automatically
cleaned up when a function ends.
Browser History: Keeps track of visited pages so you can use the back and forward buttons.
Expression Parsing: Helps in programming languages to interpret and process expressions in code.
Plate Stacking: Solves problems like the Tower of Hanoi, where disks or plates are moved between rods
using a stack.
To evaluate a postfix expression (also known as Reverse Polish Notation) using a stack, we follow these
simple steps:
2. Result:
o After processing all elements, the result will be the single element left in the stack.
Example Walkthrough
4. Read *: It's an operator, so pop 2 and 3, multiply them (3 * 2 = 6), and push 6 back onto the
stack.
o Stack: [5, 6]
5. Read +: It's an operator, so pop 6 and 5, add them (5 + 6 = 11), and push 11 back onto the stack.
o Stack: [11]
The stack now contains only one element, 11, which is the final result.
#include <iostream>
#include <stack>
#include <sstream>
using namespace std;
string token;
while (tokens >> token) {
if (isdigit(token[0])) {
// If it's a number, push onto the stack
s.push(stoi(token));
} else {
// Operator case: pop two numbers, apply the operator, and
push result
int operand2 = s.top(); s.pop();
int operand1 = s.top(); s.pop();
int result;
switch (token[0]) {
case '+': result = operand1 + operand2; break;
case '-': result = operand1 - operand2; break;
case '*': result = operand1 * operand2; break;
case '/': result = operand1 / operand2; break;
default: throw runtime_error("Unsupported operator");
}
s.push(result);
}
}
return s.top(); // Final result
}
int main() {
string postfixExpr = "5 3 2 * +";
cout << "Result of postfix expression '" << postfixExpr << "' is: "
<< evaluatePostfix(postfixExpr) << endl;
return 0;
To evaluate a prefix expression (also known as Polish Notation) using a stack, we follow these steps:
2. Result:
o After processing all elements, the result will be the single element left in the stack.
Example Walkthrough
3. Read *: It's an operator, so pop 3 and 2, multiply them (3 * 2 = 6), and push 6 back onto the
stack.
o Stack: [6]
5. Read +: It's an operator, so pop 5 and 6, add them (5 + 6 = 11), and push 11 back onto the stack.
o Stack: [11]
The stack now contains only one element, 11, which is the final result.
#include <iostream>
#include <stack>
#include <sstream>
#include <vector>
#include <algorithm>
using namespace std;
int result;
switch (token[0]) {
case '+': result = operand1 + operand2; break;
case '-': result = operand1 - operand2; break;
case '*': result = operand1 * operand2; break;
case '/': result = operand1 / operand2; break;
default: throw runtime_error("Unsupported operator");
}
s.push(result);
}
}
return s.top(); // Final result
}
int main() {
string prefixExpr = "+ 5 * 3 2";
cout << "Result of prefix expression '" << prefixExpr << "' is: "
<< evaluatePrefix(prefixExpr) << endl;
return 0;
}
1. Token List Setup: We first read each token into a vector and reverse the vector so we can process it
from right to left.
2. Token Processing:
o If a token is a number, it’s pushed onto the stack.
o If a token is an operator, we pop two numbers, apply the operator, and push the result back
onto the stack.
3. Result: After processing the expression, the final result is the single element remaining in the stack.
Example Output:
csharp
Copy code
Result of prefix expression '+ 5 * 3 2' is: 11
Example Walkthrough
4. Read *: It’s an operator. Since * has higher precedence than +, we push it onto the stack.
o Stack: [+, *]
6. End of Expression:
o Pop all operators from the stack to the postfix result.
o Pop * and then +.
o Final Postfix: A B C * +
This method ensures that operations are arranged in the correct order for postfix notation, where operators
appear after their operands.
#include <iostream>
#include <stack>
#include <string>
using namespace std;
return postfix;
}
int main() {
string infixExpr = "A+B*C";
cout << "Postfix expression for '" << infixExpr << "' is: "
<< infixToPostfix(infixExpr) << endl;
return 0;
}
Question ) CONVERT THE FOLLOWING EXPRESSION FROM INFIX TO POSTFIX USING A STACK
a && b || c || ! (e>f)
To convert the infix expression a && b || c || ! (e > f) to postfix using a stack, we’ll apply the
rules of precedence and associativity as we build the postfix expression.
Let's walk through each character in the expression and apply our rules.
2. Read &&: It’s an operator, and the stack is empty, so push it onto the stack.
o Stack: [&&]
6. Read ||: It’s an operator with equal precedence to the || already on the stack.
o Pop || from the stack and add it to the postfix result.
o Push the new || onto the stack.
o Postfix: a b && c ||
o Stack: [||]
7. Read !: It’s a unary operator (NOT) with the highest precedence, so push it onto the stack.
o Stack: [||, !]
8. Read (: It’s an opening parenthesis, so push it onto the stack to mark the beginning of a group.
o Stack: [||, !, (]
10. Read >: It’s a relational operator. Push it onto the stack since there’s only ( above it.
o Stack: [||, !, (, >]
12. Read ): It’s a closing parenthesis, so pop from the stack until we encounter the opening parenthesis (.
o Pop > and add it to the postfix result.
o Remove ( from the stack.
o Postfix: a b && c || e f >
o Stack: [||, !]
13. End of Expression: Now we pop all remaining operators from the stack and add them to the postfix
result.
o Pop ! and add it to the postfix result.
o Pop || and add it to the postfix result.
o Final Postfix: a b && c || e f > ! ||
css
Copy code
a b && c || e f > ! ||
This postfix expression evaluates in the correct order of precedence for logical and relational operators.
To convert a postfix expression to infix, we use a stack to gradually build the expression with the correct
placement of operators and parentheses.
Example Walkthrough
Step-by-Step Conversion:
The stack now contains a single element, which is our final infix expression:
css
Copy code
(((a && b) || c) || (!(e > f)))
This is the infix expression for the given postfix notation, with correct placement of operators and parentheses
for clarity and precedence.
#include <iostream>
#include <stack>
#include <string>
#include <cctype>
using namespace std;
int main() {
string infixExpr = "a && b || c || ! (e > f)";
cout << "Postfix expression: " << infixToPostfix(infixExpr) << endl;
return 0;
}
#include <iostream>
#include <stack>
#include <string>
#include <cctype>
using namespace std;
// Skip whitespaces
if (isspace(ch)) continue;
if (op == "!") {
// Unary operator: pop one operand
string operand1 = s.top();
s.pop();
s.push("!(" + operand1 + ")");
} else {
// Binary operator: pop two operands
string operand2 = s.top(); s.pop();
string operand1 = s.top(); s.pop();
s.push("(" + operand1 + " " + op + " " + operand2 + ")");
}
}
}
return s.top(); // The final element in the stack is the full infix
expression
}
int main() {
string postfixExpr = "a b && c || e f > ! ||";
cout << "Infix expression: " << postfixToInfix(postfixExpr) << endl;
return 0;
}