Insert at End Tail Insert in DSA Go - Time & Space Complexity
We want to understand how long it takes to add a new item at the end of a linked list.
How does the time needed change as the list grows bigger?
Analyze the time complexity of the following code snippet.
// Insert a new node at the end of a singly linked list
type Node struct {
value int
next *Node
}
func InsertAtEnd(head *Node, val int) *Node {
newNode := &Node{value: val, next: nil}
if head == nil {
return newNode
}
current := head
for current.next != nil {
current = current.next
}
current.next = newNode
return head
}
This code adds a new node at the end by walking through the list until it finds the last node.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Loop that moves through each node until the last one.
- How many times: Once for each node in the list until the end (depends on list length).
As the list gets longer, the time to find the end grows roughly in a straight line with the number of nodes.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 steps to reach the end |
| 100 | About 100 steps to reach the end |
| 1000 | About 1000 steps to reach the end |
Pattern observation: The time grows directly with the number of nodes; doubling nodes roughly doubles the work.
Time Complexity: O(n)
This means the time to insert at the end grows linearly with the list size.
[X] Wrong: "Inserting at the end is always fast and takes constant time."
[OK] Correct: Without a direct pointer to the last node, we must walk through the whole list, so time grows with list length.
Understanding this helps you explain why some linked list designs keep a tail pointer to speed up end insertions.
"What if we kept a pointer to the last node (tail)? How would the time complexity change?"
Practice
Solution
Step 1: Understand the operation name
"Insert at End" means adding a new element at the tail or last position of the list.Step 2: Compare with other options
Adding at the beginning is different, and deleting nodes is not insertion.Final Answer:
Adds a new node at the end of the list -> Option CQuick Check:
Insert at End = Add node at tail [OK]
- Confusing insert at end with insert at beginning
- Thinking it deletes nodes
- Assuming it inserts in the middle
Solution
Step 1: Understand Go struct initialization
In Go, to create a pointer to a struct with named fields, use &Node{field: value, ...}.Step 2: Check each option
newNode := &Node{data: value, next: nil} correctly uses &Node with named fields and sets next to nil for tail node.Final Answer:
newNode := &Node{data: value, next: nil} -> Option BQuick Check:
Pointer to struct with named fields = newNode := &Node{data: value, next: nil} [OK]
- Missing & to create pointer
- Not setting next to nil for tail
- Using unnamed fields incorrectly
Solution
Step 1: Understand tail insert effect
Inserting 4 at the end adds it after 3, so list becomes 1 -> 2 -> 3 -> 4 -> nil.Step 2: Compare options
Only 1 -> 2 -> 3 -> 4 -> nil shows 4 at the end; others show wrong order or no change.Final Answer:
1 -> 2 -> 3 -> 4 -> nil -> Option AQuick Check:
Tail insert adds node at end [OK]
- Inserting at beginning instead of end
- Inserting in the middle
- Not updating last node's next pointer
func InsertAtEnd(head *Node, value int) *Node {
newNode := &Node{data: value, next: nil}
if head == nil {
head = newNode
} else {
temp := head
for temp.next != nil {
temp = temp.next
}
temp = newNode
}
return head
}Solution
Step 1: Analyze the loop and insertion
The loop finds the last node (temp.next == nil). Then temp = newNode only changes temp pointer, not the last node's next.Step 2: Identify correct linking
To insert, we must set temp.next = newNode, not temp = newNode.Final Answer:
temp = newNode does not link newNode to the list -> Option AQuick Check:
Link last node's next to newNode [OK]
- Assigning newNode to temp instead of temp.next
- Not handling empty list correctly
- Wrong loop condition
Solution
Step 1: Understand repeated tail insert cost
Traversing from head to end for each insert is costly (O(n) per insert), total O(n^2).Step 2: Use tail pointer optimization
Keeping a tail pointer allows direct access to last node, so insertion is O(1) each, total O(n).Final Answer:
Keep a tail pointer to last node and update it on each insert -> Option DQuick Check:
Tail pointer reduces insertion time [OK]
- Traversing full list every time
- Inserting at beginning instead of end
- Creating multiple lists unnecessarily
Ready to prove it?
Pass the test and this pattern moves unknown
