先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就都有序了。
归并排序的实现过程
实现代码//n为要排序数组的元素个数
func MergeSort(array *[]int, n int) {
MergeSortDetail(array, 0, n-1)
}
//l,r分别为需要排序的数组的最左、最右元素的下标
func MergeSortDetail(array *[]int, l, r int) {
if l >= r {
return
}
//分解过程
mid := (r + l) / 2
MergeSortDetail(array, l, mid)
MergeSortDetail(array, mid+1, r)
//合并过程
if (*array)[mid] > (*array)[mid+1] {
Merge(array, l, mid, r)
}
}
func Merge(array *[]int, l, mid, r int) {
//temp为需要合并的两个数组无序合并而成的数组,方便下面遍历比较,再调整原数组的元素成有序状态
temp := make([]int, r+1)
for i := l; i <= r; i++ {
temp[i] = (*array)[i]
}
//定义两个要合并的数组第一个元素的下标
i := l
j := mid + 1
for k := l; k <= r; k++ {
//需要合并的两个数组的下标不可以越界,设置判断条件i > mid,j > r
if i > mid {
(*array)[k] = temp[j]
j++
} else if j > r {
(*array)[k] = temp[i]
i++
} else if temp[j] < temp[i] {
(*array)[k] = temp[j]
j++
} else {
(*array)[k] = temp[i]
i++
}
}
}
func main() {
array := []int{39, 2, 5, 23, 54, 12, 78, 34, 45, 40}
MergeSort(&array, len(array))
for i, v := range array {
fmt.Printf("下标为%d的值为%d", i, v)
fmt.Println()
}
}
总结
- 空间复杂度:归并排序不是原地排序算法,在合并两个数组的过程中需要借助额外的空间,空间复杂度是O(n)。
- 稳定性:归并排序是稳定的排序算法,在合并[l,mid] [mid+1,r]过程中,如果两个区间中有相同的元素,可以处理[l,mid]中的元素,从而保证稳定性。
- 时间复杂度:归并排序的时间复杂度是 O(nlogn)。从代码中可以看到,归并排序的执行效率与要排序的原始数组的有序程度无关,所以其时间复杂度是非常稳定的,不管是最好情况、最坏情况,还是平均情况,时间复杂度都是 O(nlogn)。