分治法 - 合并算法设计

来源:互联网 发布:java 电商平台 编辑:程序博客网 时间:2024/04/30 05:00

分治法 - 合并算法设计

何为分治法?

分治策略:将圆问题划分为n个规模较小而结构与圆问题相似的子问题;地鬼地解决这些子问题。然后合并结果,即得到原问题的解。

分治模式每一层的递归上都有三个步骤:

分解:将原问题分解为一系列子问题;

解决:递归地解决各子问题。若子问题较小,则直接求解。

合并:将子问题的解合并为原问题的解。

一. 问题描述:

由n个数组成的序列a1,a2, …, an; 对上述序列采用合并排序算法进行排序。

二. 算法分析

合并排序算法完全依照了上述模式,步骤如下:

分解:将n个元素分成各含n/2个元素的子序列;

解决:用合并排序算法对两个子序列递归地排序;

合并:合并两个以排序的子序列的以得到原序列的排序结果。

在对子序列排序时,长度为1时递归结束,单个元素被视为已排好序的。

合并排序算法的关键步骤在于合并两个已经排好序的子序列。为做合并,引入辅助过程merge(A, p, q, r),其中A是数组,p, q, r是数组下标满足p<=q<r, A[p, q]和A[p+1, r]是已经排号序的数组。merge(A, p, q, r)就是将A[p, q]和A[q+1, r]合并为数组A[p, r]。

以扑克牌为例,现有两堆扑克牌,都是已经排好序的,最小的放在最上面。现在我们希望把两堆扑克牌合并为排好序的一堆。基本步骤如下,从两堆中选取较小的一张,将其取出,面朝下放在输出堆中,直至某一堆完全为空为止(或定义一个哨兵牌,即直至某一堆出现哨兵牌为止),然后把另一输入堆余下的牌全部放入输出堆上。因为之多n次比较,所以时间复杂度为O(n)。

Merge(A, p, q, r){         定义m1=q-p+1,m2=r-q;    创建序列L(1,m1),R(1, m2);    /* 定义序列L(1, m) ,R(1, m2)*/    for i = 1~m1        L(i) = A(p+i-1)    for j = 1~m1        R(j) = A(p+j)再定义哨兵L(m1+1)= 无穷大;R(m2+1) = 无穷大;定义i=1; j=1;for k = p~r    if L(i) <= R(j)        then A[k] = L(i);i=i+1;    else        then A[k] = R(j);j=j+1;}

合并排序的算法

Merge_sort(A, p, r){    if (p<r)    {        q={小于或等于(p+r)/2的最大整数};        Merge_sort(A, p, q);Merge_sort(A, q+1, r);Merge (A, p, q, r);    }}

三. 效率分析

设T(n)表示一个规模为n的问题的运行时间。如果问题规模足够小,如n<=c(一常数),则其直接解的为常量,设为O(1)。

假设把问题分解为a个子问题;每一个子问题的规模是原问题的n/b,并假设分解该问题和合并该问题的时间为D(n)和C(n),从而的效率模型为T(n) = aT(n/b)+ D(n)+C(n),可由master theory知,时间复杂度T(n) =O(nlgn);

四. C实现

/** * merge - 将已经排好序的array[low,mid]与array[mid+1,high] *        合并为一个array[low,high],并且也是排好序的 * Param.: *     @array: 数组 *     @low:起始脚标 *     @mid:中间脚标 *     @high:终止脚标 * Return: *     无 */void merge(intarray[], int low, int high, int mid){    int i, j, k, tmp;      i = low;    j = mid + 1;    while (i < j  && j <= high)    {        if (array[i] > array[j])        {            tmp = array[j];            for (k = j; k > i; k--)                array[k] = array[k - 1];            array[i] = tmp;            j++;        }        i++;    }} /** * merge_sort - 合并排序,排序后序列放入源数组 * Param.: *     @array: 数组 *     @low:起始脚标 *     @high:终止脚标 * Return: *     无 */void merge_sort(intarray[], int low, int high){    int mid;    if (low >=  high)        return;     mid = (low + high) / 2;    merge_sort(array, low, mid);    merge_sort(array, mid + 1, high);    merge(array, low, high, mid);}


原创粉丝点击