算法导论-分治法



      我们可以选择的算法设计有很多。如:插入排序方法用到的是“增量方法”,可以理解为“串行”地从一个小问题开始解决,然后不断的放大这个问题,直到最终解决这个大问题。还是以插入排序为例,先排序A[1...j-1],然后将A[j]插入A[1...j-1]形成A[1...j]的有序数列。

       本文的要介绍的算法设计方案是“分治法”,大部分内容来源于《算法导论》,个人学习使用。

       很多有用的高效算法在结构上都利用了递归的思想:为了解决一个给定的大问题,将其拆解为相似的一个个更小的问题,s府一次或多次的地递归调用自身,以解决紧密相关的若干子问题,最终达到解决大问题的目的。这类算法遵循的就是“分治法”的思想:将原问题分解为几个规模较小的类似子问题,求解这些子问题,然后再合并这些子问题的结果达到解决大问题的目的。

        分治模式在每次递归时基本遵三个步骤:

        (1).分解:将原问题分解为若干子问题;

        (2).解决:递归地求解各个子问题,一般来说当子问题足够小时,则直接求解;

        (3).合并:合并这些子问题的解,得到原问题的解。

        本文以归并排序为例,说明一下分治法的具体应用:

        按照上述的三个步骤来分析归并排序,则归并排序的三个步骤为

        (1).分解:将待排序的n个元素序列分解为2个子序列,每个有n/2个元素;

        (2).解决:递归的解决2个子序列的排序问题;

        (3).合并:合并2个已排序的子序列,得到原问题的解。

        1.归并排序的分解解决

        归并排序算法的第一步是如何“分解”序列,如下所示。merge-sort()实现排序A[p...q],若p>=r,则该数组最多有1个元素,一定是排列好的,此时递归就可以返回了。

        然后利用merge()来实现,子序列的合并。

算法导论-分治法

        2.归并排序的合并

        归并排序算法的关键也就是在于如何“合并”2个已经排序序列。假设利用merge(A,p,q,r)函数实现合并操作,其中A为数组,p、q和r都是数组下标,满足p<=q<r。该过程假设A[p...q]和A[q+1...r]都已经排序完成。merge的过程如下所示,实际上就和洗牌是一样的,最小的牌都在上方,两堆牌只有最上方的两张是可以看见的,我们按照大小顺序,选择大牌(或小牌)。剩下的还是只有2张牌可见,重复这个步骤,直到一摞牌堆为空,则将另一摞牌直接放在牌堆底部即可。如下所示:

 算法导论-分治法

算法导论-分治法

         2.归并排序的代价

        在网上可以找到很多具体的有关归并排序时间复杂度的推到,归并排序的总代价为cnlogn+cn,忽略低阶项和常量c便给出了期望的结果nlog2n。