关于erlang随机算法优化

不得不说用 erlang 写一些算法实现是给自己找抽。。。

但游戏服务端选择使用erlang必能在其他方面占据优势,而我们能做便是把牺牲降低到最小

需求:长度N的列表中,随机出M个不同的数值。

因为游戏中业务基数量极小,一般是100个物品中随机10出来,所以使用最暴力的方法反而是最快...切勿使用复杂的数据结构搞...切记

%% List 中选取 N 个不同的对象
rand_n(N, List) when is_list(List) ->
    %% Len = length(List),
    %% Ns = rand_n(N, 1, Len),
    %% [lists:nth(Index, List) || Index <- Ns];
    rand_n(N, list_to_tuple(List));
rand_n(N, Tuple) when is_tuple(Tuple) ->
    Len = tuple_size(Tuple),
    Ns = rand_n1(N, 1, Len),
    [element(Index, Tuple) || Index <- Ns].


%% 从[min , max] 中取出 N个数,不重复
rand_n1(Count, Min, Max) 
  when (Max - Min)+1 > Count->
    rand_n2(Count, Min, Max, []);
rand_n1(_Count, Min, Max) ->
    shuffle(lists:seq(Min, Max)).
	
rand_n2(0, _Min, _Max, List) ->
	List;
rand_n2(Count, Min, Max, List) ->
    Num = rand(Min, Max),
    case lists:member(Num, List) of
        false->
            rand_n2(Count - 1, Min, Max, [Num|List]);
        true ->
            rand_n2(Count, Min, Max, List)
    end.

shuffle(L) ->
    List1 = [{rand(1, 10000000), X} || X <- L], 
    List2 = lists:keysort(1, List1), 
    [E || {_, E} <- List2]. 

以下方案弄巧成捉了。。。

网络上关乎随机算法就不介绍了,我使用也是网络上泛用的两个随机算法结合,互补优缺点。

算法一:每次随机出一个值放到容器中,随机出的数,先去容器中找是否存在,有则抛弃并再次重复随机,无则存入容器

算法二:分两个容器A、B,每次在A中随机出一个数Num,A中删除Num,  并将Num放进B中

明显算法二比算法一好,当能C、C++写最好,但是若是基于Erlang来做,算法二的牺牲会超过算法一,所以跑测试用例

时便能找出猫腻。

结论: 当 M div N < 0.6, 算法一占有优势,否则算法二

(可以自己测)测试数据对比:

算法一:

M = 99999,  N = 100000  T = 1925383(微妙)

M = 80000,  N = 100000  T = 394174(微妙)

M = 10000,  N = 100000  T = 36135(微妙)

算法二:

M = 99999,  N = 100000  T = 350859(微妙)

M = 80000,  N = 100000  T = 288753(微妙)

M = 10000,  N = 100000  T = 53911(微妙)

%% ------------------------------------------------------

rand_n(N, List) ->
    Len = length(List),
    if 
        N/Len > 0.6 ->
            Ns = rand_n1(N, 1, Len, List);
        true ->
            NewNs = rand_n2(N, 1, Len),
            traversal_list(NewNs, 1, List, [])
    end.
    
%% 从[min , max] 中取出 N个数,不重复
rand_n1(Count, Min, Max, List) 
  when (Max - Min)+1 > Count->
    {Tree, _, []} = make_tree(Min, Max, List),
    rand_n1(Count, Min, Max, Tree, []).
	
rand_n1(0, _Min, _Max, _Tree, List) ->
    List;
rand_n1(Count, Min, Max, Tree, List) ->
    Num = hmisc:rand(Min, Max),
    {NTree, Val} = queue_tree(Num, Tree),
    rand_n1(Count - 1, Min, Max-1, NTree, [Val | List]). %% Max - 1
% {sum, left_chail, right_chail} 线段树
make_tree(Left, Right, [H|T]) 
  when Left =:= Right ->
    {{1, none, none, H}, 1, T};
make_tree(Left, Right, List) ->
    Mid = (Left + Right) bsr 1,
    {LeftChail, LSum, NList} = make_tree(Left, Mid, List),
    {RightChail, RSum, NewList} = make_tree(Mid+1, Right, NList),
    Sum = LSum + RSum,
    {{Sum, LeftChail, RightChail}, Sum, NewList}.

queue_tree(Key, {Sum, none, none, Index})
  when Key =:= Sum ->
    {{0, none, none, Index}, Index};

queue_tree(Key, {Sum, LeftChail, RightChail} = _Tree) ->
    LSum = get_sum(LeftChail),
    if 
        Key > LSum ->
            {NewRightTree, Val} = queue_tree(Key - LSum, RightChail),
            {{Sum-1, LeftChail, NewRightTree}, Val};
        true ->
            {NewLeftTree, Val} = queue_tree(Key, LeftChail),
            {{Sum-1, NewLeftTree, RightChail}, Val}
    end.

get_sum({Sum, _LeftChail, _RightChail}) ->
    Sum;
get_sum({Sum, none, none, _Index}) ->
    Sum.

%% 从[min , max] 中取出 N个数,不重复
rand_n2(Count, Min, Max) 
  when (Max - Min)+1 > Count->
    rand_n2(Count, Min, Max, gb_sets:empty()). %% max 不变
	
rand_n2(0, _Min, _Max, GbSets) ->
    gb_sets:to_list(GbSets);
rand_n2(Count, Min, Max, GbSets) ->
    Num = hmisc:rand(Min, Max),
    case gb_sets:is_member(Num, GbSets) of
        false->
            rand_n2(Count - 1, Min, Max, gb_sets:insert(Num, GbSets));
        true ->
            rand_n2(Count, Min, Max, GbSets)
    end.

traversal_list([Index1 | TNs], Index2, [H|T], AccList) 
  when Index1 =:= Index2 ->
    traversal_list(TNs, Index2+1, T, [H | AccList]);
traversal_list(Ns, Index2, [_H|T], AccList) ->
    traversal_list(Ns, Index2+1, T, AccList);
traversal_list([], _, _, AccList) ->
    AccList.

%% ------------------------------------------------------------------


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值