排序(2) 分治与归并排序

分治法主要思想

基本思想:归并排序用了分治的思想。所谓分治法,顾名思义分而治之。将原问题分解为几个规模较小的但类似原问题的子问题,然后算法多次递归的调用自身以解决这些紧密相关的若干子问题,然后再合并这些子问题的解来建立原问题的解。

分治法(Divide and Conquer)解决问题遵循三个步骤:
①:分解原问题为若干子问题,这些子问题是原问题的规模较小的实例。
②:解决这些子问题,递归求解这些子问题。若子问题规模足够小,则直接求解。
③:合并这些子问题的解构成原问题的解。

归并排序的实现

归并排序遵循分治思想:
①:分解n个元素的待排序列为2个各具n/2个元素的待排序列。
②:使用归并排序递归的排序两个子序列。
③:合并两个已排序的子序列的结果。
归并排序的关键点在于合并子序列结果。

下面是归并排序的python实现,其中包括了合并子过程:

#合并操作
def merge(A,first,mid,last):
    L = A[first : mid+1]  #把A[first],...,A[mid]依次复制给左子数组L
    R = A[mid+1 : last+1] #把A[mid+1],...,A[last]依次复制给右子数组R
    i = j = 0
    k = first
    while i < len(L) and j < len(R): #将L,R中的记录由小到大的并入A中
        if L[i] <= R[j]:
            A[k] = L[i]
            i += 1
        else:
            A[k] = R[j]
            j += 1
        k += 1
    while i < len(L): #将L中剩余记录并入A中
        A[k] = L[i]   #C++中可以写成A[k++] = L[i++],一句顶三
        i += 1
        k += 1
    while j < len(R): #将R中剩余记录并入A中
        A[k] = R[j]
        j += 1
        k += 1

#Merge Sort , T = O(nlgn)
def MergeSort(A,first,last):
    if first < last:
        mid = (first+last) >> 1
        MergeSort(A,first,mid)
        MergeSort(A,mid+1,last)
        merge(A,first,mid,last)

合并操作的代码很简单,过程基本一目了然。这里图示说明一下:
这里写图片描述
初始状态如图,第一次执行的时候L[i] > R[j] 所以把R[j]复制给A[k],然后递增j和k的值,第二次的时候L[i] < R[j],把L[i]复制给A[k],然后递增i和k的值,以此循环,直到L和R中任有一个数组复制完,然后将另一个数组依次复制到A数组中,至此结束。

整个算法执行的递归轨迹图如下:

归并排序性能评价

归并排序是稳定的,任何情况下的时间复杂度均为O(nlgn),但是需要O(n)的额外辅助空间以及需要递归调用自身。实际情况中,若是大规模问题,O(n)的额外空间开销值得思考。另外虽然递归能在解决问题时展现清晰的思路,但是平时能用循环代替递归、能避免递归调用则尽量避免,这皆因递归调用本身有效率问题,甚至有造成栈溢出的风险。

改进和拓展

上述python实现的是二路归并排序。改进的方面有多路归并、归并排序的非递归算法、当问题规模分解的足够小时用插入排序。《算法4(塞克威奇)》中还提到检测待合并数组段是否有序(当A[mid]<=A[mid+1]时)和通过递归中交换参数避免数组复制来改进,个人认为这属于编码层面的改进,这里暂不讨论,但是实现也非常简单。这里主要简要说一下非递归版归并排序和加快小数组排序的归并排序。

非递归版本的归并排序在《算法4》中被称为自底向上的归并排序,其方法是直接从最小的序列开始归并,而省略了分解数组的步骤。
这里写图片描述
可与前面的图做比较,

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值