《Learn You Some Erlang for Great Good!》的学习笔记(六)

来源:互联网 发布:c语言中float什么意思 编辑:程序博客网 时间:2024/05/18 03:06

     看到现在你也许会差异,为什么还没有介绍循环语句。作为一个B格很高的语言,erlang并不提供for/while等类似的循环控制关键字,而是使用递归的方式实现循环。递归的话,大家一定不陌生,简单地说就是调用自身函数实现循环,递归的实现有两个要素:
1. 一个基础条件(一般作为结束递归条件)
2. 一个调用自身的函数
以阶乘为例子:

fac(N) when N == 0 -> 1;fac(N) when N > 0  -> N*fac(N-1).

这样就实现了一个递归,我们展开4的阶乘来看一看递归调用的过程:

fac(4) = 4*fac(4-1)       = 4*3*fac(3-1)       = 4*3*2*fac(2-1)       = 4*3*2*1*fac(0)       = 4*3*2*1*1

上面就完美了吗?NO!可以发现,当计算4的阶乘时,最大展开了5个参数。数据越大,计算时耗费内存也就越多。该是“尾递归“大显神威的时候啦!
为了避免大量的内存耗费,我们在入参中引入Accumlator作为保存计算结果临时变量,如下所示:

tail_fac(N) -> tail_fac(N,1).tail_fac(0,Acc) -> Acc;tail_fac(N,Acc) when N > 0 -> tail_fac(N-1,N*Acc).

问题就这么解决了?是的,看一下展开效果你就知道了。

tail_fac(4)    = tail_fac(4,1)tail_fac(4,1)  = tail_fac(4-1, 4*1)tail_fac(3,4)  = tail_fac(3-1, 3*4)tail_fac(2,12) = tail_fac(2-1, 2*12)tail_fac(1,24) = tail_fac(1-1, 1*24)tail_fac(0,24) = 24

在内存中至多只保存着两个项目,不会随着数据变化有增多。
     由于递归是erlang中实现循环的唯一方式,为了让你能够更加得心应手的使用,这里会给出更多更加复杂的例子。
1.数据复制成数组:

duplicate(N, T) -> duplicate(N, T, []).duplicate(0, _, Acc) -> Acc;duplicate(N, T, Acc) -> duplicate(N - 1, T, [T|Acc]).

2.数组反转

reverse(T) when is_list(T) -> reverse(T, []).reverse([], Acc) -> Acc;reverse([H|T], Acc) -> reverse(T, [H|Acc]).

3.子数组(去数组前N个数据)

sublist(T, N) when is_list(T),length(T) >= N -> sublist(T,N,[]).sublist(T, 0, Acc) -> Acc;sublist([H|T], N, Acc) -> sublist(T, N-1, Acc ++ [H]).

4.相等大小的数组组合(zip)

zip(A1, A2) when is_list(A1), is_list(A2), length(A1)=:=length(A2)-> zip(A1, A2, []).zip([],[], Acc) -> Acc;zip([H1|T1], [H2|T2], Acc) -> zip(T1, T2, Acc++[{H1, H2}]).

5.快速排序

quicksort([]) -> [];quicksort([Pivot|Rest]) ->  quicksort([Smaller|| Smaller <- Rest, Smaller =< Pivot])  ++ [Pivot] ++  quicksort([Larger||Larger <- Rest, Larger > Pivot]).

最后,附上作者对递归的理解:

recursion coupled with pattern matching is sometimes an optimal solution to the problem of writing concise algorithms that are easy to understand. By subdividing each part of a problem into separate functions until they can no longer be simplified, the algorithm becomes nothing but assembling a bunch of correct answers coming from short rou- tines (that’s a bit similar to what we did with quicksort). This kind of mental abstraction is also possible with your everyday loops, but I believe the practice is easier with recursion. Your mileage may vary.

0 0
原创粉丝点击