Sort a Linked List Using Merge Sort in DSA Go - Time & Space Complexity
We want to understand how the time needed to sort a linked list grows as the list gets bigger.
Specifically, how does merge sort handle this task efficiently?
Analyze the time complexity of the following code snippet.
func mergeSort(head *Node) *Node {
if head == nil || head.next == nil {
return head
}
middle := getMiddle(head)
nextToMiddle := middle.next
middle.next = nil
left := mergeSort(head)
right := mergeSort(nextToMiddle)
sortedList := sortedMerge(left, right)
return sortedList
}
This code splits the linked list into halves recursively and merges sorted halves back together.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursively splitting the list and merging sorted halves.
- How many times: The list is split about log n times, and merging touches all nodes each time.
As the list size doubles, the number of splitting steps grows slowly, but merging touches all nodes each time.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 * 4 = 40 |
| 100 | About 100 * 7 = 700 |
| 1000 | About 1000 * 10 = 10,000 |
Pattern observation: Operations grow roughly as n times log n, meaning growth is faster than linear but much slower than quadratic.
Time Complexity: O(n log n)
This means the time to sort grows a bit faster than the list size but stays efficient even for large lists.
[X] Wrong: "Merge sort on linked list is as slow as bubble sort, so it takes O(n²) time."
[OK] Correct: Merge sort splits the list and merges efficiently, touching each node only a few times, so it runs much faster than bubble sort.
Understanding merge sort on linked lists shows you can handle recursion and linked data well, a skill useful in many coding challenges.
"What if we used quicksort instead of merge sort on the linked list? How would the time complexity change?"
Practice
Solution
Step 1: Understand merge sort with linked lists
Merge sort splits the list into halves recursively and merges sorted halves. It works well with linked lists because it does not need random access.Step 2: Compare with other sorting methods
Other sorts like quicksort or bubble sort may require extra space or inefficient node access. Merge sort uses pointers efficiently without extra arrays.Final Answer:
It does not require extra space for arrays and works efficiently with linked lists. -> Option DQuick Check:
Merge sort suits linked lists due to pointer use, no extra array needed [OK]
- Thinking merge sort swaps adjacent nodes only
- Assuming merge sort sorts in one pass
- Believing merge sort compares only first and last elements
Solution
Step 1: Identify parameter types for linked list nodes
Linked lists use pointers to nodes, so parameters must be pointers: *Node.Step 2: Identify return type for merged list head
The merge function returns the head pointer of the merged sorted list, so return type is *Node.Final Answer:
func merge(left *Node, right *Node) *Node -> Option BQuick Check:
Merge uses pointers and returns pointer to merged list head [OK]
- Using value types instead of pointers for nodes
- Returning int instead of node pointer
- Using slices instead of linked list nodes
Solution
Step 1: Split the list recursively
Split into halves: (4 -> 2) and (1 -> 3). Then split further until single nodes.Step 2: Merge sorted halves
Merge single nodes in order: 2 -> 4 and 1 -> 3 become 1 -> 2 -> 3 -> 4.Final Answer:
1 -> 2 -> 3 -> 4 -> null -> Option CQuick Check:
Sorted order is ascending: 1, 2, 3, 4 [OK]
- Confusing merge order and producing descending list
- Not splitting list fully before merging
- Mixing node values during merge
func mergeSort(head *Node) *Node {
if head == nil || head.next == nil {
return head
}
mid := getMiddle(head)
left := head
right := mid.next
mid.next = nil
left = mergeSort(left)
right = mergeSort(right)
return merge(left, right)
}
func getMiddle(head *Node) *Node {
slow, fast := head, head.next
for fast != nil && fast.next != nil {
slow = slow.next
fast = fast.next.next
}
return slow
}Solution
Step 1: Analyze getMiddle function
Fast starts at head.next to find middle node correctly for even length lists.Step 2: Check mergeSort logic
Splits list at mid, sets mid.next to nil to break list, recursively sorts left and right, then merges.Final Answer:
No error; code correctly splits and merges the list. -> Option AQuick Check:
Code uses standard merge sort steps correctly [OK]
- Initializing fast pointer incorrectly causing wrong middle
- Breaking list after recursion causing infinite loops
- Wrong return type for mergeSort function
Solution
Step 1: Understand merge sort handles duplicates
Merge sort compares node values and merges in ascending order, preserving duplicates in sorted order.Step 2: Sort the list step-by-step
Splitting and merging results in sorted order: 3, 3, 5, 5, 8.Final Answer:
3 -> 3 -> 5 -> 5 -> 8 -> null -> Option AQuick Check:
Duplicates appear in sorted order, merge sort preserves all nodes [OK]
- Removing duplicates accidentally during merge
- Sorting incorrectly and mixing node order
- Assuming duplicates are removed automatically
Ready to prove it?
Pass the test and this pattern moves unknown
