Наибольшее количество совпадений слов в 3 файлах с использованием java-команды -Xmx32m

#java #algorithm #file #word #counting

#java #алгоритм #файл #word #подсчет

Вопрос:

Мне нужно разработать приложение, которое извлекает наибольшее количество вхождений слов, присутствующих в 3 файлах txt, обратите внимание, что все слова сортируются по возрастанию внутри этих файлов, а некоторые слова могут присутствовать в нескольких файлах. Для запуска приложения мы будем использовать команду -Xmx32m (которая делает максимальный размер кучи 32 МБ) в качестве примера ниже:

java -Xmx32m наибольшее количество встречаемости слов в 3 файлах

Я выполнил приложение, используя hashmap и связанные списки, но как только я пытаюсь использовать команду -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, 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 (thirdReader.hasNextLine()) {
                line = thirdReader.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);
                }
            }

            //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();
    }

}
  

Ответ №1:

Есть несколько вещей, которые вы можете сделать, чтобы уменьшить потребление памяти вашей программой.

Во-первых, вы можете закрыть каждый файл после его чтения. В настоящее время вы открываете 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 или логику для открытия файлов один раз.

Вы используете a LinkedHashmap для хранения слов. Сколько уникальных слов в ваших файлах? Если это обычный текст, у вас не должно возникнуть проблем с сохранением минимального объема памяти. Однако, если слова генерируются машиной, ни один выбор карты не сможет сохранить их все в памяти. Между ними другие типы реализации map могут требовать меньше памяти — например, a HashMap , не сохраняя порядок, требует несколько меньше места на запись, чем a LinkedHashmap . Использование a 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