使用场景
玩家战力排行榜,可以实时的同步排行榜的信息,排行榜的数量设定为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.