根据列表中出现的频率排列列表元素(带有重复元素)的好方法。
我需要使用列表中排名前5位的项目。
我正在考虑使用HashMap通过在每次元素出现时递增相应的计数器来计算元素的频率。然后做5次HashMap迭代以找到最高频率。每次迭代的元素。
答案 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 Multiset
和order 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");
}