0% found this document useful (0 votes)
5 views2 pages

Stack and Queue Data Structures Guide

Uploaded by

jisarvashrestha
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)
5 views2 pages

Stack and Queue Data Structures Guide

Uploaded by

jisarvashrestha
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

■ Stack (LIFO – Last In First Out)

1. Implementation

Using Array
• Stack has fixed size.
• Use a variable top to track the top element.
• Push → stack[++top] = item;
• Pop → item = stack[top--];

Using Linked List


• Each node = data + pointer to next.
• Push → Insert at head.
• Pop → Delete from head.

2. Operations

• Push → Add element at top


• Pop → Remove element from top
• Peek → View element at top without removing

Example (Array stack):


Stack = [10, 20, 30], top=2
Push(40) → [10,20,30,40]
Pop() → returns 40, Stack=[10,20,30]
Peek() → 30

3. Applications

(a) Expression Conversion


Infix → Postfix/Prefix using stack for operators.
Example: Infix A + B * C
Postfix: A B C * +
Prefix: + A * B C

(b) Postfix Evaluation


Expression: 6 3 2 + *
Steps:
Push 6 → [6]
Push 3 → [6,3]
Push 2 → [6,3,2]
Encounter + → Pop(3,2)=5 → Push 5 → [6,5]
Encounter * → Pop(6,5)=30 → Push 30 → [30]
■ Result = 30

(c) Recursion
Recursion uses system stack.
Example: Factorial(3)
fact(3) → fact(2) → fact(1)
fact(1) returns 1 → fact(2)=2 → fact(3)=6

(d) Tower of Hanoi


Problem: Move n disks from source → destination using auxiliary rod.
Rule: Only one disk moved at a time, smaller always above bigger.
Solution uses recursion (stack is used internally).

■ Queue (FIFO – First In First Out)


1. Implementation

Using Array
• Maintain front and rear.
• Enqueue → queue[++rear] = item;
• Dequeue → item = queue[front++];

Using Linked List


• Maintain front and rear pointers.
• Enqueue → Add node at rear.
• Dequeue → Remove node at front.

2. Operations

• Enqueue → Insert element at rear.


• Dequeue → Remove element from front.

Example (Array queue):


Queue = [10,20,30], front=0, rear=2
Enqueue(40) → [10,20,30,40]
Dequeue() → returns 10 → [20,30,40]

3. Types of Queues

(a) Circular Queue


• Last position connects back to first.
• Formula for next position:
rear = (rear + 1) % size

(b) Dequeue (Double-Ended Queue)


• Insertion and deletion can be done from both ends.
• Used in sliding window problems.

(c) Priority Queue


• Each element has a priority.
• Highest priority element served first (not always FIFO).
• Example: Job scheduling in OS.

Common questions

Powered by AI

In calculating the factorial of a number recursively, a system stack plays the role of managing function calls. When calculating factorial(n), a function call is made, which is pushed onto the stack. Inside factorial(n), if n is greater than 1, another recursive call is made to factorial(n-1), pushing a new frame onto the stack for this call with its own state and parameters. This deepens until the base case, factorial(1), is reached, which returns 1. Each return value is then used by the previous call on top of the stack, unwinding in reverse order of execution until the initial call's frame uses the accumulated result from all sub-calculations present on the stack until it finishes with the result, factorial(n). This deep factorial expansion uses the stack for maintaining state through each distinct call, ensuring that results accumulate correctly on return.

The Tower of Hanoi problem is a classic example of recursion where the stack-like behavior of recursive function calls is prominently utilized. Each move in the problem essentially reduces it to a smaller instance, stacking calls for the number of disks minus one to be moved to an auxiliary rod before finally moving the largest disk. Each state of the recursion reflects the elements temporarily 'stacked' onto intermediate rods until they can reach their destination. This sequential dependency mimics a stack's push and pop operations, stacking smaller tasks temporarily until conditions are met to perform the main operation (moving the largest disk) and then resolving the stacked tasks - much like how a recursive call stacks frames until the base case resolves . This problem exemplifies recursive patterns in computer science by showcasing how complex problems are broken down into simpler subproblems, with systems taking advantage of the call stack for temporary bookkeeping.

Using arrays, a stack has a fixed size, and the operations like push and pop involve updating a 'top' index to track the top element of the stack. For a queue implemented with arrays, 'front' and 'rear' indices manage the insertion and deletion operations. These implementations have predictable memory allocation but are limited by the static size of the array . In contrast, using linked lists allows stacks and queues to grow dynamically, with nodes comprising data and a pointer to the next element. Stacks with linked lists involve pushing elements by inserting at the head and popping by removing from the head. Queues involve pointers at both the front and rear, which are updated during enqueue and dequeue operations respectively. This approach provides flexibility in memory usage as it allows dynamic resizing and is not constrained by initial memory allocation size .

Recursion uses the system stack to manage function calls, where each call is pushed onto the stack as a new stack frame containing the function's local variables and the return address. As each recursive call is made, a new frame is pushed onto the stack, and once the base case is reached, function calls begin to return, executing from the top frame and unwinding the stack . This usage can impact memory significantly, especially for deep recursive calls, as each invocation consumes additional stack space, potentially leading to a stack overflow if the recursion is too deep or if extensive local data is stored in each frame.

In a stack, the operations are based on the LIFO (Last In First Out) principle, meaning the last element added is the first to be removed. This is implemented with operations such as push (adding an element to the top) and pop (removing the top element). A stack can be implemented using arrays or linked lists, and it is characterized by a 'top' pointer that monitors the top element of the stack . Meanwhile, a queue operates on the FIFO (First In First Out) principle, where the first element added is the first one to be removed. This is managed with enqueue (adding an element to the rear) and dequeue (removing the element at the front). Queues can also be implemented using arrays or linked lists, with 'front' and 'rear' pointers to track the respective ends .

Stacks are particularly suitable for expression evaluation and conversion from infix to postfix due to their LIFO nature, which aligns well with the order of operations and precedence handling required in expressions. In infix to postfix conversion, operators are pushed onto the stack until a lower precedence operator or a parenthesis is encountered, at which point they are popped from the stack until the condition no longer holds, enabling the proper application of the operator precedence rules. This process allows handling expressions without considering precedence explicitly in the resulting postfix expression, as the order of operations is captured inherently by the stack manipulation . The ability to undo the latest action (pop) efficiently suits the need to backtrack nested operations and ensure their correct placement in the output expression.

The core distinction between priority queues and standard queues is in their operational behavior; while standard queues adhere strictly to the FIFO order, priority queues require elements to be dequeued based on priority rather than the time of enqueue. In a priority queue, each element is associated with a priority, and the highest priority element is served first, which often results in more complex internal management to ensure elements are sorted by priority. This could involve maintaining a heap data structure (commonly a binary heap) or other sorting mechanisms to allow efficient insertion (O(log n) in heaps) and removal of the highest priority element (also O(log n) for heaps), as opposed to the O(1) enqueue and dequeue operations of simple queues . These complexities provide priority-driven processing beneficial for applications like job scheduling where tasks need processing based on urgency rather than arrival time.

A circular queue connects the last position of the queue back to the first position, effectively forming a loop. This allows a better utilization of the storage space by reusing the empty slots left by dequeued elements once the end of the queue is reached, thus avoiding the queue overflow issue when there are empty slots at the beginning of the queue. This is achieved using the formula rear = (rear + 1) % size for computing the position of the rear for enqueue operations . In contrast, a standard queue may leave unused memory in the beginning after several dequeue operations, and could result in a potential underuse of allotted space without programmatic recycling of space.

Deques (double-ended queues) offer significant structural advantages over ordinary stacks and queues by allowing insertion and deletion of elements from both ends, providing increased flexibility. This dual capability makes deques particularly well-suited for problems requiring access from both ends, such as sliding window problems where windows need to dynamically extend or contract from either side efficiently . In contrast, stacks restrict access to only one end, and queues restrict it to one end for insertion and the other for deletion, making them less adaptable for such bidirectional processing. The deque's properties enable applications requiring adjustments at both ends without significant overhead, offering better performance in cases such as managing time-bound data streams or maintaining state over moving intervals.

In a stack implemented using arrays, the 'push' operation involves adding an element to the stack at the position indicated by the 'top' index, that is incremented each time a push is made. Conversely, 'pop' involves returning the element at the current 'top' index and decrementing the 'top' index to remove the element . With a linked list implementation, a 'push' operation involves allocating a new node and inserting it at the head of the list to become the new top, effectively linking it to the previous top node. The 'pop' operation removes the node at the head, effectively advancing the head pointer to the next node in the list . This approach allows more dynamic growth as elements are added.

You might also like