Stack Implementation Using Linked List in DSA C - Time & Space Complexity
We want to understand how fast stack operations run when using a linked list.
Specifically, how does the time to push or pop items change as the stack grows?
Analyze the time complexity of the following code snippet.
// Push operation in stack using linked list
void push(Node** top, int value) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = value;
newNode->next = *top;
*top = newNode;
}
// Pop operation in stack using linked list
int pop(Node** top) {
if (*top == NULL) return -1; // stack empty
Node* temp = *top;
int val = temp->data;
*top = temp->next;
free(temp);
return val;
}
This code adds or removes items at the start of the linked list to simulate stack push and pop.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Adding or removing one node at the head of the linked list.
- How many times: Each push or pop does this once, no loops involved.
Each push or pop takes the same steps no matter how many items are in the stack.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 5 steps (allocate, assign, link, update pointer, free) |
| 100 | 5 steps (same as above) |
| 1000 | 5 steps (same as above) |
Pattern observation: The number of steps stays the same regardless of stack size.
Time Complexity: O(1)
This means push and pop operations take constant time no matter how big the stack is.
[X] Wrong: "Push or pop takes longer as the stack grows because more nodes exist."
[OK] Correct: Push and pop only change the top node, so they do not need to look at other nodes.
Knowing that stack operations with linked lists run in constant time shows you understand efficient data structure design.
"What if we implemented the stack using an array instead of a linked list? How would the time complexity change for push and pop?"
Practice
Solution
Step 1: Understand stack size limitation in arrays
Arrays have fixed size, so stack implemented with arrays has a maximum capacity.Step 2: Linked list dynamic size
Linked lists allocate memory dynamically, so the stack can grow as needed without fixed size.Final Answer:
The stack can grow dynamically without a fixed size limit -> Option AQuick Check:
Dynamic size = Advantage of linked list stack [OK]
- Thinking linked list uses less memory always
- Confusing stack with queue behavior
- Assuming random access is possible in stack
Solution
Step 1: Understand node structure for linked list
A node must hold data and a pointer to the next node.Step 2: Check pointer types
Next must be a pointer to struct Node, not an int or struct Node itself.Final Answer:
struct Node { int data; struct Node* next; }; -> Option CQuick Check:
Node has data + pointer to next [OK]
- Using int instead of pointer for next
- Declaring next as struct Node instead of pointer
- Using pointer for data unnecessarily
void push(struct Node** top_ref, int new_data) {
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = *top_ref;
*top_ref = new_node;
}
// Initial stack is empty (top_ref = NULL)
push(&top, 10);
push(&top, 20);
push(&top, 30);
What will be the order of elements in the stack from top to bottom after these pushes?Solution
Step 1: Trace first push(10)
Stack top points to node with data 10, next is NULL.Step 2: Trace second push(20) and third push(30)
Each new node becomes top, so order is 30 (top) -> 20 -> 10 -> NULL.Final Answer:
30 -> 20 -> 10 -> NULL -> Option BQuick Check:
Last pushed is top = 30 [OK]
- Assuming order is insertion order (FIFO)
- Confusing next pointer direction
- Forgetting top points to last pushed node
int pop(struct Node** top_ref) {
struct Node* temp;
int popped;
if (*top_ref == NULL) {
printf("Stack Underflow\n");
return -1;
}
temp = *top_ref;
popped = temp->data;
*top_ref = temp->next;
free(temp);
return popped;
}
Solution
Step 1: Check for empty stack
Code correctly checks if *top_ref is NULL and returns underflow error.Step 2: Pop operation correctness
It saves top node, retrieves data, updates top to next node, frees old top, and returns data.Final Answer:
No error, code correctly pops the top element -> Option DQuick Check:
Pop code with free and update top is correct [OK]
- Forgetting to free popped node causing memory leak
- Not checking for empty stack before pop
- Incorrectly updating top pointer
reverseStack that reverses the elements of a stack implemented using a linked list without using any extra stack or array. Which approach is correct?Solution
Step 1: Understand constraints
No extra stack or array allowed, so iterative copying or extra data structures are not allowed.Step 2: Use recursion to reverse
Recursion can pop all elements, then push them back in reverse order naturally using call stack.Step 3: Other options use extra data or incorrect method
Swapping data repeatedly is complex and error-prone; copying creates extra list; queue uses extra structure.Final Answer:
Use recursion to pop all elements, then push them back in reverse order -> Option AQuick Check:
Recursion reverses stack without extra data structures [OK]
- Trying to swap node data instead of rearranging nodes
- Using extra arrays or stacks against constraints
- Confusing queue usage for stack reversal
Ready to prove it?
Pass the test and this pattern moves unknown
