参考:1.网课:数据结构与算法基础(青岛大学-王卓)
2.教材:数据结构(c语言版)第二版,严蔚敏,李冬梅等著
非科班自学,如有错误望不吝赐教。
递归与栈
0.递归的定义
简单来说,递归就是自己调用自己,然后一层一层的返回。
函数可以调用自己
注意要设置停止条件
1.递归的过程,与栈的关系
栈与递归的关系,函数的递归调用和普通函数调用是一样的。当程序执行到某个函数时,将这个函数进行入栈操作,在入栈之前,通常需要完成三件事。
1、将所有的实参、返回地址等信息传递给被调函数保存。
2、为被调函数的局部变量分配存储区。
3、将控制转移到北调函数入口。
当一个函数完成之后会进行出栈操作,出栈之前同样要完成三件事。
1、保存被调函数的计算结果。
2、释放被调函数的数据区。
3、依照被调函数保存的返回地址将控制转移到调用函数。
上述操作必须通过栈来实现,即将整个程序的运行空间安排在一个栈中。每当运行一个函数时,就在栈顶分配空间,函数退出后,释放这块空间。所以当前运行的函数一定在栈顶。
(个人理解)
调用:就是把参数依次入栈
回退:把参数(对应的值)依次出栈
比如:
依次将8,4,2,1,0入栈;
再将0对应的1,1对应的1F(0),…,8对应的8F(4)出栈
2.Ackerman函数
递归方法
#include <stdio.h>
int Ack(int m,int n)
{
if(n<0||m<0){
return 0;
}
else if(m==0){
return n+1;
}
else if(n==0){
return Ack(m-1,1);
}
else
return Ack(m-1,Ack(m,n-1));
}
int main(){
int m=4,n=3;
printf("%d",Ack(m,n));
}
非递归方法:
#include "stdio.h"
#include <stdlib.h>
typedef int DataType;
typedef struct node
{
DataType m, n;
struct node* next;
} LinkStack;//每个结点由数据域m和n,以及指针域next构成
void Show(LinkStack* p)
{
printf("m:%d n:%d\n", p->m, p->n);
}//打印当前节点的m和n值
DataType Akm(DataType m, DataType n)
{
printf("以下模拟进出栈过程:");
LinkStack* Top = (LinkStack*)malloc(sizeof(LinkStack));
Top->m = m;
Top->n = n;
Top->next = NULL;//初始化链栈
Show(Top);
DataType result = 0;
while (Top != NULL)
{
//akm(m,n)=n+1,if m=0
if (Top->m == 0 && Top->n >= 0)
{
DataType x = Top->n + 1;
while (Top != NULL && Top->n >= 0)//把到(0,n)上的结点全部释放掉
{
//出栈
LinkStack* p = Top;
Top = Top->next;
free(p);
printf("pop\n");
}
if (Top == NULL) //最终结果
{
result = x;
break;
}
else if (Top->n < 0)//把中间结果入栈(替换原来的-1)
{
Top->n = x;
}
}
//akm(m,n)=akm(m-1,1),if m>0&&n=0 将m-1和1入栈
else if (Top->m > 0 && Top->n == 0)
{
LinkStack* p = (LinkStack*)malloc(sizeof(LinkStack));
p->m = Top->m - 1;
p->n = 1;
p->next = Top;
Top = p;
Show(Top);
}
//akm(m,n)=akm(m-1,akm(m,n-1)),if m>0&&n>0 先将m-1和-1入栈再将m和n-1入栈 ,接下来是计算akm(m,n-1)了
else if (Top->m > 0 && Top->n > 0)
{
LinkStack* p = (LinkStack*)malloc(sizeof(LinkStack));
LinkStack* q = (LinkStack*)malloc(sizeof(LinkStack));
p->m = Top->m - 1;
p->n = -1;
q->m = Top->m;
q->n = Top->n - 1;
p->next = Top;
Top = p;
Show(Top);
q->next = Top;
Top = q;
Show(Top);
}
}
return result;
}
void main()
{
int m,n;
scanf("%d,%d",&m,&n);
if(m<0 ||n<0) return 0;
DataType r = Akm(m, n);
printf("结果为:%d\n", r);
}
这篇博客讲的很详细:如何使用栈非递归地求解Ackerman函数