分治法复习

   分治法(divide and conquer method)是最著名的算法设计技术,在计算机科学领域孕育了许多重要的和有效的算法。作为解决问题的一般性策略,分治法在政治和军事领域也是克敌制胜的法宝。

   分治法将一个难以直接解决的大问题划分成一些规模较小的子问题,分别求解各个子问题,再合并子问题的解得到原问题的解。一般来说,分治法的求解过程由以下三个阶段组成: (1)划分:把规模为 n 的原问题划分为 k 个(通常 k = 2)规模较小的子问题。 (2)求解子问题:分别求解各个子问题。 (3)合并:把各个子问题的解合并起来。

  从大量实践中发现,在进行问题划分时,遵循以下启发式原则: (1)平衡子问题(balancing sub-problom):子问题的规模最好大致相同。 (2)各子问题之间相互独立:如果各子问题不是独立的,分治法需要重复求解公共的子问题,此时虽然也可以用分治法,但一般用动态规划法较好。

   

归并排序

【问题】归并排序(merge sort)的分治策略是: (1)划分:将待排序序列从中间位置划分为两个长度相等的子序列; (2)求解子问题:分别对这两个子序列进行排序,得到两个有序子序列; (3)合并:将这两个有序子序列合并成一个有序序列。

  【想法】一个归并排序的例子

【算法实现】设函数Merge实现合并操作,程序如下:

void Merge(int r[ ], int s, int m, int t)  
{
    int r1[t], i = s, j = m + 1, k = s;
    while (i <= m && j <= t)
    {   
        if (r[i] <= r[j]) r1[k++] = r[i++];         //较小者放入r1[k]
        else r1[k++] = r[j++]; 
    }
    while (i <= m)                                        //处理第一个子序列剩余记录
        r1[k++] = r[i++]; 
    while (j <= t)                                          //处理第二个子序列剩余记录
        r1[k++] = r[j++];    
    for (i = s; i <= t; i++)                             //将合并结果传回数组r
        r[i] = r1[i];
}





void MergeSort(int r[ ], int s, int t)          //对序列r[s]~r[t]进行归并排序
{                       
    if (s == t) return;                                 //只有一个记录,已经有序
    else { 
        int m = (s + t)/2;                            //划分
        MergeSort(r, s, m);                       //归并排序前半个子序列
        MergeSort(r, m+1, t);                   //归并排序后半个子序列
        Merge(r, s, m, t);                         //合并两个有序子序列
    }
}

快速排序

【问题】快速排序(quick sort)的分治策略是: (1)划分:选定一个记录作为轴值,以轴值为基准将整个序列划分为两个子序列,轴值的位置在划分的过程中确定,并且左侧子序列的所有记录均小于或等于轴值,右侧子序列的所有记录均大于或等于轴值; (2)求解子问题:分别对划分后的每一个子序列递归处理; (3)合并:由于对子序列的排序是就地进行的,所以合并不需要执行任何操作。

【算法实现】设函数Partition实现对序列 r[first] ~ r[end] 进行划分,程序如下:

int Partition(int r[ ], int first, int end)          
{	
    int temp, i = first, j = end; 
    while (i < j)	
    {  
        while (i < j && r[i] <= r[j]) j--;               //右侧扫描
        if (i < j)  { 
            temp = r[i]; r[i] = r[j]; r[j] = temp;      //将较小记录交换到前面
            i++; 
        }
        while (i < j && r[i] <= r[j]) i++;             //左侧扫描
        if (i < j)  {
            temp = r[i]; r[i] = r[j]; r[j] = temp;      //将较大记录交换到后面
            j--; 
        }
    }
    return i;                                //返回轴值记录的位置
}




void QuickSort(int r[ ], int first, int end)        //快速排序
{	
    if (first < end) 
    {      
        int pivot = Partition(r, first, end);         //划分,pivot是轴值的位置
        QuickSort(r, first, pivot-1);              //对左侧子序列进行快速排序
        QuickSort(r, pivot+1, end);              //对右侧子序列进行快速排序
    }
}

  • 14
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值