数据结构---归并排序

基本思想:

归并排序与之前的交换(快速)、选择(堆)等排序的思想不一样,“归并”的含义就是:

将两个或者两个以上的有序表组合成一个新的有序表,假定待排序表含有n个记录,则可以看做是n个有序的子表,每个子表的长度为1,然后两两归并,得到\left \lceil n/2 \right \rceil个长度为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),一共要\left \lceil log_{2} n\right \rceil趟归并,所以算法时间复杂度是O(nlogn)

稳定性:

merge不会改变相同关键字记录的相对次序,所以2路归并排序是一个稳定的排序算法。

猜你喜欢

转载自blog.csdn.net/mr_xiaoz/article/details/81260775