归并排序
归并排序是一种常见并且广泛运用的排序算法。由于其采用了二叉树层级的理念从而降低时间复杂度 充分提升了性能。常见的我们会运用递归来写归并排序的代码 其实通过迭代的方式来实现归并排序不失为一种好的方式。
原理讲解
归并排序基于分治策略(Divide and Conquer Stretegy)实现。分:先将要排序长度为n的列表或者数组折中分成两个子列表或者数组长度分别为(n/2) 第二次则分别将子序列分成总共4个子序列 每个子序列长度为(n/4) 以此继续分下去,直到子序列只剩下1个元素不能再分而停止。治:将最后分成的n个元素开始逐级合并,第一层治策略是将分策略最后一层得到的元素根据分策略逐个“修补”起来,俗话说就是分策略的逆过程。如图所示:
Python实现
1 def mergeSort(a, l, r): 2 tmp = [0 for _ in range(len(a))] # 开辟一个与列表a相同长度的临时列表空间 3 sort(a, l, r, tmp) 4 5 def sort(a, l, r, tmp): 6 if l < r: 7 mid = (l + r)//2 8 sort(a, l, mid, tmp) # 左边归并排序 使左边子序列有序 9 sort(a, mid+1, r, tmp) # 右边归并排序 使右边子序列有序 10 merge(a, l, mid, r, tmp) # 将左右两个有序的子序列合并操作 11 12 def merge(a, l, mid, r, tmp): 13 t = 0 14 i = l 15 j = mid+1 16 while i <= mid and j <= r: 17 if a[i] <= a[j]: 18 tmp[t] = a[i]; t+=1; i+=1 19 else: 20 tmp[t] = a[j]; t+=1; j+=1 21 22 while i <= mid: # 右子序列比较完没有元素后 将左子序列剩下的添加临时列表后面 23 tmp[t] = a[i]; t+=1; i+=1 24 25 while j <= r: # 左子序列比较完没有元素后 将右子序列剩下的添加临时列表后面 26 tmp[t] = a[j]; t+=1; j+=1 27 28 t = 0 29 while l <= r: # 将临时列表中的数复制到原来数组当中 30 a[l] = tmp[t]; l+=1; t+=1 31 32 if __name__ == '__main__': 33 a = [4, 2, 7, 8, 1, 3, 5, 6] 34 r = len(a)-1 35 l = 0 36 mergeSort(a, l, r) 37 print(a)
时间、空间复杂度 稳定性分析
时间复杂度:归并排序由于运用了二叉树的策略所以在分策略上是logn的时间复杂度,治策略每一层都必须比较所以n个元素, 总共有n层所以最后的时间复杂度是O(nlogn)。它不受待排序列表完全逆序的影响所以平均时间复杂度是O(nlogn)。
空间复杂度:过程开辟了长度为n的临时空间 所以空间复杂度是O(n)
稳定性分析:当左右子序列比较的两个元素相等时,左子序列的相同元素为先加入到临时序列中 所以相同元素的顺序在排序之后未发生改变 ,归并排序是稳定性排序。
总结
各种排序算法都有其自身的不可替代性,在实际运用的过程中,特别是数量巨大时,一定要结合数据的性质本身和排序算法本身来决定要用何种算法。