簡體   English   中英

如何在文本文件中找到 N 條最長的行

[英]How to find N longest lines in a text file

編寫一個程序來讀取多行文本文件並將“N”個最長的行寫入標准輸出。

有一個類似的問題,但我並不真正理解它,因為它涉及使用最小堆,並且由於我必須創建一個最小堆數據結構,這會產生更多的工作。

我試圖創建一個大小為 n 的數組。 然后對其進行排序,但每次在數組中插入新行時,我都必須對其進行排序。 我想知道什么是簡單的方法,什么是最佳方法。

創建一個包含 N 個字符串的數組。

循環瀏覽文件。

如果數組中的項目數 < N 則只需將其添加到末尾。

在所有情況下,將最短的行存儲在數組中。 如果數組已滿,則與最短的行進行比較,如果新行>則該行,替換並找到最短的行。

重復循環。

打印字符串。

假設不允許多條相同長度的行。 這是算法:

  1. 使用 key => 字符串的長度和 value => 行創建一個排序字典。
  2. 打印字典的最后 N 行。

如果允許具有相同長度的多行,則必須修改 Dictionary 以包含 List 作為值。 這是代碼:

SortedDictionary> 已處理 = 新的 SortedDictionary>();

        int N;
        StreamReader reader = File.OpenText(args[0]);

        N = int.Parse(reader.ReadLine());

        while (!reader.EndOfStream)
        {
            string line = reader.ReadLine();

            if (string.IsNullOrWhiteSpace(line) || string.IsNullOrEmpty(line))
                continue;

            line.Trim();

            if (processed.ContainsKey(line.Length))
            {
                processed[line.Length].Add(line);
            }
            else
            {
                processed.Add(line.Length, new List<string> { line });
            }
        }
        while(N != 0)
        {
            foreach (KeyValuePair<int, List<string>> kvp in processed.Reverse())
            {
                kvp.Value.ForEach(c => Console.WriteLine(c));
                if (--N == 0)
                    break;
            }
        }

編輯:正如其他人提到的,我的第一個解決方案不適用於相同長度的行。 更好的方法是使用java.util.PriorityQueue<Line>並像這樣定義 object Line:

class Line {
  private final String line;
  public Line(String line) {
    this.line = line;
  }

  public int getLen() {
    return line.length();
  }

  public String getLine() {
    return line;
  }
} 

然后實例化一個PriorityQueue並使用Comparator指定順序。

PriorityQueue<E> : PriorityQueue(int initialCapacity, Comparator<? super E> comparator)

創建一個具有指定初始容量的 PriorityQueue,它根據指定的比較器對其元素進行排序。

這是一個使用單元測試的實驗。

        int n = 1;
        PriorityQueue<Line> queue = new PriorityQueue<Line>(n, new Comparator<Line>() {
            @Override
            public int compare(Line a, Line b) {
                return a.getLen() - b.getLen();
            }
        });

        queue.add(new Line("abcd"));
        queue.add(new Line("abcde"));
        queue.add(new Line("abc"));

        assertEquals(queue.poll().getLine(), "abc");
        assertEquals(queue.poll().getLine(), "abcd");
        assertEquals(queue.poll().getLine(), "abcde");

在這個例子中,我們看到 poll remove 首先刪除列表中的最小元素。 如果queue.size() > n在每行插入后,您可以簡單地調用queue.poll()

這是我的解決方案

使用樹形圖的原因是為了處理具有相同長度的多行,在這種情況下,所有行將被添加到同一個 ArrayList

public class DataCollector {

    private int size;
    private TreeMap<Integer, List<String>> data = new TreeMap<Integer, List<String>>();

    public DataCollector(int nthLargest) {

        if (nthLargest < 1) {
            throw new IllegalArgumentException("can not be smaller than 1");
        }

        this.size = nthLargest;
    }

    public void feed(String line) {

        int length = line.length();

        if (data.size() > 0 && length < data.firstKey()) {
            return;
        }

        getList(length).add(line);



        if (data.size() > size) {
            data.remove(data.firstKey());
        }
    }

    private List<String> getList(int key) {
        if (!data.containsKey(key)) {
            data.put(key, new ArrayList<String>());
        }

        return data.get(key);
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();

        for (Entry<Integer, List<String>> entry : data.entrySet()) {
            builder.append(entry.getKey()).append("=").append(entry.getValue()).append("\r\n");
        }

        return builder.toString();
    }

    public List<String> getResult() {


        if (data.isEmpty()) {
            return Collections.EMPTY_LIST;
        }

        return data.firstEntry().getValue();
    }
    public static void main(String[] args) {

        DataCollector co = new DataCollector(1);


        co.feed("b");
        co.feed("abc");
        co.feed("abc1");
        co.feed("abc2");
        co.feed("abc33");
        co.feed("abc34");
        co.feed("abc23");
        co.feed("abc23b");
        co.feed("abc23b");
        co.feed("abc23c");
        co.feed("abc23dd");
        co.feed("abc23ee");
        co.feed("a");

        System.out.println(co);
        System.out.println(co.getResult());

    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM