我试图得到一个关于我上面提出的算法性能的更准确的信息,阅读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