问题描述
我需要开发一个应用程序,以检索出现在3个文件txt中的单词出现次数最多的应用程序,请注意,所有单词在这些文件中的升序排列,并且某些单词可以出现在多个文件中。要运行该应用程序,我们将使用-Xmx32m命令(使最大堆大小为32MB),如下所示:
java -Xmx32m greatNrOccurrencies
我已经使用哈希映射和链接列表完成了应用程序,但是一旦我尝试使用命令-Xmx32m,应用程序就会发出内存不足错误。如果有人可以提供任何想法,我将不胜感激。
您可以在下面找到代码;
package topkwordsocurrences;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.PrintWriter;
import java.util.*;
public class TopKWordOcurrences {
public static void getKWordOcurrences() {
Scanner firstReader,secondReader,thirdReader;
Map<String,Integer> uniqueWords = new LinkedHashMap<>();
String line;
try {
PrintWriter out = new PrintWriter(".\\src\\topkwordsocurrences\\out.txt");
firstReader = new Scanner(new FileReader(".\\src\\topkwordsocurrences\\f1.txt"));
secondReader = new Scanner(new FileReader(".\\src\\topkwordsocurrences\\f2.txt"));
thirdReader = new Scanner(new FileReader(".\\src\\topkwordsocurrences\\f3.txt"));
while (firstReader.hasNextLine()) {
line = firstReader.nextLine();
if (uniqueWords.containsKey(line)) {
// if your keys is already in map,increment count of it
uniqueWords.put(line,uniqueWords.getorDefault(line,0) + 1);
} else {
// if it isn't in it,add it
uniqueWords.put(line,1);
}
}
while (secondReader.hasNextLine()) {
line = secondReader.nextLine();
if (uniqueWords.containsKey(line)) {
// if your keys is already in map,1);
}
}
while (thirdReader.hasNextLine()) {
line = thirdReader.nextLine();
if (uniqueWords.containsKey(line)) {
// if your keys is already in map,1);
}
}
//convert HashMap into List
List<Map.Entry<String,Integer>> list = new ArrayList<>(uniqueWords.entrySet());
//sorting the list elements in descending order // to make ascending order alter return o1.getValue().compareto(o2.getValue());
Collections.sort(list,new Comparator<Map.Entry<String,Integer>>() {
public int compare(Map.Entry<String,Integer> o1,Map.Entry<String,Integer> o2) {
return o2.getValue().compareto(o1.getValue());
}
});
List<Map.Entry<String,Integer>> top5 = list.subList(0,5);
for (Map.Entry<String,Integer> i : top5) {
System.out.println(i.getKey());
}
} catch (FileNotFoundException e) {
e.printstacktrace();
}
}
public static void main(String[] args) {
getKWordOcurrences();
}
}
解决方法
您可以采取几种措施来减少程序的内存消耗。
首先,您可以在阅读每个文件后将其关闭。您当前打开了3个阅读器,在程序结束之前不要关闭它们。您可以做得更好:
String[] fileNames = new String[]{
".\\src\\topkwordsocurrences\\f1.txt",".\\src\\topkwordsocurrences\\f2.txt",".\\src\\topkwordsocurrences\\f3.txt"
};
for (String fileName : fileNames) {
try (Scanner s = new Scanner(new FileReader(fileName))) {
while (s.hasNextLine()) {
processWord(s.nextLine());
}
} // file is closed when this line is reached,even if exceptions thrown
}
请注意,上述方法也消除了很多重复:您只需实现processWord
或一次打开文件的逻辑即可。
您使用LinkedHashmap
来存储单词。您的文件中有多少个独特的单词?如果是普通文本,则保持在低内存限制内应该没有问题。但是,如果单词是机器生成的,则无法选择映射来将所有单词存储在内存中。在这两者之间,其他类型的地图实现可能需要较少的内存-例如,HashMap
尽管不保留顺序,但每个条目所需的空间却比LinkedHashmap
少。使用Scanner
也会产生开销(并且要以较小的内存成本执行预读以提高性能)。如果迫切需要记忆,可以直接使用阅读器 。
如果您有很多不同的单词,尽管进行了这些更改,但内存用完了,您可以完全避免使用哈希表:您只在寻找最频繁的单词-或K最-频繁的单词,因此仅存储前K个单词及其频率就足够了。
使用伪代码:
open all scanners
for each scanner,count all occurrences of its 1st word
until all scanners are empty:
sort last-read-words from scanners
merge counts for the lexicographically smallest word (if found in several scanners)
check to see if smallest word should enter into top-k list
for each scanner which had smallest word,count occurrences for its next word