归并排序
介绍
假定待排序表含有n个记录,则可以看成是n个有序的子表,每个子表长度为1,然后两两归并,得到 ⌈n/2⌉个长度为2或1的有序表;再两两归并,……如此重复,直到合并成一个长度为n的有序表为止,这种排序方法称为2-路归并排序
步骤
49 38 65 97 76 13 27
- 首先将整个序列的每个关键字看成一个单独的有序的子序列
- 两两归并,49和38归并成{38 49} ,65和97归并成{65 97},76和13归并成{13 76},27没有归并对象
- 两两归并,{38 49}和{65 97}归并成{38 49 65 97},{13,76}和27归并成{13 27 76}
- 两两归并,{38 49 65 97}和{13 27 76}归并成{13 27 38 49 65 76 97}
代码实现
def merge_sort(alist):
if len(alist) <= 1:
return alist
"""二分"""
middle = len(alist) // 2
left = merge_sort(alist[:middle])
right = merge_sort(alist[middle:])
print("========left========")
print(left)
print("========right========")
print(right)
return merge(left, right)
def merge(left, right):
"""合并操作,将两个有序数组left[]和right[]合并成一个大的有序数组"""
"""left与right的index"""
l, r = 0, 0
result = []
while l < len(left) and r < len(right):
if left[l] < right[r]:
result.append(left[l])
l += 1
else:
result.append(right[r])
r += 1
result += left[l:]
result += right[r:]
return result
alist = [49, 38, 65, 97, 76, 13, 27]
print(alist)
sorted_alist = merge_sort(alist)
print(sorted_alist)
运行结果:
[49, 38, 65, 97, 76, 13, 27]
========left========
[38]
========right========
[65]
========left========
[49]
========right========
[38, 65]
========left========
[97]
========right========
[76]
========left========
[13]
========right========
[27]
========left========
[76, 97]
========right========
[13, 27]
========left========
[38, 49, 65]
========right========
[13, 27, 76, 97]
[13, 27, 38, 49, 65, 76, 97]
分析
时间复杂度
一共n个元素
-
第1趟归并:子序列长度为2,所以有n/2对子序列,每个子序列需要执行1次Merge, Merge时间复杂度为子序列长度之和即2
所以第①趟merge的时间复杂度为O(n/2*2)=O(n)49 38| 65 97| 76 13| 27 45 n/2对
-
第2趟归并:子序列长度为4,所以有n/4对子序列,每个子序列需要执行1次Merge,Merge时间复杂度为子序列长度之和即4
所以第2趟merge的时间复杂度为O(n/4*4)=O(n)38 49 65 97| 13 76 27 45 n/4对
-
第k趟归并:子序列长度为2k,所以有n/2k对子序列
当n/2k=1时,k=log2n 此时需要归并的两个子序列长度为n/2,只需要一次Merge就能实现整个序列有序。所以一共执行了k=log2n趟排序,每趟排序的时间复杂度都是O(n)所以整个归并排序的时间复杂度为O(nlog2n)
空间复杂度
空间复杂度:因为需要将这个待排序序列转存到一个数组,所以需要额外开辟大小为n的存储空间,即空间复杂度为O(n)