合并(归并)排序和快速排序一样也采用了分而治之(divide and conquer,D&C)的思想
不过对比快速排序,mergesort没有pivot(中心点)
分的部分:
- 它是把一个无序数组按照数组大小的中心数分为两部分
if len(n) < 2: #分的阶段,即divide
return n
mid = len(n) // 2
- 然后采用递归的思想把分好的两部分,再分成两部分,这样总共就有4部分了,依次类推。
left = mergesort(n[:mid])
right = mergesort(n[mid:])
治的部分:
- 创建一个空的列表
merged = []
- 把分好的两部分按照索引比较,如果是从小到大排序,那么左右两部分哪个数值小,就把哪个放到新创建的列表中
- 然后对之对应的部分(左部或者右部)的索引值+1,依次类推,直到一方的数值全部比较完,即索引值=len(left/right)
while i < len(left) and j < len(right):
if left[i] <= right[j]:
merged.append(left[i])
i += 1
else:
merged.append(right[j])
j += 1
- 最后把还没有比较完的部分(左部或者右部)的剩下的列表里的数值,直接放到创建好的列表的最后
merged.extend(left[i:])
merged.extend(right[j:])
图解思想请参考:https://www.cnblogs.com/chengxiao/p/6194356.html
完整的mergesort代码以及测试
#mergesort
def merge(left,right): #治的阶段,即conquer
merged = []
i,j = 0,0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
merged.append(left[i])
i += 1
else:
merged.append(right[j])
j += 1
merged.extend(left[i:])
merged.extend(right[j:])
return merged
def mergesort(n):
if len(n) < 2: #分的阶段,即divide
return n
mid = len(n) // 2
left = mergesort(n[:mid])
right = mergesort(n[mid:])
return merge(left,right)
if __name__ == '__main__':
test = [49, 38, 65, 97, 76, 13, 27, 49]
print(mergesort(test))
那么现在很容易就看出合并排序和快速排序的差别了,即合并排序需要先分再治,即O(2*logn)
再乘上每层递归上的操作,时间复杂度O(2nlogn),因为在算时间复杂度的时候要忽略前面的系数2
所以虽然合并排序的时间复杂度和快速排序的平均时间复杂度一样为O(nlogn)
但快速排序并没有前面的系数2,所以在一般情况下,快速排序要比合并排序略快,有兴趣的朋友可以加个时间做比较。
PS:如果时间允许的情况下,笔者会在写完常用的几种排序算法之后,做个时间比较。