简体   繁体   English

实现游戏记分牌 API 的最佳数据结构

[英]Best data structure to implement the APIs for Game Scoreboard

I want to design a Scoreboard for a game.我想为游戏设计记分牌。 The score board is sorted in descending order, based on score.计分板根据分数按降序排列。 The Scoreboard looks like below:记分牌如下所示:
----------------------------- -----------------------------------------
|User Name | |用户名 | score |分数 |
----------------------------- -----------------------------------------
|DragonSlayer | |屠龙者 | 98765 | 98765 |
|Pikachu | |皮卡丘 | 98762 | 98762 |
...... ……
|User123 | |用户123 | 12568 | 12568 |
----------------------------- -----------------------------------------

The basic APIs that needs to be supported are:需要支持的基本 API 有:
String getLeader() -> returns the user name which is currently at the top of the leaderboard. String getLeader() -> 返回当前在排行榜顶部的用户名。
int getScore(username) -> returns the corresponding score for a given username. int getScore(username) -> 返回给定用户名的相应分数。
List<UserAndScore> getTop(int n) -> returns top n number of usernames and their corresponding score. List<UserAndScore> getTop(int n) -> 返回前 n 个用户名及其对应的分数。
void insert(String userName, int score) -> insert the score for a given user. void insert(String userName, int score) -> 插入给定用户的分数。

What could be the best data structure (in terms of speed) for working with the leaderboard.与排行榜一起工作的最佳数据结构(就速度而言)可能是什么。 I have thought of using 2 data structures and their corresponding time complexity for each API:我曾想过为每个 API 使用 2 个数据结构及其相应的时间复杂度:

  1. HashMap -> getLeader() API takes O(n). HashMap -> getLeader() API 需要 O(n)。 getScore() API takes O(1), getTop() API takes O(nlogn) (where O(nlogn) is the time taken for sorting the values in map and insert API takes O(1). getScore() API takes O(1), getTop() API takes O(nlogn) (where O(nlogn) is the time taken for sorting the values in map and insert API takes O(1).
  2. LinkedList -> While inserting the data, I would ensure that the data are in descending order. LinkedList -> 在插入数据时,我会确保数据按降序排列。 getLeader() API takes O(1), as we are returning the first element, getScore() API takes O(n), getTop() API takes O(1) and insert API takes O(n). getLeader() API takes O(1), as we are returning the first element, getScore() API takes O(n), getTop() API takes O(1) and insert API takes O(n).

I'm more leaning towards using LinkedList as it is a leaderboard and getLeader() and getTop(n) are the frequently called APIs.我更倾向于使用LinkedList ,因为它是一个排行榜,而getLeader()getTop(n)是经常被调用的 API。

I thought of using a TreeMap .我想过使用TreeMap If I use the 'username' as key, the data would be ordered by username, but, I would like to have it by score though.如果我使用“用户名”作为键,数据将按用户名排序,但是,我希望按分数来排序。 It is not right to use the 'score' as the key in the TreeMap .TreeMap中使用“分数”作为键是不对的。

is there a data structure which could be having time complexity less than the LinkedList implementation?是否存在时间复杂度低于LinkedList实现的数据结构?

is there a better data structure for implementing this scenario?有没有更好的数据结构来实现这个场景?

Thanks, Pal谢谢,朋友

You can have both in maps, just create an enclosing class to make the invariants satisfied.您可以在地图中同时拥有两者,只需创建一个封闭的 class 即可满足不变量。 For example例如

static class Bimap {
    Map<String, Integer> map = new HashMap<>();
    SortedMap<Integer, Set<String>> rmap = new TreeMap<>(Collections.reverseOrder());

    // top score can have more than one entry
    // or user getTop(1).
    List<String> getLeader() {
        return new ArrayList<>(rmap.get(rmap.firstKey()));
    }

    int getScore(String username) {
        return map.get(username);
    }

    List<String> getTop(int n) {
        List<String> top = new ArrayList<>();
        int counter=0;
        for(Integer score : rmap.keySet()) {
            top.addAll(rmap.get(score));
            counter++;
            if(counter >= n) break;
        }
        return top;
    }

    // not to leave obsolete scores to keep the invariants satisfied
    void insert(String userName, int score) {
        Integer pscore = map.put(userName, score);
        if (null != pscore) {
            Set<String> names = rmap.get(pscore);
            names.remove(userName);
            if (names.size() == 0) {
                rmap.remove(pscore);
            }
        }
        rmap.computeIfAbsent(score, k -> new HashSet<>()).add(userName);
    }

}

Not tested except few trivial cases.除了少数琐碎的情况外,未经测试。 Caveat Emptor!买者自负!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM