基本思想:
归并排序与之前的交换(快速)、选择(堆)等排序的思想不一样,“归并”的含义就是:
将两个或者两个以上的有序表组合成一个新的有序表,假定待排序表含有n个记录,则可以看做是n个有序的子表,每个子表的长度为1,然后两两归并,得到个长度为2或者为1的有序表;再两两归并,....如此重复,直到合并成一个长度为n的有序表为止,这种排序方法为2-路归并排序
初始关键字: 49 38 65 97 76 13 27
一趟归并后: 38 49 65 97 13 76 27
二趟归并后: 38 49 65 97 13 27 76
三趟归并后: 13 27 38 49 65 76 97
merge()的功能是将前后相邻的两个有序表归并成为一个有序表的算法。
设两段有序表A[low,...mid]、A[mid+1,...high]放在同一个有序表的两个位置上,先让它们复制到辅助数组B里面,每次从对应B中的两个段取出一个记录进行关键字的比较,先将小者放入A中,当数组B中有一段的下标超出其对应的表长时,即该段所有的元素已经完全复制到A中,另一端中的剩余部分直接复制到A中。
递归形式的2-路归并排序是基于分治的!过程如下:
- 分解:将含有n个元素的待排序表分成各含有n/2个元素的子表,采用二路归并算法对两个子表递归的地进行排序
- 合并:合并两个已排序的子表得到排序结果
代码如下:
# merge函数的功能是将前后相邻的两个有序子表归并成为一个有序表
# left和right就是两个前后相邻的有序子表,我们需要一个辅助数组result,最后返回的result就是最后的
# 归并排序结果
# i和j一起从0开始向后走,对应位置(不一定就是下标相同)谁小谁被收到result中去,然后下去的那个指针向
# 后走一个,直到最后
# 其实result += left[i:] 和 result += right[j:]只会执行一个,因为有一个已经被收光了。
def merge(left, right):
i, j = 0, 0
result = []
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result += left[i:]
result += right[j:]
return result
# 递归形式的二路归并算法是基于分治的
# 分解:将n个记录一分为2,然后对分开的两个各含有n/2个元素的子表递归调用自身
# 合并: 合并两个已经排序的子表得到结果
def merge_sort(lists):
if len(lists) <= 1:
return lists
num = len(lists) /2
left = merge_sort(lists[:num])
right = merge_sort(lists[num:])
return merge(left, right)
性能:
- 空间:需要借助一个辅助数组B,所以空间复杂度为O(n)
- 时间:每一趟归并就是一个while循环,即O(n),一共要趟归并,所以算法时间复杂度是
稳定性:
merge不会改变相同关键字记录的相对次序,所以2路归并排序是一个稳定的排序算法。