Create and Initialize Doubly Linked List in DSA Go - Time & Space Complexity
When we create and initialize a doubly linked list, we want to know how the time needed grows as we add more items.
We ask: How much work does it take to build this list as it gets bigger?
Analyze the time complexity of the following code snippet.
package main
type Node struct {
data int
prev *Node
next *Node
}
type DoublyLinkedList struct {
head *Node
tail *Node
}
func (dll *DoublyLinkedList) Append(value int) {
newNode := &Node{data: value}
if dll.head == nil {
dll.head = newNode
dll.tail = newNode
return
}
dll.tail.next = newNode
newNode.prev = dll.tail
dll.tail = newNode
}
func main() {
dll := &DoublyLinkedList{}
for i := 1; i <= 5; i++ {
dll.Append(i)
}
}
This code creates a doubly linked list and adds 5 nodes to it, one by one.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The loop in main calls Append 5 times.
- How many times: Once per item added, so n times for n items.
- Each Append adds one node by updating pointers in constant steps.
Each new item requires a fixed number of steps to add, no matter how big the list is.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 append steps |
| 100 | About 100 append steps |
| 1000 | About 1000 append steps |
Pattern observation: The work grows directly with the number of items added.
Time Complexity: O(n)
This means adding n items takes time proportional to n; doubling items roughly doubles the work.
[X] Wrong: "Appending to a doubly linked list takes more time as the list grows because we must traverse it."
[OK] Correct: The code keeps a pointer to the tail, so it adds new nodes directly without walking through the list.
Understanding how adding nodes works helps you explain linked list operations clearly and shows you know how to manage pointers efficiently.
"What if we did not keep a tail pointer and had to find the end each time? How would the time complexity change?"
Practice
Solution
Step 1: Understand doubly linked list structure
A doubly linked list has nodes with pointers to both previous and next nodes.Step 2: Identify traversal capability
This structure allows moving forward and backward through the list easily.Final Answer:
To allow traversal in both forward and backward directions -> Option CQuick Check:
Doubly linked list = bidirectional traversal [OK]
- Confusing doubly linked list with arrays
- Thinking it sorts data automatically
- Assuming it only moves forward
Solution
Step 1: Check pointer usage for next and prev
In Go, linked list nodes must use pointers to other nodes, so next and prev should be *Node.Step 2: Verify data types
Data is int, and next and prev are pointers to Node, matching type Node struct { data int; next *Node; prev *Node }.Final Answer:
type Node struct { data int; next *Node; prev *Node } -> Option AQuick Check:
Pointers for next and prev = type Node struct { data int; next *Node; prev *Node } [OK]
- Using value types instead of pointers for next/prev
- Using wrong pointer types like *int
- Missing semicolons or commas (Go allows semicolons but usually uses new lines)
package main
import "fmt"
type Node struct {
data int
next *Node
prev *Node
}
func main() {
head := &Node{data: 1}
second := &Node{data: 2}
third := &Node{data: 3}
head.next = second
second.prev = head
second.next = third
third.prev = second
current := head
for current != nil {
fmt.Print(current.data)
if current.next != nil {
fmt.Print(" -> ")
}
current = current.next
}
fmt.Println(" -> null")
}Solution
Step 1: Understand list creation and linking
Nodes 1, 2, 3 are linked forward: head.next = second, second.next = third.Step 2: Trace forward traversal loop
Starting at head, prints 1, then 2, then 3, each followed by ' -> ', ending with ' -> null'.Final Answer:
1 -> 2 -> 3 -> null -> Option DQuick Check:
Forward traversal prints nodes in order [OK]
- Confusing forward and backward traversal
- Missing arrows in output
- Printing data without separators
type Node struct {
data int
next *Node
prev *Node
}
func main() {
node := Node{data: 10, next: nil, prev: nil}
node.next.prev = &node
}Solution
Step 1: Analyze node initialization
node.next is set to nil, so node.next does not point to any node.Step 2: Check node.next.prev assignment
Accessing node.next.prev tries to dereference nil, causing runtime panic (nil pointer dereference).Final Answer:
node.next is nil, so node.next.prev causes a runtime panic -> Option BQuick Check:
Dereferencing nil pointer = runtime panic [OK]
- Ignoring nil pointer dereference
- Thinking &node is needed for struct literal
- Confusing data type requirements
Solution
Step 1: Check pointer usage and linking
head := &Node{data: 5} second := &Node{data: 10} third := &Node{data: 15} fourth := &Node{data: 20} head.next = second second.prev = head second.next = third third.prev = second third.next = fourth fourth.prev = third uses pointers for all nodes and sets next and prev pointers explicitly and correctly.Step 2: Verify all links are consistent
Each node's next points forward, and prev points backward, matching doubly linked list rules.Final Answer:
Code snippet in Option A correctly initializes and links all nodes -> Option AQuick Check:
Proper pointer linking = head := &Node{data: 5} second := &Node{data: 10} third := &Node{data: 15} fourth := &Node{data: 20} head.next = second second.prev = head second.next = third third.prev = second third.next = fourth fourth.prev = third [OK]
- Using value types instead of pointers for nodes
- Not setting prev pointers
- Incorrect nested initialization causing nil prev
Ready to prove it?
Pass the test and this pattern moves unknown
