最大堆 最小堆 解决TOPK问题

堆:实质是一颗完全二叉树,最大堆的特点:父节点值均大于子节点;最小堆的父节点值均小于子节点;

一般使用连续内存存储堆内的值,因而可以根据当前节点的索引值推断子节点的索引值:
节点i的父节点为(i-1)/2;
节点j的左子结点:j * 2 + 1;
节点j的右子结点:j * 2 + 2;

以下代码实现了最大堆最小堆,当比较函数使用std::greater,得到最大堆,当比较函数使用std::less得到最小堆;
关键是考虑清楚小顶堆用于找最大,大顶推用于找最小,其他都简单。

大最小堆
//MaxMinHeap.h

#pragma once
#include <assert.h>

using namespace std;

template <typename T>
void mswap(T &a, T &b)
{
    T tmp = a;
    a = b;
    b = tmp;
}

template <typename T,typename Compare = std::less<T>>
class MaxMinHeap
{
public:
    int hSize ;    //堆空间
    int hCurNum;//堆内已占用空间
    T *data;

private:
    Compare comp;//比较函数
public:
    MaxMinHeap(int size)
    {
        hSize = size;
        assert(hSize>0);
        data = new T[hSize];
        hCurNum = 0;
    };
    ~MaxMinHeap(void)
    {
        if(data!=NULL)
            delete []data;
    };

    void headAdd(T num)
    {
        if (hCurNum==hSize)
        {
            if (comp(num,data[0]))//greater 大顶堆 保留最小的K个数;less 小顶堆 保留最大的K个数
                return;
            data[0]=num;
            HeapFixDown(0,hCurNum);
        }
        else
        {
            data[hCurNum++]=num;
            HeapFixUp(hCurNum-1);
        }
    };
    //最大堆排序后得到升序序列;最小堆排序后得到降序序列
    void sort()
    {
        for (int i=hCurNum-1; i >=1 ; --i)
        {
            mswap(data[i],data[0]);
            HeapFixDown(0,i);
        }
    }

    void GetHnum(T &n)//获取最大堆的最小值或者最小堆的最大值
    {
        n = data[0];
    };
    void HeapFixUp(int index)
    {
        assert (index < hCurNum);
        T tmp=data[index];
        int j = (index - 1)/2;//父节点
        while(j>=0 && index !=0)
        {
            if(comp(data[j],tmp))
                break;
            data[index]=data[j];
            index = j;
            j = (index - 1)/2;
        }
        data[index]=tmp;
    };

    //从节点index开始进行向下调整
    void HeapFixDown(int index, int n)
    {
        assert(index<hCurNum);
        assert(n<hCurNum);

        T tmp=data[index];
        int j = index*2+1;
        while(j<n)
        {
            if(j+1 < n && comp(data[j+1],data[j]))//大顶堆中左右孩子找最大的,小顶堆左右孩子找最小的
                ++j;
            if(comp(tmp,data[j]))
                break;
            data[index]=data[j];
            index = j;
            j = index*2+1;
        }
        data[index]=tmp;
    };
};

#include <functional>
#include <iostream>
#include "MaxMinHeap.h "

using namespace std;

int main(int argc ,  char ** argv)
{
    MaxMinHeap<float,greater<float>> test(20);

    for (int i = 0 ;i < 20; ++i)
    {
        test.headAdd(-i*2+38);
    }
    for (int i = 0 ; i < 20 ; ++i)
    {
        cout<<test.data[i]<<endl;
    }
    test.sort();
    for (int i = 0 ; i < 20 ; ++i)
    {
        cout<<test.data[i]<<" ";
    }
    cout<<endl;
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值