核心原理
分分合合; 分:数组从中间不断拆分,直到都剩单个元素的数组(有序数组); 合:拿两组有序小数组,从头挨个比大小,小的先放进新数组,拼成一个大有序数组,层层往上合并;
通俗步骤
- 拆分:对半劈开,拆到只剩一个数;
- 合并:两个有序小数组,小头对比拣小;
- 再合并大数组;
- 不断合并直到全部有序;
举例演示 [3,1,4,2]
中间拆分
[3,1,4,2] -> [3,1] [4,2] -> [3] [1] [4] [2]
合并过程
[3] [1] -> [1,3] [4] [2] -> [2,4]
再合并
1 < 2 → 取 1;剩 [3]、[2,4] -> [1] 3 > 2 → 取 2;剩 [3]、[4] -> [1,2] 3 < 4 → 取 3;最后剩 4 补上 -> [1,2,3,4]
代码示例
package main
import (
"fmt"
)
func main() {
arr := []int{3, 1, 4, 2}
newArr := mergeSort(arr)
fmt.Println(arr) // [3, 1, 4, 2]
fmt.Println(newArr) // [1, 2, 3, 4]
}
// 递归拆分
func mergeSort(arr []int) []int {
if len(arr) <= 1 {
return arr
}
mid := len(arr) / 2
left := mergeSort(arr[:mid])
fmt.Println("left:", left)
right := mergeSort(arr[mid:])
fmt.Println("right:", right)
return merge(left, right)
}
// 合并
func merge(left, right []int) []int {
res := make([]int, 0, len(left)+len(right))
i, j := 0, 0
// 挨个取小值
for i < len(left) && j < len(right) {
if left[i] < right[j] {
res = append(res, left[i])
i++
} else {
res = append(res, right[j])
j++
}
}
// 余下数据直接追加
for i < len(left) {
res = append(res, left[i])
i++
}
for j < len(right) {
res = append(res, right[j])
j++
}
return res
}
递归拆分流程
mergeSort([3, 1, 4, 2])
│
├─ mid = 2
├─ left = mergeSort([3, 1]) ← 先递归左半
│ │
│ ├─ mid = 1
│ ├─ left = mergeSort([3]) ← 基线,返回 [3]
│ │ 输出: left: [3]
│ ├─ right = mergeSort([1]) ← 基线,返回 [1]
│ │ 输出: right: [1]
│ └─ return merge([3], [1]) → [1, 3]
│ 输出: left: [1, 3] ← 这层 left 完成
│
├─ right = mergeSort([4, 2]) ← 再递归右半
│ │
│ ├─ mid = 1
│ ├─ left = mergeSort([4]) ← 基线,返回 [4]
│ │ 输出: left: [4]
│ ├─ right = mergeSort([2]) ← 基线,返回 [2]
│ │ 输出: right: [2]
│ └─ return merge([4], [2]) → [2, 4]
│ 输出: right: [2, 4] ← 这层 right 完成
│
└─ return merge([1, 3], [2, 4]) → [1, 2, 3, 4]
合并流程
初始: left = [1, 3, 5] right = [2, 4, 6] res = []
i=0 j=0
┌──────┬───────────┬────────────┬──────────────────┬────┐
│ 轮次 │ left[i] │ right[j] │ 比较 │ res │
├──────┼───────────┼────────────┼──────────────────┼────┤
│ 1 │ 1 │ 2 │ 1 < 2 → 取1, i++ │ [1] │
│ 2 │ 3 │ 2 │ 3 > 2 → 取2, j++ │ [1,2] │
│ 3 │ 3 │ 4 │ 3 < 4 → 取3, i++ │ [1,2,3]│
│ 4 │ 5 │ 4 │ 5 > 4 → 取4, j++ │ [1,2,3,4]│
│ 5 │ 5 │ 6 │ 5 < 6 → 取5, i++ │ [1,2,3,4,5]│
└──────┴───────────┴────────────┴──────────────────┴────┘
→ i=3 越界,主循环退出
收尾: right 还剩 [6],追加 → res = [1,2,3,4,5,6]