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

递归的基本思想

递归并不是简单的自己调用自己,也不是简单的交互调用。递归在于把问题分解成规模更小、具有与原来问题相同解法的问题,如二分查找以及求集合的子集问题。这些都是不断的把问题规模变小,新问题与原问题有着相同的解法。但是并不是所有所有可以分解的子问题都能使用递归来求解。一般来说使用递归求解问题需要满足以下的条件:
可以把要解决的问题转化为一个子问题,而这个子问题的解决方法仍与原来的解决方法相同,只是问题的规模变小了。原问题可以通过子问题解决而组合解决
例如斐波拉契数列问题,一个数列满足 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);}

调用过程 :
编程之美——递归思想的归纳_第1张图片
通过上面的例子可以总结出递归问题的分析思路

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


例题一:

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

递归的方法其实是非常巧的,它利用递归走到链表的末端,然后再更新每一个node的next 值 ,实现链表的反转。而newhead 的值没有发生改变,为该链表的最后一个结点,所以,反转后,我们可以得到新链表的head。
如下图
编程之美——递归思想的归纳_第2张图片
代码如下:

//递归方式
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

你可能感兴趣的:(数据结构)