ConcurrentSkipListMap排序:可以通过值的compareTo来完成吗?

时间:2010-09-21 16:41:05

标签: java sortedset sortedmap

在游戏中,我试图保留用户列表并按分数排序,以便我可以在任何给定时间查询列表并按分数返回(例如)前十名用户。此列表应该是线程安全的。我设想使用userName字符串作为键,值将是一个实现Comparable的User对象,并具有displayName和score等属性。因此,User对象将具有compareTo方法,该方法将比较score属性以确定其位置。

我正在考虑使用ConcurrentSkipListMap,但正如我所知,Map(而不是Set)使用键进行排序。我希望列表按User对象的score属性排序,但仍然使用Map,因为我需要能够访问任何给定用户并从线程修改其score属性。

似乎没有使用我自己的Comparator来解决我的问题,因为我怀疑我可以访问相关的值进行比较。我可以使用ConcurrentSkipListSet但是访问列表来修改单个用户的分数将是(我想象)一个昂贵的操作(由于需要每次迭代)。

有人能建议如何做到这一点吗?

3 个答案:

答案 0 :(得分:3)

不,我认为你不能。用于排序的比较器与用于索引的比较器相同。您可能需要维护2个集合。一个用于保持用户分数的顺序,用于按名称引用用户。

答案 1 :(得分:1)

get(key)取决于比较器(能够找到密钥)。您建议一个依赖于get(key)的比较器(根据该比较来访问密钥的映射值)。这必然会导致无限递归和堆栈溢出(好的一面是,你在正确的网站发帖!!)

答案 2 :(得分:1)

迈克尔是对的,你不能吃蛋糕而且也吃它;)

我认为你有3个选择:

  1. 使用地图以便快速更新用户的分数,并在排序时支付价格以找到最高分数。
  2. 使用按分数排序的SortedSet,以便找到最高分数很快,但您必须在更新用户分数时付出代价
  3. 维护两个数据结构,以便您可以拥有1和2中的最佳结果。例如,您可以按照分数对集合中的实际数据进行排序,但同时还要维护用户名到索引的映射到集合或类似。这样你总是有排序的分数,更新用户的分数只是查找,而不是搜索。您为此付出的代价是现在您在两个地方维护一些重复信息,特别是考虑到并发访问,确保两个地方始终同步更新可能会非常棘手。
  4. 我不会假设1和1之间哪个更快。我会用你的预期用法和量度来尝试它们,看看最糟糕的是什么。

    如果您真的只对前n个分数感兴趣,那么可以单独维护该列表。所以有你的用户名地图为每个人打分,但也保留一小部分最高分(及其用户)。每次添加/更新某人的分数时,只需检查最高分数列表中的分数,如果它比那里的最小分数大,那么只需添加它并使其低一些。这与上面的建议3类似,但开销较小,可能更容易维护。