编程之美——递归思想的归纳

来源:互联网 发布:长虹网络电视机顶盒 编辑:程序博客网 时间:2024/06/06 03:36

递归的基本思想

递归并不是简单的自己调用自己,也不是简单的交互调用。递归在于把问题分解成规模更小、具有与原来问题相同解法的问题,如二分查找以及求集合的子集问题。这些都是不断的把问题规模变小,新问题与原问题有着相同的解法。但是并不是所有所有可以分解的子问题都能使用递归来求解。一般来说使用递归求解问题需要满足以下的条件:
可以把要解决的问题转化为一个子问题,而这个子问题的解决方法仍与原来的解决方法相同,只是问题的规模变小了。原问题可以通过子问题解决而组合解决
例如斐波拉契数列问题,一个数列满足 1,1,2,3,5….. 的形式,即当前项为前两项之和的形式,那么则称这个数列为斐波拉契数列。假设现在要求第 n 项数列的值。
则 f(n) 我们可以通过求的 f(n-1),f(n-2) 所得,原问题可以转化为两个子问题,满足条件一。
假设我们现在得到 f(n-1)、f(n-2)。f(n)=f(n-1)+f(n-2), 满足条件二。
原问题可以通过子问题的解决而解决。而 f(1)=1,f(2)=1, 已知,即存在简单情境使得递归退出,满足条件三。所以此问题解法如下

int fib(n){ if(n==1)            return 1;   if(n==2)            return 1;   return fib(n-1)+fib(n-2);}

调用过程 :
这里写图片描述
通过上面的例子可以总结出递归问题的分析思路

分析问题看是否可以分解成子问题
子问题和原问题之间有何关系
是否有退出的简单条件


例题一:

用递归的实现方式链表的反转问题:

递归的方法其实是非常巧的,它利用递归走到链表的末端,然后再更新每一个node的next 值 ,实现链表的反转。而newhead 的值没有发生改变,为该链表的最后一个结点,所以,反转后,我们可以得到新链表的head。
如下图
这里写图片描述
代码如下:

//递归方式Node * reverseList(List head){    //如果链表为空或者链表中只有一个元素    if(head == NULL || head->next == NULL)    {        return head;    }    else    {        //先反转后面的链表,走到链表的末端结点        Node *newhead = reverseList(head->next);        //再将当前节点设置为后面节点的后续节点        head->next->next = head;        head->next = NULL;        return newhead;    }}

1、先用顺序递归找到链表的末尾,确定newhead;此时递归的函数均未解答,需要逆向解决所有函数;
2、自下而上的递归操作,每次都反转一个链表结点;然后再重复向前推进;
3、结束位置就是第一个调用的函数的位置。

例题二:
给定一个二叉树,找到其最小深度。最小深度是从根节点到最近叶节点的最短路径的节点数。

分析:
1、二叉树是可以分解为子数的形式;
2、关系就是每个数都是通过根连接子树的;
3、跳出位置,就是当根结点不存在时,返回0;当子树的右子树不存在时,计算左子树;同理计算左子树不存在时。
4、分别从左右子树出发,递归计算深度,每存在一个子叶,深度加1,最后取小值。
特别鸣谢!
资料转载:
http://blog.csdn.net/yuanmxiang/article/details/52868999
http://www.cnblogs.com/kubixuesheng/p/4394509.html