1. 程式人生 > >全服排行榜算法思路

全服排行榜算法思路

set range 包含 設計 update name private ear ret

排行榜是遊戲中一個常見的系統,不過要做好並不容易,比如要對全服幾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;
    }
}

全服排行榜算法思路