我创建了一个hashmap来存储多个文件中的单词出现,例如10,000个文本文件。然后我想从hashmap中排序并打印前10个单词。 Hashmap定义为,
Hashtable <String, Integer> problem1Counter = new Hashtable<String, Integer> ();
当我将文件保存到1000左右时,我能够使用这样的简单排序获得前十个单词,
String[] keysProblem1 = (String[]) problem1Counter.keySet().toArray(new String[0]);
Integer [] valuesProblem1 = (Integer[])problem1Counter.values().toArray(new Integer[problem1Counter.size()]);
int kk = 0; String ii = null;
for (int jj = 0; jj < valuesProblem1.length ; jj++){
for (int bb = 0; bb < valuesProblem1.length; bb++){
if(valuesProblem1[jj] < valuesProblem1[bb]){
kk = valuesProblem1[jj];
ii = keysProblem1[jj];
valuesProblem1[jj] = valuesProblem1[bb];
keysProblem1[jj] = keysProblem1[bb];
valuesProblem1 [bb] = kk;
keysProblem1 [bb] = ii;}}}
因此,当散列表的值超过553685时,上述方法无效。那么有人能建议并展示一种更好的方法来对它们进行排序吗我是java的新手,但曾参与过动作,所以我觉得有点舒服。 感谢。
答案 0 :(得分:4)
当你分开keys
和values
并尝试保持每个索引连接的东西时,你的问题就开始了。相反,保持它们耦合,并对java给你的Map.Entry
对象进行排序。
我不确定这会编译,但它应该给你一个开始。
// HashMap and Hashtable are very similar, but I generally use HashMap.
HashMap<String, Integer> answers = ...
// Get the Key/Value pairs into a list so we can sort them.
List<Map.Entry<String, Integer>> listOfAnswers =
new ArrayList<Map.Entry<String, Integer>>(answers.entrySet());
// Our comparator defines how to sort our Key/Value pairs. We sort by the
// highest value, and don't worry about the key.
java.util.Collections.sort(listOfAnswers,
new Comparator<Map.Entry<String, Integer>>() {
public int compare(
Map.Entry<String, Integer> o1,
Map.Entry<String, Integer> o2) {
return o2.getValue() - o1.getValue();
}
});
// The list is now sorted.
System.out.println( String.format("Top 3:\n%s: %d\n%s: %d\n%s: %d", +
listOfAnswers.get(0).getKey(), listOfAnswers.get(0).getValue(),
listOfAnswers.get(1).getKey(), listOfAnswers.get(1).getValue(),
listOfAnswers.get(2).getKey(), listOfAnswers.get(2).getValue()));
答案 1 :(得分:3)
为了更好地进行排序,我会这样做:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
HashMap<String, Integer> counter = new HashMap<String, Integer>();
// [... Code to populate hashtable goes here ...]
//
// Extract the map as a list
List<Map.Entry<String, Integer>> entries = new ArrayList<Map.Entry<String, Integer>>(counter.entrySet());
// Sort the list of entries.
Collections.sort(entries, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Entry<String, Integer> first, Entry<String, Integer> second) {
// This will give a *positive* value if first freq < second freq, zero if they're equal, negative if first > second.
// The result is a highest frequency first sort.
return second.getValue() - first.getValue();
}
});
// And display the results
for (Map.Entry<String, Integer> entry : entries.subList(0, 10))
System.out.println(String.format("%s: %d", entry.getKey(), entry.getValue()));
}
}
编辑解释其工作原理
您的原始算法看起来像Selection Sort的变体,它是一种O(n ^ 2)算法。您的变体也进行了大量的额外交换,因此非常慢。
如果你的问题大小乘以10,那么O(n ^ 2)的运行时间通常要长100倍。排序50万个元素需要进行2500亿次比较,其中许多将导致交换。
Collections#sort中的内置排序算法是Merge Sort的快速变体,它在O(n.log(n))时间内运行。这意味着每次将问题大小乘以10时,它只需要大约30倍的时间。对半个元素进行排序只需要进行大约1000万个比较。
这就是为什么有经验的开发人员会建议您尽可能使用库函数。编写自己的排序算法对于学习来说非常有用,但是实现一个算法需要花费很多工作,因为它可以像库中的那样快速灵活地实现。
答案 2 :(得分:1)
或者,因为你只需要前10名,所以你可以在你的单词中迭代并保持前十名。