基础-递归

这篇博客探讨了递归编程的概念,通过斐波那契数列、最大公因数计算和汉诺塔问题展示了递归的应用。递归的核心是将大问题分解为小问题,直至找到基本情况。同时,文中也提到了递归的优化,如避免重复计算以提高效率,以及快速幂运算的实现。递归在解决特定问题时能提供简洁的解决方案,但也需要注意其可能导致的性能问题。
摘要由CSDN通过智能技术生成

定义

程序调用自身的编程技巧称为递归。
递归的实质是将问题转化为规模更小的相同问题。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
它的思想类似于下面这个分段函数(斐波那契数列的第x项):在这里插入图片描述

构成递归需具备的条件

  1. 子问题须与原始问题为同样的事,且更为简单;
  2. 不能无限制地调用本身,必须有个出口,转变为非递归状况处理。

例题

斐波那契数列

题目:
无穷数列1,1,2,3,5,8,13,21,34,55…称为Fibonacci数列,它可以递归地定义为
在这里插入图片描述
现要你来求第n个斐波纳奇数。(第1个、第二个都为1)
思路:
虽然我们可以使用递推法简单快速的求出斐波那契数列,但为了熟悉一下递归,我们将使用递归法解决这个问题。
为了求f(x)的值,我们需要先求出f(x-1)和f(x-2)的值,然后返回它们的和。
当x=1或x=2时,我们就可以直接返回答案1。
用函数去模拟上述过程。
代码:

#include <stdio.h>
int Fibonacci(int x)
{
   if (x==1||x==2) return 1;
   return Fibonacci(x-1)+Fibonacci(x-2);
}
int main()
{
   int x,n;
   for (scanf("%d",&n);n--;)
   {
   	scanf("%d",&x);
   	printf("%d\n",Fibonacci(x));
   }
   return 0;
}
最大公因数

题目:
给出两个数,求他们的最大公因数。
思路:
不知道大家是否了解欧几里得算法。
我们约定gcd(x,y)表示x和y的最大公因数(x>y),欧几里得算法表明,gcd(x,y)=gcd(y,x%y)。
下面对该式进行证明:
令ans=gcd(x,y),
则x=mans,y=nans(m和n均为正整数)。
所以x-y=(m-n)ans。
因为ans为x和y的最大公因数,
所以gcd(m,n)=1。
若m-n和n不互质,则有公约数K,且存在正整数p,q,使m-n=pK,n=qK。
所以m=(m-n)+n=pK+qK=(p+q)K,说明K是m和n的公约数,这与题意条件【m和n互质】矛盾。
所以gcd(n,m-n)=1。
所以gcd(m
ans,(n-m)*ans)=ans=gcd(y,x-y)。
又因x%y=x-⌊x/y⌋ *y,
所以gcd(x,y)=gcd(y,x%y)。
用此方法即可快速缩减x和y的范围。当x恰为y的整数倍时,返回答案y。易证用此方法求gcd的时间复杂度为O(log(x+y))。
代码:

#include <stdio.h>
int gcd(int x,int y)
{
  if (x%y==0) return y;
  return gcd(y,x%y);
}
int main()
{
  int x,y,n;
  scanf("%d%d",&x,&y);
  printf("%d\n",gcd(x,y));
}
汉诺塔

题目:
有三根相邻的柱子,标号为A,B,C,A柱子上从下到上按金字塔状叠放着n个不同大小的圆盘,要把所有盘子一个一个移动到柱子B上,并且任意时刻都不能出现大盘子在小盘子上方的情况,请问至少需要移动多少次才能将n个圆盘全部转移到C柱子上。
思路:
将A柱子上的圆盘转移到C柱子上的问题可以转化为:先将n-1个圆盘转移到B柱子上,再将第n个圆盘转移到C柱子上,再将n-1个圆盘转移到C柱子上。
代码:

#include <stdio.h>
//返回把n个盘子从a柱子全部移动到c柱子的方案数 
long long qwq(int n,int a,int b,int c)
{
	if (n==1) return 1; 
	return qwq(n-1,a,c,b)+1+qwq(n-1,b,a,c);
}
int main()
{
	int n;
	scanf("%d",&n);
	printf("%lld",qwq(n,1,2,3));
}

优化:
可以发
现我们进行了过多的重复计算,比如,把n个盘子从a柱子移动到b柱子和把n个盘子从c柱子移动到b柱子没有任何区别。
由此,令a[n]表示把n个盘子由某个柱子移动到另一个柱子的方案数,我们就可以得到一个简单的递推式:a[n]=a[n-1]*2+1。
由高中数学等比数列知识可得:a[n]=2^n-1

快速幂

题目:
求a的b次方对p取余的结果。
a,b,p不超过maxint。
思路:
一个性质:aaa%p=a%pa%pa%p。
一些说法:a模p,a对p取余,a除以p取余(是一个意思)。
循环b次乘a会超时(c语言自带的函数也会超时)。
由幂的运算性质可得:
在这里插入图片描述
我们可以通过这一性质快速计算a的b次方。
代码:

#include <stdio.h>
long long ksm(long long a,long long b,long long p)
{
   if (!b) return 1%p;
   if (b%2) return ksm(a*a%p,b/2,p)*a%p;
   return ksm(a*a%p,b/2,p);
}
int main()
{
   long long a,b,p;
   scanf("%lld%lld%lld",&a,&b,&p);
   printf("%lld^%lld mod %lld=%lld\n",a,b,p,ksm(a,b,p));
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值