(本文内容摘录自百度)
定义:
特点
要求
如何设计递归算法
递归过程
1)对应于某些参数可以求值的一个或多个终止条件
实例 (内容来自 http://www.cricode.com/3489.html ):
1. Fibonacci 函数
斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …
特别指出:第0项是0,第1项是第一个1。
这个数列从第二项开始,每一项都等于前两项之和。
斐波那契数列递归实现:
f(0) = 0;
f(1) = 1;
f(n) = f(n-2)+f(n-1); (当n>1时)
2. 汉诺塔问题
有三根杆子A,B,C。A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至C杆:
每次只能移动一个圆盘;
大盘不能叠在小盘上面。
提示:可将圆盘临时置于B杆,也可将从A杆移出的圆盘重新移回A杆,但都必须遵循上述两条规则。
问:如何移?最少要移动多少次?
你汉诺塔问题的递归算法:
借助递归的思想,把n个圆盘问题简化为n-1个圆盘的问题
1) 将A上的n-1个圆盘, 借助C移到B
2)将A上最后哈一个圆盘移到C上
3)将B上n-1个圆盘借助A移到C上
move(int n, int from, int med, int to)
if (n==1) System.out.println(from+"--->" + to);
else {
move(n-1, from, to, med); //第一步
System.out.printf(n+"从" + from+"移到"+to); //第二步
move(n-1, med, from, to) //第三步
}
3. 二叉树遍历
在计算机科学中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。
遍历二叉树有以下3中方法:
1)先序遍历: 先访问根节点,然后遍历左子树,然后遍历右子树
2)中序遍历: 左子树--> 根节点 --> 右子树
3)后序遍历: 左子树 --> 右子树 --> 根节点
1)先序遍历
Status PreOrderVisit( BiTree T){
if(T) {
Visit(T->Data);
if (PreOrderVisit(T->leftChild))
if(PreOrderVisit(T->rightChild)) return OK;
return Error;
} else return OK;
}
2. 中序遍历
Status MidOrderVisit(BiTree T){
if(T) {
if(MidOrderVisit(T->leftChild) {
visit(T->data);
if(T->rightChild!=null)MidOrderVisit(T->rightChild)
return OK
}
return ERROR;
} else return OK;
}
3. 后序遍历
Status PostOrderVisit(BiTree){
if(T){
if(PostOrderVisit(T->leftChild) {
if(PostOrderVisit(T->rightChild)) {
visit(T->data);
return OK;
}
}
return ERROR;
} else return OK;
}
4. 字符串全排列
问题:
写一个函数返回一个串的所有排列。
解析:
对于一个长度为n的串,它的全排列共有A(n, n)=n!种。这个问题也是一个递归的问题, 不过我们可以用不同的思路去理解它。为了方便讲解,假设我们要考察的串是”abc”, 递归函数名叫permu。
思路三四参考: http://www.cricode.com/624.html
思路一:
假设在长度为n的字符串中求m个字符的组合。
先从头扫描第一个字符,针对第一个字符,有两种选择
一种是把这个字符放到组合中去,接下来要在剩下的 n-1 个字符中选 m-1 个字符
一种是不把这个字符放到组合中去,接下来要在剩下的 n-1个字符中选m个字符
代码实现(java)
public class Test{
public static void Combine(char[] c, int begin, int len, StringBuffer sb){
if(len == 0) {
System.out.print(sb + “ ”);
}
if (begin == c.len) {
return;
}
sb.append(c[begin]);
Combine(c, begin+1, len-1, sb);
sb.deleteCharAt(sb.length()-1);
Combine(c, begin+1; len, sb);
}
public static void main(String[] agrs) {
String s = "abc";
char[] c = s.toCharArray();
StringBuffer sb = new StringBuffer();
for (int i =1; i<=c.length; i++){
Combine(c, 0, i, sb);
}
}
}
思路二:
为了提高效率,可以构造一个长度为n的01字符串(或二进制数)表示输出结果中是否包含某个字符,例如对字符串“abc”, 001 表示输出结果不含a, b, 只含c, 而101表示输出结果不含b, 只含ac.
题目理解为输出 001 到 111这2^n-1个组合对应的字符串
思路三:我们可以把串“abc”中的第0个字符a取出来,然后递归调用permu计算剩余的串“bc” 的排列,得到{bc, cb}。然后再将字符a插入这两个串中的任何一个空位(插空法), 得到最终所有的排列。
我们可以把串“abc”中的第0个字符a取出来,然后递归调用permu计算剩余的串“bc” 的排列,得到{bc, cb}。然后再将字符a插入这两个串中的任何一个空位(插空法), 得到最终所有的排列。
比如,a插入串bc的所有(3个)空位,得到{abc,bac,bca}。 递归的终止条件是什么呢?当一个串为空,就无法再取出其中的第0个字符了, 所以此时返回一个空的排列。
思路四:
我们还可以用另一种思路来递归解这个问题。还是针对串“abc”, 我依次取出这个串中的每个字符,然后调用permu去计算剩余串的排列。 然后只需要把取出的字符加到剩余串排列的每个字符前即可。对于这个例子, 程序先取出a,然后计算剩余串的排列得到{bc,cb},然后把a加到它们的前面,得到 {abc,acb};接着取出b,计算剩余串的排列得到{ac,ca},然后把b加到它们前面, 得到{bac,bca};后面的同理。最后就可以得到“abc”的全序列。