堆的简单应用——TopK

1、海量数据top k问题

100亿个数中找出最大的前K个数,我们可以遍历K次找到,但是时间复杂度就很大为 O(KN);因此,我们可以用堆来实现,只需遍历一次,思路如下:

  • 如果要找前K个最大的数,我们用小堆,每次用堆顶元素和遍历的数比,如果堆顶元素小,则让堆顶元素的值等于它,然后向下调整
  • 如果要找前K个最小的数,我们用大堆,每次用堆顶元素和遍历的数比,如果堆顶元素大,则让堆顶元素的值等于它,然后向下调整
2、代码如下

这里我们暂时用有限的几个数模仿海量数据,来判断算法是否正确

TopK.h
#pragma once

//堆的操作见其他文章,这里只用到堆的结构体和,大堆小堆函数指针
#include "Heap.h"

//TopK
void TopK(Heap *hp, DataType * array, long size, int K);
//初始化堆
void HeapTopKInit(Heap *hp, Compare cmp, int K);
//交换元素
void SwopTopK(DataType *a, DataType *b);
//打印元素
void TopK_Print(Heap *hp, int K);
//向下调整算法
void AdjustDownTopK(Heap  *hp, DataType parent)
//测试
void TestTopK();
TopK.c
#include "TopK.h"

//求最小的3个元素
void TopK(Heap *hp, DataType * array, long size, int K)
{

    for (long i = 0; i < K; i++)
    {
        InsertHeap(hp, array[i]);
        AdjustDownTopK(hp, i);
    }
    for (long i = K; i < size; i++)
    {
        if (hp->cmp(array[0],hp->_array[i]))
        {
            SwopTopK(&hp->_array[0],&array[i]);
            AdjustDownTopK(hp, 0);
        }

    }
}

//向下调整
void AdjustDownTopK(Heap  *hp, DataType parent)
{
    int child = (parent<<1)+1;

    if (NULL == hp)
        return;
    while (child < hp->_size)
    {
        //找到孩子中较小的一个
        if ((child+1) < hp->_size && 
            hp->cmp(hp->_array[child+1], hp->_array[child]))
        {
            child += 1;
        }
        //如果双亲大于孩子,则交换
        if (hp->cmp(hp->_array[child], hp->_array[parent]))
        {
            Swop(&hp->_array[parent], &hp->_array[child]);
            parent = child;
            child = (parent << 1) + 1;
        }
        else
        {
            break;
        }
    }
}

void SwopTopK(DataType *a, DataType *b)
{
    DataType temp = *a;
    *a = *b;
    *b = temp;
}

void TopK_Print(Heap *hp, int K)
{
    int i = 0;
    for (; i < K; i++)
    {
        printf("%d ", hp->_array[i]);
    }
    printf("\n");
}

void HeapTopKInit(Heap *hp, Compare cmp, int K)
{
    if (NULL == hp)
        return;
    hp->_array = (DataType*)malloc(sizeof(DataType)* K);
    hp->_capacity = K;
    hp->_size = 0;
    hp->cmp = cmp;
}


void TestTopK()
{
    Heap hp;
    int array[] = { 53, 17, 78, 9, 45, 65, 87, 23, 31 };
    int K = 3;

    HeapTopKInit(&hp, Greater, K);
    TopK(&hp, array, sizeof(array)/sizeof(array[0]),K);
    TopK_Print(&hp, K);

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值