"Erlang实战,从实战中获得真知":有人说Erlang是一个小语种,学的人用的人太少,但是不管怎么样,Erlang在并发编程上还是能站稳脚跟,本文继续使用Erlang实现了冒泡排序、插入排序、打印九九乘法表、将两个有序列表合并成一个有序列表4个例子,希望通过这几个例子能够对前面练习的Erlang实例有一个进一步的了解,同时真正进入Erlang的世界。
练习1:将两个有序列表合并成一个有序列表。
我在Erlang实战练习(一)中的联系4中讲过将两个列表连接起来,但是两个列表没有约束,而且合并之后也没有排序,我的想法是:首先将两个列表连接起来,然后使用快排进行排序,此练习很简单,代码如下:
-module(sort_concat). -export([concatenate/2,sort_lists/2,qsort/1]). %% No1.合并两个有序列表 sort_lists(L1,L2) -> qsort(concatenate(L1,L2)). concatenate(L,[]) -> L; concatenate(L,[H|T]) -> concatenate([H|L],T). qsort([]) -> []; qsort([Pivot|T]) -> qsort([X||X <- T,X < Pivot]) ++[Pivot]++ qsort([X||X <- T,X >= Pivot]).
练习2:冒泡排序。
我的想法:长度为N的列表应该进行N-1此冒泡排序,bubble_once用于处理一次冒泡排序,此处的处理是将最小元素移到列表尾,然后再对列表的前N-1个元素使用bubble_once进行排序,代码如下:
-module(bubble_sort). -export([len/1,bubble_once/2,bubble_sort/1]). %% No2.冒泡排序 %% 函数len:求出列表的长度,系统模块中有函数length(L)可以实现此功能
len([]) -> 0; len([H|T]) -> 1 + len(T). %% 函数bubble_once:一次冒泡排序,将最小元素放入列表尾
bubble_once(H,[]) -> [H]; bubble_once(X,[H|T]) -> if X =< H -> [H|bubble_once(X,T)]; X > H -> [X|bubble_once(H,T)] end. bubble_sort(L) -> bubble_sort(L,len(L)). %% 对列表L的前N个元素进行冒泡排序,直到N=1
bubble_sort(L,1) -> L; bubble_sort([H|T],N) -> Result = bubble_once(H,T), io:format("No.~w process: ~p~n",[len([H|T])-N+1,Result]),%%显示每次排序结果
bubble_sort(Result,N-1).%%继续对列表前N-1个元素进行排序
练习3:插入排序。
算法:insert_sort(L1,L2)将列表L2中的元素依次插入L1,L1初始为空,normal函数定位新插入元素的位置并完成插入的过程,代码如下:
-module(insert_sort). -export([insert_sort/1,normal/2]). %% NO3.插入排序 insert_sort(L) -> insert_sort([],L). insert_sort(L,[]) -> L; insert_sort(L,[H|T]) -> insert_sort(normal(H,L),T). normal(X,[]) -> [X]; normal(X,[H|T]) -> if X =< H -> [X|[H|T]]; X > H -> [H | normal(X,T)] end.
练习4:打印九九乘法表。
算法:函数output/1功能是输出九九乘法表的第N行结果,print/2用于控制显示输出每一项,编译后运行:nine_table:multiply(9)将显示完美结果,据老师说这个程序只要三四行代码就OK了,可能我写得有点复杂,代码如下:
-module(nine_table). -export([output/1,print/2,multiply/1]). output(N) -> output(N,N). output(N,1) -> print(N,1); output(N,M) -> output(N,M-1), print(N,M). print(N,M) -> io:format(" ~p*~p=~p",[N,M,N*M]), if N =:= M -> io:format("~n",[]); N =/= M -> io:format(" ",[]) end. multiply(1) -> output(1); multiply(N) -> multiply(N-1), output(N).
练习5:求列表的中位数。
中位数指一个有序列表或数组的中间位置的数,求中位数时必须保证列表有序,如果列表长度为奇数,中间位置的数位中位数,若列表为偶数,中间两个数的平均值为中位数,我使用了如上的插入排序算法先将列表排序(可以使用Erlang模块中的sort/1函数),然后再求中位数,代码如下:
-module(median). -export([insert_sort/1,normal/2,get_median/1,compute_median/1,get/2,len/1]). %% No.5 求列表的中位数,要求平均复杂度O(N)。 %% 调用NO3.插入排序,先将列表排序 insert_sort(L) -> insert_sort([],L). insert_sort(L,[]) -> L; insert_sort(L,[H|T]) -> insert_sort(normal(H,L),T). normal(X,[]) -> [X]; normal(X,[H|T]) -> if X =< H -> [X|[H|T]]; X > H -> [H | normal(X,T)] end. len([]) -> 0; len([H|T]) -> 1 + len(T). get([H|T],1) -> H; get([H|T],N) -> get(T,N-1). get_median(L) -> Len = len(L), if Len rem 2 =:= 1 -> Loc1 = (len(L)+1) div 2, get(L,Loc1); Len rem 2 =:=0 -> Loc2 = len(L) div 2, (get(L,Loc2)+get(L,Loc2+1))/2 end. compute_median(L) -> Temp = insert_sort(L), get_median(Temp).
注意,我在求列表中位数的时候的时间复杂度其实等价于直接插入排序的时间复杂度,即O(N^2),当然,老师要求我们在O(N)的时间复杂度内解决这个问题,请读者自行思考。
本节主要通过5个基本的练习对Erlang有了进一步的认识和了解。(注:由于个人能力有限,有些地方难免繁琐或者有疏漏,不吝赐教。)