现在的位置: 首页 > 综合 > 正文

分治法 – 合并算法设计

2013年12月05日 ⁄ 综合 ⁄ 共 1748字 ⁄ 字号 评论关闭

分治法 - 合并算法设计

何为分治法?

分治策略:将圆问题划分为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);
}

抱歉!评论已关闭.