用迭代或递归实现分治

分治:也就是分而治之,就是把一个复杂的问题分成两个或更多的相同或者相似的子问题,再把子问题分成更小的子问题......直到最后子问题可以简单地直接求解。

这里所有子问题都和它的原问题有相同或者相似的操作。解决原问题的操作 就是 解决所有子问题的操作的合并。

迭代:迭代是对一定步骤的重复执行,在每次执行这些步骤时,都从变量的原值推出它的一个新值,直到最后满足条件停止迭代。

递归:递归就是在函数解决问题时在函数体内调用自身。“递”就是函数一直传递下去直到达到边界条件。“归”就是从最低层的那个函数(运行后并结束)返回它的上一级,然后层层返回,最后返回最外面的函数,此时最外层的函数才运行结束。

这里要重点说明一下分治,分治有一个坑,我一直以为分治就是一个问题A的操作只有分为问题B和问题C,然后问题B和问题C很好解决,然后问题A就解决了,光看定义很容易就得出这个结论。

事实上不是这样,A不会其他什么都不做只是分成B和C,不然B和C也会什么都不做,因为它们都有相同或类似的操作。

举个例子:斐波那契数列求n,用分治的话求n的操作就变为求n-1和n-2加上返回这个两个子问题结果的合,即 return=Fibon(n-1)+Fibon(n-2) 。除了分成两个子问题还有求合这个操作。

下面继续用归并排序和快速排序理解分治。

归并排序中要排好一个待排序列的操作包括以下三个操作:

  1. 找一个中间点center。
  2. 使center的左半边序列有序和右半边序列有序这两个子问题,
  3. 还有利用子问题的解进行归并这个操作。
void MSort(ElemType A[],ElemType TmpA[],int low,int high)//归并排序
{
    if(low<high)//递归结束的条件是待排序列只有一个记录
    {
        int center=(low+high)/2;//从中间划分两个子序列
        MSort( A[],TmpA[],L,center);对左侧子序列进行递归排序
        MSort( A[],TmpA[],center+1,high);对右侧子序列进行递归排序
        Merge( A[],TmpA[],low,center, high);前两步说明左右子序列已经有序了,进行归并
        
    }    
}    

这些子问题都是这样的操作,最后的子问题判断了一下if不符合条件然后退出,属于简单求解)

而快速排序中要排好一个待排序列的操作包括:

  1. 一次划分操作找到枢轴位置。
  2. 使它的枢轴左半边序列有序和枢轴右半边序列有序这个两个子问题。
void Quick_Sort(ElemType A[],int low,int high)//快速排序
{
    if(low<high)//递归跳出的条件
    {
        int pivotpos=Partition(A,low,high);
        Quick_Sort( A,low,pivotpos-1);
        Quick_Sort( A,pivotpos+1,high);
        
    }     
}

 

回归正题,分治是一种解决问题的方法,迭代和递归是实现分治法的具体方法。我们以求斐波那契数列的第n个数为例。

分治法:要求第n个数,我们求n-1和n-2之和。求n-1又分为求n-2和n-3之和,求n-2又分为求n-3和n-4之和,直到最后我们已经知道了第一个数和第二个数是多少。

迭代实现:我们要从最简单的子问题开始迭代。

当n=1或者2时,我们直接解决了问题。

当n=3时,我们发现n不是1和2然后迭代到了3,然后解决了问题。

当n=6时,我们一直从3迭代到4然后5然后6就解决了问题。

这个过程就是解决小问题然后接着解决了大问题的过程,而且也满足对一定步骤重复执行的操作,也满足都从变量的原值推出它的一个新值,直到最后满足条件停止迭代。

#include <stdio.h>
int Fibon(int n)
{
    if(n == 1 || n == 2)return 1;
    int first = 1;
    int second = 1;
    int temp = 0;
    for (int i = 0; i < n - 2; i++)
    {
        temp = first + second;
        first = second;
        second = temp;
    }
    return temp;
}
int main()
{
    int n;
    scanf("%d", &n);
    int Fibon_n = Fibon(n);
    printf("%d", Fibon_n);
    return 0;
}

递归实现:编译器是用栈实现递归的,相当于自动把问题一层一层分解为子问题压入栈中,最后再逆序一层一层回退,这与分治的解决问题的思路一致。

#include <stdio.h>
int Fibon(int n)
{
    if (n == 1 || n == 2) return 1;
    return Fibon(n - 1) + Fibon(n - 2);
}
int main()
{
    int n;
    scanf("%d", &n);
    int Fibon_n = Fibon(n);
    printf("%d", Fibon_n);
    return 0;
}

我们可以看出递归和迭代都是对分治法的具体实现。

递归的优点是代码简洁,更容易理解。缺点是容易栈溢出且效率太低,可能会包含许多重复运算。

迭代的优点就是递归的缺点,迭代的缺点是复杂情况时代码需要考虑很多边界情况。

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

晴落

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

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

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

打赏作者

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

抵扣说明:

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

余额充值