递 归

1递归的定义:

递归:

参加“递归”。

什么?这个定义什么也没有说啊!好吧,说一下:

递归:

如果还是没明白递归是什么意思,参加“递归”。

噢,也许这次你明白了,原来递归就是“自己用到自己”的意思。

也可理解为:

A经理:“这事不归我管,去找B经理。”于是你去找B经理。

B经理:“这事不归我管,去找A经理。”于是你又回到了A经理这儿。

接下来发生的事情就不难想到了。是要两个经理的说辞不变,你又始终听话,你将会永远往返于两个经理之间,这叫无限递归(Infinite Recursion)。尽管在这里,A经理并没有让你找他自己,但还是回到了他这里。换句话说,“间接地用到自己”也算递归。

2栈:

2.1调用栈(递归中用到的一个知识,粗略讲解):

all stack(通常译作“调用栈”)也是计算机系统中的一个重要概念。在介绍 call stack 之前,我们首先来回顾一下 procedure 是什么。

在计算机程序当中,一个 procedure(通常译作“过程”)吃进来一些参数,干一些事情,再吐出去一个返回值(或者什么也不吐)。我们熟悉的 function、method、handler 等等其实都是 procedure。

当一个 procedure A 调用另一个 procedure B 的时候,计算机其实需要干好几件事。

一是转移控制——计算机要暂停 A 并开始执行 B,并让 B 在执行完之后还能回到 A 继续执行。

二是转移数据——A 要能够传递参数给 B,并且 B 也能返回值给 A。

三是分配和释放内存——在 B 开始执行时为它的局部变量分配内存,并在 B 返回时释放这部分内存。

同学们想一下,假设 A 调用 B,B 再调用 C,C 执行完返回给 B,B 再执行完返回给 A,哪种数据结构最适合管理它们所使用的内存?没错,是 stack,因为过程调用具有 last-in first-out 的特点。当 A 调用 B 的时候,A 只要将它需要传递给 B 的参数 push 进这个 stack,再把将来 B 返回之后 A 应当继续执行的指令的地址(学名叫 return address)也 push 进这个 stack,就万事大吉了。之后 B 可以继续在这个 stack 上面保存一些寄存器的值,分配局部变量,进而继续构造调用 C 时需要传递的参数等等。

这个 stack 其实就是我们所说的 call stack。(这里的描述有些简化,实际当中计算机会做一些优化,如果参数和局部变量不太多的话就懒得放在 call stack 里,而是直接使用寄存器了。)

Call stack 在 virtual memory 里其实就是一段连续的地址空间,靠一个叫做 SP 的寄存器(32-bit 叫 ESP,64-bit 叫 RSP)来指向栈顶。既然是连续的,于是它在使用上比我们理论课上讲的抽象的 stack 要更灵活一些,更接近 array 而不是 linked list,可以访问任意元素,而不仅仅是栈顶元素。(当然进栈出栈还是只能在栈顶进行。)这也就是为什么尽管它叫做 call stack,我们依然可以同时有不止一个参数和不止一个局部变量的原因。

如果任然无法理解,可以做如下比喻。

皇帝(拥有main函数的栈帧):大臣你给我算一下f(3)。

大臣(拥有f(3)函数的栈帧):大臣你给我算一下f(2)。

知府(拥有f(2)函数的栈帧):大臣你给我算一下f(1)。

县令(拥有f(1)函数的栈帧):大臣你给我算一下f(0)。

师爷(拥有f(0)函数的栈帧):回老爷,f(0)=1。

县令(心算f(1)=f(0)*1=1):回知府,f(1)=1。

知府(心算f(2)=f(1)*2=2):回大人,f(2)=2。

大臣(心算f(3)=f(2)*3=6):回皇上,f(3)=6。

2.2函数栈帧的创建和销毁:

2.2.1寄存器:

eax

ebx

ecx

edx

ebp

esp等

且ebp和esp两个寄存器为函数栈帧。其存放的为地址,用来维护函数栈帧。

压栈:给栈顶放一个元素。

出栈:给栈顶删除一个元素。

栈帧是由高地址移向低地址。

2.2.2定义:

我们在写C语言代码的时候,经常会把一个独立的功能抽象为函数,所以C程序是以函数为基本单位的。

那函数是如何调用的?函数的返回值又是如何待会的?函数参数是如何传递的?这些问题都和函数栈帧有关系。

函数栈帧(stack frame)就是函数调用过程中在程序的调用栈(call stack)所开辟的空间,这些空间是用来存放:

函数参数和函数返回值
临时变量(包括函数的非静态的局部变量以及编译器自动生产的其他临时变量)
保存上下文信息(包括在函数调用前后需要保持不变的寄存器)。

3递归函数:

有5个学生坐在一起,问第5个学生多少岁,他说比第4个学生大2岁。问第
4个学生岁数,他说比第3个学生大2岁。问第3个学生,又说比第2个学生大2岁。问第
2个学生,说比第1个学生大2岁。最后问第1个学生,他说是10岁。请问第5个学生
多大。

递归图像详解。

对应程序如下:


#include <stdio.h>
 
int get(int c)//调用函数get
{
	int age;
	if(c==1){
		age=10;
	}else {
		age=getAge(c-1)+2;//运用递归求解
	}
	return age;
}
 
 
int main()
{
	int age;
	int num;
	printf("你要知道第几个学生的年龄?\n");
	scanf("%d",&num);
	age=get(num);
	printf("第%d个学生年龄为:%d\n",num,age);
	return 0;
}

例如:数学函数也可以递归定义。例如,阶乘函数f(n)=n!可以定义为。

f(0)=1;f(n)=f(n-1)*n(n>=1)

对应的程序如下:

#include <stdio.h>

int Di(int a) {
	int o = 0;
	if (a == 1)
		o = 1;
	else
		o = Di(a - 1) * a;
	return o;
}

int main() {
	int a = 0;
	scanf("%d", &a);
	int rew = Di(a);
	printf("%d", rew);
	return 0;

}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值