游戏排行榜算法设计实现比较

转载 2016年05月30日 15:01:25

以前在音乐做过一些实时投票,积分排名;单曲、专辑等排行榜;游戏中也有类似的战斗力排行;SNS的游戏又有好友排行等,对于此类的排行算法在此做个总结。


  需求背景:


  查看前top N的排名用户


  查看自己的排名


  用户积分变更后,排名及时更新


  方案一:


  利用MySQL来实现,存放一张用户积分表user_score,结构如下:


游戏排行榜算法设计实现比较


  取前top N,自己的排名都可以通过简单的sql语句搞定。


  算法简单,利用sql的功能,不需要其他复杂逻辑,对于数据量比较少、性能要求不高,可以使用。但是对于海量数据,性能是无法接受的。


  方案二:积分排名数组实现


  如有1百万用户进行排名,就用一个大小为1,000,000的数组表示积分和排名的对应关系,其中rank[ s ]表示积分s所对应的排名。初始化时,rank数组可以由user_score表在O(n)的复杂度内计算而来。用户排名的查询和更新基于这个数组来进行。查询积分s所对应的排名直接返回rank[ s ]即可,复杂度为O(1);当用户积分从s变为s+n,只需要把rank[ s ]到rank[s+n-1]这n个元素的值增加1即可,复杂度为O(n)。


  方案三:用GCC的pb_ds库中有assoc_container来进行实现。


  参考如下:tree_order_statistics.cc


  存取效率都可以达到O(log(n)),不足就是程序重启后数据会丢失。


  方案四:自己实现排序树


  大致实现思路如下:


  我们可以把[0, 1,000,000)作为一级区间;再把一级区间分为两个2级区间[0, 500,000), [500,000, 1,000,000),然后把二级区间二分为4个3级区间[0, 250,000), [250,000, 500,000), [500,000, 750,000), [750,000, 1,000,000),依此类推,最终我们会得到1,000,000个21级区间[0,1), [1,2) … [999,999, 1,000,000)。这实际上是把区间组织成了一种平衡二叉树结构,根结点代表一级区间,每个非叶子结点有两个子结点,左子结点代表低分区间,右子结点代表高分区间。树形分区结构需要在更新时保持一种不变量,非叶子结点的count值总是等于其左右子结点的count值之和。


  以后,每次用户积分有变化所需要更新的区间数量和积分变化量有关系,积分变化越小更新的区间层次越低。总体上,每次所需要更新的区间数量是用户积分变量的log(n)级别的,也就是说如果用户积分一次变化在百万级,更新区间的数量在二十这个级别。在这种树形分区积分表的辅助下查询积分为s的用户排名,实际上是一个在区间树上由上至下、由粗到细一步步明确s所在位置的过程。比如,对于积分499,000,我们用一个初值为0的排名变量来做累加;首先,它属于1级区间的左子树[0, 500,000),那么该用户排名应该在右子树[500,000, 1,000,000)的用户数count之后,我们把该count值累加到该用户排名变量,进入下一级区间;其次,它属于3级区间的[250,000, 500,000),这是2级区间的右子树,所以不用累加count到排名变量,直接进入下一级区间;再次,它属于4级区间的…;直到最后我们把用户积分精确定位在21级区间[499,000, 499,001),整个累加过程完成,得出排名!


  虽然,本算法的更新和查询都涉及到若干个操作,但如果我们为区间的from_score和to_score建立索引,这些操作都是基于键的查询和更新,不会产生表扫描,因此效率更高。另外,本算法并不依赖于关系数据模型和SQL运算,可以轻易地改造为NoSQL等其他存储方式,而基于键的操作也很容易引入缓存机制进一步优化性能。进一步,我们可以估算一下树形区间的数目大约为2,000,000,考虑每个结点的大小,整个结构只占用几十M空间。所以,我们完全可以在内存建立区间树结构,并通过user_score表在O(n)的时间内初始化区间树,然后排名的查询和更新操作都可以在内存进行。一般来讲,同样的算法,从数据库到内存算法的性能提升常常可以达到10^5以上;因此,本算法可以达到非常高的性能。


  算法特点


  优点:结构稳定,不受积分分布影响;每次查询或更新的复杂度为积分最大值的O(log(n))级别,且与用户规模无关,可以应对海量规模;不依赖于SQL,容易改造为NoSQL或内存数据结构。


  缺点:算法相对更复杂。


  方案五:skiplist的实现


  实现方案四的时候,发现代码比较复杂,调试起来特别不方便。游戏这边有个同事也实现了个,代码地址:http: //km.oa.com/articles/show/158740


  于是就想到的跳表,发现用这个实现起来比较简单;用hashmap来存储具体的对象;用skiplist用来排序。也可以简单的用一个map和set来实现。Map内面存具体对象,set用来排序。


  关于skip list这里简单介绍下:skip list是链表的一种特殊形式,对链表的一种优化;保证INSERT和REMOVE操作是O(logn),而通用链表的复杂度为O(n);


  优点:实现较简单,效率基本上O(log(N))


  缺点:当达到亿级别时的数据时,性能会急剧下降


  方案六:基于redis的 sort set的实现


  后来看redis发现redis的zset天生是用来做排行榜的、好友列表, 去重, 历史记录等业务需求。接口使用非常简单。接口非常丰富,基本上需要的实现都能满足,说明如下:


  ZAdd/ZRem是O(log(N)),ZRangeByScore/ZRemRangeByScore是O(log(N)+M),N是Set大小,M是结果/操作元素的个数。


  ZSET的实现用到了两个数据结构:hash table 和 skip list(跳跃表),其中hash table是具体使用redis中的dict来实现的,主要是为了保证查询效率为O(1) ,而skip list(跳跃表)主要是保证元素有序并能够保证INSERT和REMOVE操作是O(logn)的复杂度。


  音乐现在的通用投票排名系统就是基于redis来实现的,运行还不错。


  优点:基于redis开发,速度快;使用redis相关特性


  缺点:当达到亿级别时的数据时,性能会急剧下降


  来实现排行榜的方法很多,可以根据自己的具体需求,参考选用。


游戏排行榜的实现

在没有接触游戏行业的排行版时,就觉得排行版的实现非常不简单,也不知道是不是自己想的太过于复杂,然后自己特意去百度了游戏排行版的算法设计的比较(http://www.cocoachina.com/gam...

编程之美之实时排名算法

参考文献 某海量用户网站,用户拥有积分,积分可能会在使用过程中随时更新。现在要为该网站设计一种算法,在每次用户登录时显示其当前积分排名。用户最大规模为2亿;积分为非负整数,且小于100万。 存储结构...

得分排行算法

题目 假设有一教师依学生座号输入考试分数,现希望在输入完毕后自动显示学生分数的排行,当然学生的分数可能相同 算法: 1、 走访分数阵列A1,获得各分数人数的阵列A2 2、 对A2分数阵列进行向左相...
  • vivitue
  • vivitue
  • 2014年08月20日 22:56
  • 3555

游戏与常用的五大算法---上篇

前言:       什么时候,我们之间竟然变得这么生疏       什么时候,我想见到你,却又害怕见到你       什么时候,才能在我身边,告诉我。其实,你一直都在                 ...

排行榜的算法

好久不来博客园了,前几天更新个人状态时,也把“技术博客”四个字改成了“荒废已久的博客”。 好久不总结自己的工作和学习了,怎么说也过不去,就来这写一篇浅显的文章,没什么新鲜的内容,算是一篇经验的汇总把...

数据实时排名

排行榜是很多软件的功能需求,比如我们常玩的各类游戏,视频直播,微博等等都有排行榜。现在的排行榜实现方式大都有这两种:1.定时排名,2实时排名,下面就让我来介绍我对实时排行榜的理解。 实时排行有两个问题...

使用vendor管理Golang项目依赖

The Vendor Tool for Go go get -u github.com/kardianos/govendor New users please read theFAQ Packa...

Runaway Robot游戏过关通用算法设计并java语言实现

这是一个游戏,感觉不错,加上有固定的套路去寻找答案,所以就决定用程序实现。 这个小游戏的网址:点击打开链接        http://www.hacker.org/runaway/inde...
  • fxleyu
  • fxleyu
  • 2013年01月24日 13:28
  • 534

【算法设计与分析基础】关灯游戏

Java实现关灯游戏的图形界面,附带关灯游戏算法分析ppt。可以输出所有结果。 如果不想要算法演示的话,请去掉File → Demo 的勾号。...

致佳音: 推箱子游戏自动求解算法设计(二)

这一个小节我们说一说传说中的A×算法,其实之前也上传过类似的小件件,这里我们就去剖析一下它 毕竟在游戏程序,我们要从一点移动到另一点,并得到最短路程的轨迹,类似这种算法还有好几种,执行效率都差不多,...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:游戏排行榜算法设计实现比较
举报原因:
原因补充:

(最多只允许输入30个字)