递归简介
2015-09-05 13:41
405 查看
关于递归
递归算法的设计思路Recursive_SOLVE (P) //P是当前问题 if P的规模足够小 then 直接求解 else 将P转换为规模较小问题P' Recursive_SOLVE(P') //递归调用 将P'还原成为原问题P,结果合并 endif END Recursive_SOLVE
递归的低效率
递归调用实际上是函数自己在调用自己,而函数的调用开销是很大的,系统要为每次函数调用分配存储空间,并将调用点压栈予以记录。而在函数调用结束后,还要释放空间,弹栈恢复断点。所以说,函数调用不仅浪费空间,还浪费时间。
递归计算的过程可能会造成重复计算。
低效率的解决方法
改进方法:保存中间结果(将递归转化为递推),如下:
递归:递归是一种从上至下的“分解求解“的过程,即不断地把大问题分解为小问题,直到小问题规模足够小,然后求解并进行递归返回和结果合并。——效率差!
递推:递推是一种从下往上的“合并求解“过程,即从解决小问题出发,记录小问题的答案,并根据已有的小问题的答案,把问题往大里扩展,“滚雪球”,直到达到大问题的规模为止。并通常用迭代(循环)的方式实现,而不是递归调用,一般认为效率上比递归好。
递推算法的设计思想
将递归转化为递推,需要解决如下几个问题:
1.如何体现递归反映出来的、通过调用自身实现的重复计算——从程序入口重复执行本程序的代码的过程?
2.每次递归完成后要接着递归点往下继续执行,递推时如何记录重复执行点,以实现与递归类似的、在重复点重复执行、执行完后又能接着重复点之后的代码继续执行?
3.如果递归函数有返回值,返回值需要返回至递归调用点,用迭代实现时,如何处理返回值?(小问题的解数组ans)
Recurrence_SOLVE(P) //P是当前问题 定义数组ans[P] //定义一个与问题规模P相适应的数组,用于存放答案 for i from 边界问题P0 to P do //从小问题求解做起 if i是边界值 then 直接求解,将结果保存在ans中 else 将i转换为规模较小问题i' ans[i] ←build answer by ans[i'] //用已得到的答案构造i的解ans[i] endif repeat END Recurrence_SOLVE
递归式及其求解
递归式
递归式是一组等式或不等式,它所描述的函数是用在更小的输入下该函数的值来定义的。
如:归并排序(MERGESORT)的运行时间T(n)表示如下:
顺便说一下递推式(类似于我们平常说的数列)
通过给出数列的第1项(或前若干项),并给出数列的某一项与它的前一项(或前若干项)的关系式来表示数列,这种表示数列的式子叫做这个数列的递推公式。
1.斐波纳契数列的递推公式为
fn=fn-1+fn-2
2.等差数列递推公式:
an=an-1+d
3.等比数列递推公式:
bn=bn-1×q
递推式与递归式之间的联系
当递推式中只含数列中的项,而无常数项或其它项时,就叫做递归公式。
递归式的求解
求解递归式就是化简递归式,以得到形式简单的函数表示。三种常用方法:
1.代换法
2.递归树法
3.主方法
关于二叉树的几个递归操作
//搜索 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> using namespace std; typedef int ElementType; // 类型的重命名 typedef struct TreeNode *Position; typedef struct TreeNode *Tree; struct TreeNode { ElementType Element; Tree Left; Tree Right; }; // struct需要分号 char str[101] = "abc##de#g##f###"; int count_temp = 0; /* 创建二叉树 * 使用双指针的原因: * 指针本身也是变量的一种,在(单指针)参数的传递中,也是使用传值的方式, * 也就是说函数只能改变指针指向的内容,无法修改指针的内容。 * 但是,在二叉树中涉及到对节点的递归重建(递归遍历也是一样,都改变了指针的指向),此时就要改变指针的内容来实现对各节点的操作, * 这就要借助于指针的指针,即使用二重指针,这本来就是一个难点,仔细体会下! */ void createBtree(Tree *T) { if (str[count_temp++] == '#') { *T = NULL; } else { *T = (Tree )malloc(sizeof(TreeNode)); (*T)->Element = str[count_temp - 1]; createBtree(&(*T)->Left); createBtree(&(*T)->Right); } } /* * 1. 如果二叉树为空,而返回0 * 2. 如果二叉树不为空,二叉树节点树=左子树节点个数+右子树节点个数+1 */ int GetNodeNum(Tree T) { if( T == NULL)//递归出口 { return 0; } return GetNodeNum(T->Left) + GetNodeNum(T->Right) + 1; } /* * 1. 如果二叉树为空,二叉树的深度为0 * 2. 如果二叉树不为空,二叉树的深度 = max(左子树深度,右子树深度)+ 1; */ int GetDepth(Tree T) { if( T == NULL)// { return 0; } int LeftDepth = GetDepth(T->Left); int RightDepth = GetDepth(T->Right); return LeftDepth > RightDepth ? (LeftDepth+1) : (RightDepth+1); } //先序遍历二叉树 void preOrder(Tree T) { if( T != NULL) { printf("%c ",T->Element); preOrder(T->Left); preOrder(T->Right); } } //中序遍历二叉树 void inOrder(Tree T) { if( T != NULL) { inOrder(T->Left); printf("%c ",T->Element); inOrder(T->Right); } } //后续遍历二叉树 void postOrder(Tree T) { if( T != NULL) { postOrder(T->Left); postOrder(T->Right); printf("%c ",T->Element); } } /* * 1. 如果二叉树为空,或者k<1返回0 * 2. 如果二叉树不为空并且k==1,返回1; * 3. 如果二叉树不为空且k>1,返回左子树中k-1层的节点个数与右子树k-1层节点个数之和。 */ int GetNodeNumKthLevel(Tree T, int k) { if( T==NULL || k<1) return 0; if( k == 1) return 1; int numLeft = GetNodeNumKthLevel(T->Left, k-1); int numRight= GetNodeNumKthLevel(T->Right,k-1); return (numLeft + numRight); } /* * 1. 如果二叉树为空,或者k<1返回0 * 2. 如果二叉树不为空且左右子树为空,返回1 * 3. 如果二叉树不为空且左右子树不为空,返回左子树叶子节点个数加上右子树叶子节点个数。 */ int GetLeafNodeNum( Tree T) { if( T == NULL ) return 0; if( T->Left == NULL && T->Right == NULL) return 1; int numLeft = GetLeafNodeNum( T->Left); int numRight = GetLeafNodeNum(T->Right); return (numLeft + numRight); } /* * 1. 如果两棵二叉树都为空,返回真 * 2. 如果两棵二叉树为空,另一棵不为空,返回假 * 3. 如果两棵二叉树都不为空,如果对应的左子树和右子树都同构返回真,其他返回假 */ bool StructureCmp(Tree T1, Tree T2) { if( T1 == NULL && T2 == NULL)//都为空 return true; else if( T1 == NULL || T2 == NULL)//一个空,一个非空 return false; bool left = StructureCmp(T1->Left, T2->Left); bool right =StructureCmp(T2->Right,T2->Right); return (left&right); } /* * 1. 如果二叉树为空,返回真 * 2. 如果二叉树非空,如果左右子树都是AVL树并且左右子树高度相差不大于1,返回真,其他返回假。 */ bool IsAVL(Tree T, int* height) { if(T == NULL ) { height = 0; return true; } int heightLeft,heightRight; bool left = IsAVL(T->Left, &heightLeft); bool right =IsAVL(T->Right,&heightRight); if( left && right && abs(heightLeft-heightRight)<=1) { *height = max(heightLeft, heightRight) + 1; return true; } else { *height = max( heightLeft, heightRight) + 1; return false; } } /* * 将当前二叉树转化为其镜像二叉树 */ Tree Mirror(Tree T) { if( T == NULL ) return 0; if( T->Left == NULL && T->Right == NULL) return 0; Position temp = T->Right; T->Right = T->Left; T->Left = temp; Mirror(T->Left); Mirror(T->Right); } /* * 如果二叉树为空,返回0,即同时记录左子树和右子树的深度——0; * 如果二叉树不为空,最大距离要么是左子树中的最大距离,要么是右子树的最大距离, * 要么是 左子树节点到根节点的最大距离+右子树节点中到根节点的最大距离,同时记录左右子树节点中到 根节点的最大距离。 */ int GetMaxDistance(Tree T, int *maxLeft, int *maxRight) { // maxLeft:左子树中节点距离根节点最远距离 // maxRight:右子树中节点距离根节点最远距离 if( T == NULL) { maxLeft = 0; maxRight = 0; return 0; } int maxLL, maxLR, maxRL, maxRR; int maxDistLeft, maxDistRight; if( T->Left != NULL) { maxDistLeft = GetMaxDistance(T->Left, &maxLL, &maxLR); *maxLeft = max(maxLL, maxLR) + 1; } else { maxDistLeft = 0; *maxLeft = 0; } if( T->Right != NULL) { maxDistRight = GetMaxDistance( T->Right, &maxRL, &maxRR); *maxRight = max( maxRL, maxRR) + 1; } else { maxDistRight = 0; *maxRight = 0; } return max( max(maxDistLeft, maxDistRight), *maxLeft+*maxRight); } int main() { Tree T; int temp; /* 创建二叉树 */ createBtree(&T); // 参数是**TreeNode /* 求解二叉树中的节点个数 */ temp = GetNodeNum(T); printf("二叉树的节点个数:%d\n", temp); /* 求解二叉树的深度 */ temp = GetDepth(T); printf("二叉树的深度:%d\n", temp); /* 遍历 */ printf("前序遍历(递归):"); preOrder(T); printf("\n"); printf("中序遍历(递归):"); inOrder(T); printf("\n"); printf("后序遍历(递归):"); postOrder(T); printf("\n"); // 求二叉树第k层节点的个数 temp = GetNodeNumKthLevel(T, 2); printf("二叉树第k层节点的个数:%d\n", temp); // 求二叉树中叶子节点的个数 temp = GetLeafNodeNum(T); printf("二叉树中叶子节点的个数:%d\n", temp); // 判断二叉树结构是否相同相 strcpy(str, "abc##de#g##f###"); count_temp = 0; Tree T0; createBtree(&T0); if(StructureCmp(T, T0)) { printf("两个二叉树的结构相同\n"); } else { printf("两个二叉树的结构不同\n"); } // 判断二叉树是不是平衡二叉树 int height; if(IsAVL(T, &height)) { printf("该二叉树是平衡二叉树\n"); } else { printf("该二叉树不是平衡二叉树\n"); } // 求二叉树的镜像二叉树 Mirror(T); printf("镜像二叉树的后序遍历(递归):"); postOrder(T); printf("\n"); // 求二叉树中节点的最大距离(二叉树中相距最远的两个节点) int maxleft, maxright; temp = GetMaxDistance(T, &maxleft, &maxright); printf("二叉树中节点距离最大为:%d", temp); system("pause"); return 0; }
结果如下:
相关文章推荐
- javascript面向对象设计
- 使用MediaPlayer播放音频文件
- 表格编辑表头多行并列多列并列
- 图像信号的稀疏性
- 图像信号的稀疏性
- 使用python绘制4个相切的圆形
- 浅谈UIAlertView
- HDU 5237 Base64
- 黑马程序员——46,enum枚举类的简单应用
- 3款强大的BootStrap的可视化制作工具推荐
- java_常用对象API
- android学习笔记(14)Status Bar Notification 状态栏、通知栏推送
- java 数组小结
- ubuntu下tcpdump总结
- 带多种编辑功能的网页表格可插入TextBox
- c++ 虚函数动态多态性
- IOS程序员简单利用JAVA网络数据抓包
- transaction 的那些事
- UVa 340 Master-Mind Hints
- POJ 1637 Sightseeing tour(混合图的欧拉回路)