关于排行榜算法的处理

使用场景

玩家战力排行榜,可以实时的同步排行榜的信息,排行榜的数量设定为200条,玩家战力变化,可以及时在排行榜中体现出来,相应的排名也发生变化,并且可以不用提前进行数据的排他性处理;

使用说明

  • erlang本身的列表排序采用归并排序的算法,而且也做了一定的优化,一般来说,归并排序是两两合并,但是erlang本身的lists:sort采用的是3个数组的合并所以,相比两个数组的合并效率有所提升,归并排序的时间复杂度是 N*lgN,所以可以计算得出 如果数据长度时1000, 则时间复杂度是10000
  • 本次采用的是遍历的方式,为了进行数据的筛选,特定设定了一个maps,有大佬建议,是否可以采用二叉树的查找,基于对maps的设定,查找速度是1,所以总体的时间复杂度是N,相比列全排序会快一点;当前使用的erlang版本是17.3,maps的is_key查找的时间复杂度是N,所以总体来说,整个的时间复杂度N(原始列表长度)M(改变的列表长度长度),所以在长度为1000,改变了3个数据量的情况下,时间复杂度是31000=3000,整体上的时间复杂度还是相比erlang本身的列表排序具有优势,理论上效率可以提升3倍以上,实际测试下来,性能提升在2倍多。

代办事项

  • 测试代码功能逻辑的正确性
  • 分析代码设计的适用场景
  • 分析代码在大数据下的处理性能
  • 分析lists:keysort算法的设计原理
  • 分析lists:keysort算法的设计和当前归并排序算法的差异性
  • 设计可以通用的接口,具有普适性

算法分析

  • 剔除无效数据

有最大值设定,如果超过最大值,则停止排行榜计算
原始数据有序,改变数据有序,如果当做无序来排序,浪费性能

  • 时空转换

1.保存信息改变列表中的玩家id为map结构,key为玩家id,剔除掉玩家已经在排行榜中的数据,直接实现了覆盖,空间复杂度O(m)
2.将排行序的数据保存在另外一个列表中,空间复杂度是O(n)

  • 时间复杂度

O(n)

数据测试

  • 日志信息

算法逻辑代码如下

make_change_id_map(ChangeDataList, KeyElement) ->

    F =
        fun(ChangeData, AccMaps) ->
            Id = element(KeyElement, ChangeData),
            maps:put(Id, [], AccMaps)
        end,
    lists:foldl(F, maps:new(), ChangeDataList).


usort_rank(Func, KeyElement,RankElement, RankList, ChangeDataList, MaxIdx)  when is_function(Func, 2)->

    Maps = make_change_id_map(ChangeDataList, KeyElement),
    RankList_1 = usort_rank_1(RankList, ChangeDataList, [], 1, MaxIdx, Maps, Func, {KeyElement,RankElement}),

    lists:reverse(RankList_1).

usort_rank_1(_, _, TotalRankList, RankIdx, MaxRankIdx, _, _Func, _) when RankIdx =:= MaxRankIdx ->
    TotalRankList;
usort_rank_1([], [], TotalRankList, _RankIdx, _MaxRankIdx, _, _Func, _) ->
    TotalRankList;
usort_rank_1([], [ChangeData | RestChangeList], TotalRankList, RankIdx, MaxRankIdx, ChangeIdMaps, _Func, {_, RankElement}= RecordElementList) ->
    ChangeData_1 = setelement(RankElement, ChangeData, RankIdx),
    TotalRankList_1 = [ChangeData_1|TotalRankList],
    usort_rank_1([], RestChangeList, TotalRankList_1, RankIdx+1, MaxRankIdx, ChangeIdMaps, _Func, RecordElementList);
usort_rank_1([Rank|RestRankList], [], TotalRankList, RankIdx, MaxRankIdx,ChangeIdMaps, _Func, {KeyElement, RankElement} = RecordElementList) ->

    Id = element(KeyElement, Rank),
    case maps:is_key(Id, ChangeIdMaps) of
        true ->
            usort_rank_1(RestRankList, [], TotalRankList, RankIdx, MaxRankIdx, ChangeIdMaps, _Func, RecordElementList);
        false ->

            Rank_1 = setelement(RankElement, Rank, RankIdx),
            TotalRankList_1 = [Rank_1|TotalRankList],
            usort_rank_1(RestRankList, [], TotalRankList_1, RankIdx+1, MaxRankIdx, ChangeIdMaps, _Func, RecordElementList)
    end;
usort_rank_1([Rank|RestRankList]=RankList, [ChangeData | RestChangeList]=ChangeList, TotalRankList, RankIdx, MaxRankIdx, ChangeIdMaps, Func, {KeyElement, RankElement} = RecordElementList) ->
%%     Rank > ChangeData
    case Func(Rank, ChangeData) of
        true ->
            case Func(ChangeData, Rank) of
                true ->  %% equal data
%%                    ChangeIdMaps = maps:put(element(KeyElement, ChangeData), [], ChangeIdMaps0),
                    Id = element(KeyElement, Rank),
                    case maps:is_key(Id, ChangeIdMaps) of
                        true ->
                            ChangeData_1 = setelement(RankElement, ChangeData, RankIdx),
                            TotalRankList_1 = [ChangeData_1 | TotalRankList],
                            usort_rank_1(RestRankList, RestChangeList, TotalRankList_1, RankIdx+1, MaxRankIdx, ChangeIdMaps, Func, RecordElementList);
                        false ->
                            Rank_1 = setelement(RankElement, Rank, RankIdx),
                            ChangeData_1 = setelement(RankElement, ChangeData, RankIdx+1),

                            TotalRankList_1 = [ChangeData_1, Rank_1 | TotalRankList],
                            usort_rank_1(RestRankList, RestChangeList, TotalRankList_1, RankIdx+2, MaxRankIdx, ChangeIdMaps, Func, RecordElementList)
                    end;
                false ->
                    Id = element(KeyElement, Rank),
                    case maps:is_key(Id, ChangeIdMaps) of
                        true ->
                            usort_rank_1(RestRankList, ChangeList, TotalRankList, RankIdx, MaxRankIdx, ChangeIdMaps, Func, RecordElementList);
                        false ->
                            Rank_1 = setelement(RankElement, Rank, RankIdx),
                            TotalRankList_1 = [Rank_1 | TotalRankList],
                            usort_rank_1(RestRankList, ChangeList, TotalRankList_1, RankIdx+1, MaxRankIdx, ChangeIdMaps, Func, RecordElementList)
                    end
            end;
        false ->
            ChangeData_1 = setelement(RankElement, ChangeData, RankIdx),
            TotalRankList_1 = [ChangeData_1 | TotalRankList],
            usort_rank_1(RankList, RestChangeList, TotalRankList_1, RankIdx+1, MaxRankIdx, ChangeIdMaps, Func, RecordElementList)
    end.


测试代码


-record(rank_data, {
    id = 0,
    rank = 1,
    val = 1
}).

test_rank(Count) ->

    F =
        fun(Id, RankList) ->
            RandomVal = util:rand(1,Count),
            ChangeList = [#rank_data{id = Id, val = RandomVal}],
    %%  接口调用
            usort_rank(fun sort_rank/2, #rank_data.id, #rank_data.rank, RankList, ChangeList, 20000)
        end,
    _RankList = lists:foldl(F, [], lists:seq(1,Count)),
    ok.

sort_rank(#rank_data{val = Val1}, #rank_data{val = Val2}) ->
    Val1 >= Val2.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章