topK问题:
假如需要从十亿个数据中找出最大的前k个数,也就是海量数据处理问题。
一般遇见这种问题,我们肯定会想到先排序,再取前K个数据就可以了。但是海量数据如果这样处理,那就会大大提高时间复杂度了。那么我们应该如何处理呢?
首先假如这是一组大数据,取出前K个元素放入小堆里:
在小堆里,这前K个元素是有序的,最小的元素放在堆顶。依次取数组里的下一个数据与堆顶元素进行比较,如果数组数据大于堆顶元素,就可以利用对结构来删除堆顶元素,删除后的堆结构仍然是有序的;然后将该数组数据利用堆结构放入堆中,此时堆结构仍是有序的。图解如下所示:
程序源码:
test.c
#include"Heap.h"
#include"PriorityQueue.h"
#include<iostream>
#include<stdio.h>
#include<Windows.h>
#define N 10
#define K 4
using namespace std;
//堆
void test(){
int arr[] = { 53, 17, 78, 9, 45, 65, 87, 23 };
Heap<int,Less<int>> hp(arr, sizeof(arr) / sizeof(arr[0]));
hp.Push(80);
hp.Pop();
cout << hp.Size() << endl;
cout << hp.Top() << endl;
cout << hp.Back() << endl;
}
//优先级队列
void test2(){
int arr[] = { 53, 17, 78, 9, 45, 65, 87, 23 };
PriorityQueue<int> prq;
for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i){
prq.Push(arr[i]);
}
cout << prq.Top() << endl;
cout << prq.Size() << endl;
prq.Pop();
cout << prq.Top() << endl;
cout << prq.Size() << endl;
}
//TopK(海量数据处理问题)
void TopK(){
int arr[N];
int max[K];
for (size_t i = 0; i < N; ++i){
arr[i] = rand() % N;
}
for (size_t j = 0; j < K; ++j){
max[j] = arr[j];
}
//前K个元素建一个小堆
Heap<int, Less<int>> hp(max, sizeof(max) / sizeof(max[0]));
//依次读取arr[]之后的数据,与小堆堆头元素比较,若该数据大于堆头元素,则删除堆头元素,将该数据放到堆里,堆会自己排好序
for (size_t k = K; k < N; ++k){
if (arr[k] > hp.Top()){
hp.Pop();
hp.Push(arr[k]);
}
}
//依次输出最大的K个数据
hp.Print();
}
int main(){
//test();
//test2();
TopK();
system("pause");
return 0;
}
测试结果:
N=10,K=4时:
N=100,K=20 时:
随机产生的数组arr[100]部分数据展示:
最大的前K个数据: