根据出现的频率排列列表的元素(具有重复元素)

时间:2011-05-13 09:16:50

标签: java collections

根据列表中出现的频率排列列表元素(带有重复元素)的好方法。

我需要使用列表中排名前5位的项目。

我正在考虑使用HashMap通过在每次元素出现时递增相应的计数器来计算元素的频率。然后做5次HashMap迭代以找到最高频率。每次迭代的元素。

4 个答案:

答案 0 :(得分:5)

这种做法怎么样?

维护一个包含计数的地图

public static Map  <Foo,Integer>;

class Foo implements Comparator<Foo>{  
      private Bar element;


      public int compare(Foo f1, Foo f2){
       return SomeClass.map.get(f1) - SomeClass.map.get(f2);
      }

    }

只需使用list中的更新更新地图。

使用addFooToList()removeFooFromList()强制包含对List的访问,并在那里封装地图更新逻辑。

答案 1 :(得分:5)

您可以使用Guava Multisetorder it by frequency


关于表现。当然,这取决于你有多少不同的值,但这个测试代码在我的机器上花了大约一秒钟。而且我认为这对10 M项来说足够合理了:

Multiset<Integer> set = HashMultiset.create();
int amount = 10000000;
Random random = new Random();
for (int i = 0; i < amount; i++) {
    set.add(Integer.valueOf(random.nextInt(255)));
}
TreeSet<Entry<Integer>> sortedEntries = Sets.newTreeSet(
        new Comparator<Entry<Integer>>() {
    public int compare(Entry<Integer> a, Entry<Integer> b) {
        return Ints.compare(a.getCount(), b.getCount());
    }
});
Iterables.addAll(sortedEntries, set.entrySet());
for (Entry<Integer> entry : Iterables.limit(sortedEntries, 5)) {
    System.out.println(entry.getElement());
}

答案 2 :(得分:2)

任何基于比较的排序都会导致O(N log N)或更糟的时间复杂度,因此(渐近地)这些不是好建议。

您的方法有O(N)时间复杂度,而且这是您可以获得的最佳效果。您可以尝试降低常量(目前您正在对列表元素进行大约6*N次访问。)

我会在这样的两次迭代中完成:首先使用HashMap计算频率。接下来,迭代映射中的条目,并保留到目前为止看到的5个最常见值的有序5元素数组。对于每个新元素,检查该值是否比目前为止最常见的第5个更常见,并更新&#34;前5&#34;如果有必要的话。


更新更简单的解决方案具有相同的时间复杂度。首先,使用HashMap计算频率。接下来,将所有条目放入PriorityQueue并弹出五个值。条目应该是价值 - 频率对,可以按频率进行比较(如在@Jigar的解决方案中)。这样的排序不会与等于&#34; (请参阅Comparable以获得解释),但那没关系。

答案 3 :(得分:0)

我也会使用HashMap。我发现了一些我只做过的代码:

HashMap<String, Integer> counts = new HashMap<String, Integer>();

void increment(String s) {
    Integer oldCount = counts.get(s);
    if (oldCount == null) {
        counts.put(s, 1);
    } else {
        counts.put(s, oldCount + 1);
    }
}

列出元素:

Map.Entry<String, Integer>[] array = new Map.Entry[counts.size()];
counts.entrySet().toArray(array);
Arrays.sort(array, new Comparator<Map.Entry<String, Integer>>() {
    public int compare(Map.Entry<String, Integer> a, Map.Entry<String, Integer> b) {
        return b.getValue() - a.getValue();
    }
});
int x = 0, min = 0;
for (Map.Entry<String, Integer> el : array) {
    String k = el.getKey();
    println("Count: " + el.getValue() + "\n" + k + "\n\n");
}