归并排序(Merge Sort)
先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就都有序了
分之思想,分而治之。
分治是一种解决问题的处理思想,递归是一种编程技巧
递推公式:
merge_sort(p…r) = merge(merge_sort(p…q), merge_sort(q+1…r))
终止条件: p >= r 不用再继续分解
伪代码:
// 归并排序算法, A 是数组,n 表示数组大小
merge_sort(A, n) {
merge_sort_c(A, 0, n-1)
}
// 递归调用函数
merge_sort_c(A, p, r) {
// 递归终止条件
if p >= r then return
// 取 p 到 r 之间的中间位置 q
q = (p+r) / 2
// 分治递归
merge_sort_c(A, p, q)
merge_sort_c(A, q+1, r)
// 将 A[p...q] 和 A[q+1...r] 合并为 A[p...r]
merge(A[p...r], A[p...q], A[q+1...r])
}
分析过程:
1.申请一个临时数组 tmp,大小与 A[p…r] 相同。
2.我们用两个游标 i 和 j,分别指向 A[p…q] 和 A[q+1…r] 的第一个元素。
3.比较这两个元素 A[i] 和 A[j],如果 A[i]<=A[j],我们就把 A[i] 放入到临时数组 tmp,并且 i 后移一位,否则将 A[j] 放入数组 tmp,j 后移一位。
4.重复上述过程,直到一个数组全部放完,再依次放另一个数组中元素。
5.最后再把临时数组 tmp 中的数据拷贝到原数组 A[p…r]...
稳定性:稳定排序,
时间复杂度:
T(1) = C; n=1 时,只需要常量级的执行时间,所以表示为 C。
T(n) = 2*T(n/2) + n; n>1
T(n) = 2*T(n/2) + n
= 2*(2*T(n/4) + n/2) + n = 4*T(n/4) + 2*n
= 4*(2*T(n/8) + n/4) + 2*n = 8*T(n/8) + 3*n
= 8*(2*T(n/16) + n/8) + 3*n = 16*T(n/16) + 4*n
......
= 2^k * T(n/2^k) + k * n
......
T(n) = 2^kT(n/2^k)+kn。
当 T(n/2^k)=T(1) 时,也就是 n/2^k=1,我们得到 k=log2n 。我们将 k 值代入上面的公式,得到 T(n)==Cn+nlog2n 。如果我们用大 O 标记法来表示的话,T(n) 就等于 O(nlogn)。
执行效率与要排序的原始数组的有序程度无关,所以其时间复杂度是非常稳定的,不管是最好情况、最坏情况,还是平均情况,时间复杂度都是 O(nlogn)。
空间复杂度:需要开开辟一个临时空间为n的数组,所以空间复杂度O(n),致命弱点。
实现:
package main
import "fmt"
func main() {
arr := []int{8, 9, 5, 7, 1, 2, 5, 7, 6, 3, 5, 4, 8, 1, 8, 5, 3, 5, 8, 4}
tempArr := mergeSort(arr)
fmt.Println(tempArr)
}
/**
归并排序(Merge sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用
分治思想,时间复杂度为:O(n*log(n))
*/
func mergeSort(arr []int) []int {
if len(arr) < 2 {
return arr
}
i := len(arr) / 2
left := mergeSort(arr[0:i])
right := mergeSort(arr[i:])
tempArr := merge(left, right)
return tempArr
}
func merge(left, right []int) []int {
tempArr := make([]int, 0)
m, n := 0, 0 // left和right的index位置
l, r := len(left), len(right)
for m < l && n < r {
if left[m] > right[n] {
tempArr = append(tempArr, right[n])
n++
continue
}
tempArr = append(tempArr, left[m])
m++
}
tempArr = append(tempArr, right[n:]...) // 这里竟然没有报数组越界的异常?
tempArr = append(tempArr, left[m:]...)
return tempArr
}