这篇博客是对极客时间上王争课程 —— 数据结构与算法之美的个人学习总结。文章中的图出自课程中。我会对课程中的 Java 代码用 Python 来实现,所有的代码会放在我的 ​​GitHub ​​上。


4. 归并排序(Merge Sort)

归并排序使用递推的方式来实现,把需要排序的数组逐步分成更小的部分,进行排序,然后再组合起来。由于是递推,最重要的是要建立递推公式:

看这里的递推公式:

递推公式
merge_sort(p...r) = merge(merge_sort(p...q), merge_sort(q+1...r))

终止条件
p >= r 不用再继续分解

递推如果看代码去理解的话会很复杂,但是建立了递推公式,按照公式来进行就会变得简单很多。这个公式就是把数组分为 p 到 q,q+1 到 r 两部分,对每一部分都进行同样的操作,直到不能再分。

按照递推公式来弄成代码就是:

# Copyright(c) strongnine

## 归并排序算法, A 是数组
def merge_sort(A):
n = len(A)
return merge_sort_c(A, 0, n - 1)

def merge_sort_c(A, p, r):
## 递归终止条件
if p >= r:
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]
A = merge(A, p, q, r)
return A

def merge(A, p, q, r):
i = p
j = q + 1
tmp = []
while (i <= q) & (j <= r):
if A[i] <= A[j]:
tmp.append(A[i])
i += 1
else:
tmp.append(A[j])
j += 1


## 判断哪个子数组中有剩余的数据
start = i
end = q
if j <= r:
start = j
end = r
## 将剩余的数据拷贝到临时数据 tmp
while start <= end:
tmp.append(A[start])
start += 1

return tmp


if __name__ == '__main__':
A = [1, 5, 6, 2, 3, 4]
B = [1, 2, 3, 5, 7, 8, 9, 11]
A = merge_sort(A)
B = merge_sort(B)
print(A, B)

其中最重要的就是 merge_sort_c() 这个函数,它有个嵌套。

归并排序的过程分解如下:

归并排序、快速排序_数据结构

归并排序是非原地的稳定的算法,时间复杂度 O(nlogn),空间复杂度 O(n)。

5. 快速排序(Quicksort)

快速排序简称快排,也是用的分治思想。递推公式:

递推公式:
quick_sort(p...r) = quick_sort(p...q-1) + quick_sort(q+1, r)

终止条件:
p >= r

代码:

# Copyright(c) strongnine

## 快速排序
def quick_sort(A):
n = len(A)

quick_sort_c(A, 0, n - 1)

return A

def quick_sort_c(A, p, r):
if p >= r:
return

## 获取分区点
q = partition(A, p, r)
quick_sort_c(A, p, q - 1)
quick_sort_c(A, q + 1, r)

return A

def partition(A, p, r):
pivot = A[r]
i = p
for j in range(p, r):
if A[j] < pivot:
A[i], A[j] = A[j], A[i]
i += 1

A[i], A[r] = A[r], A[i]

return i


if __name__ == '__main__':
A = [11, 8, 3, 9, 7, 1, 2, 5]
A = quick_sort(A)
print(A)