归并排序(自底向上)
算法概述
自底向上归并排序是一种非递归排序算法。它首先把待排序的数组拆分为多个长度为 2 的子序列(不足2的部分也作为一个子序列看待),接着对每个子序列进行排序,保证每个子序列内部是有序的,然后在这个基础上把数组拆分为多个长度为 4 的子序列,对每个子序列进行排序,以此类推,每次迭代子序列的长度翻倍,直到子序列长度能覆盖数组长度,最终完成排序。
算法实现
package main
func SortBU(arr []int) {
n := len(arr)
temp := make([]int, n)
// 对数组中的每 16 个元素进行插入排序处理,16 是一个经验值
// 数据量少和基本有序的情况下插入排序效率更高
for i := 0; i < n; i += 16 {
InsertionSort(arr, i, min(n-1, i+15))
}
// 划分子序列,子序列的半长以 16 为起始值(不再重复处理插入排序中已排序的部分),每次翻倍
for sz := 16; sz < n; sz += sz {
// 对每个子序列进行归并排序
for i := 0; i+sz < n; i += 2 * sz {
// 子序列前一半的最后一个元素大于后一半的第一个元素时,证明子序列内部存在乱序需要进行归并
if arr[i+sz-1] > arr[i+sz] {
// min(i+sz+sz-1, n-1) 用于处理 i+sz+sz-1 大于 n-1 的情况
merge(arr, temp, i, i+sz-1, min(i+sz+sz-1, n-1))
}
}
}
}
func InsertionSort(arr []int, left, right int) {
for i := left + 1; i <= right; i++ {
temp := arr[i]
j := i - 1
for ; j >= left && arr[j] > temp; j-- {
arr[j+1] = arr[j]
}
arr[j+1] = temp
}
}
func merge(arr, temp []int, l, mid, r int) {
// 把 arr 指定位置的元素复制到 temp 保存副本
// 后续排序时就是取 temp 中指定位置的前半部分和后半部分元素进行比较,出结果后再放到 arr 中合适的位置
copy(temp[l:r+1], arr[l:r+1])
// i 为左子序列的起始位置,j 为右子序列的起始位置
i, j := l, mid+1
// 对子序列进行排序
for k := l; k <= r; k++ {
// 子序列的左边已经处理完毕
if i > mid {
arr[k] = temp[j]
j++
// 子序列的右边已经处理完毕
} else if j > r {
arr[k] = temp[i]
i++
} else if temp[i] <= temp[j] {
arr[k] = temp[i]
i++
} else {
arr[k] = temp[j]
j++
}
}
}