我正在逐行解析一个大文件,读取每一行中的子字符串。我将从每个子字符串中获取一个整数值,每行大约有30个子字符串,需要返回文件中最高的5个值。在进行此过程时,哪种数据结构最有效用于跟踪最大的5个值?
我正在逐行解析一个大文件,读取每一行中的子字符串。我将从每个子字符串中获取一个整数值,每行大约有30个子字符串,需要返回文件中最高的5个值。在进行此过程时,哪种数据结构最有效用于跟踪最大的5个值?
这个问题通常使用堆来解决,但(也许是违反直觉的)你使用了一个最小堆(最小元素是堆的“顶部”)。
算法基本上是这样的:
对于每个解析的项 如果堆中包含少于n个项, 将新项添加到堆中 否则 如果新项“大于”堆中的“最小”项, 删除最小项并用新项替换它
完成后,您可以从小到大从堆中弹出元素。
或者,具体地说:
static <T extends Comparable<T>> List<T> top(Iterable<? extends T> items, int k) {
if (k < 0) throw new IllegalArgumentException();
if (k == 0) return Collections.emptyList();
PriorityQueue<T> top = new PriorityQueue<>(k);
for (T item : items) {
if (top.size() < k) top.add(item);
else if (item.compareTo(top.peek()) > 0) {
top.remove();
top.add(item);
}
}
List<T> hits = new ArrayList<>(top.size());
while (!top.isEmpty())
hits.add(top.remove());
Collections.reverse(hits);
return hits;
}
TreeSet
)更快。TreeSet
(基本上是一个排序集合),每次添加到集合中时删除first
(最低)元素。 这将丢弃重复项。
SortedSet<Integer> set = new TreeSet<>();
for (...) {
...
if (set.size() < 5) {
set.add(num);
} else if (num > set.first()) {
set.remove(set.first());
set.add(num);
}
}
set.last()
将返回最高的数字。您确定要删除它吗? - dnaultInteger#compareTo
“符合等式”。文章链接:http://www.codelord.net/2010/11/24/liskov-substitution-principle-violation-spotted-in-the-wild/。 - 4castleSortedSet
实现是极端的。它们非常有用,而且很容易通过遵循简单、易懂、广泛记录和直觉的实践方法——使equals()
与compareTo()
保持一致来减轻它们的缺点。 - ericksonGuava库有一个Ordering.greatestOf
方法,可以在O(N)时间和O(K)空间内从Iterable
中返回最大的K个元素。
实现在一个包私有的TopKSelector
类中。
int
数组。 - Elliott FrischSet
是否适用于此。 - 4castle