3递归式的三种方法

递归的概念

递归函数

用函数自身给出定义的函数

递归算法

一个算法包含对自身的调用(直接或间接调用)

整数划分

问题:
将正整数n表示成一系列正整数之和:
n=n1+n2+…+nk,其中n1≥n2≥…≥nk≥1,k≥1
正整数n的这种表示称为正整数n的划分
正整数n的不同的划分个数称为正整数n的划分数p(n)
目标:求正整数n的不同划分个数p(n)

思路:
我们假设函数f(n,m)
n为要整数划分的数,m为划分中出现的最大加数
且加数都是大于等于1,可以是一个加数即自己本身

p(6)=11
6
5+1
4+2,4+1+1
3+3,3+2+1,3+1+1+1
2+2+22+2+1+12+1+1+1+1
1+1+1+1+1+1

根据n和m的关系,考虑以下几种情况:

   (1)当n=1时,不论m的值为多少(m>0),只有一种划分即{1};

    (2)  当m=1时,不论n的值为多少,只有一种划分即n个1,{1,1,1,...,1};

    (3)  当n=m时,根据划分中是否包含n,可以分为两种情况:

          (a). 划分中【包含n】的情况,只有一个即{n};

          (b). 划分中【不包含n】的情况,这时划分中最【】大的数字也一定比n小】,即n的所有(n-1)划分。

          因此 f(n,n) =1 + f(n,n-1);
          例如:f(6,6)=1+f(6,5)
    (4) 当n<m时,由于划分中不可能出现负数,因此就相当于f(n,n);例如f(3,5)=f(3,3)

    (5) 但n>m时,根据划分中是否包含最大值m,可以分为两种情况:
           (a). 划分中包含m的情况,即{m, {x1,x2,...xi}}, 其中{x1,x2,... xi} 的和为n-m,可能再次出现m,因此是(n-m)的m划分,因此这种划分 ,个数为f(n-m, m);

           (b). 划分中不包含m的情况,则划分中所有值都比m小,即【n的(m-1)】划分,个数为f(n,m-1);

          因此 f(n, m) = f(n-m, m)+f(n,m-1);

综合以上情况,我们可以看出,上面的结论具有递归定义特征,其中(1)和(2)属于回归条件,(3)和(4)属于特殊情况,将会转换为情况(5)。而情况(5)为通用情况,属于递推的方法,其本质主要是通过减小m以达到回归条件,从而解决问题。其递推表达式如下:

f(n, m)= 1; (n=1 or m=1)

f(n, n); (n<m)

1+ f(n, m-1); (n=m)

f(n-m,m)+f(n,m-1); (n>m)
在这里插入图片描述
最后p(n)==f(n,n)

 #include <stdio.h>
int split(int n,int m)
{
	 if (n==1||m==1) 
	      return 1;
	 else if (n<m) 
	     return split(n,n);
	 else if (n==m) 
	      return 1+split(n,n-1);
	 else  
	     return split(n,m-1)+split(n-m,m);
 
} 
 
int main()
{
	int n;
	printf("输入划分数:");
	scanf("%d",&n);
	printf("整数划分为:%d\n",split(n,n));
	return 0;
}

汉诺(Hanoi)塔问题

问题:任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。在这里插入图片描述
思路:
假设总共需要移动n个盘子
1.将A柱上的n-1个盘子借助C柱移向B柱
2.将A柱上仅剩的最后一个盘子移向C柱
3.将B柱上的n-1个盘子借助A柱移向C柱

Hn是n个盘子从a移动到c的次数

  • n=1 a的盘移动到c; 即直接移动不用借助其他柱子 所以不写move

  • n=2 将a柱上面的小盘移到b,将a最下面的大盘移到c,再将b上的移到c ,移了3次,H2=3

  • n>2 将a柱上面的n-1个小盘移到b(借助c),将a最下面的大盘移到c,再将b上的n-1个盘移到c(借助a) , 总共移动Hn-1 + 1 + Hn-1 所以Hn=2Hn-1 + 1

  • 将n个圆盘从a柱子上借助c柱子移动到b柱子上move(n-1,a,c,b) move(n-1,b,a,c)

代码实现

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

//将n个圆盘从x柱子上借助y柱子移动到z柱子上
void move(int n, char x, char y, char z)	
{	
	if(n==1)					//圆盘只有一个时,只需将其从x塔移到z塔
		printf("圆盘编号%d :从 %c 移动到 %c\n", n, x, z);
	else
	{
		move(n-1, x, z, y);		//递归,把x塔上编号1~n-1的圆盘移到y上,以z为辅助塔
		printf("圆盘编号%d :从 %c 移动到 %c\n", n, x, z);
		move(n-1, y, x, z);		//递归,把y塔上编号1~n-1的圆盘移到z上,以a为辅助塔
	}
}

int main()
{
	int n;		//n代表圆盘的个数
	
	/*A,B,C分别代表三个柱子*/
	char ch1 = 'A';
	char ch2 = 'B';
	char ch3 = 'C';
	
	printf("请输入圆盘的个数:");
	scanf("%d", &n);
	move(n, ch1, ch2, ch3);
	return 0;
}

递归式

当一个算法包含对自身的递归调用时,其
运行时间通常可以用递归式来表示

在这里插入图片描述

在这里插入图片描述

递归式解法

代换法(substitution method)
递归树方法(recursion-tree method)
主方法(master method
代换法
步骤

  • 猜测解的形式
  • 用数学归纳法证明之
  • 只适用于解的形式很容易猜的情形
  • 如何猜测则需要经验
  • 不常用 (例子可不看)
    在这里插入图片描述在这里插入图片描述在这里插入图片描述
    递归树
  • 每一个节点代表递归函数调用集合中一个 子问题的代价,将所有层的代价相加得到 总代价,递归式作为孩子结点(T(xn)部分O(xn)部分作为父结点
    例子:
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
T(n)=4T(n/2)+n 的递归树

在这里插入图片描述

  • 该树长度为 log2n

因为原本的问题规模为 n ,到了树的最底层,为 1 了,也就是说,每次往下一层,规模变为 1/2,假设它变成 i 个节点,则 n / 2i = 1 ,即 n = 2i ,所以 i = log2n

  • 图中所有节点之和为:

在这里插入图片描述
n+2n+4n+8n+16n+…(2i)n = (1+2+4+…+2i)n 根据等比数列求和公式可得: 1*(1-2i)/(1-2) = 2i-1 因为i=log2n 所以2^(log2n) - 1
所以图中所有节点之和为:n(n-1)=n2-n 所以时间复杂度为O(n2)

主方法
主定理1
在这里插入图片描述
在这里插入图片描述
主定理2
在这里插入图片描述
在这里插入图片描述

直觉上来说两个函数的较大者决定了递归式的解,如果两个函数相当,则乘上一个对数因子logn

  需要注意的是主方法并没有覆盖所有可能性,所有的大于和小于都是`多项式意义上的大于和小于`,对于有些递归式夹在三种情况的间隙中,是无法用主方法来求解的。下面解释一下什么是多项式意义上的小于和大于:

 f(x)多项式大于g(x):存在实数e>0,使得`f(x)>g(x)*n^e`
 f(x)多项式小于g(x):存在实数e>0,使得`f(x)<g(x)*n^e`

举个例子,有递归式T(n) = 2T(n/2)+nlgn, 在这里插入图片描述= n,nlgn/n = lgn,此时不存在e>0,使得nlgn>nn^e,所以就不能用主方法求解。
主方法的应用:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

求递推式的例子

在这里插入图片描述在这里插入图片描述
假设mergesort总体时间是T(n) 所以对半mergesort是T(n/2) merge是O(n) ,当c无穷大时,O(n)==cn,且因为序列不断二分进行mergesort所以序列长度n=2^k
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

快速排序

在这里插入图片描述

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值