计算机算法设计与分析之----- 递归与分治策略

本文探讨了递归与分治策略在算法中的应用,重点讲解了Master定理在快速排序优化中的运用,包括快速排序的基本原理、最优情况与最坏情况下的时间复杂度分析,以及如何通过随机化改进快速排序。此外,文中还涉及逆序对的归并算法、火柴排队问题、集合求和的组合数学方法以及一些经典问题如越狱、平面上的最接近点对和棋盘覆盖的解决方案。

【Master定理】

主定理【Master定理】提供了分治方法带来的递归表达式的渐进复杂度分析。
将规模为 n 的问题通过分治,得到 a 个规模为 n/b 的问题,每次递归带来的额外计算为 c ( n d ) c(n^d) c(nd)
T ( n ) = a ( n / b ) + c ( n d ) T(n)=a(n/b)+c(nd) T(n)=a(n/b)+c(nd)

  • a = b d , T ( n ) = O ( n d l o g ( n ) ) a=bd , T(n)=O(ndlog(n)) a=bd,T(n)=O(ndlog(n))
  • a < b d , T ( n ) = O ( n d ) a<bd , T(n)=O(nd) a<bd,T(n)=O(nd)
  • a > b d , T ( n ) = O ( n l o g b ( a ) ) a>bd , T(n)=O(nlogb(a)) a>bd,T(n)=O(nlogb(a))

快速排序

快速排序算法是基于分治策略的另一个排序算法。其基本思想是,对于输入的子数组a【p:r】,按以下三个步骤进行排序。
①分解(Divide) :以a【p】为基准元素将a【p : 】划分成3段a 【p : q-1) ,a 【g】和a【g+1 :r】,使ap : q-1】中任何一个元素小于等于a 【g】,而a【q+1:】中任何一个元素大于等于a【g】 】。下标q在划分过程中确定。
②递归求解(Conquer):通过递归调用快速排序算法,分别对a 【p : q-1】和a【g+1:】进行排序。
③合并(Merge):由于对a 【p: q-1】和a【g+1 : r】的排序是就地进行的,因此在a【p: g-1】和a 【g+1 :r】都已排好的序后,不需要执行任何计算,a【p: r】则已排好序。
基于这个思想,可实现快速排序算法如下:

根据基本思路,得到以下代码:

对应的题目【模板】快速排序

代码:

#include<iostream>
#include<algorithm>
using namespace std;

const int N = 1E5 + 10;

int n , a[N];

int Partition(int a[] , int p ,int r){
   
   
    int i = p , j = r + 1 ;
    int x = a[p];
    while(true){
   
   
        while(a[++i] < x && i < r ); // 我们向右拓展,直到找到一个比 x 大或者等于的
        while(a[--j] > x ); // 我们向左延伸,直到遇到一个 <= x 的数
        if(i >= j)break; // 因为有不等式 a[i] >= x >= a[j] ,也就是最终i应该在x 右边,j在其左边
        swap(a[i],a[j]); // 但 j 如果在右边,i在左边,则交换
    }
    a[p] = a[j] , a[j] = x; // j为划分点
    return j;
}

void qsort(int a[] , int p , int r){
   
   
    if(p < r){
   
   
        int q = Partition(a , p ,r); // 分解,分为以 a[q]为界限分为三段
        qsort(a , p ,q - 1); // 对左半段排序
        qsort(a , q + 1 ,r); // 对右半段排序
    }
}

int main(){
   
   
    cin>>n;
    for(int i = 1 ; i <= n ; ++i)cin>>a[i];
    qsort(a , 1 , n);
    for(int i = 1 ; i <= n ; ++i)cout<<a[i]<<" ";
    return 0;
}

快速排序的运行时间与划分是否对称有关,其最坏情况发生在划分过程产生的两个区域分别包含n-1个元素和1个元素的时候。由于函数Partition)的计算时间为O(n),所以如果算法Partition的每步都出现这种不对称划分,则其计算时间复杂性T(n)满足
T ( n ) = { O ( 1 ) n < = 1 T ( n − 1 ) O ( n ) x > 1 T(n) = \begin{cases} O(1) & n <= 1 \\ T(n-1) O(n) & x >1 \\ \end{cases} Tn={ O(1)T(n1)O(n)n<=1x>1

我们可以通过递归子树来求解。如下图
在这里插入图片描述
这很明显是一个等差数列,我们利用求和公式很容易解出,此递归方程,可得 T ( n ) = O ( n 2 ) T(n) = O(n^2) T(n)=O(n2)
在最好情况下,每次划分所取的基准都恰好为中值,即每次划分都产生两个大小为n/2的区域,此时,Partition算法的计算时间T(n)满足
T ( n ) = { O ( 1 ) n < = 1 2 T ( n / 2 ) + O ( n ) x > 1 T(n) = \begin{cases} O(1) & n <= 1 \\ 2T(n/2) + O(n) & x >1 \\ \end{cases} Tn={ O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落春只在无意间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值