数据结构之递归

栏目: 数据库 · 发布时间: 5年前

内容简介:本篇是数据结构与算法之美学习笔记递归在计算机科学中指一种通过将重复问题分解为同列子问题来解决问题的方法。递归是一种常见的算法或者编程技巧。很多数据结构和算法的编码实现都会使用到递归,比附DFS深度搜索,前中后序二叉树遍历等等。

本篇是数据结构与算法之美学习笔记

递归在计算机科学中指一种通过将重复问题分解为同列子问题来解决问题的方法。

递归是一种常见的算法或者编程技巧。很多数据结构和算法的编码实现都会使用到递归,比附DFS深度搜索,前中后序二叉树遍历等等。

递归需要满足三个条件

1.一个问题的解可以分成几个解。

子问题就是数据规模更小的的问题

2.这个问题和分解之后的子问题,除了数据规模不同,解决思路是一样的。

3.存在递归的终止条件

如果没有终止条件就成了无限循环了。

如何写一个递归呢?最关键的两部就是写出递推公式,和找到终止条件。

例子一:求阶乘

int f(int n)  
{  
    if(n==0)//递归边界  
        return 1;  
    return n*f(n-1);//递归公式  
}

例子二:假如有n个台阶,每次可以跨一个或者两个台阶,请问走着n个台阶有多少种走法?

根据第一步的走法可以分成两类:第一步走了一个台阶和第一步走了两个台阶。所以n个台阶的走法就等于西安欧一阶后n-1个台阶的走法加上先走两阶后n-2个台阶的走法。

int f(int n){
  if(n == 1) return 1;//递归边界  
  if(n == 2) return 2;//递归边界  
  return f(n-1) + f(n-2) //递归公式  
}

写递归代码,关键就是找到如何将大问题分解为小问题的规律,并且基于此写出递推公式,然后在推敲终止条件,最后将递推公式和终止条件翻译成代码。

递归代码要警惕堆栈溢出

在实际开发中,写递归代码经常会遇到堆栈溢出的情况,后果非常严重。为什么会造成堆栈溢出呢?怎么可以防止堆栈溢出?

我们知道,函数的调用会使用栈来保存临时变量,每调用一个函数,都会讲临时变量封装成栈帧亚茹内存中,等函数执行完成返回时才出栈。系统或虚拟机的栈控件一般都不大。如果递归求解的数据很大,调用层次很深,一直压入栈,就会有堆栈溢出的风险了。

我们可以通过在代码中限制递归效用的最大深度的方式来解决这个问题,比如在递归深度超过1000之后就不往下递归了,直接返回错误

不过这种方法并不能完全解决问题,因为最大允许的递归深度跟当前的线程剩的栈的空间大小有关,事先无法计算,如果实时计算代码过于复杂。所以如果深度太深,就不要用递归了。

递归代码需警惕重复计算

比如上面的第二个例子加入n为6我们分解开的话

f(6)->f(5)->f(4)->f(3)->f(2)

f(6)->f(5)->f(4)->f(3)->f(1)

f(6)->f(5)->f(4)->f(2)

f(6)->f(5)->f(3)->f(2)

f(6)->f(5)->f(3)->f(1)

f(6)->f(4)->f(3)->f(2)

f(6)->f(4)->f(3)->f(1)

f(6)->f(4)->f(2)

从上面可以看到f(3)被计算了很多次。

为了避免重复计算,我们可以通过一个数据结果(比如散列表)来保存已经求结果的f(k)。当递归调用到f(k)的时候,先看一下是否求解过了,如果是直接在删列表中取值返回。

例子二的代码可以改为下面实现

public int f(int n) {
  if (n == 1) return 1;
  if (n == 2) return 2;
  
  // hasSolvedList 可以理解成一个 Map,key 是 n,value 是 f(n)
  if (hasSolvedList.containsKey(n)) {
    return hasSovledList.get(n);
  }
  
  int ret = f(n-1) + f(n-2);
  hasSovledList.put(n, ret);
  return ret;
}

递归调试,对于比较浅的递归,可以使用单步追踪的方法调试,对于比较深的,可以通过打印日志的方式来调试。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

软件调试

软件调试

张银奎 / 电子工业出版社 / 2008-6 / 128.00元

围绕如何实现高效调试这一主题,本书深入系统地介绍了以调试器为核心的各种软件调试技术。本书共30章,分为6篇。第1篇介绍了软件调试的概况和简要历史。第2篇以英特尔架构(IA)的CPU为例,介绍了计算机系统的硬件核心所提供的调试支持,包括异常、断点指令、单步执行标志、分支监视、JTAG和MCE等。第3篇以Windows操作系统为例,介绍了计算机系统的软件核心中的调试设施,包括内核调试引擎、用户态调试子......一起来看看 《软件调试》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具