我試圖得到一個關於我上面提出的算法性能的更準確的信息,閱讀Stemm非常有趣的解決方案,我決定使用tc:timer/3函數。大欺騙:o)。在我的筆記本電腦上,我的時間精確度很差。所以我決定離開我的corei5(2核心* 2線程)+ 2Gb DDR3 + Windows XP 32位以使用我的家用PC:Phantom(6核心)+ 8Gb + Linux 64bit。
現在tc:計時器按預期工作,我可以操縱100 000 000個整數列表。我能看到,我失去了很多時間打電話在每一步的長度的功能,所以我重新分解代碼一點,以避免它:
-module(finder).
-export([test/2,find/2,insert/2,remove/2,new/0]).
%% interface
new() -> {0,[]}.
insert(V,{S,L}) ->
{R,P} = locate(V,L,S,undefined,-1),
insert(V,R,P,L,S).
find(V,{S,L}) ->
locate(V,L,S,undefined,-1).
remove(V,{S,L}) ->
{R,P} = locate(V,L,S,undefined,-1),
remove(V,R,P,L,S).
remove(_,_,-1,L,S) -> {S,L};
remove(V,V,P,L,S) ->
{L1,[V|L2]} = lists:split(P,L),
{S-1,L1 ++ L2};
remove(_,_,_,L,S) ->{S,L}.
%% local
insert(V,V,_,L,S) -> {S,L};
insert(V,_,-1,L,S) -> {S+1,[V|L]};
insert(V,_,P,L,S) ->
{L1,L2} = lists:split(P+1,L),
{S+1,L1 ++ [V] ++ L2}.
locate(_,[],_,R,P) -> {R,P};
locate (V,L,S,R,P) ->
S1 = S div 2,
S2 = S - S1 -1,
{L1,[M|L2]} = lists:split(S1, L),
locate(V,R,P,S1+1,L1,S1,M,L2,S2).
locate(V,_,P,Le,_,_,V,_,_) -> {V,P+Le};
locate(V,_,P,Le,_,_,M,L2,S2) when V > M -> locate(V,L2,S2,M,P+Le);
locate(V,R,P,_,L1,S1,_,_,_) -> locate(V,L1,S1,R,P).
%% test
test(Max,Iter) ->
{A,B,C} = erlang:now(),
random:seed(A,B,C),
L = {Max+1,lists:seq(0,100*Max,100)},
Ins = test_insert(L,Iter,[]),
io:format("insert:~n~s~n",[stat(Ins,Iter)]),
Fin = test_find(L,Iter,[]),
io:format("find:~n ~s~n",[stat(Fin,Iter)]).
test_insert(_L,0,Res) -> Res;
test_insert(L,I,Res) ->
V = random:uniform(1000000000),
{T,_} = timer:tc(finder,insert,[V,L]),
test_insert(L,I-1,[T|Res]).
test_find(_L,0,Res) -> Res;
test_find(L,I,Res) ->
V = random:uniform(1000000000),
{T,_} = timer:tc(finder,find,[V,L]),
test_find(L,I-1,[T|Res]).
stat(L,N) ->
Aver = lists:sum(L)/N,
{Min,Max,Var} = lists:foldl(fun (X,{Mi,Ma,Va}) -> {min(X,Mi),max(X,Ma),Va+(X-Aver)*(X-Aver)} end, {999999999999999999999999999,0,0}, L),
Sig = math:sqrt(Var/N),
io_lib:format(" average: ~p,~n minimum: ~p,~n maximum: ~p,~n sigma : ~p.~n",[Aver,Min,Max,Sig]).
這裏有一些結果。
1> finder:test(1000,10)。 刀片:
平均:266.7,
最小:216,
最大:324,
西格瑪:36.98121144581393。
發現:
average: 136.1,
最小:105,
最大:162,
西格瑪:15.378231367748375。
ok
2> finder:test(100000,10)。
插入:
平均值:10096。5,
最小:9541,
最大:12222,
西格瑪:762.5642595873478。
發現:
average: 5077.4,
最低:4666,
最大:6937,
西格瑪:627.126494417195。
ok
3> finder:test(1000000,10)。
刀片:
平均:109871.1,
最小:94747,
最大:139916,
西格瑪:13852.211285206417。
發現: 平均:40428.0,
最低:31297,
最大:56965,
西格瑪:7797.425562325042。
ok
4> finder:test(100000000,10)。
刀片:
平均:8067547.8,
最小:6265625,
最大:16590349,
西格瑪:3199868.809140206。
發現:
average: 8484876.4,
最低:5158504,
最大:15950944,
西格瑪:4044848.707872872。
確定
在100 000 000列表,它是緩慢的,並且,多進程的解決方案在這種二分法算法不能幫助...這是該解決方案的不足之處,但如果你有幾個並行處理請求找到最接近的值,無論如何,它將能夠使用多核。
帕斯卡。
如果值是*不*排序,這將如果樣本數據是*不*排序,則更清楚。 (排序的方法絕對是最簡單的,並且具有很好的時間複雜性,尤其是在多次調用時分期付款。) – 2012-09-06 17:45:56