Sorting Stability and When to Use Which Sort in DSA Go - Time & Space Complexity
Sorting algorithms arrange data in order, but they differ in speed and behavior.
We want to understand how their running time changes as data size grows and when to pick each sort.
Analyze the time complexity of different sorting algorithms.
// Example: Bubble Sort
func bubbleSort(arr []int) {
n := len(arr)
for i := 0; i < n-1; i++ {
for j := 0; j < n-i-1; j++ {
if arr[j] > arr[j+1] {
arr[j], arr[j+1] = arr[j+1], arr[j]
}
}
}
}
// Example: Merge Sort
func mergeSort(arr []int) []int {
if len(arr) <= 1 {
return arr
}
mid := len(arr) / 2
left := mergeSort(arr[:mid])
right := mergeSort(arr[mid:])
return merge(left, right)
}
func merge(left, right []int) []int {
result := []int{}
i, j := 0, 0
for i < len(left) && j < len(right) {
if left[i] <= right[j] {
result = append(result, left[i])
i++
} else {
result = append(result, right[j])
j++
}
}
result = append(result, left[i:]...)
result = append(result, right[j:]...)
return result
}
This code shows Bubble Sort and Merge Sort, two common sorting methods with different speeds and stability.
Look at the loops and recursion that repeat work.
- Bubble Sort: Nested loops comparing and swapping elements repeatedly.
- Merge Sort: Recursion splitting array and merging sorted parts.
- Dominant operation: Comparisons and swaps in Bubble Sort; recursive splitting and merging in Merge Sort.
As input size grows, the work done changes differently for each sort.
| Input Size (n) | Bubble Sort Operations | Merge Sort Operations |
|---|---|---|
| 10 | About 45 comparisons | About 30 comparisons |
| 100 | About 4,950 comparisons | About 664 comparisons |
| 1000 | About 499,500 comparisons | About 9,966 comparisons |
Bubble Sort grows very fast (square of n), Merge Sort grows slower (n times log n).
Time Complexity: O(n²) for Bubble Sort, O(n log n) for Merge Sort
Bubble Sort gets much slower as data grows; Merge Sort stays efficient even for large data.
[X] Wrong: "All sorting algorithms are equally fast for any data size."
[OK] Correct: Some sorts like Bubble Sort slow down a lot with more data, while others like Merge Sort handle growth better.
Knowing sorting speeds and stability helps you pick the right tool for the job and explain your choices clearly.
"What if we used Quick Sort instead of Merge Sort? How would the time complexity and stability change?"
Practice
stable?Solution
Step 1: Understand stability in sorting
A stable sort keeps the relative order of items that compare equal the same as before sorting.Step 2: Compare options
Only It keeps the original order of equal elements after sorting describes this property correctly. Other options describe speed, memory, or data type restrictions, which are unrelated to stability.Final Answer:
It keeps the original order of equal elements after sorting -> Option AQuick Check:
Stable sort = keeps equal items order [OK]
- Confusing stability with speed
- Thinking stability means less memory use
- Believing stability depends on data type
sort.SliceStable function to sort a slice of structs by an integer field Age?Solution
Step 1: Identify stable sort usage
The question asks for stable sorting by Age ascending.sort.SliceStableis the stable function.Step 2: Check comparison function
The comparison must bepeople[i].Age < people[j].Agefor ascending order.Final Answer:
sort.SliceStable(people, func(i, j int) bool { return people[i].Age < people[j].Age }) -> Option DQuick Check:
Stable + ascending = sort.SliceStable(people, func(i, j int) bool { return people[i].Age < people[j].Age }) [OK]
- Using sort.Slice instead of sort.SliceStable
- Reversing comparison for ascending order
- Mixing stable and unstable sort functions
type Item struct {
Name string
Rank int
}
items := []Item{{"A", 2}, {"B", 1}, {"C", 2}}
sort.Slice(items, func(i, j int) bool { return items[i].Rank < items[j].Rank })
for _, item := range items {
fmt.Print(item.Name, " ")
}Solution
Step 1: Understand sorting criteria
The slice is sorted by Rank ascending usingsort.Slice, which is unstable.Step 2: Analyze order of equal Rank elements
Items with Rank 2 are "A" and "C". Sincesort.Sliceis unstable, their relative order may change. The output shows "B" first (Rank 1), then "C", then "A".Final Answer:
B C A -> Option CQuick Check:
Unstable sort may change equal items order [OK]
- Assuming stable order with sort.Slice
- Mixing up item names and ranks
- Ignoring unstable sort behavior
words := []string{"cat", "bat", "apple", "dog"}
sort.Slice(words, func(i, j int) bool { return len(words[i]) < len(words[j]) })Solution
Step 1: Identify sorting function used
The code usessort.Slice, which is unstable.Step 2: Understand stability requirement
To sort stably by length,sort.SliceStablemust be used instead.Final Answer:
Using sort.Slice instead of sort.SliceStable causes unstable sort -> Option AQuick Check:
Stable sort requires SliceStable, not Slice [OK]
- Thinking comparison direction affects stability
- Believing slice type conversion is needed
- Assuming sort.Slice is stable
Name and Department. You want to sort them first by Department alphabetically and then by Name alphabetically within each department, preserving the order of employees with the same name. Which sorting approach is best in Go?Solution
Step 1: Understand multi-level sorting with stability
To sort by Department then Name, stable sorts allow sorting by the secondary key first, then primary key.Step 2: Apply stable sorts in correct order
Sort first by Name (secondary key) stably, then by Department (primary key) stably. This preserves Name order within Departments.Final Answer:
Use two stable sorts: first by Name, then by Department -> Option BQuick Check:
Two stable sorts in reverse order = correct multi-level sort [OK]
- Using unstable sorts causing order loss
- Sorting primary key first losing secondary order
- Trying one sort on combined keys without stability
Ready to prove it?
Pass the test and this pattern moves unknown
