12.归并排序

归并排序(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
}
发布了127 篇原创文章 · 获赞 24 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/Linzhongyilisha/article/details/100110826