堆的应用:topk问题以及堆排序

堆的应用:topk问题以及堆排序

一. topk问题
topk问题就是给上一大堆数据,然后找出其中最大的k个数据
(1).使用这些数据的前k个数据建一个堆(求最大k个数需要建小堆,反之则用大堆)
(2).读取下一数据,与堆顶数据作比较,满足条件则用这个数据将堆顶数据替换掉(求最大k个数时读取到的数据应大于堆顶数据才满足替换条件,反之则需要小于堆顶数据),替换之后重新调整堆为大堆或者小堆,不满足条件的数据直接掠过,无需进堆
(3).继续读取数据重复步骤(2)
如下是求这个数组中的最大三个数的过程
这里写图片描述

void TopK(const vector<int>& v, int K)
{
    Heap<int> MinHeap;//建小堆
    for (int i = 0; i < v.size(); i++)
    {
        if (MinHeap.Size() < K)
        {
            MinHeap.Push(v[i]);
        }
        else
        {
            if (v[i]>MinHeap.Root())//与堆顶数据比较
            {
                size_t root = (K - 2) / 2;
                MinHeap.Root() = v[i];//替换
                MinHeap._AdjDown(root);//调整堆
            }
        }
    }
    MinHeap._Dispaly(K);//打印输出
}

在数据量特别大时,数据存在磁盘文件之中,用堆求取topk问题原理与此是相同的,只是从内存中读取数据变为从硬盘读取。

二. 堆排序
用堆进行排序,所有的数据都需要放进同一个堆中,数据量不能特别大
(1).用所给数据建小堆(用于降序)(要升序则建大堆)
(2).将堆顶数据与堆中最后一个数据进行交换,这时最大或者最小数据就是堆中最后一个数据,堆的容量减一
(3).将剩下的数据重新调整为小堆或者大堆
(4).重复步骤(2)和(3)直至所有数据排完

这里写图片描述

void _AdjDown(size_t root,size_t size)
    {
        size_t parent = root;
        size_t child = parent * 2 + 1;
        while (child < size)
        {
            if ((child + 1 < size) && (_a[child] > _a[child + 1]))
                ++child;
            if (_a[parent] > _a[child])
            {
                swap(_a[child], _a[parent]);
                parent = child;
                child = parent * 2 + 1;
            }
            else
            {
                break;
            }
        }
    }

void _HeapSort()
    {
        size_t size = _a.size();
        while (size > 0)
        {
            swap(_a[0], _a[size-1]);
            size--;
            _AdjDown(0,size);
        }
    }
void HeapSort(int* a, size_t n)
{
    Heap<int> MinHeap;
    for (int i = 0; i < n; i++)
    {
        MinHeap.Push(a[i]);
    }
    MinHeap._HeapSort();
    MinHeap._Dispaly(n);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值