数据结构学习-递归初接触
来源:互联网 发布:淘宝hot什么意思 编辑:程序博客网 时间:2024/04/29 05:57
数据结构学习-递归初接触
学习资料-<<数据结构与算法分析-C++版>>,<<算法I-IV-基础,数据结构,排序与搜索>>
一:递归概述
如果一种算法调用自己来完成它的部分工作,就称这种算法是递归的(recursive)。这种方法要想取得成功,必须在比原始问题小的问题上调用自己。总而言之,一个递归算法必须有两个部分:初始情况(base)和递归部分。初始情况只处理可以直接解决而不要再次递归调用的简单输入。递归部分则包含对算法的一次或者多次递归调用,每一次的调用参数都在某种程度上更接近初始情况。
二:递归用法举例:
(1):计算n!
这个例子十分简单:它基于n!=n*(n-1)!
long fact(int n)
{
if(n<=1) return 1;
return n*fact(n-1);
}
它的非递归版本为:
long fact(int n)
{
int result=1;
for(int i=1;i<=n;i++)
{
result*=i;
}
return result;
}
(2):Fibonacci数列的求解
比如要列举出第N个Fibonacci数:
int Fib(int N)
{
if(N==1) return 1;
if(N==2) return 1;
return Fib(N-1)+Fib(N-2);
}
它的非递归版本为:
int Fib(int N)
{
if(N==1 || N==2) return 1;
int a=1;
int b=1;
for(int i=3;i<=N;i++)
{
int temp=a;
a=b;
b=temp+b;
}
return b;
}
(3):欧几里德算法求两数的最大公约数
作为有2000年历史的最老的著名算法之一,这是一个找出两个整数的最大公约数的递归方法,它基于这样一种观察:两个整数x和y(x>y)的最大公约数等同于y与x mod y的最大公约数。t除以x和y等价于t除以y和x mod y,因为x等同于x mod y加上一个y的倍数。对于该算法而言,递归的深度由参数的属性算术(即参数的对数)决定。
int gcd(int m,int n) //要求m>n
{
if(n==0) return m;
return gcd(n,m%n);
}
这是对碾转相除法的一种运用,我能想到的非递归实现求两数的最大公约数的只有这个笨办法了:
int gcd(int m,int n) //同样要求m>n
{
for(int i=n;i>0;i--)
{
if(m%i==0 &&n%i==0)
{
return i;
}
}
}
(4):Hanoi塔的递归解法
前面两个递归实现看上去并不那么复杂,因为用一个while循环就可以达到同样的效果。下面给出一个计算Hanoi塔的解法问题。它的实现有多个递归调用,而且不是那么容易就能用while循环改写的。
如果不费劲去考虑细节,这个问题是非常容易的。只要考虑所有的圆盘必须从start柱移到end柱上,因此必须首先把最下面(最大)的盘移到end柱上。要达到这个目的,end柱必须是空的,而且start柱上只能有最下面一个圆盘,因此其余的n-1的圆盘只能在temp柱上。假设X是一个函数,可以把start柱上面的n-1个圆盘移动到tmp柱上,然后把start柱最下面一个圆盘移动到end柱上,最后,再用函数X把其余的n-1个圆盘移动到end柱上即可。在这两种情况中,“函数X”只不过是调用更小问题的hanoi塔函数而已。成功的秘密在于汉诺塔算法为我们做了这些工作。我们不必关心汉诺塔的子问题如何解决这些细节,只要做好两件事,问题就迎刃而解了。第一,必须有一个初始情况(如果只有一个圆盘怎么做),以便使递归过程不会永远进行下去。第二,对汉诺塔问题的递归调用只能用来解决更小的问题,而且只有一种正确形式(一种满足汉诺塔问题初始定义的形式,假定对柱子适当地重命名)。
void TOH(int n,Pole start,Pole goal,Pole temp)
{
if(n==0) return;
TOH(n-1,start,temp,goal);
move(start,goal);
TOH(n-1,temp,goal,start);
}
(5):递归与链表操作
先看下面的4个函数
int count(LINK x)
{
if(x==0) return 0;
return 1+count(x->next);
}
void traverse(LINK h)
{
if(h==0) return;
visit(h);
traverse(h->next);
}
void traverseR(LINK h)
{
if(h==0) return;
visit(h);
traverse(h->next);
}
void remove(LINK & x,Item v)
{
while(x!=0 && x->Item==v)
{
LINK t=x;
x=x->next;
delete t;
}
if(x!=0) remove(x->next,v);
}
第一个函数计算链表中的节点数。每二个函数从头到尾为每一个链表上的节点调用函数visit()。这两个函数都很容易用while或for循环来实现。第三个函数并无一个简单的循环可以与之对应。它为链表中每一个节点调用函数visit。但用相反的顺序进行。第四个函数从链表中消除带有给定值的节点。该实现的关键在每一个要被删除的节点的前驱中能改变x=x->next的这样一种链接,由于使用引用参数使实现成为可能。
(6):一个有问题的递归程序
如果参数N是奇数,这个函数用3N-1作为参数调用本身,如果N是偶数,函数用N/2作为参数调用本身。我们不能使用归纳法证明该程序终止,,因为并非每一个递归调用都使用一个比上面所给的更小的参数。
如果没有N的范围,我们就无从知道这种计算对于每个N是否会终止。对于能表示为int的小整数,我们已经检验过了它会终止,但是对于大整数,(比如64位的数),我们无从得知这个程序是否会进入无限循环当中去。
int puzzle(int N)
{
if(N==1) return 1;
if(N%2==0)
{
return puzzle(N/2);
}
else
{
return puzzle(3*N+1);
}
}
我做得实验每次都以16,8,4,2,1,结束递归,我也记得有一个数学趣味题就是用得这个原理,可一时记不起来了。Please tell me if you know!
三:递归算法的运行时间问题
递归算法的运行时间问题跟普通的循环时间计算稍有一点不同,总之最后归结为级数求和形式,现在我也不会写什么要求高效率的程序,所以以后碰到了再来看书,反正我已经知道在哪能得到这方面的知识了,呵呵。
- 数据结构学习-递归初接触
- 数据结构学习-递归与分治
- 数据结构学习-递归与动态编程
- 数据结构递归的学习
- 数据结构学习五 递归
- QT学习:初接触
- 六.学习数据结构之递归
- 数据结构学习-递归(1)
- 数据结构学习-递归(2)
- 数据结构——递归学习
- C/C++学习笔记——初次接触递归
- 数据结构-递归
- java学习之初接触
- moqui学习之初接触
- C语言学习:初接触
- “第一次亲密接触”--数据结构,迷宫的生成、走通(非递归)
- 数据结构学习之递归求解汉诺塔问题
- 数据结构学习之_汉诺塔递归算法
- 从ASP.NET服务器控件插入客户端脚本
- 网卡MAC地址相关信息大全(整理)(
- 高效率C/C++Builder 2006程序设计研讨会
- asp程序添加验证码
- PNG文件格式白皮书
- 数据结构学习-递归初接触
- 关于“马太效应”,“蝴蝶效应”、“鲶鱼效应”的解释(转贴)
- Linux 在哪里流行,哪里不流行
- applicationresource.properties中的中文问题
- [读书笔记] Collections of objects
- 从ASP.NET服务器控件插入客户端脚本
- ideal
- 2005 IDE 无法打开设计界面
- SQL语句判断某表是否存在