• 递归与分治策略-学习笔记


     

    递归的概念

     

    递归算法:直接或间接地调用自身的算法

    递归函数:用函数自身给出定义的函数

    递归方法的构造

    构造递归方法的关键在于建立递归关系。这里的递归关系可以是递归描述的,也可以是递推描述的。下面由一个求n的阶乘的程序为例,总结出构造递归方法的一般步骤。

    [1]从键盘输入正整数N0<=N<=20),输出N!

    [分析]N!的计算是一个典型的递归问题。使用递归方法来描述程序,十分简单且易于理解。

    [步骤1]描述递归关系 递归关系是这样的一种关系。设{U1,U2,U3,,Un}是一个序列,如果从某一项k开始,Un和它之前的若干项之间存在一种只与n有关的关系,这便称为递归关系。

    注意到,当N>=1时,N!=N*(N-1)!N=1时,0!=1),这就是一种递归关系。对于特定的K!,它只与K(K-1)!有关。

    [步骤2]确定递归边界 在步骤1的递归关系中,对大于kUn的求解将最终归结为对Uk的求解。这里的Uk称为递归边界(或递归出口)。在本例中,递归边界为k=0,即0!=1对于任意给定的N!,程序将最终求解到0!

    确定递归边界十分重要,如果没有确定递归边界,将导致程序无限递归而引起死循环。例如以下程序:

    #include <iostream.h>
    
    int f(int x){
    
     return(f(x-1));
    
    }
    
    main(){
    
     cout<<f(10);
    
    }

    它没有规定递归边界,运行时将无限循环,会导致错误。

    [步骤3]写出递归函数并译为代码 将步骤1和步骤2中的递归关系与边界统一起来用数学语言来表示,即

         N*(N-1)! 当N>=1

    n!=

         1       N=0

    再将这种关系翻译为代码,即一个函数:

    long f(int n){
    
     if (n==0)
    
      return(1);
    
     else
    
      return(n*f(n-1));
    
    }

    [步骤4]完善程序 主要的递归函数已经完成,将程序依题意补充完整即可。

    #include <iostream.h>
    
    long f(int n){
    
     if (n==0)
    
      return(1);
    
     else
    
      return(n*f(n-1));
    
    }
    
    main(){
    
     int n;
    
     cin>>n;
    
     cout<<endl<<f(n);
    
    }

     

    经典递归问题

    [2]Fibonacci数列(兔子繁殖)问题:已知无穷数列A,满足:A(1)=A(2)=1A(N)=A(N-1)+A(N-2)N>=3)。从键盘输入N,输出A(N)

    [分析]递归关系十分明显,由A(N)的表达式给出。需要注意的是本例中对于N>=3A(N)的值与A(N-1)A(N-2)都有关。

    #include <iostream.h>
    
    long fibonacci(int x)
    
    {
    
     if ( (x==1) || (x==2) )
    
      return(1);
    
     else
    
      return(fibonacci(x-1)+fibonacci(x-2));
    
    }
    
    main(){
    
     int n;
    
     cin>>n;
    
     cout>>endl>>fibonacci(n);
    
    }

     [3]Hanoi塔问题。

    [问题描述]在霍比特人的圣庙里,有一块黄铜板,上面插着3根宝石针(分别为A号,B号和C号)。在A号针上从下到上套着从大到小的n个圆形金片。现要将A针上的金片全部移到C针上,且仍按照原来的顺序叠置。移动的规则如下:这些金片只能在3根针间移动,一次只能一片,且任何时候都不允许将较大的金片压在较小的上面。从键盘输入n,要求给出移动的次数和方案。

    [分析]由金片的个数建立递归关系。当n=1时,只要将唯一的金片从A移到C即可。当n>1时,只要把较小的(n-1)片按移动规则从A移到B,再将剩下的最大的从A移到C(即中间“借助”B把金片从A移到C),再将B上的(n-1)个金片按照规则从B移到C(中间“借助”A)。

    本题的特点在于不容易用数学语言写出具体的递归函数,但递归关系明显,仍可用递归方法求解。

    #include <iostream.h>
    
    hanoi(int n,char t1,char t2,char t3){
    
     if (n==1)
    
      cout<<"1 "<<t1<<" "<<t3<<endl;
    
     else
    
     {
    
     hanoi(n-1,t1,t3,t2);
    
      cout<<n<<" "<<t1<<" "<<t3<<endl;
    
     hanoi(n-1,t2,t1,t3);
    
     }
    
    }
    
    main(){
    
     int n;
    
     cout<<"Please enter the number of Hanoi:";
    
     cin>>n;
    
     cout<<"Answer:"<<endl;
    
     hanoi(n,'A','B','C');
    
    }

     

    分治策略

    基本概念

    分治策略是对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。

    基本步骤

    step1分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;

    step2解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题;

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

    它的一般的算法设计模式如下:

        Divide-and-Conquer(P)

        if |P|≤n0

         then return(ADHOC(P))

        将P分解为较小的子问题 P1 ,P2 ,...,Pk

         for i←1 to k

         do yi ← Divide-and-Conquer(Pi) △递归解决Pi

        T ← MERGE(y1,y2,...,yk) △合并子问题

         return(T)

    其中|P|表示问题P的规模,n0为一阈值,表示当问题P的规模不超过n0时,问题已容易直接解出,不必再继续分解。ADHOC(P)是该分治法中的基本子算法,用于直接解小规模的问题P,因此,当P的规模不超过n0时直接用算法ADHOC(P)求解。算法MERGE(y1,y2,...,yk)是该分治法中的合并子算法,用于将P的子问题P1 ,P2 ,...,Pk的相应的解y1,y2,...,yk合并为P的解。

    (例)二分查找

    public class partFind {
        public static int whilefind(int[] arr,int val){//5  6  7  10
            int right=0;
            int left=arr.length-1;
            while (right<=left){
                int mid=(right+left)/2;//当范围数值过大可以采用:mid=left+(right-left)/2    0.618
                if (val==arr[mid]){
                    while (mid>0&&arr[mid-1]==val) --mid;//如果数组中存在相同元素,且要求返回的是最右边值的下标
                    return mid;
                }
                if (val<arr[mid]){
                    left=mid-1;
                }
                if (val>arr[mid]){
                    right=mid+1;
                }
            }
            return -1;
        }
        public static void main(String[] args) {
            int[] arr={12,12,23,23,23,34,45,56};
            System.out.println(whilefind(arr,12));
        }
    }
  • 相关阅读:
    面向对象设计原则
    面向对象设计流程
    mysql远程连接命令(转)
    如何使用matplotlib绘制一个函数的图像
    svn:ignore eclipse开发一般忽略文件
    zookeeper client 常用操作
    pip使用
    vi常用快捷键
    python常用函数
    RabbitMQ 学习记录
  • 原文地址:https://www.cnblogs.com/Ytcstrive/p/13423235.html
Copyright © 2020-2023  润新知