排行榜功能

游戏中的排行榜功能太常见了。各种战力排行榜,积分排行榜,连抢红包都有排行榜。

时间复杂度分析

后端程序实现的时候,第一个想到的肯定是排序算法,把要进行排行的数据收集起来,使用排序算法排好序,第一个元素排名为1,依次类推。我们知道,排序算法,使用快排的平均时间复杂度为O(nlogn), 获取玩家的排名,需要遍历计算排名,时间复杂度为O(n)。 那么更新玩家积分并获取玩家最新排名,这个操作的时间复杂度为 O(nlogn) + O(n), 对于少量玩家排行榜系统来说,是可以接受的。但是对于100万,甚至1000万玩家的排行榜系统来说,每次更新都要重新排序,显然不可接受,我们需要更快的算法。
更快的算法,基本思路就是空间换时间,摒除每次都将所有数据重新排序的思路,改为部分数据调整,Redis的Sorted Set数据结构使用了 跳表哈希表 结合的方式,更新数据的时间复杂度为 O(logn), 获取排行的时间复杂度为 O(logn), 即使数据量很大,也能高效排序。

示例代码

-- 更新充值排行 score为double类型
local function update(pid, score)
    redis:zadd("charge_rank", score, pid)
    return redis:zrevrank("charge_rank", pid) + 1
end

如果服务器框架没有使用Redis, 也可以参考Redis手动实现一个 Sorted Set在服务器内部使用。

细节补充

  • 如果用于排序的值,多个玩家相同,如何处理?
    redis在score相同时,默认按member的字母表顺序排序。

While the same element can’t be repeated in a sorted set since every element is unique, it is possible to add multiple different elements having the same score. When multiple elements have the same score, they are ordered lexicographically (they are still ordered by score as a first key, however, locally, all the elements with the same score are relatively ordered lexicographically).
The lexicographic ordering used is binary, it compares strings as array of bytes.

所以我们要根据策划的需求来调整代码,看策划是否需要对相同排序值,显示相同排名?或者按先来后到的方式?

被忽略的排行:登录排队

登录排队,也是一个排行榜,和普通的排行榜不一样的是,登录排队一般严格按照先来后到的方式排序,最适合的score参数是时间戳。
登录排队,score参数一样的情况下如何处理?我们先来看看参数一样,会造成什么结果。玩家B先进入排队,时间戳为100,显示当前排位为第5位,玩家A后进入排队,时间戳也为100,因为玩家A按字母表顺序排在玩家B前面,显示当前排位为第5位。排队等待期间,玩家B的排位更新了,显示当前排位为第6位!被插队了!玩家B表示很生气!不能忍!怒删游戏!此时可以采取score值相同,显示相同排名的方法。更佳的做法是延后1~3秒更新当前玩家的排名,这样就不会出现看起来被插队的情况了(实际上还是插队了)。

结语

与人斗,其乐无穷,排行榜,这个功能,可以说是荣誉榜,也可以说是竞争榜,还可以是名利榜,游戏中有江湖,排行榜就是江湖之始。

你可能感兴趣的:(服务器开发,lua,游戏,游戏开发,后端)