This is a 3-day lab focusing on the functional implementation of stacks and queues. In a functional style, data structures are immutable; instead of modifying an existing structure, every operation returns a new version of that structure.
| Date | Topic | Data Structure |
|---|---|---|
| Day 1 — April 20 | Array Stack | ArrayList wrapper |
| Day 2 — April 22 | Array Queue | ArrayList wrapper |
| Day 3 — April 24 | Linked List Stacks & Queues | Two-Stack Queue (Linked List) |
In this part of the lab, you will complete the implementation of a stack built on top of an underlying array.
The ArrayStack is a wrapper around an underlying ArrayList structure.
@dataclass
class ArrayStack:
stack: ArrayListImportant
Functional Requirements:
- Do not mutate the original stack.
- Always return a new
ArrayStack. - The original stack must remain unchanged.
Complete the following functions in the provided template:
pushpoppeekis_empty
push(s, n): Appendnto the array; return a new stack.pop(s): Get the top value; remove the top value; return both the value and the new stack.peek(s): Return the top value without removing it.is_empty(s): Check if the stack size is 0.
- The top of the stack corresponds to the last logical element in the underlying array.
popmust return a tuple:(removed_value, new_stack).
You will implement a queue using an underlying array, following the First In, First Out (FIFO) principle.
@dataclass
class ArrayQueue:
queue: ArrayListImportant
This lab uses an immutable/functional style. Every operation must return a new queue state while leaving the original untouched. Use the helper functions from array_code.py.
- Enqueue: Items are added at the back (end of the array).
- Dequeue: Items are removed from the front (index 0).
- Peek: Look at the front (index 0).
enqueue(q, n): Appendnto the array; return a new queue.dequeue(q): Get value at index 0; delete value at index 0; return both value and new queue.peek(q): Return value at index 0.
Complete the array-based queue functions in lab4_2.py.
You will implement a queue using two stacks, where each stack is represented by an immutable linked list. This is a classic functional programming pattern to achieve efficient queue operations.
@dataclass(frozen=True)
class TwoStackQueue:
read: Node | None = None
write: Node | None = Noneread: A linked list storing items ready to be removed from the front.write: A linked list storing newly added items (in reverse order).
Important
Immutability: Both the linked lists and the TwoStackQueue wrapper are frozen. You must initialize and return new structures for every operation.
enqueue(s, v):- Add value
vas the new head of thewritestack. - Return a new
TwoStackQueue.
- Add value
dequeue(s):- If
readis empty: Reverse thewritestack and make it the newreadstack. - Remove the head of the
readstack. - Return the value and the new
TwoStackQueue.
- If
peek(s):- If
readis empty: Reversewriteintoread. - Return the head value of the
readstack.
- If
is_empty(s):- Returns
Trueonly if bothreadandwriteare empty.
- Returns
- Use
new_headfromlinked_list.pyto push onto thewritestack. - Use the
reversefunction when thereadstack is empty. - Never modify existing nodes.
Complete the TwoStackQueue functions in lab4_3.py.