關於排行榜算法的處理

使用場景

玩家戰力排行榜,可以實時的同步排行榜的信息,排行榜的數量設定爲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.


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