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.

  求集合的交合并操作比较简单,交操作主要步骤如下:

  1. 调用lists:sort/1对两个列表进行排序;
  2. 若列表L1或列表L2为空,返回Ret,否则进入第三步;
  3. 将两个列表L1、L2首元进行比较,分三种情况,首元相等、大于、小于依次处理。

  并操作与交类似,只是在L1或L2为空时将不空的列表并入结果集Ret中,就不再详细说其步骤了。

  好了,这次的学习讨论就到这了,这三个程序还是比较简单的,关键是思路要清晰,其次是要以Erlang的角度来思考问题,那么用Erlang实现这三个程序就显得简单了。接下去,我还是会探讨一些小程序,不过,我将花几个专题专门讨论Erlang中并行算法的实现,主要是并行枚举排序、并行快速排序、PSRS排序等,也算是这个实战系列最难得一部分吧,多谢大家的支持。

 

  注:如无特殊说明,本博客内容纯属原创,转载请注明:http://www.cnblogs.com/itfreer/ | IT闲人,谢谢!

 

  

posted @ 2012-05-07 13:59  chinagragon  阅读(2508)  评论(4编辑  收藏  举报

Powered by中国龙 博客空间 IT闲人,不干实事