如何在文本文件中查找N个最长行

时间:2011-07-04 02:07:14

标签: java

编写程序以读取多行文本文件,并将“N”个最长行写入stdout。

有一个类似的问题,但我并没有真正理解它,因为它涉及使用min-heap,因为我必须创建一个min-heap数据结构,所以会创建更多的工作。

我尝试创建一个大小为n的数组。然后排序它,但每次我在数组中插入一个新行时我都要对它进行排序。我想知道什么是简单的方法,什么是最优的方法。

4 个答案:

答案 0 :(得分:1)

创建一个包含N个字符串的数组。

循环浏览文件。

如果数组中的项目数是< N然后将它添加到最后。

在所有情况下,都会在数组中存储最短的行长度。 如果阵列已满,则与最短线比较,如果新线是>那条线,替换,并找到最短的线。

重复循环。

打印字符串。

答案 1 :(得分:0)

编辑:正如其他提到的那样,我的第一个解决方案不适用于相同长度的行。一个更好的方法是使用java.util.PriorityQueue<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删除首先删除列表中的最小元素。您可以在每次插入行后queue.poll()致电queue.size() > n

答案 2 :(得分:0)

这是我的解决方案

使用树形图的原因是处理具有相同长度的多行,在这种情况下,所有行都将被添加到相同的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());

    }

}

答案 3 :(得分:0)

假设不允许多条相同长度的行。这是算法:

  1. 使用key =&gt;创建一个排序字典;字符串的长度和值=&gt;线。
  2. 打印字典的最后N行。
  3. 如果允许多个相同长度的行,则必须修改Dictionary以将List包含为值。 这是代码:

    SortedDictionary&GT; processed = new SortedDictionary&gt;();

            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;
                }
            }