递归,就是在运行的过程中调用自己。
构成递归需具备的条件:
1. 子问题须与原始问题为同样的事,且更为简单;
2. 不能无限制地调用本身,须有个出口,化简为非递归状况处理。
递归关系就是实体自己与自己建立关系。斐波那契数列就是(Fibonacci Sequence), 又称黄金分割数列, 指的是这样一个数列:
1, 1, 2, 3, 5, 8, 13, 21, 34......, 斐波那契数列是典型的递归案例。
递归算法一般用于解决三类问题 :
(1)数据的定义是按递归定义的。
例 : 用递归函数输出斐波那契数列
构成递归需具备的条件:
1. 子问题须与原始问题为同样的事,且更为简单;
2. 不能无限制地调用本身,须有个出口,化简为非递归状况处理。
递归关系就是实体自己与自己建立关系。斐波那契数列就是(Fibonacci Sequence), 又称黄金分割数列, 指的是这样一个数列:
1, 1, 2, 3, 5, 8, 13, 21, 34......, 斐波那契数列是典型的递归案例。
递归算法一般用于解决三类问题 :
(1)数据的定义是按递归定义的。
例 : 用递归函数输出斐波那契数列
#include<stdio.h> int Fibonacci(int n)//函数部分; { if(n==1 || n==2) return 1; if(n>=3) return Fibonacci(n-1) + Fibonacci(n-2); } void main() { int Fibonacci(int n); int n; printf("请输入n的值:"); scanf("%d",&n); for(int i=1; i<=n; i++) { printf("%12ld",Fibonacci(i)); if(i%4==0) //用于换行 4个一行; printf("\n"); } }
(2)问题解法按递归算法实现。
例 : 汉诺塔问题
如下图所示,从左到右有A、B、C三根柱子,其中A柱子上面有从小叠到大的n个圆盘,现要求将A柱子上的圆盘移到C柱子上去,期间只有一个原则:一次只能移到一个盘子且大盘子不能在小盘子上面,求移动的步骤和移动的次数。
解:(1)n == 1
第1次 1号盘 A---->C sum = 1 次
(2) n == 2
第1次 1号盘 A---->B
第2次 2号盘 A---->C
第3次 1号盘 B---->C sum = 3 次
(3)n == 3
第1次 1号盘 A---->C
第2次 2号盘 A---->B
第3次 1号盘 C---->B
第4次 3号盘 A---->C
第5次 1号盘 B---->A
第6次 2号盘 B---->C
第7次 1号盘 A---->C sum = 7 次
第1次 1号盘 A---->C sum = 1 次
(2) n == 2
第1次 1号盘 A---->B
第2次 2号盘 A---->C
第3次 1号盘 B---->C sum = 3 次
(3)n == 3
第1次 1号盘 A---->C
第2次 2号盘 A---->B
第3次 1号盘 C---->B
第4次 3号盘 A---->C
第5次 1号盘 B---->A
第6次 2号盘 B---->C
第7次 1号盘 A---->C sum = 7 次
不难发现规律:1个圆盘的次数 2的1次方减1
2个圆盘的次数 2的2次方减1
3个圆盘的次数 2的3次方减1
。 。 。 。 。
n个圆盘的次数 2的n次方减1
故:移动次数为:2^n - 1
2个圆盘的次数 2的2次方减1
3个圆盘的次数 2的3次方减1
。 。 。 。 。
n个圆盘的次数 2的n次方减1
故:移动次数为:2^n - 1
void m(int n,char x,char y,char z){ if (n==1) { //如果只有一个需要移动,直接输出 printf("%c-->%c\n",x,z); } else{ //如果有n>1个需要从x移动z,将x最上面的n-1个移动到y,将最后一个移动到z,最后利用递归。将y上面的n-1个移动到z。 m(n-1,x, z, y); printf("%c-->%c\n",x,z); m(n-1, y,x,z); } } int main(){ int n=0; printf("请输入汉诺塔的层数:"); scanf("%d",&n); m(n, 'A', 'B', 'C'); }
(3)数据的结构形式按递归定义
。
例:树递归遍历
// 递归树.cpp: 定义控制台应用程序的入口点。 // #include "stdio.h" #include "stdlib.h" //用递归的方式遍历二叉树 typedef struct node //定义二叉树的结点 { int data; //结点的数据 struct node*lChild, *rChild; //结点左右子 }Node; int i = -1; //控制下面函数中循环的 Node *buildTree(int *b) //产生二叉树(利用先序递归产生) { Node *p; //创建一个根结点指针 if (b[++i] == 0)p = NULL; //如果传入的当前值为0 则设其为空结点 else { p = (Node*)malloc(sizeof(Node)); //开辟内存 p->data = b[i]; //设置当前结点的数据 p->lChild = buildTree(b); //左子结点 p->rChild = buildTree(b); //右子 } return p; //把创建的树的根节点返回 } void preOrder(Node *root) //前序遍历 { if (root != 0) //如果根节点不为0 { printf("%d ", root->data); //打印当前结点 preOrder(root->lChild); //指向左子 preOrder(root->rChild); //指向右子 } } void inOrder(Node *root) //中序遍历 { if (root != 0) //如果根节点不为0 { inOrder(root->lChild); //指向左子 printf("%d ", root->data); //打印当前结点 inOrder(root->rChild); //指向右子 } } void postOrder(Node *root) { if (root != 0) { postOrder(root->lChild); //指向左子 postOrder(root->rChild); //指向右子 printf("%d ", root->data); //打印当前结点 } } void main() { //按先序次序输入树的结点(非0整数)来创建一个树 空结点用0表示 int a[] = { 1,2,4,0,7,0,0,0,3,5,0,0,6,8,0,0,9,0,0 }; int *b = a; //将指向数组首地址的指针传给 bulidTree 函数 来创建树 Node *root = buildTree(b); printf("用递归方法 \n\n前序遍历: "); //打印提示内容 preOrder(root); //调用前序遍历函数 printf("\n中序遍历: "); //打印提示内容 inOrder(root); //调用中序遍历函数 printf("\n后序遍历: "); //打印提示内容 postOrder(root); //调用后序遍历函数 }