Insert at End of Doubly Linked List in DSA Go - Time & Space Complexity
We want to understand how the time to insert a new item at the end of a doubly linked list changes as the list grows.
How does the number of steps needed grow when the list gets longer?
Analyze the time complexity of the following code snippet.
// InsertAtEnd adds a new node with value at the end of the list
func (dll *DoublyLinkedList) InsertAtEnd(value int) {
newNode := &Node{data: value}
if dll.tail == nil {
dll.head = newNode
dll.tail = newNode
return
}
dll.tail.next = newNode
newNode.prev = dll.tail
dll.tail = newNode
}
This code adds a new node to the end of a doubly linked list by updating pointers.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Pointer updates to add the new node.
- How many times: Exactly once per insertion, no loops or traversals.
Each insertion takes the same small number of steps, no matter how long the list is.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 5 steps |
| 100 | 5 steps |
| 1000 | 5 steps |
Pattern observation: The number of steps stays the same as the list grows.
Time Complexity: O(1)
This means inserting at the end takes a constant amount of time, no matter how big the list is.
[X] Wrong: "Inserting at the end takes longer as the list grows because we have to find the end each time."
[OK] Correct: Because we keep a direct pointer to the tail node, we do not need to search; insertion is always quick.
Knowing this helps you explain why doubly linked lists are useful for quick insertions at both ends, a common interview topic.
"What if we did not keep a tail pointer? How would the time complexity change?"
Practice
Solution
Step 1: Understand the structure of a doubly linked list
A doubly linked list has nodes connected forward and backward, allowing traversal in both directions.Step 2: Identify the effect of inserting at the end
Inserting at the end means adding a new node after the current last node, updating pointers accordingly.Final Answer:
To add a new element after the last node -> Option AQuick Check:
Insert at end = add after last node [OK]
- Confusing insertion at end with deletion
- Thinking insertion reverses the list
- Assuming insertion happens at the start
Solution
Step 1: Identify the last node's next pointer update
When inserting at the end, the last node's next pointer should point to the new node.Step 2: Match correct pointer assignment
Setting last.next = newNode correctly links the last node to the new node.Final Answer:
last.next = newNode -> Option CQuick Check:
last.next points to new node [OK]
- Assigning newNode.prev to last.next incorrectly
- Setting newNode.next to last (wrong direction)
- Changing last.prev instead of last.next
Solution
Step 1: Insert 10 at end when list is empty
List becomes: 10 -> nullStep 2: Insert 20 at end
List becomes: 10 <-> 20 -> nullStep 3: Insert 30 at end
List becomes: 10 <-> 20 <-> 30 -> nullFinal Answer:
10 <-> 20 <-> 30 <-> null -> Option DQuick Check:
Insert order preserved from head to tail [OK]
- Assuming insertion reverses order
- Printing null at start instead of end
- Mixing node order in output
func InsertEnd(head *Node, data int) *Node {
newNode := &Node{data: data}
if head == nil {
head = newNode
} else {
temp := head
for temp.next != nil {
temp = temp.next
}
temp.next = newNode
newNode.prev = temp
}
return head
}Solution
Step 1: Check newNode pointer initialization
In Go, uninitialized pointers default to nil, but explicitly setting newNode.next = nil is safer.Step 2: Identify missing explicit next pointer assignment
The code does not set newNode.next = nil, which can cause issues if newNode is reused or inspected.Final Answer:
The newNode's next pointer is not set to nil -> Option BQuick Check:
Always set newNode.next = nil at insertion [OK]
- Ignoring explicit nil assignment for newNode.next
- Confusing prev and next pointers
- Incorrect loop condition for traversal
Solution
Step 1: Identify the last node before insertion
The last node is the one with value 25.Step 2: Update pointers to insert new node at end
Set last node's next to new node, new node's prev to last node, and new node's next to nil to mark end.Final Answer:
Set last node's next to new node, new node's prev to last node, new node's next to nil -> Option AQuick Check:
Last.next = new, new.prev = last, new.next = nil [OK]
- Reversing prev and next pointers
- Not setting new node's next to nil
- Changing head pointers incorrectly
Ready to prove it?
Pass the test and this pattern moves unknown
