Lisp.使用递归(Using Recursion)
来源:互联网 发布:少女前线枪娘数据 编辑:程序博客网 时间:2024/05/16 14:54
相比于其它语言,在Lisp中递归扮演着更加重要的角色。这其中可能有三个主要的原因:
1. 函数式变成。递归算法引入副作用的可能性看上去比较小。
2. 递归数据结构。Lisp的隐式指针使得创建递归定义的数据结构变得简单。最普遍的就是列表:一个列表或者是nil,或者是一个cdr为列表的cons。
3. 优雅。Lisp程序员非常关心他们的程序是否漂亮,而递归算法通常比它们的递归版本更加优雅。
学生一开始的时候会经常感到递归难以理解。但是,你不必考虑一个递归函数的所有的调用来判断它是否正确。
如果你想写一个递归函数也是一样的。如果你可以描述一个问题的递归解决方案,那么将你的方案翻译成代码也是很直接的。要使用递归来解决问题,你必须要做两件事情:
1. 你必须了解怎样通过将问题分解成有限数量的相似的,但是更小的问题。
2. 你必须了解怎样解决最小版本的问题——基础情况(base case)。
如果你做了这些,你就做到了。你知道一个有限的问题最终会被解决,因为每个递归都使得问题更小,并且最小的问题使用了有限数量的步骤。
比如,下面这个找出一个列表长度的递归算法,我们在每次递归的时候都会找到小一些列表的长度:
1. 一般情况下,一个列表的长度是一个列表的cdr的长度加上1
2. 一个空列表的长度是0。
当这种描述被翻译成代码时,基本情况必须先出现;但是当构想递归函数的时候,人们通常是从一般情况开始的。
前面的描述显式得描述了找到一个列表的长度的方法。当你定义一个递归函数的时候,你必须确认你分解问题的方式会带来更小的子问题。一个普通列表的cdr对于length来说会产生一个较小的子问题,但是一个循环列表的cdr不会。
这里有另外两个递归算法的例子。注意在第二个中,我们在每次递归中都将我呢提分成了两个更小的问题:
member:某个东西如果是列表的第一个元素,或者是这个列表的cdr中member,那么这个东西就是这个列表的member。没有东西是一个空列表的member。
copy-tree:一个cons的copy-tree,是一个由它的的car的copy-tree和它的的cdr的copy-tree组成的cons。一个原子的copy-tree是它自身。
一旦你能够以这种方式来描述一个算法,写出递归定义就是很小的一步了。
一些算法可以很自然地以这种方式表达出来,而有的却不是这样。如果不使用递归来定义ou-copy-tree,那么你可能费尽九牛二虎之力来定义它。另一方面,迭代版本的show-squares相比于递归版本来说,迭代版本的实现可能更容易理解。有时候,在你尝试写代码之前,哪种方式更自然一些可能没有那么明显。
如果你关心效率,有其它两个方面需要考虑。第一,尾递归。在有一个好的编译器的情况下,尾递归和循环在速度上应该没有什么差异。然而,如果你将要走出很远才能完成一个函数尾递归,那么使用迭代可能更好一些。
另外一点需要铭记在心的是,显而易见的递归算法并不一直是最有效率的。经典的例子是Fibonacci函数,它是以递归的方式定义的,
1. Fib(0) = Fib(1) = 1
2. Fin(n) = Fib(n-1) + Fib(n-2)
但是直译过来的形式
(defun fib (n) (if (<= n 1) 1 (+ (fib (- n 1)) (fib (- n 2)))))确实令人毛骨悚然的没有效率。同样的计算一次又一次地被重复。如果你计算(fib 10),那么函数就会计算(fib 9) 和(fib 8)。但是计算(fib 9),它必须又一次计算(fib 8),如此等等。
这里有一个迭代版本的函数,它和上面的函数产生同样的结果:
(defun fib (n) (do ((i n (- i 1)) (f1 1 (+ f1 f2)) (f2 1 f1)) ((<= i 1) f1)))
迭代版本并不那么清晰,但是更加有效率。在实践中这种事情发生的可能性多大呢?很少见——这就是为什么所有的教科书都使用相同的例子——但是这是我们应该了解的。
- Lisp.使用递归(Using Recursion)
- 递归(recursion)
- 递归(Recursion)
- 递归(recursion)
- C++ Using recursion to process linked list, 深入理解递归的过程(part1)
- C++ Using recursion to process linked list, 深入理解递归的过程(part2)
- Using recursion
- 递归算法(recursion algorithm)
- 用递归翻转一个栈 Reverse a stack using recursion
- python 递归实例(recursion in real world using python)
- 递归生成格雷码 gray code generation using recursion(c++)
- 递归与尾递归(Tail Recursion)
- 递归 recursion
- Recursion--递归
- 尾递归(tail recursion) 的简单使用
- lisp自动递归(续)
- 消递归(recursion)的一种方式
- 迭代(Iteration)与递归(Recursion)
- 左偏树 模板
- [noi2009]植物大战僵尸
- (百例编程)83.卡布列克常数
- uboot-2009.03成功移植到mini2440
- 第十一,short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
- Lisp.使用递归(Using Recursion)
- 求两个数的整除余数
- Linux环境下的JAVA开发环境部署
- shell export 作用
- SCX项目思考-1.模型建立和股权分配方案
- STM32F10x的启动汇编分析
- 0/1背包问题算法的python实现
- 面试题3
- OpenStack版本升级之Keystone