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

Stack - Institution and Implementation

The document discusses stack data structures and their implementation. It describes what a stack is, basic stack operations like push, pop and top, and different types of stacks. It also covers stack implementation using arrays and linked lists, complexity analysis, and examples of stack applications.

Uploaded by

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

Stack - Institution and Implementation

The document discusses stack data structures and their implementation. It describes what a stack is, basic stack operations like push, pop and top, and different types of stacks. It also covers stack implementation using arrays and linked lists, complexity analysis, and examples of stack applications.

Uploaded by

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

STACK : INSTITUTION AND

IMPLEMENTATION
16 February 2024 17:21

CREATED BY SHIVAM BAREKAR


STACK IMPLEMENTION
17 March 2024 11:45

What is Stack ?
A stack is a linear data structure in which the insertion of a new element and removal of an
existing element takes place at the same end represented as the top of the stack.
To implement the stack, it is required to maintain the pointer to the top of the stack, which
is the last element to be inserted because we can access the elements only on the top of
the stack.

LIFO( Last In First Out ) :


This strategy states that the element that is inserted last will come out first. You can take a
pile of plates kept on top of each other as a real-life example. The plate which we put last is
on the top and since we remove the plate that is at the top, we can say that the plate that
was put last comes out first.

Basic Operations on Stack


In order to make manipulations in a stack, there are certain operations provided to us.
• push() to insert an element into the stack
• pop() to remove an element from the stack
• top() Returns the top element of the stack.
• isEmpty() returns true if stack is empty else false.
• size() returns the size of stack.
Push:
Adds an item to the stack. If the stack is full, then it is said to be an Overflow condition.

Algorithm for push :

begin
if stack is full
return
endif
else
increment top
stack[top] assign value
end else
end procedure

Pop:

Removes an item from the stack. The items are popped in the reversed order in which they
are pushed. If the stack is empty, then it is said to be an Underflow condition.

Algorithm for pop:

begin
if stack is empty
return
endif
else
store value of stack[top]
decrement top
return value
end else
end procedure

Top:

Returns the top element of the stack.

Algorithm for Top:


begin
return stack[top]
end procedure

isEmpty:

Returns true if the stack is empty, else false.


Algorithm for isEmpty:
begin
if top < 1
return true
else
return false
end procedure

Understanding stack practically:

There are many real-life examples of a stack. Consider the simple example of plates stacked
over one another in a canteen. The plate which is at the top is the first one to be removed,
i.e. the plate which has been placed at the bottommost position remains in the stack for the
longest period of time. So, it can be simply seen to follow the LIFO/FILO order.

Complexity Analysis:
• Time Complexity

Operations Complexity
push() O(1)
pop() O(1)
isEmpty() O(1)
size() O(1)

Types of Stacks:
• Fixed Size Stack: As the name suggests, a 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.
• Dynamic Size Stack: 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. This type of stack is implemented using a
linked list, as it allows for easy resizing of the stack.
In addition to these two main types, there are several other variations of Stacks, including :
1. Infix to Postfix Stack: This type of stack is used to convert infix expressions to postfix
expressions.
2. Expression Evaluation Stack: This type of stack is used to evaluate postfix
expressions.
3. Recursion Stack: This type of stack is used to keep track of function calls in a computer
program and to return control to the correct function when a function returns.
4. Memory Management Stack: This type of stack is used to store the values of the
program counter and the values of the registers in a computer program, allowing the
program to return to the previous state when a function returns.
5. Balanced Parenthesis Stack: This type of stack is used to check the balance of
parentheses in an expression.
6. Undo-Redo Stack: This type of stack is used in computer programs to allow users to
undo and redo actions.

Applications of the stack :


• Infix to Postfix /Prefix conversion
• Redo-undo features at many places like editors, photoshop.
• Forward and backward features in web browsers
• Used in many algorithms like Tower of Hanoi, tree traversals, stock span problems,
and histogram problems.
• Backtracking is used to solve problems like the Knight-Tour problem, N-Queen
problem, maze problems, and game-like chess or checkers in all these problems we
dive into someway if that way is inefficient, we come back to the previous state and go
into some another path. To get back from a current state we need to store the
previous state in a stack.
• In Graph Algorithms like Topological Sorting and Strongly Connected Components
• In Memory management, any modern computer uses a stack as the primary
management for a running purpose. Each program that is running in a computer
system has its own memory allocations.
• Stack also helps in implementing function call in computers. The last called function is
always completed first.

Implementation of Stack :

The basic operations that can be performed on a stack include push, pop, and peek. There
are two ways to implement a stack –
• Using array
• Using linked list
In an array-based implementation, the push operation is implemented by incrementing the
index of the top element and storing the new element at that index. The pop operation is
implemented by decrementing the index of the top element and returning the value stored
at that index.
In a linked list-based implementation, the push operation is implemented by creating a new
node with the new element and setting the next pointer of the current top node to the new
node. The pop operation is implemented by setting the next pointer of the current top node
to the next node and returning the value of the current top node.

Implementing Stack using Arrays:


Output : 10 pushed into stack
20 pushed into stack
30 pushed into stack
30 Popped from stack
Top element is : 20
Elements present in stack : 20 10
Advantages of array implementation:
• Easy to implement.
• Memory is saved as pointers are not involved.

Disadvantages of array implementation:


• It is not dynamic i.e., it doesn’t grow and shrink depending on needs at runtime. [But
in case of dynamic sized arrays like vector in C++, list in Python, ArrayList in Java,
stacks can grow and shrink with array implementation as well].
• The total size of the stack must be defined beforehand.

Implementing Stack using Linked List :


Output : 10 pushed to stack
20 pushed to stack
30 pushed to stack
30 popped from stack
Top element is 20
Elements present in stack : 20 10
Advantages of Linked List implementation:
• The linked list implementation of a stack can grow and shrink according to the needs
at runtime.
• It is used in many virtual machines like JVM.

Disadvantages of Linked List implementation:


• Requires extra memory due to the involvement of pointers.
• Random accessing is not possible in stack.
PROBLEM ON STACK
17 March 2024 12:15

Problem-01 : Implement Stack using Queues

Implement a last-in-first-out (LIFO) stack using only two queues.


The implemented stack should support all the functions of a normal
stack (push, top, pop, and empty).
Implement the MyStack class:
• void push(int x) Pushes element x to the top of the stack.
• int pop() Removes the element on the top of the stack and
returns it.
• int top() Returns the element on the top of the stack.
• boolean empty() Returns true if the stack is empty, false
otherwise.
Notes:
• You must use only standard operations of a queue, which means
that only push to back, peek/pop from front, size and is
empty operations are valid.
• Depending on your language, the queue may not be supported
natively. You may simulate a queue using a list or deque (double-
ended queue) as long as you use only a queue's standard
operations.

Example 1:
Input
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]

Output
[null, null, null, 2, 2, false]

Explanation
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // return 2
myStack.pop(); // return 2
myStack.empty(); // return False

Constraints:
• 1 <= x <= 9
• At most 100 calls will be made to push, pop, top, and empty.
• All the calls to pop and top are valid.

Problem Understanding
Description :

The task is to implement a stack (Last In, First Out - LIFO) using queues. The
stack should support the following functions: push, pop, top, and empty. These
operations should behave just as they do in a typical stack data structure.

Key Points to Consider

1. Understand the Constraints

• The stack must be implemented using only standard queue operations.


• The integer values pushed onto the stack are between 1 and 9.
• There will be at most 100 calls to each of the stack's functions (push, pop,
top, and empty).
• All calls to pop and top will be made when the stack is not empty.

2. Approaches to Solve the Problem

Two-Queue Approach :

• How it Works: Utilize two queues and move elements between them to
mimic stack operations.
• Time Complexity: O(n)O(n)O(n) for pop and top, O(1)O(1)O(1) for push and
empty.
• When to Use: Choose this approach when the frequency of push and empty
operations is higher than pop and top.

One-Queue Approach :

• How it Works: Use a single queue and reorganize (rotate) its elements
when pushing a new element.
• Time Complexity: O(n)O(n)O(n) for push, O(1)O(1)O(1) for pop, top, and
empty.
• When to Use: Choose this approach when you expect pop and top
operations to be more frequent than push.
3. Thought Process

• The two-queue approach is more straightforward but involves more


element transfers for pop and top.
• The one-queue approach requires more work during the push operation but
makes pop and top more efficient.

Conclusion

The problem is a good exercise in understanding how one data structure can be
implemented using another while maintaining its essential characteristics with
both one-queue and two-queue approaches.

Approach : Two-Queue Approach

Key Data Structures

• Two queues, often implemented using Python's deque from the collections
library.

Enhanced Breakdown

1. Initialization:
• Create two empty queues, referred to as q1 and q2. q1 will serve as the
main queue where new elements are pushed, while q2 will serve as an
auxiliary queue for temporary operations.

2. Base Cases:
• For the empty function, directly check the length or size of q1. If it's
empty, return True, otherwise return False.

3. Main Algorithm:

Push Operation
• For the push operation, simply add the new element to the back (enqueue)
of q1.

Pop Operation
• For the pop operation, you need to access the last element pushed into q1,
which is at the back.
• To do this, dequeue from q1 and enqueue into q2 until only one element
remains in q1.
• The remaining element is the one to be popped. Dequeue it from q1.
Top Operation
• Similar to the pop operation, but after accessing the last element, it
should be enqueued back into q2.

4. Wrap-up:
• After each pop and top operation, swap q1 and q2 to make q2 the new main
queue and q1 the new auxiliary queue.

Complexity

Time Complexity :

• O(n)O(n)O(n) for the pop and top operations as you have to move n−1n-1n−1
elements between the two queues.
• O(1)O(1)O(1) for the push and empty operations as they are direct enqueue
and length check operations.

Space Complexity :

• O(n)O(n)O(n) for storing the elements in the queues.

Approach: One-Queue Approach

Key Data Structures

• A single queue, again best implemented using Python's deque from the
collections library.

Enhanced Breakdown

1. Initialization:
• Create a single empty queue, referred to as q.

2. Base Cases:
• Similar to the Two-Queue Approach, directly check if the queue q is empty
for the empty operation.

3. Main Algorithm :

Push Operation
• Enqueue the new element at the back of q.
• To ensure that the last element can be accessed from the front, rotate
the queue by dequeueing and enqueuing each element except the newly
pushed element.

Pop and Top Operations


• Simply dequeue from the front for pop and peek at the front for top.
4. Wrap-up:
• There's no need to swap or move elements for pop and top, making these
operations faster compared to the Two-Queue Approach.

Complexity

Time Complexity:

• O(n)O(n)O(n) for the push operation due to the rotation required to bring
the last element to the front.
• O(1)O(1)O(1) for the pop, top, and empty operations.

Space Complexity:

• O(n)O(n)O(n) for storing the elements in the queue.

Performance :

Language Approach Runtime (ms) Memory (MB)


Rust 1Q 0 ms 2.2 MB
Go 1Q 1 ms 2 MB
C++ 1Q 0 ms 6.7 MB
Java 1Q 0 ms 40.5 MB
PHP 1Q 0 ms 18.8 MB
Python3 1Q 24 ms 16.5 MB
Python3 2Q 40 ms 16.4 MB
JavaScript 1Q 45 ms 41.6 MB
C# 1Q 105 ms 40.7 MB
Code One-Queue :

Problem-02 : Min Stack

Design a stack that supports push, pop, top, and retrieving the
minimum element in constant time.

Implement the MinStack class:


• MinStack() initializes the stack object.
• void push(int val) pushes the element val onto the stack.
• void pop() removes the element on the top of the stack.
• int top() gets the top element of the stack.
• int getMin() retrieves the minimum element in the stack.

You must implement a solution with O(1) time complexity for each
function.
Example 1:

Input
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

Output
[null,null,null,null,-3,null,0,-2]

Explanation
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); // return -3
minStack.pop();
minStack.top(); // return 0
minStack.getMin(); // return -2

Constraints:

• -231 <= val <= 231 - 1


• Methods pop, top and getMin operations will always be called on
non-empty stacks.
• At most 3 * 104 calls will be made to push, pop, top, and getMin.

Solution:

Solution 1 : Using pairs to store the value and minimum element till now.

Approach :

The first element in the pair will store the value and the second element
will store the minimum element till now.
When the first push operation comes in we will push the value and store it
as minimum itself in the pair.
In the second push operation, we will check if the top element’s minimum
is less than the new value. If it is then we will push the value with
minimum as the previous top’s minimum. To get the getMin element to
take the top’s second element.

Code :

Time Complexity: O(1)


Space Complexity: O(2N)
Solution 2:

Approach :

Let’s take a variable that stores the minimum number. So whenever a push
operation comes in just take that number put it in the stack and update
the variable to the number.

Push operation:

Now if there is a push operation just check whether that number is less
than the min number. If it is smaller than min we will push a modified
value which is a push(2 * Val – min) into the stack and will update min to
the value of the original number. If it’s not then we will just push it as it
is.

getMin() operation :

We will just return the value of min.

Top operation :

While returning the top value we know that it is a modified value. We will
check if the top value is lesser than min, If it is then we will return the
min as the top value.

Pop operation :

While making pop we will check if the top value is lesser than min, If it is
then we must update our min to its previous value. In order to do that min
= (2 * min) – (modified value) and we will pop the element.
Code :

Time Complexity: O(1)


Space Complexity: O(N)

You might also like