Erlang实战:杨辉三角、选择排序、集合交与并
相信大家都听说过杨辉三角、选择排序、集合交与并操作,本文就是用Erlang语言实现这三个有趣的程序,相信大家都知道这三个概念,那么正式我们的erlang实战之旅吧!
实战1:输出杨辉三角:接口为start(N),N为行数。
-module(triangle). -export([start/1]). start(N) -> L=getN(N), %% 获取第杨辉三角第N行元素列表 if N =:= 1 -> %% N=1,直接输出第一行,递归调用结束 output(L); N =/= 1 -> %% N>1,递归调用start,先输出第N-1行 start(N-1), output(L) end. %% 控制输出第N行,列表L保存第N行元素,杨辉三角第N行有N个元素 output(L) -> output(L,1). output(L,No) -> if length(L) =:= No -> io:format("~p~n",[lists:nth(length(L), L)]); length(L) =/= No -> io:format("~p,",[lists:nth(No,L)]), output(L,No+1) end. getN(N) -> if N =:= 1 -> [1]; N =:= 2 -> [1,1]; N > 2 -> L = getN(N-1), %%获得第N-1行元素 process(L) %% 通过第N-1行元素,推导出第N行 end. process(Ele) -> process(Ele,1,[]). process(Ele,No,L) -> Len = length(Ele)+1, if Len =:= No -> Temp = [1|L], lists:reverse(Temp); Len =/= No -> if No =:=1 -> process(Ele,No+1,[No | L]); No =/=1 -> E1 = lists:nth(No-1,Ele), E2 = lists:nth(No,Ele), process(Ele,No+1,[E1+E2 | L]) end end.
在程序中主要部分我都作了注释,这完全是按照我的想法来写的,如果大家对程序比较苛刻的话,自己回去再精炼一下吧。在Windows下运行结果如下:
实战2:选择排序:接口为sort(L),L为输入数组。
要求:给定一个无序数组,用选择排序法进行排序(从小到大),要求将中间过程的每一步都输出。
原理:首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾(目前已被排序的序列)。以此类推,直到所有元素均排序完毕。
程序代码如下:
-module(choose_sort). -export([sort/1]). sort(L) -> sort(L,[]). sort([],Ret) -> io:format("Final:~p~nsort finished.",[Ret]); sort(L,Ret) -> Min = findMin(L), Minimum = lists:nth(Min,L), NewL = lists:delete(Minimum,L), %% 在L中删除最小元素 if length(Ret) =:= 0 -> Ele = [Minimum], io:format("No.~p sort:~p~n",[length(Ele),Ele]); length(Ret) =/= 0 -> %% 使用两个列表逆置的操作是因为,要将一个元素插入列表尾 %% 注:在Erlang中,将一个元素到列表头很简单,插入到列表尾好像不直接,因此我用了两次逆置 Temp = lists:reverse(Ret), Ele = lists:reverse([Minimum|Temp]), io:format("No.~p sort:~p~n",[length(Ele),Ele]) end, sort(NewL,Ele). %% 找到最小元素位置 findMin(L) -> findMin(L,1,1). findMin(L,Start,Loc) -> Ele = lists:nth(Start,L), Minimum = lists:nth(Loc,L), if length(L) =:= Start -> if Ele < Minimum -> Start; Ele >= Minimum -> Loc end; length(L) =/= Start -> if Ele < Minimum -> findMin(L,Start+1,Start); Ele >= Minimum -> findMin(L,Start+1,Loc) end end.
注:最初我的想法是在原列表L上进行选择排序,但是,在原列表上进行选择排序可能需要交换列表的两个元素,在Erlang中,交换列表的两个元素没有直接的方法,因此,我的最初想法比较繁琐。上述代码思想:(1)从列表L中选择最小元素,然后插入到结果列表Ret,;(2)将最小元素从L中删除;(3)递归调用(1)知道L中元素为空,返回结果Ret为最终排序结果。
程序运行结果如下:
实战3:集合交与并操作。
用列表表示集合,求两个集合的交集和并集,例如[1,3,4,5]和[4,5,7,9,10]的交集为[4,5],并集为[1,3,4,5,7,9,10]。
代码如下:
-module(set). -export([inter/2]). -export([union/2]). inter(L1,L2) -> S1 = lists:sort(L1), S2 = lists:sort(L2), inter(S1,S2,[]). inter(S1,S2,Ret) -> Len1 = length(S1), Len2 = length(S2), Log = (Len1 =:=0) or (Len2 =:= 0), if Log =:= true -> lists:reverse(Ret); Log =/= ture -> F1 = lists:nth(1,S1), F2 = lists:nth(1,S2), if F1 =:= F2 -> inter(lists:delete(F1,S1),lists:delete(F2,S2),[F1|Ret]); F1 < F2 -> inter(lists:delete(F1,S1),S2,Ret); F1 > F2 -> inter(S1,lists:delete(F2,S2),Ret) end end. union(L1,L2) -> S1 = lists:sort(L1), S2 = lists:sort(L2), lists:reverse(union(S1,S2,[])). union(S1,S2,Ret) -> Len1 = length(S1), Len2 = length(S2), Log = (Len1 =/= 0) and (Len2 =/= 0), if Len1 =:= 0 -> lists:append(Ret,S2); Len2 =:=0 -> lists:append(Ret,S1); Log =:= true -> F1 = lists:nth(1,S1), F2 = lists:nth(1,S2), if F1 =:= F2 -> union(lists:delete(F1,S1),lists:delete(F2,S2),[F1|Ret]); F1 =/= F2 -> Temp = [F1|Ret], Temp2 = [F2 | Temp], union(lists:delete(F1,S1),lists:delete(F2,S2),Temp2) end end.
求集合的交合并操作比较简单,交操作主要步骤如下:
- 调用lists:sort/1对两个列表进行排序;
- 若列表L1或列表L2为空,返回Ret,否则进入第三步;
- 将两个列表L1、L2首元进行比较,分三种情况,首元相等、大于、小于依次处理。
并操作与交类似,只是在L1或L2为空时将不空的列表并入结果集Ret中,就不再详细说其步骤了。
好了,这次的学习讨论就到这了,这三个程序还是比较简单的,关键是思路要清晰,其次是要以Erlang的角度来思考问题,那么用Erlang实现这三个程序就显得简单了。接下去,我还是会探讨一些小程序,不过,我将花几个专题专门讨论Erlang中并行算法的实现,主要是并行枚举排序、并行快速排序、PSRS排序等,也算是这个实战系列最难得一部分吧,多谢大家的支持。
注:如无特殊说明,本博客内容纯属原创,转载请注明:http://www.cnblogs.com/itfreer/ | IT闲人,谢谢!