《算法图解》第三章笔记

第三章讲的是递归和栈。

书中对学习递归的人分为三个阵营:恨它的,爱它的,狠了几年后又爱上它的。

我认为我是第三种,恨是因为无法理解,爱上是因为它的优雅。

以前写递归主要问题都是递归出口条件不知道怎么写,什么时候调用自身。学习完这章后也只是大概了解了,具体应用还需要去leetcode磨练。

假设你在祖母的阁楼中翻箱倒柜发现了了一个上锁的神秘手提箱。
在这里插入图片描述
在这里插入图片描述

  • 非递归式找钥匙

    除了这个“创建盒子堆”的操作脑补不出来,其他都还好。“只要盒子堆不空”那不就是while循环嘛。
    在这里插入图片描述

  • 递归式找钥匙
    在这里插入图片描述
    来看看书中代码模拟实现

    • 非递归式
      在这里插入图片描述

    • 递归式

def look_for_key(box):
	for item in box:
		if item.is_a_box();
			look_for_key(item)	<------递归
		elif item.is_a_key():
			print "found the key!"

相对而言递归式代码看起来就清晰简洁多了。

下面用一个书本例子切实理解递归,建议手敲运行一下,看一万遍也不如写一遍体会来的深

用递归编写一个倒计时函数。(没学过递归的,估计都是用for循环实现)

//python 2.7
def countdown(i):
	print i
	countdown(i-1)

//java
public int countdown(int n){
	System.out.println(n);
	return countdown(n-1);
}

运行上述代码会发现函数停不下来。(ps:说是这么说,但是内存满了会停下来报错的)
黑窗口用 ctrl+c停止

在这里插入图片描述
所以,编写递归函数时,必须告诉它何时停止递归。【PS:写递归函数一定要想出停止递归的条件】

每个递归函数都有两个部分:基线条件和递归条件

  • 基线条件,让递归(或者说是循环)停下来的条件。
  • 递归条件,调用函数自身。
//python 2.7
def countdown(i):
	print i
	if i <= 1:	<-----基线条件
		return
	else
		countdown(i-1)	<----递归条件

//java
public int countdown(int n){
	System.out.println(n);
	if(n<=1)	
		return n;   <----你也可以把n改成0,无关紧要,因为打印在上面那句
	else	
		return countdown(n-1);
}

在这里插入图片描述
这个就需要多做题锻炼了,练多了就有感觉知道怎么写基线条件了。

接下来,讲栈的概念,并用图像告诉你递归时栈是怎么做的。

栈有两个操作:压入(插入)和弹出(删除并读取)

假设你去野外烧烤,并为此创建了一个待办事项清单。

在这里插入图片描述
具体操作:
在这里0插入图片描述
普通的函数调用(非递归式)栈

//python 2.7
def greet(name):
	print "hello," + name + "!"
	greet2(name)
	print "getting ready to say bye..."
	bye()

def greet2(name):
	print "how are you," + name + "?"

def bye():
	print "ok bey!"

//假设你运行个greet("Tom")

在这里插入图片描述

函数递归调用栈

//计算 n! ,例如5!=5*4*3*2*1
def fact(x):
	if x==1:
		return 1
	else
		return x * fact(x-1)
		
//假设运行fact(3)
  • 第一次调用,x=3
    在这里插入图片描述
  • 第二次调用,x=2,此时 fact(3) 暂停等待 fact(2) 完成。
    在这里插入图片描述
  • 第三次调用,x=1,此时 fact(3) 在等待 fact(2) 完成,fact(2) 在等待 fact(1) 完成。
    在这里插入图片描述
    PS:每个 fact 函数调用都有自己的 x 变量。在一个函数调用中不能访问另一个的 x 变量。

理解完上面的东西后,我们可以写一个斐波那契数列练练手了。

斐波那契数列公式:f(n) = f(n-1) + f(n-2) ( f(1) = 1,f(2) = 1,n > 2)

public class Demo {
    public static void main(String[] args) {
        int n = 6;
        Demo demo = new Demo();
        int res = demo.fibonacci(n);
        System.out.println(res);
    }

    public int fibonacci(int n){
        if(n == 1 || n == 2){  
            return 1; //递归出口,基线条件
        }else{
            return fibonacci(n-1)+fibonacci(n-2); //递归条件
        }
    }
}

如果你的程序没完没了的运行,说明你的基线条件没有写对。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值