在Map中查找最高n值

时间:2010-08-31 14:52:33

标签: java algorithm data-structures optimization

我有一个String-> Integer的大地图,我想找到地图中最高的5个值。我当前的方法是将映射转换为pair(key,value)对象的数组列表,然后在获取第一个5之前使用Collections.sort()进行排序。一个键可以在操作过程中更新其值

我认为这种方法是可以接受的单线程,但是如果我有多个线程全部触发转置并经常排序它似乎不是很有效。替代方案似乎是维护最高5个条目的单独列表,并在地图上的相关操作发生时保持更新。

我可以提供一些优化的建议/替代方案吗?如果有好处,我很乐意考虑不同的数据结构。

谢谢!

7 个答案:

答案 0 :(得分:5)

好吧,要在Map中找到最高的5个值,您可以在O(n)时间内执行此操作,其中任何排序都比此慢。

最简单的方法是简单地通过Map的入口集进行for循环。

for (Entry<String, Integer> entry: map.entrySet()) {
    if (entry.getValue() > smallestMaxSoFar) 
        updateListOfMaximums();
}

答案 1 :(得分:3)

您可以使用两张地图:

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

// Maps value to names
NavigableMap<Integer, Collection<String>> byValue

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

答案 2 :(得分:2)

  

我认为这种方法是可以接受的单线程,但是如果我有多个线程全部触发转置并经常排序它似乎不是很有效。替代方案似乎是维护最高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;
}

理想情况下,如果您有多个线程访问某些状态(例如此映射),则将该状态封装在其他类的后面,以便每个线程不直接更新映射。

答案 3 :(得分:1)

我会创建一个方法,如:

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;
}

利用Collections.max()Collections.singleton()

答案 4 :(得分:1)

有两种方法可以轻松完成:

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

答案 5 :(得分:0)

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

compareTo(无论它在哪里)方法应该像这样定义: 的compareTo(参数){  return value2 - value1; //下降 }

其余的很容易。使用List并调用Collections.sort(参数)方法将执行排序部分。

我不知道Collections.sort(参数)使用的排序算法。但是如果您觉得某些数据可能会随着时间的推移而出现,则需要插入排序。因为它对于几乎排序的数据是好的,它是online

答案 6 :(得分:0)

如果修改很少,我会实现一些SortedByValHashMap<K,V> extends HashMap <K,V>,类似于LinkedHashMap),以保持按值排序的条目。