搬运自 http://blog.sina.com.cn/s/blog_7daf3d040101od8p.html
问题来源 SICP
线性递归和迭代(尾递归)
树形递归(优化尽量先从瓶颈优化,尽量先从算法优化)
指数级 线性
这个结果不能说树形递归是无用的,对于层级数据结构而不是数,就会发现树形递归是很自然并强大的工具。即使对与数的计算,它也可能帮助我们理解和设计程序,更加的直观。
实例:对于1美元,给定1/2美元、1/4美元、10美分、5美分、1美分,将1美元换成零钱,有多少种方式?更一般的问题是,对于任意数量的现金,有多少种换零钱的方式?
对于现金a,硬币种类数目n,换零钱的方式数目等于:
- 用除了第一种硬币之外的硬币换的数目,加上
- 把现金a-d用n种硬币换的数目,d为第一种硬币的面额
这样逐步缩小问题的规模,但应有下列规则:
- 当a=0,返回换零钱方式数目为1
- 当a<0,返回换零钱方式数目为0
- 当n=0,返回换零钱方式数目为0
转换为代码:
(
define (count-change
amount)
(cc
amount
5))
( define (cc
amount
kinds-of-coins)
(
cond ((=
amount
0)
1)
((
or (<
amount
0) (=
kinds-of-coins
0))
0)
(
else (+
(cc
amount
(-
kinds-of-coins
1))
(cc
(-
amount
(first-denomination
kinds-of-coins))
kinds-of-coins)))))
( define (first-denomination
kinds-of-coins)
(
cond ((=
kinds-of-coins
1)
1)
((=
kinds-of-coins
2)
5)
((=
kinds-of-coins
3)
10)
((=
kinds-of-coins
4)
25)
((=
kinds-of-coins
5)
50)))
( define
( define
树形递归会有很多冗余计算,但也同样直观,易于理解。如果要想一个其他的更好的算法,就不那么容易了。对于冗余,可以把计算过的过程保存下来,下次再计算时查看是否计算过,避免重复计算。
临时想了一个迭代的算法,结果很不直观啊
//
博主的评论:
第二个方法相当于先用1分填满;然后清空加进去一个5分,再执行同样的操作,直至5分这个位置也被填满;接着扔进去一个10分.... 以此一直到50分也被填满。同时巧妙地用sum记录总数
另外,
((> temp amount) (cc-iter-1 n1 n2 n3 n4 n5 amount sum))) 很漂亮,比如说如果是1001分,20个50分和1个1分恰好覆盖,这时再多一个50分就超出总数了,于是次数再跳回cc-iter-1,n2到n5都为0,直接print sum。