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