算法与设计分析-递归算法(JAVA+Python)

目录

一、递归

递归的概念

示例1:阶乘函数

示例2:斐波那契数列

示例3 全排列问题

示例4整数划分问题

示例5汉诺塔


一、递归

递归的概念

        直接或间接地调用自身的算法称为递归算法。用函数自身给出定义的函数称为递归函数。在计算机算法设计与分析中,递归技术是十分有用的。使用递归技术往往使函数的定义和算法的描述简洁且易于理解。有些数据结构如二又树等,由于其本身固有的递归特性,特别适合用递归的形式来描述。另外,还有一些问题,虽然其本身并没有明显的递归结构,但用递归技术来求解使设计出的算法简洁易懂且易于分析。

示例1:阶乘函数

我们都知道n!=n*(n-1)*(n-2)*(n-3)*......*1

推导出公式

所以可以从n开始,递推出下一个数,这里利用递推式即可实现递归函数的设计

JAVA代码

public static int factorial(int n){
  if(n==0)return 0 ;
  return n*factorial(n-1);
}

Python3代码

def factorial(n):
    if n == 0:
        return 1
    return n*factorial(n-1)


print(factorial(3))

示例2:斐波那契数列

无穷数列1,1,2,3,5,8,13,21,34,55,......,称为斐波那契数列。

原理:从第三个数开始,数的值为前两个数的和。

所以第n(n>2)个数可以由第(n-1),(n-2)个数推出。

总结出推出递归式子

所以可写出代码求第n个斐波那契数

JAVA代码

public static int fibonacci(int n){
  if(n<=1)return 1;
  return fibonacci(n-1)+fibonacci(n-2);
}

python3代码

def fib(n) 
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fib(n-1) + fib(n-2)


print(fib(2))

示例3 全排列问题

从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。

现有数组

int xlist = [1, 2, 3, 4]

全排列即为

1 2 3 4 
1 3 2 4 
2 1 3 4 
2 3 1 4 
3 2 1 4 
3 1 2 4 
4 2 3 1 
4 3 2 1 
2 4 3 1 
2 3 4 1 
3 2 4 1 
3 4 2 1 
1 4 3 2 
1 3 4 2

简单点取数组=【1,2, 3 】

 

 第一行表示待进行排列的第一个数的待选数。

红色表示选择

第二行表示排列第一个数被选出后第二个数的待选数。

红色表示选择

第三行由于只剩一个待选数,直接构成排列。

可以看出共计6种排列情况,123,132,213,231,312,321

代码实现输出一组数的全排列

python

#定义函数
def perm(xlist, k, m):
    if k == m:
        for x in xlist:
            print(x, end=' ')#这样将末尾的换行符换成空格好看点
        print()#这个是为了换行
    else:
        for i in range(k-1, m-1):
            xlist[k-1], xlist[i] = xlist[i], xlist[k-1]
            perm(xlist, k+1, m)
            xlist[k-1], xlist[i] = xlist[i], xlist[k-1]

#执行函数
xlist = [1, 2, 3, 4]
k = 0
m = len(xlist)
print(perm(xlist, k, m))

结果如下 

 JAVA(swap()报错的话大家自己解决一下)

    public static void perm(int [] list, int k, int m) {
        if (k == m) {
            for (int i = 0; i <= m; i++) {
                System.out.println(list[i]);
            }
            System.out.println();
        } else {
            for (int i = k; i <= m; i++) {
                swap(list, k, i);//算法没问题,我不会java,不知道咋解决这个Mymath库的问题
                perm(list, k + 1, m);
                swap(list, k, i);
            }
        }
    }

    public static void main(String[] args) {
        int []list={1,2,3};
        int k=0;
        int m=list.length;
        perm(list, k, m);
    }

 

示例4整数划分问题

  将正整数n表示为一系列正整数之和

n=n1+n2+n3+n4+......+nk (n1\geqslant n2\geqslant n3\geqslant n4 \cdot \cdot \cdot \geqslant nk\geqslant 1 )

正整数n的这种表示成为正整数n的划分。正整数n的不同划分个数成为正整数n的划分数,记作p(n)。

例如,正整数6有如下11种划分,所以p(6)=11:

6;

5+1;

4+2,4+1+1;

3+3,3+2+1,3+1+1+1;

2+2+2,2+2+1+1,2+1+1+1+1;

1+1+1+1+1+1;

 我们就以这个为实例,推导递推式

在正整数n的所有不同规划中,将最大加数n1不大于m的划分方法个数记作q(n,m)。

我们考虑4种情况

(1)最大加数n1不大于1,此时任何整数n只有一种划分方式

        即q(n,1)=1

q(6,1)=1    即1+1+1+1+1+1。 就是n个1相加。

(2)最大加数n1大于等于n,q(n,m)=q(n,n),m>=n

但实际上不可能大于n,所以也只有一种可能

q(6,6)=1 即6 这一项。

 (3)正整数n的划分由n1=n的划分和n1<=n-1的划分组成。

q(n,n)=1+q(n,n-1)。

(4)正整数n的最大加数n1不大于m的划分由n1=m的划分和n1<=m-1的划分组成。

q(n,m)=q(n,m-1)+q(n-m,m) n>m>1 

 综合4条关系,可得出递归式

q=\left\{\begin{matrix}1 \ \ \ \ \ \ \ \ \ \ \ \ \ \ n=1,m=1 & \\q(n,n) \ \ \ \ \ \ \ \ \ \ \ \ \ \ n<m & \\1+q(n,n-1) \ \ \ \ \ \ \ \ \ \ n=m & \\q(n,m-1)+q(n-m,m) \ \ \ \ \ \ \ n>m>1 & \end{matrix}\right.

 JAVA代码

public static int q(int n,int m){

if((n<1)||(m<1))
return 0;

if((n==1)||(m==1))
return 1;

if(n<m)
return q(n,n);

if(n==m)
return q(n,m-1)+1;

return q(n,m-1)+q(n-m,m);
}

 python代码

def q(n, m):
    if n < 1 or m < 1:
        return 0
    if n == 1 or m == 1:
        return 1
    if n < m:
        return q(n, n)
    if n == m:
        return q(n, m-1)+1
    return q(n, m-1)+q(n-m, m)


print(q(4, 4))

示例5汉诺塔

设x,y,z为3个塔座,开始时,x上有n个圆盘,这些圆盘自上而下,由大到小叠在一起.先要求将x上的一摞圆盘移动到z上。

且要满足规则

规则(1):每次只能移动1个圆盘。
规则(2):任何时刻都不允许将较大的圆盘压在较小的圆盘之上。
规则(3):在满足移动规则(1)和规则(2)的前提下,可将圆盘移至x,y,z中任一塔座上。

下面是动画演示

         上述算法简洁明确,可以证明它是正确的。但只看算法的计算步骤,很难理解它的道理,也很难理解它的设计思想。下面用递归技术来解决同一问题。

        当n=1时,问题比较简单,只要将编号为1的圆盘从塔座x直接移至塔座z上即可。

        当n>1时,需要利用塔座y作为辅助塔座。此时若能设法将n-1个较小的圆盘依照移动规则从塔座x移至塔座y,然后,将剩下的最大圆盘从塔座x移至塔座y,最后,再设法将n-1个较小的圆盘依照移动规则从塔座y移至塔座z。

        由此可见,n个圆盘的移动问题可分为两次n-1个圆盘的移动问题,这又可以递归地用上述方法来做。由此可以设计出解Hanoi塔问题的递归算法如下:

java代码 

public static void hanoi(int n,int x,int y,int z)
{
    if(n>0){
        hanoi(n-1,x,y,z);
        move(x,z);
        hanoi(n-1,y,z,x);
    }
}

//move函数此处不给出,别问,问就是我写不出

python代码(以列表x,y,z做塔座) 

def hanoi(n, x, y, z):
    if n > 0:
        hanoi(n-1, x, y, z)
        move(x, z)
        hanoi(n-1, y, z, x)
#move函数此处不给出,别问,问就是我写不出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

予我心安A3

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

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

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

打赏作者

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

抵扣说明:

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

余额充值