C Primer Plus学习_35 递归

C允许函数调用他自己,这种调用的过程成为递归(recursion)。递归有时难以捉摸,有时却很方便实用。结束递归是使用递归的难点,因为如果递归代码中没有终止递归的条件测试部分,一个调用自己的函数就会无限递归(有点像循环)

演示递归

/*recur.c -- 递归演示*/
#include <stdio.h> 
void up_and_down(int);

int main (void)
{
	up_and_down(1);
	return 0;
}

void up_and_down(int n)
{
	printf("Level %d: n location %p\n", n, &n);	// #1
	if (n < 4){
		up_and_down(n + 1);
	}
	printf("LEVEL %d: n location %p\n", n, &n);	// #2
}

下面是Windos系统的输出结果:

首先,main()调用了带参数1的up_and_down()函数,执行结果是up_and_down()中的形参n的值是1,打印语句#1 Level1。然后由于n<4,up_and_down()(第1级)调用实际参数为n+1(2)的up_and_down()(第2级),于是第2级调用的n值是2,打印语句#1, Level2。以此类推到Level4.

当执行到第4级的时候,n的值是4,使用if测试条件为假。up_and_down()函数不再调用自己。第4级调用接着执行写一条语句,也就是#2,即打印LEVEL4。此时第4级调用结束,控制被传回他的主调函数(第3级),接着打印LEVEL3,以此类推到LEVEL1.

 尾递归

最简单的递归形式是把递归放在函数的末尾,在return语句前,这种形式的递归被称为尾递归。相当于循环。

下面是一个分别用循环和递归计算阶乘的程序:

/*factor.c -- 分别用循环和递归计算阶乘*/
#include <stdio.h>
long fact(int n);
long rfact(int n);
int main (void)
{
	int num;
	
	printf("计算阶乘!\n");
	printf("输入一个0-12是数(q退出):\n");
	while (scanf("%d", &num) == 1){
		if(num < 0 || num > 12){
			printf("输入错误,范围0-12!\n");
		}else{
			printf("循环:%d!结果为%ld\n", num, fact(num));
			printf("递归:%d!结果为%ld\n", num, rfact(num));
		}
	}
	printf("结束,告辞!\n");
	
	return 0;
} 

long fact(int n){
	long ans;
	
	for(ans = 1; n > 1; n--){
		ans *= n;
	}
	
	return ans;
}

long rfact(int n){
	long ans;
	if(n > 1){
		ans = n * rfact(n - 1); 
	}else{
		ans = 1;
	}
	
	return ans;
}

运行结果为:

计算阶乘!
输入一个0-12是数(q退出):
5
循环:5!结果为120
递归:5!结果为120
12
循环:12!结果为479001600
递归:12!结果为479001600
13
输入错误,范围0-12!
0
循环:0!结果为1
递归:0!结果为1
-2
输入错误,范围0-12!
q

使用循环的函数把初始值ans初始化为1,如何与n~12的数相乘,根据阶乘公式应当乘1,但没有影响。

使用递归的函数,该函数的关键是n! = n * (n-1)! 。可以这样做是因为(n-1)!是(n-1)~ 1的所有整数的乘积。因此,n乘以n-1就得到了n的阶乘。 

既然递归和循环都可以用来计算,那么到底该用谁呢?

一般而言,选择循环比较好。

首先,使用递归每次都会创建一组变量,所以递归使用的内存更多,而且每次递归都会创建一个新的变量在栈内存中,因此递归受到内存的限制。其次每次还是调用都要花费一定的时间,使用递归执行的速度会比较慢。

递归和倒序计算

递归在处理倒序计算是比较方便。

编写一个函数,打印一个整数的二进制数。

/*binary.c -- 打印一个二进制数*/
#include <stdio.h>
void to_binary(unsigned long n);

int main (void)
{
	unsigned long n;
	
	printf("Enter an integer (q to quit):\n");
	while(scanf("%lu", &n) == 1){
		printf("Binary equivalent:");
		to_binary(n);
		putchar('\n');
		printf("Enter an integer (q to quit):\n");	
	}
	printf("Done.\n");
	
	return 0;
}

void to_binary(unsigned long n)
{
	int r;
	
	r = n % 2;
	if(n >= 2){
		to_binary(n/2);
	} 
	putchar(r == 0 ? '0' : '1');
	
	return;
}

运行结果为:

设计一个二进制形式表示整数的算法。例如,用二进制数表示十进制5?在二进制中,奇数末尾一定是1,偶数末尾一定是0,所以通过(5%2)来确定末尾是1还是0。一般而言,对于数字n,其二进制的最后一位是n%2。因此第一位数字实际上是待输出二进制数的最后一位数。这一规律提示我们,在递归函数调用之前计算n%2,递归调用之后打印结果。这样n%2的值,正好在最后一位。

 递归的优缺点

优点:递归为某些编程问题提供了最简单的解决方案。

缺点:一些递归算法会快速消耗内存空间。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值