算法稳定性,时间复杂度,空间复杂度等算法基础知识: 经典算法----基础知识
冒泡排序: 基础算法----冒泡排序
选择排序: 基础算法----选择排序
插入排序: 基础算法----插入排序
快速排序: 基础算法----快速排序
希尔排序: 基础算法----希尔排序
归并排序: 基础算法----归并排序
计数排序: 基础算法----计数排序
桶排序: 基础算法----桶排序
基数排序: 基础算法----基数排序
堆排序: 基础算法----堆排序
一 算法简介
归并排序将待排序序列分割成若干个子序列,递归分割子序列,直到不能分割,然后递归合并子序列(递归地使每个子序列有序,然后再把有序的子序列合并成一个有序的序列)
归并排序的速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列
归并排序是采用分治法(Divide and Conquer)的排序算法,比较占用内存,但却是一种效率高且稳定的算法
二 时间复杂度,空间复杂度
一) 时间复杂度
每次都将当前序列分割为长度接近的两个子序列,最好和最坏情况的时间复杂度都一样
假设每一次把原序列分成两部分:X1,X2
所以时间复杂度 T(n) = D(n) + T(X1) + T(X2)
T(n) = D(n) + 2T(n/2)
= D(n) + 2D(n/2) + 4T(n/4)
= D(n) + 2D(n/2) + 4D(n/4) + 8T(n/8)
= D(n) + 2D(n/2) + … + 2kD(n/2k)
其中 D(n) = n -1, k = log2n
D(n) 表示每一次递归操作的比较次数,k表示经过log2n分割,即可得到长度为1的子序列
所以T(n) = n-1 + n-2 + … + n - 2k
= nlog2n - 2n +1
平均时间复杂度为 T(n) = O(nlog2n)
二) 空间复杂度
空间复杂度为临时数组和递归时程序栈层数占用的空间总和:S(n) = n + log2n
空间复杂度为 S(n) = O(n)
三 算法稳定性
相同元素的相对位置不会由于归并发生变化,归并排序是一种稳定的排序算法
四 实现
一) 步骤
1) 将待排序序列分割成长度为 n/2 的子序列
2) 递归分割子序列,直到不能分割
3) 递归合并子序列
二) 过程图
使用 {40, 30, 50, 40, 20, 60, 10, 70} 演示从小到大的排序过程
三) 代码实现
func MergeSort(arr []int) []int {
if len(arr) <= 1 {
return arr
}
n := len(arr) / 2
return merge(MergeSort(arr[:n]), MergeSort(arr[n:]))
}
func merge(leftSubArr, rightSubArr []int) (res []int) {
length := len(leftSubArr) + len(rightSubArr)
res = make([]int, length)
l, r := 0, 0
for i := 0; i < length; i++ {
//说明rightSubArr中存在比leftSubArr最后一个元素(最大元素)大的元素
if l >= len(leftSubArr) {
res[i] = rightSubArr[r]
r++
//说明leftSubArr中存在比rightSubArr最后一个元素(最大元素)大的元素
} else if r >= len(rightSubArr) {
res[i] = leftSubArr[l]
l++
} else if leftSubArr[l] < rightSubArr[r] {
res[i] = leftSubArr[l]
l++
} else {
res[i] = rightSubArr[r]
r++
}
}
return
}