码迷,mamicode.com
首页 > 编程语言 > 详细

全服排行榜算法思路

时间:2017-08-05 09:58:35      阅读:151      评论:0      收藏:0      [点我收藏+]

标签:private   ret   for   简单   多少   一个   规模   弊端   var   

排行榜是游戏中一个常见的系统,不过要做好并不容易,比如要对全服几W名玩家做实时排行的话,性能需要花心思去优化的问题。

这里设计了一个基于桶排序的面向全服玩家的通用排行榜

一个简单的思路就是按排序的KEY的分值进行分桶,但是一个弊端就是随着游戏生命推进,会出现一个分数段类的玩家大规模集中,导致分桶失去意义。

所以这里采用了对桶的容量做上限,然后达到上限就分裂桶然后动态计算桶的上下限的做法

桶的定义如下(代码采用c#编写):

        class sub_rank_list
        {
            public Hashtable low;
            public Hashtable up;

            private HashSet<String> mem_set;
            public List<Hashtable> rank_list;

            private IComparer<Hashtable> comparer;
        }

使用Hashtable描述排序的信息是为了排行榜的通用性。

每个Hashtable中需要包含对应玩家的unionid和排序信息

玩家的unionid保存在mem_set中(在mem_set中可以找到玩家的id,表示玩家在这个桶内)

要获取一个玩家在排行榜上的排名,则先查找到玩家在哪个桶内,然后计算 这个桶前有多少玩家和玩家在该桶内的排名之和就是玩家的排名

        public int get_rank(String uuid)
        {
            int rank = 0;
            foreach(var sub_rank_list in rank_data)
            {
                if (!sub_rank_list.in_rank(uuid))
                {
                    rank += sub_rank_list.count();
                    continue;
                }

                rank += sub_rank_list.rank(uuid);

                break;
            }

            return rank;
        }

整个排行榜的代码如下:

using System;
using System.Collections;
using System.Collections.Generic;

namespace rank
{
    //升序排行
    class rank
    {
        public rank(IComparer<Hashtable> _comparer)
        {
            rank_data = new List<sub_rank_list>();
            comparer = _comparer;
        }

        public void clear_rank()
        {
            rank_data = new List<sub_rank_list>();
        }

        public void update_rank(Hashtable data)
        {
            String uuid = (String)data["uuid"];

            foreach(var sub_list in rank_data)
            {
                if (!sub_list.in_rank(uuid))
                {
                    continue;
                }

                if (sub_list.in_range(data))
                {
                    sub_list.update_rank(data);
                }
                else
                {
                    sub_list.del_rank(uuid);
                    insert_rank(data);
                }

                break;
            }
        }

        public void insert_rank(Hashtable data)
        {
            sub_rank_list sub_list = null;
            sub_rank_list up_list = null;
            sub_rank_list low_list = null;
            foreach (var _sub_list in rank_data)
            {
                if (up_list == null)
                {
                    up_list = _sub_list;
                }
                else
                {
                    if (comparer.Compare(up_list.up, _sub_list.up) < 0)
                    {
                        up_list = _sub_list;
                    }
                }

                if (low_list == null)
                {
                    low_list = _sub_list;
                }
                else
                {
                    if (comparer.Compare(low_list.low, _sub_list.low) > 0)
                    {
                        low_list = _sub_list;
                    }
                }

                if (!_sub_list.in_range(data))
                {
                    continue;
                }

                sub_list = _sub_list;
                break;
            }
            if (sub_list == null)
            {
                if (low_list == null && up_list == null)
                {
                    sub_list = new sub_rank_list(data, data, comparer);
                }
                else
                {
                    if (comparer.Compare(low_list.low, data) > 0)
                    {
                        sub_list = low_list;
                        sub_list.low = data;
                    }
                    if (comparer.Compare(up_list.up, data) < 0)
                    {
                        sub_list = up_list;
                        sub_list.up = data;
                    }
                }
            }
            sub_list.insert_rank(data);

            if (sub_list.count() > 2000)
            {
                var new_rank = sub_list.split_rank();
                rank_data.Add(new_rank);

                for(int i = 0; i < rank_data.Count - 1; i++)
                {
                    var rank1 = rank_data[i];
                    var rank2 = rank_data[i + 1];

                    if (comparer.Compare(rank1.low, rank2.up) < 0)
                    {
                        rank_data[i] = rank2;
                        rank_data[i + 1] = rank1;
                    }
                }
            }
        }

        public int get_rank(String uuid)
        {
            int rank = 0;
            foreach(var sub_rank_list in rank_data)
            {
                if (!sub_rank_list.in_rank(uuid))
                {
                    rank += sub_rank_list.count();
                    continue;
                }

                rank += sub_rank_list.rank(uuid);

                break;
            }

            return rank;
        }

        public Hashtable get_rank(int rank)
        {
            int rank_low = 0;
            int rank_up = 1;
            foreach(var sub_rank_list in rank_data)
            {
                rank_low = rank_up;
                rank_up += sub_rank_list.count();

                if (rank >= rank_low && rank < rank_up)
                {
                    return sub_rank_list.rank_list[rank - rank_low];
                }
            }

            return null;
        }

        class sub_rank_list
        {
            public sub_rank_list(Hashtable _low, Hashtable _up, IComparer<Hashtable> _comparer)
            {
                low = _low;
                up = _up;
                mem_set = new HashSet<String>();
                rank_list = new List<Hashtable>();

                comparer = _comparer;
            }

            public bool in_range(Hashtable data)
            {
                int c1 = comparer.Compare(data, up);
                int c2 = comparer.Compare(data, low);

                return c1 <= 0 && c2 > 0;
            }

            public bool in_rank(String uuid)
            {
                return mem_set.Contains(uuid);
            }

            public int count()
            {
                return mem_set.Count;
            }

            public int rank(String uuid)
            {
                int rank = 0;
                foreach(var mem in rank_list)
                {
                    rank++;

                    if (uuid == (String)mem["uuid"])
                    {
                        break;
                    }
                }

                return rank;
            }

            public void update_rank(Hashtable data)
            {
                foreach(var _data in rank_list)
                {
                    if ((String)_data["uuid"] != (String)data["uuid"])
                    {
                        continue;
                    }

                    rank_list.Remove(_data);
                    break;
                }
                rank_list.Add(data);
                rank_list.Sort(comparer);
            }

            public void del_rank(String uuid)
            {
                foreach (var _data in rank_list)
                {
                    if ((String)_data["uuid"] != uuid)
                    {
                        continue;
                    }

                    mem_set.Remove(uuid);
                    rank_list.Remove(_data);
                    break;
                }
            }

            public void insert_rank(Hashtable data)
            {
                mem_set.Add((String)data["uuid"]);
                rank_list.Add(data);
                rank_list.Sort(comparer);
            }

            public sub_rank_list split_rank()
            {
                sub_rank_list new_rank = new sub_rank_list(low, up, comparer);

                int _count = count() / 2;
                Hashtable data = null;
                for (int i = 0; i < _count; i++)
                {
                    data = rank_list[i];
                    del_rank((String)data["uuid"]);
                    new_rank.insert_rank(data);
                }
                new_rank.low = data;
                up = rank_list[0];

                return new_rank;
            }

            public Hashtable low;
            public Hashtable up;

            private HashSet<String> mem_set;
            public List<Hashtable> rank_list;

            private IComparer<Hashtable> comparer;
        }
        private List<sub_rank_list> rank_data;
        private IComparer<Hashtable> comparer;
    }
}

 

全服排行榜算法思路

标签:private   ret   for   简单   多少   一个   规模   弊端   var   

原文地址:http://www.cnblogs.com/qianqians/p/7288474.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!