Insert at Beginning of Circular Linked List in DSA Go - Time & Space Complexity
We want to understand how the time needed changes when we insert a new node at the start of a circular linked list.
How does the number of steps grow as the list gets bigger?
Analyze the time complexity of the following code snippet.
// Insert new node at beginning of circular linked list
func insertAtBeginning(head *Node, data int) *Node {
newNode := &Node{data: data}
if head == nil {
newNode.next = newNode
return newNode
}
temp := head
for temp.next != head {
temp = temp.next
}
temp.next = newNode
newNode.next = head
return newNode
}
This code adds a new node at the start of a circular linked list by first finding the last node, then linking the new node before the current head.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Loop to find the last node (where next points back to head).
- How many times: This loop runs once for each node in the list until it reaches the last node, so it runs n times for a list of size n.
As the list grows, the loop to find the last node takes longer because it checks each node once.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 steps to find last node |
| 100 | About 100 steps to find last node |
| 1000 | About 1000 steps to find last node |
Pattern observation: The number of steps grows directly with the size of the list.
Time Complexity: O(n)
This means the time to insert at the beginning grows linearly with the number of nodes in the list.
[X] Wrong: "Inserting at the beginning is always O(1) because we just change a few pointers."
[OK] Correct: In a circular linked list, we must find the last node to update its pointer, which takes time proportional to the list size, so it is not constant time.
Understanding this helps you explain how linked list operations work in real systems, showing you can analyze and improve data structure efficiency.
"What if we kept a pointer to the last node? How would the time complexity of inserting at the beginning change?"
Practice
Solution
Step 1: Understand the circular linked list structure
A circular linked list has its last node pointing back to the head, forming a circle.Step 2: Insert new node at beginning
The new node is linked to the current head, and the last node's next pointer is updated to this new node, making it the new head.Final Answer:
The new node becomes the head and points to the old head, maintaining the circular link. -> Option AQuick Check:
New head points to old head, circle intact = A [OK]
- Not updating last node's next pointer
- Breaking the circular link
- Adding node at end instead of beginning
Solution
Step 1: Link new node to current head
Assign newNode.next = head to point new node to the current head.Step 2: Update last node to point to new node and update head
Set last.next = newNode to maintain circular link, then update head = newNode.Final Answer:
newNode.next = head last.next = newNode head = newNode -> Option CQuick Check:
Correct pointer updates = B [OK]
- Setting newNode.next to nil breaks circular link
- Not updating last.next to new node
- Incorrect order of pointer assignments
func printList(head *Node) {
if head == nil {
fmt.Println("List is empty")
return
}
temp := head
for {
fmt.Printf("%d -> ", temp.data)
temp = temp.next
if temp == head {
break
}
}
fmt.Println("null")
}
// Insert 10 at beginning
newNode := &Node{data: 10}
// Assume last points to node with 40
newNode.next = head
last.next = newNode
head = newNode
printList(head)Solution
Step 1: Insert new node 10 at beginning
New node 10 points to old head 20, last node 40 points to new node 10, head updated to 10.Step 2: Print list starting from new head
Traverse from 10: 10 -> 20 -> 30 -> 40, then stop at head again.Final Answer:
10 -> 20 -> 30 -> 40 -> null -> Option DQuick Check:
New head 10 followed by old nodes = A [OK]
- Printing extra node causing repeated values
- Not updating last.next causing infinite loop
- Confusing order of nodes after insertion
func insertAtBeginning(head *Node, data int) *Node {
newNode := &Node{data: data}
if head == nil {
newNode.next = newNode
return newNode
}
temp := head
for temp.next != nil {
temp = temp.next
}
newNode.next = head
temp.next = newNode
head = newNode
return head
}Solution
Step 1: Analyze loop condition for circular list
In circular linked list, last node's next points to head, so loop should check temp.next != head, not nil.Step 2: Identify impact of wrong condition
Checking temp.next != nil causes infinite loop or crash because next is never nil in circular list.Final Answer:
The loop condition should check for temp.next != head, not nil. -> Option BQuick Check:
Loop must stop at head, not nil [OK]
- Using nil instead of head in loop condition
- Not updating head after insertion
- Returning wrong pointer from function
Solution
Step 1: Link new node to current head
Assign newNode.next = head so new node points to old head.Step 2: Update last node to point to new node and update head
Find last node (with value 25) and set last.next = newNode to maintain circular link, then update head = newNode.Final Answer:
Set newNode.next = head; find last node and set last.next = newNode; update head = newNode -> Option AQuick Check:
New head points to old head; last points to new head [OK]
- Setting newNode.next to nil breaks circle
- Updating head before linking nodes
- Not updating last.next to new node
Ready to prove it?
Pass the test and this pattern moves unknown
