版权声明:本文为匆忙拥挤repeat(stone)原创文章,转载请注明出处 —— http://blog.csdn.net/jjwwmlp456 https://blog.csdn.net/jjwwmlp456/article/details/88878946
什么是 Top K 问题
求(随机的)序列中第 n 大的元素?
求(随机的)序列中前 n 大的元素, 或者说 最大的 n 个元素?
反之求第 n 小的,最小的 n 个元素,都可以说是 Top K 问题
以下讨论的求 最大的情况
快速排序解
快排的思想:
每次指定序列中的一个(比如是首位的)值,通过一次快排,返回的索引之前的值就是大于(或等于) 指定值的,之后的就是小于指定值的。
那么要解决 最大 n 的问题:可以在递归函数中,判断 目标 n 的索引 是在 快排函数的返回索引值的 前面还是后面,而不需要完整的递归调用,以至完全排序。
代码:
int destIndex = n-1;
private void quickSort(int[] ary, int l, int r) {
if (l >= r)
return;
int p = qs(ary, l, r);
//比较 目标索引,与 qs 返回索引的大小
if (destIndex == p) {
//return;
} else if (destIndex > p) {
quickSort(ary, p + 1, r);
} else {//destIndex < p
quickSort(ary, l, p - 1);
}
}
private void qs(int[] ary, int l, int r) {
... //省略一次快排实现
}
堆排序解
堆排序思想:
要倒序排序,这时要先创建的是小顶堆。然后循环中交换首尾,再下移; 每次下移时,末端是较小的元素,这样末端就是有序的;再继续循环至完成,就成了 从大到小的 倒序序列了。
那么要解决 最大 n 的问题:就只需要反过来,用堆排-顺序排序来解决。
这样,堆排的过程中,保持了序列尾部向前,是从大到小的序列。
int destIndex = n - 1;
public void heapSort(int[] ary) {
long startTime = System.nanoTime();
int len = ary.length;
for (int i = (len - 1) / 2; i >= 0; i--) {
siftDown(ary, i, len - 1);
}
//限定 i 的区间,这样只循环 destIndex+1次
for (int i = len - 1; i >= len -1 - destIndex; i--) {
Util.swap(ary, 0, i);
siftDown(ary, 0, i - 1);
}
System.out.println("total time:" + ((System.nanoTime() - startTime) / 1.0e9));
}
private void siftDown(int[] ary, int start, int end) { //省略下移实现
}
如上,交换+下移的循环, 只要执行 n 次就可以了, 即 destIndex+1次。