TD Stack Corr
TD Stack Corr
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)
2. Stack Operations
3. Applications of Stacks
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.
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).
To convert an infix expression to postfix, use a stack to hold operators and parentheses while
traversing the infix expression:
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 - * +.
A stack is ideal for checking balanced parentheses because of its LIFO property. The algorithm
is:
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.
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.
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.
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
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:
Implementation of stack.c:
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;
}
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:
Page 6 of 10
(opening == '[' && closing == ']');
}
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:
Page 7 of 10
Stack stack;
initStack(&stack);
char postfix[MAX_SIZE] = "";
int k = 0;
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);
}
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:
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);
}
Description:
To reverse a stack, we recursively pop elements and store them at the bottom of the stack.
Solution:
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