【问题标题】:Fast word count in java using linked list [duplicate]java中使用链表的快速字数统计[重复]
【发布时间】:2018-09-23 18:20:09
【问题描述】:

所以这里的程序计算文本文档中出现次数最多的单词的出现。然而,由于我认为的 get(i) 方法,它非常慢。任何想法如何使它更快?我知道如果我使用数组会更快,但我希望它保持为链表,如果可能的话,只需更改 get(i) 部分。

import java.io.File;
    import java.util.Scanner;
    import java.util.Map.Entry;
    import java.util.AbstractMap;
    import java.util.LinkedList;

public class wordcount {


    public static Entry<String, Integer> count_LINKED_LIST(String[] tokens) {
        LinkedList<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>();
        for (int j = 0; j < tokens.length; j++) {
            String word = tokens[j];
            boolean found = false;
            for (int i = 0; i < list.size(); i++) {
                Entry<String, Integer> e = list.get(i);

                if (word.equals(e.getKey())) {
                    e.setValue(e.getValue() + 1);
                    list.set(i, e);
                    found = true;
                    break;
                }
            }
            if (!found)
                list.add(new AbstractMap.SimpleEntry<String, Integer>(word, 1));
        }

        int maxCount = 0;
        String maxWord = "";
        for (int i = 0; i < list.size(); i++) {
            int count = list.get(i).getValue();
            if (count > maxCount) {
                maxWord = list.get(i).getKey();
                maxCount = count;
            }
        }
        return new AbstractMap.SimpleEntry<String, Integer>(maxWord, maxCount);
    }

    static String[] readText(String PATH) throws Exception {
        Scanner doc = new Scanner(new File(PATH)).useDelimiter("[^a-zA-Z]+");
        int length = 0;
        while (doc.hasNext()) {
            doc.next();
            length++;
        }

        String[] tokens = new String[length];
        Scanner s = new Scanner(new File(PATH)).useDelimiter("[^a-zA-Z]+");
        length = 0;
        while (s.hasNext()) {
            tokens[length] = s.next().toLowerCase();
            length++;
        }
        doc.close();

        return tokens;
    }

    public static void main(String[] args) throws Exception {

        String PATH = "/Users/username/foldername/textdocument.txt";
        String[] tokens = readText(PATH);
        long startTime = System.currentTimeMillis();
        Entry<String, Integer> entry = count_LINKED_LIST(tokens);
        long endTime = System.currentTimeMillis();
        String time = String.format("%12d", endTime - startTime);
        System.out.println("time\t" + time + "\t" + entry.getKey() + ":" + entry.getValue());
    }

}

【问题讨论】:

  • 您是否尝试过使用 for each 循环?
  • get(int i)LinkedList 上非常慢,因为它必须从头开始扫描以定位索引i。要使其更快,请使用ArrayList。但是,实际上要快速实现“计算出现次数最多的单词的出现次数”,请使用Map&lt;String, Integer&gt;
  • LinkedList 是您可以为此任务选择的最糟糕的集合(实际上对于任何任务),并且您通过使用索引来访问元素以极其低效的方式使用它,首先获取元素,然后设置它们(尽管这完全没有必要)。使用适当的数据结构:HashMap。
  • @FallaCoulibaly 使用迭代器循环或 foreach 循环可能会更快。但是 HashMap 确实更合适。
  • @JBNizet 我不同意“事实上,对于任何任务来说,链表都是最糟糕的集合”。例如,链接列表对于编程来说是非常基础的,并且用于在您的操作系统中实现哈希和任务队列。确实,它不适合 this 任务,也许您正在专门讨论 Java 的 LL 集合实现。当您需要暗示访问前后元素时,使用 LinkedList 而不是 ArrayList 可能是合适的,例如在队列和堆栈中。如果您使用的是list.get 方法,则可能是结构错误。

标签: java


【解决方案1】:

您可以为此使用映射(令牌是键,令牌出现次数是值)并使用 Java8+ Stream API:

public static Map<String, Long> count(String[] tokens) { 
    return Arrays.stream(tokens).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-05
    • 1970-01-01
    • 2012-07-07
    • 1970-01-01
    • 2014-01-28
    • 1970-01-01
    • 2019-04-27
    相关资源
    最近更新 更多