Java 在映射中查找最高的-n值

Java 在映射中查找最高的-n值,java,algorithm,data-structures,optimization,Java,Algorithm,Data Structures,Optimization,我有一个字符串->整数的大映射,我想在映射中找到最高的5个值。我目前的方法是将映射转换为成对(键、值)对象的数组列表,然后使用Collections.sort()进行排序,然后再进行前5次排序。键可以在操作过程中更新其值 我认为这种方法是可以接受的单线程方法,但是如果我有多个线程都触发转置和频繁排序,那么它似乎不是很有效。另一种选择似乎是维护一个包含最高5个条目的单独列表,并在地图上进行相关操作时保持更新 请给我一些优化的建议/备选方案好吗?如果有好处,我很乐意考虑不同的数据结构。 谢谢 好吧,

我有一个字符串->整数的大映射,我想在映射中找到最高的5个值。我目前的方法是将映射转换为成对(键、值)对象的数组列表,然后使用Collections.sort()进行排序,然后再进行前5次排序。键可以在操作过程中更新其值

我认为这种方法是可以接受的单线程方法,但是如果我有多个线程都触发转置和频繁排序,那么它似乎不是很有效。另一种选择似乎是维护一个包含最高5个条目的单独列表,并在地图上进行相关操作时保持更新

请给我一些优化的建议/备选方案好吗?如果有好处,我很乐意考虑不同的数据结构。
谢谢

好吧,要在地图中找到最高的5个值,你可以在
O(n)
时间内找到,任何排序都比这慢

最简单的方法是通过映射的条目集执行for循环

for (Entry<String, Integer> entry: map.entrySet()) {
    if (entry.getValue() > smallestMaxSoFar) 
        updateListOfMaximums();
}
for(条目:map.entrySet()){
if(entry.getValue()>smallestMaxSoFar)
updateListOfMaximums();
}
我认为这种方法是可以接受的单线程方法,但是如果我有多个线程都触发转置和频繁排序,那么它似乎不是很有效。另一种选择似乎是维护一个包含最高5个条目的单独列表,并在地图上进行相关操作时保持更新

在这两者之间,你也可以采取一种方法。当一个线程请求地图的“排序视图”时,创建一个地图副本,然后在此基础上处理排序

public List<Integer> getMaxFive() {
    Map<String, Integer> copy = null;
    synchronized(lockObject) {
        copy = new HashMap<String, Integer>(originalMap);
    }

    //sort the copy as usual
    return list;
}
public List getMaxFive(){
映射副本=空;
已同步(锁定对象){
复制=新哈希映射(原始映射);
}
//像往常一样对副本进行排序
退货清单;
}

理想情况下,如果多个线程访问某个状态(如此映射),则将该状态封装在其他类之后,这样每个线程就不会直接更新映射。

请尝试其他数据结构。假设有一个名为MyClass的类,它的属性是key(String)和value(int)。当然,MyClass需要实现类似的接口。另一种方法是创建一个名为MyClassComparator的类,它扩展了Comparator

compareTo(无论在何处)方法的定义如下: 比较(参数){ 返回值2-值1;//递减 }

剩下的很简单。使用List并调用Collections.sort(parameters)方法将完成排序部分


我不知道集合的排序算法。排序(参数)使用什么。但是,如果您觉得随着时间的推移可能会出现一些数据,则需要进行插入排序。由于它适用于几乎已排序的数据,并且它是。

您可以使用两个映射:

// Map name to value
Map<String, Integer> byName

// Maps value to names
NavigableMap<Integer, Collection<String>> byValue
//将名称映射到值
按名称映射
//将值映射到名称
NavigableMap byValue

并确保始终保持它们的同步(可能将它们包装在另一个负责put、get等的类中)。对于最高值,请使用
byValue.navigableKeySet().degendingIterator()

如果修改很少,我将实现一些
SortedByValHashMap扩展HashMap
,类似于
LinkedHashMap
),以按值排序条目。

我将创建如下方法:

private static int[] getMaxFromMap(Map<String, Integer> map, int qty) {
    int[] max = new int[qty];
    for (int a=0; a<qty; a++) {
        max[a] = Collections.max(map.values());
        map.values().removeAll(Collections.singleton(max[a]));
        if (map.size() == 0)
            break;
    }
    return max;
}
private static int[]getMaxFromMap(映射映射,int数量){
整数[]最大=新整数[数量];

对于(int a=0;a有两种方法可以轻松实现:

  • 将地图放入a中,然后从中检索所需的
    n
    元素
  • 遍历映射并使用每个条目更新
    n
    最高值列表
  • 如果要检索未知值或大量最高值,第一种方法是可行的。如果要检索固定的少量值,第二种方法对某些程序员来说可能更容易理解。
    就个人而言,我更喜欢第一种方法。

    两个问题:1)为什么有一个映射?你需要查找给定键的值吗?2)你还需要知道5个最高值的键吗?@pgras-是的,API的另一个功能是接收键并返回当前值,因此映射是一个很好的起点。我们需要知道最高值的键,这就是为什么我被迫使用对象对的原因d不只是创建一个整数列表。您能具体说明您对运行时间的具体要求吗?您当前的
    getHighestFive
    O(n log n)
    ,而使用
    lookup
    insert
    delete
    更改映射时是
    O(log n)
    每个。是否要将
    getHighestFive
    降到
    O(1)
    在保留其他运行时间的同时?这与多线程有什么关系,是否要并行化
    getHighestFive
    ?API的另一个函数需要快速检索密钥,因此交换集合而不是映射会对性能造成不可接受的影响,因为列表很大。但是,您的想法是ound-我没有理由不能将(key->composite(key,value))映射到复合实现可比较的位置。然后我可以说Collections.sort(map.values())。不幸的是,当您引入多个线程时,这仍然会影响性能,因为每个线程都可以进行合并排序(O(n log n))。我很喜欢这样,但从内存来看,这样做并不要求所有值都是唯一的。在我的域中不太可能出现这种情况,因此byValue映射可能会损坏。很好,我修改了
    byValue
    ,以保留给定值的所有名称。这是O(n),但实际上与其他方法相比,执行速度非常慢。