"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有了進一步的認識和了解。(注:由於個人能力有限,有些地方難免繁瑣或者有疏漏,不吝賜教。)