【数据结构】topK问题,海量数据找出前K个大的数据

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个数据:

这里写图片描述

这里写图片描述

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值