在List中提取给定数量的最高值

时间:2010-04-12 20:31:20

标签: java algorithm sorting highest

我正在寻求在网页上根据各自的权重显示固定数量的项目(由Integer表示)。找到这些物品的清单几乎可以是任何尺寸。

首先想到的解决方案是执行Collections.sort()并通过List逐个获取项目。是否有一个更优雅的解决方案虽然可以用来准备前八项?

10 个答案:

答案 0 :(得分:6)

Collections.sort(..)。它足够有效。

  

此算法可提供有保证的n log(n)性能。

如果您知道列表的某些独特属性,可以尝试为您的具体案例实现更高效的,但这是不合理的。此外,如果您的列表来自数据库,例如,您可以LIMIT它&在那里订购而不是代码。

答案 1 :(得分:5)

您的选择:

  1. 执行线性搜索,保持沿途找到的前N个权重。 如果由于某种原因,您无法在显示页面之间重复使用排序结果(例如列表正在快速变化),这应该比排序长度列表更快。

    更新:我认为线性搜索必须比排序更好。有关更好的选择算法,请参阅维基百科文章“Selection_algorithm - Selecting k smallest or largest elements”。

  2. 手动维护按重量顺序排序的List(原始的或平行的)。您可以使用Collections.binarySearch()之类的方法来确定每个新项目的插入位置。

  3. 维护List(原始的或平行的)按重量顺序排序,在每次修改,批量修改或显示之前调用Collections.sort()(可能保留修改标记)避免对已排序的列表进行排序。)

  4. 使用维护已排序权重顺序的数据结构:priority queuetree set等。您还可以创建自己的数据结构。

  5. 手动维护前N个项目的第二个(可能是重量排序的)数据结构。只要修改原始数据结构,就会更新此数据结构。您可以创建自己的数据结构来将原始列表和这个“前N个缓存”包装在一起。

答案 2 :(得分:3)

您可以使用max-heap

如果您的数据来自数据库,请在该列上添加索引并使用ORDER BY和TOP或LIMIT仅获取您需要显示的记录。

答案 3 :(得分:3)

答案 4 :(得分:3)

使用dollar

List<Integer> topTen = $(list).sort().slice(10).toList();

不使用美元,您应sort()使用Collections.sort(),然后使用list.sublist(0, n)获取前n项。

答案 5 :(得分:2)

既然你说从中提取这些前N个的项目列表可能是任何大小的,所以可能很大我假设,我会增加上面的简单sort()答案(这完全适合于合理大小的输入)通过建议这里的大部分工作是找到前N - 然后排序那些N是微不足道的。那就是:

Queue<Integer> topN = new PriorityQueue<Integer>(n);
for (Integer item : input) {
  if (topN.size() < n) {
    topN.add(item);        
  } else if (item > topN.peek()) {
    topN.add(item);          
    topN.poll();
  }
}

List<Integer> result = new ArrayList<Integer>(n);
result.addAll(topN);
Collections.sort(result, Collections.reverseOrder());

这里的堆(最小堆)的大小至少有限。没有必要从你的所有物品中堆出来。

答案 6 :(得分:1)

不,不是真的。至少不使用Java的内置方法。

有一些聪明的方法可以比列表O(n*log(n))更快地从列表中获取最多(或最低)的N个项目,但这需要您手动编写此解决方案。如果项目数量保持相对较低(不超过几百),使用Collections.sort()对其进行排序,然后获取前N个数字是IMO的方法。

答案 7 :(得分:1)

取决于多少。让我们将n定义为键的总数,将m定义为您想要显示的数字 对整个事物进行排序:O(nlogn)
每次扫描阵列以获得下一个最高数字:O(n*m)
所以问题是 - n与m之间的关系是什么? 如果m < log n,扫描效率会更高 否则,m >= log n,这意味着排序会更好。 (因为对于m = log n的边缘情况它实际上并不重要,但排序也会给你带来好处,好吧,排序数组,总是很好。

答案 8 :(得分:0)

如果列表的大小为N,并且要检索的项目数为K,则需要在列表上调用Heapify,该列表将列表(必须是可索引的,例如数组)转换为优先级队列。 (参见http://en.wikipedia.org/wiki/Heapsort)中的heapify函数

检索堆顶部的项目(最大项目)需要O(lg N)时间。所以你的总时间是:

O(N + k lg N)

假设k远小于N,则

优于O(N lg N)。

答案 9 :(得分:0)

如果不能选择保留已排序的数组或使用不同的数据结构,则可以尝试以下方法。 O时间类似于对大型数组进行排序,但实际上这应该更有效。

small_array = big_array.slice( number_of_items_to_find );
small_array.sort();
least_found_value = small_array.get(0).value;

for ( item in big_array ) {  // needs to skip first few items
  if ( item.value > least_found_value ) {
    small_array.remove(0);
    small_array.insert_sorted(item);
    least_found_value = small_array.get(0).value;
  }
}

small_array可以是一个Object [],内部循环可以通过交换完成,而不是实际删除和插入数组。