Stack Implementation Using Linked List in DSA Python - Time & Space Complexity
We want to understand how fast stack operations run when using a linked list.
How does the time to push or pop change as the stack grows?
Analyze the time complexity of the following stack operations using a linked list.
class Node:
def __init__(self, data):
self.data = data
self.next = None
class Stack:
def __init__(self):
self.top = None
def push(self, data):
new_node = Node(data)
new_node.next = self.top
self.top = new_node
def pop(self):
if self.top is None:
return None
popped = self.top.data
self.top = self.top.next
return popped
This code adds (push) and removes (pop) items at the top of the stack using linked nodes.
Look for loops or repeated steps in push and pop.
- Primary operation: Assigning pointers to add or remove the top node.
- How many times: Each push or pop does a fixed number of steps, no loops.
Each push or pop takes the same small number of steps no matter how big the stack is.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 5-6 steps per push/pop |
| 100 | 5-6 steps per push/pop |
| 1000 | 5-6 steps per push/pop |
Pattern observation: The time stays about the same no matter how many items are in the stack.
Time Complexity: O(1)
This means each push or pop happens in constant time, quickly and independently of stack size.
[X] Wrong: "Push or pop takes longer as the stack grows because there are more nodes."
[OK] Correct: Push and pop only change the top node pointer, so they do not look through the whole stack.
Knowing that stack operations with linked lists run in constant time shows you understand efficient data handling, a key skill in coding interviews.
"What if we changed the stack to use an array instead of a linked list? How would the time complexity of push and pop change?"
Practice
Solution
Step 1: Understand stack size limitation in arrays
Arrays have a fixed size, so stacks implemented with arrays have a maximum capacity.Step 2: Linked list dynamic size advantage
Linked lists allocate memory dynamically, so the stack can grow as needed without size limits.Final Answer:
The stack can grow dynamically without a fixed size limit -> Option AQuick Check:
Linked list stacks grow dynamically [OK]
- Thinking linked lists use less memory always
- Confusing stack with queue behavior
- Assuming random access is possible in stacks
Solution
Step 1: Check Node class constructor parameters
The node should store data and a pointer to next node, initialized to None.Step 2: Verify correct attribute assignment
class Node:\n def __init__(self, data):\n self.data = data\n self.next = None correctly assigns data and sets next to None for a new node.Final Answer:
class Node:\n def __init__(self, data):\n self.data = data\n self.next = None -> Option CQuick Check:
Node stores data and next pointer [OK]
- Swapping data and next assignments
- Forgetting to initialize next to None
- Adding unnecessary parameters in constructor
class Node:
def __init__(self, data):
self.data = data
self.next = None
class Stack:
def __init__(self):
self.top = None
def push(self, data):
new_node = Node(data)
new_node.next = self.top
self.top = new_node
def print_stack(self):
current = self.top
while current:
print(current.data, end=' -> ')
current = current.next
print('null')
stack = Stack()
stack.push(10)
stack.push(20)
stack.push(30)
stack.print_stack()Solution
Step 1: Trace push operations
Push 10: top points to node with 10. Push 20: new node with 20 points to 10, top updated to 20. Push 30: new node with 30 points to 20, top updated to 30.Step 2: Trace print_stack output
Print starts at top (30), then 20, then 10, then null.Final Answer:
30 -> 20 -> 10 -> null -> Option AQuick Check:
Stack top is last pushed [OK]
- Printing in insertion order instead of stack order
- Confusing next pointer direction
- Forgetting to print null at end
def pop(self):
if self.top is None:
return None
popped_node = self.top
self.top = popped_node.next
return popped_nodeSolution
Step 1: Understand pop method return value
Pop should return the data of the popped node, not the node object itself.Step 2: Fix return statement
Change return popped_node to return popped_node.data to return the value.Final Answer:
Return popped_node.data instead of popped_node -> Option DQuick Check:
Pop returns data, not node object [OK]
- Returning node object instead of data
- Not updating top pointer
- Not handling empty stack case
reverse_stack that reverses the elements of a stack implemented using a linked list without using extra data structures. Which approach correctly achieves this?Solution
Step 1: Understand constraints - no extra data structures
Options C and D use extra structures (array or new stack), so they are invalid.Step 2: Recursive approach to reverse stack
Recursively pop elements until empty, then push them back in reverse order using call stack, reversing the stack without extra storage.Final Answer:
Recursively pop all elements, then push them back in reverse order -> Option BQuick Check:
Recursion reverses stack without extra data structures [OK]
- Using extra arrays or stacks despite constraints
- Trying to swap node data incorrectly
- Not handling base case in recursion
Ready to prove it?
Pass the test and this pattern moves unknown
