0% found this document useful (0 votes)
19 views10 pages

TD Stack Corr

A stack is a linear data structure that operates on the Last In, First Out (LIFO) principle, supporting operations like push, pop, and peek with constant time complexity. Stacks are used in various applications such as function call management, expression evaluation, and undo/redo functionalities. The document also discusses practical problems like parenthesis matching, infix to postfix conversion, and stack reversal using recursion.

Uploaded by

NESSRIN HANA
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views10 pages

TD Stack Corr

A stack is a linear data structure that operates on the Last In, First Out (LIFO) principle, supporting operations like push, pop, and peek with constant time complexity. Stacks are used in various applications such as function call management, expression evaluation, and undo/redo functionalities. The document also discusses practical problems like parenthesis matching, infix to postfix conversion, and stack reversal using recursion.

Uploaded by

NESSRIN HANA
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 10

TD Stack

TheoreƟcal Problems

1. What is a Stack?

A stack is a linear data structure that follows the Last In, First Out (LIFO) principle, meaning
that the last element added to the stack is the first one to be removed. Think of it as a stack of
plates where you can only add or remove the plate from the top.

 Example:
o Push operation: Push 1 → Stack: [1]
o Push operation: Push 2 → Stack: [1, 2]
o Pop operation: Pop → Stack: [1] (Element 2 is removed)
o Push operation: Push 3 → Stack: [1, 3]
o Pop operation: Pop → Stack: [1] (Element 3 is removed)

Here, element 2 is removed before element 3 because of the LIFO property.

2. Stack Operations

Stacks support the following basic operations:

1. Push: Adds an element to the top of the stack.


o Time Complexity: O(1) (constant time)
2. Pop: Removes and returns the top element from the stack.
o Time Complexity: O(1) (constant time)
3. Peek (Top): Returns the top element without removing it.
o Time Complexity: O(1) (constant time)
4. is_empty: Checks if the stack is empty.
o Time Complexity: O(1) (constant time)
5. is_full: Checks if the stack is full (applicable for array-based implementations).
o Time Complexity: O(1) (constant time)

In most stack implementations, these operations are executed in constant time.

3. Applications of Stacks

1. Function Call Stack (Memory Management in Recursion):


The stack is used to manage function calls and local variables. When a function is called,
its data (return address, local variables, etc.) is pushed onto the stack. When the function

Page 1 of 10
finishes execution, this data is popped from the stack to resume execution at the correct
place.
2. Expression Evaluation and Conversion:
Stacks are used for converting infix expressions to postfix (or prefix) notation, and for
evaluating postfix expressions. Operators and operands are processed using a stack to
ensure correct order of operations.
3. Undo/Redo in Software Applications:
Many applications like word processors or image editors use stacks to keep track of
operations for undo and redo. Each user action (like typing or drawing) is pushed onto a
stack. To undo, the last operation is popped and reverted, while redo pushes the operation
back.

4. Stack Overflow and Underflow

1. Stack Overflow:
Stack overflow occurs when the stack exceeds its allocated size, typically in a fixed-size
stack (like in array-based implementations). It happens when there is an attempt to push
an element onto a full stack.
o Prevention: Use dynamic resizing for the stack (if implemented using an array),
or set an appropriate limit on recursive calls to avoid excessive depth.
2. Stack Underflow:
Stack underflow occurs when an attempt is made to pop an element from an empty stack.
o Prevention: Always check if the stack is empty before performing a pop
operation (using is_empty).

5. Converting Infix to Postfix

To convert an infix expression to postfix, use a stack to hold operators and parentheses while
traversing the infix expression:

1. If the character is an operand (a number or variable), add it directly to the postfix


expression.
2. If the character is an operator, pop operators from the stack to the postfix expression until
an operator of lower precedence or a left parenthesis is encountered. Then, push the
current operator onto the stack.
3. If the character is an opening parenthesis, push it onto the stack.
4. If the character is a closing parenthesis, pop operators from the stack to the postfix
expression until a left parenthesis is encountered. Pop and discard the left parenthesis.

Example (Infix to Postfix):

 Infix: A + B * (C - D)

Page 2 of 10
 Steps:
o Push ( onto stack.
o Push C, -, and D to the stack as C - D becomes CD -.
o Multiply B by (C - D) becomes B * (C - D).
o Add A + B * (C - D) becomes A B C D - * +.
 Postfix: A B C D - * +.

6. Balanced Parentheses Problem

A stack is ideal for checking balanced parentheses because of its LIFO property. The algorithm
is:

1. Traverse the expression character by character.


2. If an opening parenthesis is encountered ((, {, [), push it onto the stack.
3. If a closing parenthesis is encountered (), }, ]), pop from the stack. If the popped element
doesn't match the corresponding opening parenthesis, the expression is unbalanced.
4. If the stack is empty after processing the expression, the parentheses are balanced.
Otherwise, they are unbalanced.

Example:

 Expression: {[()]}
Stack: Push {, then [, then (. Pop ) and check if the previous is a (. Then pop ] and
check if the previous is [. Finally, pop } and check if the previous is {. The stack is
empty, so the expression is balanced.

7. Evaluating Postfix Expressions

To evaluate a postfix expression:

1. Traverse the expression from left to right.


2. If the character is an operand, push it onto the stack.
3. If the character is an operator, pop the top two operands from the stack, apply the
operator, and push the result back onto the stack.
4. After the whole expression is evaluated, the stack will contain the final result.

Example:

 Expression: 3 4 + 2 * 7 /
 Steps:
1. Push 3 and 4 onto the stack.

Page 3 of 10
2. Encounter +, pop 3 and 4, add them (3 + 4 = 7), and push the result back onto
the stack.
3. Push 2 onto the stack.
4. Encounter *, pop 7 and 2, multiply them (7 * 2 = 14), and push the result back
onto the stack.
5. Push 7 onto the stack.
6. Encounter /, pop 14 and 7, divide them (14 / 7 = 2), and push the result back
onto the stack.
 Result: 2.

8. Stack as a Memory Model

The call stack is used to manage function calls and local variables in most programming
languages. Each time a function is called:

1. A "stack frame" is pushed onto the stack with the function's return address and local
variables.
2. When the function completes, its stack frame is popped, and control returns to the calling
function.
3. Recursion relies on the call stack, as each recursive call pushes a new frame, and
popping the frame happens when the base case is reached.

9. Reverse a String Using Stack

A stack is an excellent choice for reversing a string because of its LIFO property. The algorithm
is:

1. Traverse the string and push each character onto the stack.
2. Once the string has been processed, pop characters from the stack and append them to the
result string.

Why Stack?
A stack allows us to reverse the string efficiently by ensuring that the last character pushed (i.e.,
the first character of the string) is the first one to be popped.

Example:

 String: "Hello"
 Steps:
o Push H, e, l, l, o onto the stack.
o Pop characters in reverse order and append to result: o, l, l, e, H.
 Reversed String: "olleH".

Page 4 of 10
PracƟcal Problems

Exercise 1: Implement a Stack Using Arrays

Description:
To implement a stack, we use the stack.h file. It defines the Stack structure and essential stack
operations. The stack is managed as an array with a top pointer to track the current position.
Here's the explanation of the functions and their implementation in stack.c:

Explanation of stack.h Functions:

1. void initStack(Stack* stack)


o Initializes the stack by setting top to -1.
o Indicates that the stack is empty initially.
2. int is_empty(const Stack* stack)
o Checks if the stack is empty by verifying if top == -1.
3. int is_full(const Stack* stack)
o Checks if the stack is full by comparing top with MAX_SIZE - 1.
4. void push(Stack* stack, int item)
o Adds an item to the stack if it’s not full. Updates the top index.
5. int pop(Stack* stack)
o Removes and returns the top item from the stack. Reduces the top index.
6. int peek(const Stack* stack)
o Returns the top item of the stack without removing it.
7. void clear(Stack* stack)
o Resets the top to -1, effectively clearing the stack.

Implementation of stack.c:

// Initialize the stack


void initStack(Stack* stack) {
stack->top = -1;
}

// Check if the stack is empty


int is_empty(const Stack* stack) {
return stack->top == -1;
}

// Check if the stack is full


int is_full(const Stack* stack) {
return stack->top == MAX_SIZE - 1;
}

// Push an item onto the stack

Page 5 of 10
void push(Stack* stack, int item) {
if (is_full(stack)) {
printf("Stack Overflow! Cannot push %d\n", item);
return;
}
stack->items[++stack->top] = item;
}

// Pop an item from the stack


int pop(Stack* stack) {
if (is_empty(stack)) {
printf("Stack Underflow! Cannot pop.\n");
return -1; // Error value
}
return stack->items[stack->top--];
}

// Peek the top item of the stack


int peek(const Stack* stack) {
if (is_empty(stack)) {
printf("Stack is empty! Cannot peek.\n");
return -1; // Error value
}
return stack->items[stack->top];
}

// Clear the stack


void clear(Stack* stack) {
stack->top = -1;
}

Exercise 2: Parenthesis Matching

Description:
To check for balanced parentheses, we push opening parentheses onto the stack. When
encountering a closing parenthesis, we ensure it matches the top of the stack. At the end, if the
stack is empty, the expression is balanced.

Solution:

// Check if the characters match


int is_matching_pair(char opening, char closing) {
return (opening == '(' && closing == ')') ||
(opening == '{' && closing == '}') ||

Page 6 of 10
(opening == '[' && closing == ']');
}

// Check for balanced parentheses


void check_parentheses(const char* expression) {
Stack stack;
initStack(&stack);

for (int i = 0; i < strlen(expression); i++) {


char ch = expression[i];

if (ch == '(' || ch == '{' || ch == '[') {


push(&stack, ch);
} else if (ch == ')' || ch == '}' || ch == ']') {
if (is_empty(&stack) || !is_matching_pair(pop(&stack), ch)) {
printf("Unbalanced\n");
return;
}
}
}

printf(is_empty(&stack) ? "Balanced\n" : "Unbalanced\n");


}

Exercise 3: Infix to Postfix Conversion

Description:
To convert infix to postfix, we use a stack to handle operators and parentheses. Operands are
added directly to the postfix string, while operators are pushed onto the stack based on
precedence rules.

Solution:

// Get precedence of operators


int precedence(char op) {
if (op == '+' || op == '-') return 1;
if (op == '*' || op == '/') return 2;
return 0;
}

// Convert infix to postfix


void infix_to_postfix(const char* infix) {

Page 7 of 10
Stack stack;
initStack(&stack);
char postfix[MAX_SIZE] = "";
int k = 0;

for (int i = 0; infix[i] != '\0'; i++) {


char ch = infix[i];

if (isalnum(ch)) {
postfix[k++] = ch; // Add operands to postfix
} else if (ch == '(') {
push(&stack, ch);
} else if (ch == ')') {
while (!is_empty(&stack) && peek(&stack) != '(')
postfix[k++] = pop(&stack);
pop(&stack); // Remove '('
} else {
while (!is_empty(&stack) && precedence(peek(&stack)) >=
precedence(ch))
postfix[k++] = pop(&stack);
push(&stack, ch);
}
}

while (!is_empty(&stack))
postfix[k++] = pop(&stack);

postfix[k] = '\0';
printf("Postfix: %s\n", postfix);
}

Exercise 4: Evaluate a Postfix Expression

Description:
Postfix evaluation involves reading the expression left-to-right. Operands are pushed onto the
stack. Operators pop two operands, perform the operation, and push the result.

Solution:

// Evaluate a postfix expression


int evaluate_postfix(const char* postfix) {
Stack stack;
initStack(&stack);

Page 8 of 10
for (int i = 0; postfix[i] != '\0'; i++) {
char ch = postfix[i];

if (isdigit(ch)) {
push(&stack, ch - '0');
} else {
int b = pop(&stack);
int a = pop(&stack);

switch (ch) {
case '+': push(&stack, a + b); break;
case '-': push(&stack, a - b); break;
case '*': push(&stack, a * b); break;
case '/': push(&stack, a / b); break;
}
}
}

return pop(&stack);
}

Exercise 5: Reverse a Stack Using Recursion

Description:
To reverse a stack, we recursively pop elements and store them at the bottom of the stack.

Solution:

// Insert element at the bottom of stack


void insert_at_bottom(Stack* stack, int item) {
if (is_empty(stack)) {
push(stack, item);
return;
}
int temp = pop(stack);
insert_at_bottom(stack, item);
push(stack, temp);
}

// Reverse the stack


void reverse_stack(Stack* stack) {
if (!is_empty(stack)) {

Page 9 of 10
int temp = pop(stack);
reverse_stack(stack);
insert_at_bottom(stack, temp);
}
}

// Example Usage
int main() {
Stack stack;
initStack(&stack);

push(&stack, 1);
push(&stack, 2);
push(&stack, 3);
push(&stack, 4);

reverse_stack(&stack);

while (!is_empty(&stack)) {
printf("%d ", pop(&stack)); // Output: 4 3 2 1
}

return 0;
}

Page 10 of 10

You might also like