递归与分治策略

递归概念:直接或者间接调用自身的算法称为递归算法。

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

分治法的基本思想:将一个规模为n的问题分解为k个规模较小的子问题,这些子问题是相互独立些与原问题相同。

递归地解决这些子问题,然后将各子问题的解合并得到原问题的解。

1.阶乘函数

n!={1            n=0

       n(n-1)!   n>0

public static int factorial(int n)//参数n为非负数

{ if(n==0) return 1;

  return n*factorial(n-1);

}

2.Fibonacci数列

数列1,1,2,3,5,8,13,21,34,55,称为Fibonacci数列

F(n)={1                     n=0,1

          F(n-1)+F(n-2)  n>1

public static int fibonacci(int n)

{if(n<=1){return 1;}

return fibonacci(n-1)+fibonacci(n-2)

}

3.排列问题

我们先分析一下全排列算法是如何实现的

以list[3]={1,2,3}为例。

一、先是123,然后1与1自己对换,递归排列23,2与2自己对换,递归排列3,再递归时满足start==length,即越界,所以把123打印出来;

然后上一步2与2自己对换后,2与3对换,(暂时是132),递归到2与2对换,再递归满足start==length,打印132;

二、最先一步1与1自己对换后,1与2对换,(暂时是213),递归排列13,1与1自己对换,递归排列3. 3与3自己对换,然后满足If条件打印213:

然后退一步,1与3对换,(暂时是231),递归到1与1自己对换,再递归满足打印条件,打印231;

三、1与1、2对换后,1最后与3对换,(暂时是321),递归排列21,2与2对换,递归排列1.1与1自己对换,后来满足打印条件打印321. 2再与1对换,再递归到2与2自己对换,后来打印出312.

附带程序:

public static void perm(Object[] list,int k,int m)

{

if(k==m)

{     for(int i=0;i<=m;i++){

            System.out.print(list[i]);

           }

       System.out.println();


}

else{

     for(int i=k;i<=m;i++)

     {MyMath.swap(list,k,i);

      perm(list,k+1,m);

      MyMath.swap(list,k,i);

       }


}

}

4.Hanoi塔问题

汉诺(Hanoi)塔问题:古代有一个梵塔,塔内有三个座A、B、C,A座上有64个盘子,盘子大小不等,大的在下,小的在上(如图)。有一个和尚想把这64个盘子从A座移到B座,但每次只能允许移动一个盘子,并且在移动过程中,3个座上的盘子始终保持大盘在下,小盘在上。在移动过程中可以利用B座,要求打印移动的步骤。如果只有一个盘子,则不需要利用B座,直接将盘子从A移动到C。

  • 如果有2个盘子,可以先将盘子1上的盘子2移动到B;将盘子1移动到c;将盘子2移动到c。这说明了:可以借助B将2个盘子从A移动到C,当然,也可以借助C将2个盘子从A移动到B。
  • 如果有3个盘子,那么根据2个盘子的结论,可以借助c将盘子1上的两个盘子从A移动到B;将盘子1从A移动到C,A变成空座;借助A座,将B上的两个盘子移动到C。这说明:可以借助一个空座,将3个盘子从一个座移动到另一个。
  • 如果有4个盘子,那么首先借助空座C,将盘子1上的三个盘子从A移动到B;将盘子1移动到C,A变成空座;借助空座A,将B座上的三个盘子移动到C。

public static void hanoi(int n,int a,int b,int c){

if(n>0){

hanoi(n-1,a,c,b);//表示将n-1个圆盘从a移动到c,借助于b盘

move(a,b);//表示将塔座a上的圆盘移动到塔座b上

hanoi(n-1,c,b,a);

}

}

5.二分搜索递归表示

public static int binarySearch(int [] a,int x,int n){

int left=0;int right=n-1;

while(left<=right)

{int middle=(left+right)/2;

if(x==a[middle])return middle;

if(x>a[middle])left=middle;

else{right==middle-1}

}

return -1;//未找到x

}

6.合并排序(未实现)

public static void mergeSort(int a[],int left,int right)

{

if(left<right){//至少有两个元素

int i=(left+right)/2;

mergeSort(a,left,i);

mergeSort(a,i+1,right);

merge(a,b,left,i,right);//合并到数组b

copy(a,b,left,right);//复制回数组a

}

}

7.快速排序

private static void qSort(int p,int r)//q为第一个元素下标,r为最后一个元素下标

{  if(p<r){

      int q=partitiion(p,r);

     qSort(p,q-1);//

     qSort(q+1,r);

   }

}

private static int partition(int p,int r)

{ int i=p;

  int j=r+1;

  int x=a[p];

  while(true){

  while(a[++i].compareTo(x)<0 && i<r);//从第二个元素找(++i先加后计算)找到比第一个元素大的元素,i为其下标

  while(a[++j].compareTo(x)>0);从最后一个元素开始找,找到比第一元素小的,j为其下标。

  if(i>=j) break;

  MyMath.swap(a,i,j);

 }

 a[p]=a[j];//将j下标的元素放到第一个位置上。

 a[j]=x;//将原来第一个元素放到,它排完序的具体位置。

 return j;//返回第一个元素具体在哪个位置的下标。

}

算法改进

可以在a集合中随机产生一个,而不是将第一个元素作为要排的第一个元素。

private static int randomizedPartition(int p,int r)

{   int i=random(p,r);

    MyMath.swap(a,i,p);

    return partition(p,r);

}


7.线性时间选择

问题描述:给定线性序集中n个元素和一个整数k,k>=1并且k<=n,要求找出n个元素中第k小的元素。

private static Comparable randomizedSelect(int p,int r,int k)

{    if(p==r) return a[p];//找到了第k小元素

     int i=randomizedpartition(p,r);//排好了第i位置的元素。(即当前第i个位置就放的是排好序的那个元素)。

     int j=i-p+1;//左区域的元素个数。

     if(k<=j){

         return randomizedSelect(p,i,k);//去左边区域找。

      }

     else{

         return randomizedSelect(i+1,r,k-j);//(k-j)为n个元素中第k小元素在右边区域是第几小,则为k-j。

           }

     

}


8.最接近点对问题

问题描述:找距离最近的两个点

以下算法未实现

public static double cpair1(s)

{   n=|s|;

    if(n<2) return ;

    d1=cpairl(s1);

    d2=cpairl(s2);

    p=max(s1);

    q=min(s2);

    d=min(d1,d2,q-p);

    return d;

    

}

     



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

醒悟wjn

打赏可获取源码

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

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

打赏作者

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

抵扣说明:

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

余额充值