堆的定义及性质

堆是一棵完全二叉树,以大顶堆为例,每个节点的值不小于其左右孩子节点。用数组实现堆,下标为i的节点其左右孩子节点的小标为2i和2i+1。

相关操作

建堆:从最后一个有孩子的节点开始,逆序枚举,每个节点向下调整

插入元素:将新增元素插入堆尾,向上调整

删除(堆顶)元素:将最后一个元素覆盖堆顶,从堆顶向下调整

#include <bits/stdc++.h>
using namespace std;


const int maxn = 100; // 堆的总容量
int n;  // 堆内元素个数
vector<int>heap(100,0); // 以大顶堆为例
// 节点i的左右孩子节点下标为2i和2i+1

// 调整[low,high]范围内的节点
// 向下调整堆
void downAdjust(int low,int high)
{
    int i = low, j = i*2;
    while(j<=high)
    {
        // 如果右孩子存在且值大于左孩子
        if(j+1<=high && heap[j+1]>heap[j])
        {
            // 记住较大孩子的下标
            j = j+1;
        }
        // 如果孩子中的最大权值比欲调整的节点i要大,就交换
        if(heap[j]>heap[i])
        {
            int tmp = heap[i];
            heap[i] = heap[j];
            heap[j] = tmp;
            i = j;
            j = i*2;
        }
        else break; // 孩子节点的值均比根小
    }
}
// 在下标[low,high]范围内上调
void upAdjust(int low,int high)
{
    int i = high, j = i/2;
    while(j>=low)
    {
        // 大于根节点
        if(heap[i]>heap[j])
        {
            int tmp = heap[i];
            heap[i] = heap[j];
            heap[j] = tmp;
            i = j;
            j = i/2;
        }
        else break; // 没有比根节点大
    }

}
// 往堆内添加元素
void insert(int x)
{
    heap[++n] = x;
    upAdjust(1,n);
}

// 删除元素
void deleteTop()
{
    // 最后一个元素覆盖堆顶,再向下调整
    heap[1] = heap[n--];
    downAdjust(1,n);
}
//排序
void HeapSort()
{
    while(n>=1)
    {
         cout<<heap[1]<<" ";
         deleteTop();
    }
    cout<<endl;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;++i)
        cin>>heap[i];
    //建堆,从最后一个有孩子的节点开始调整
    for(int i=n/2;i>=1;--i)
    {
        downAdjust(i,n);
    }

    //  堆排序
    HeapSort();
    /////insert(100);
     ////HeapSort();
    //deleteTop();
    //HeapSort();

    return 0;
}

具体例子

1.topK问题(找最大的k的元素--建小顶堆;最小的k个元素--建大顶堆)

图片说明

class Solution {
public:
    // 优先级队列自定义数据类型的比较
    struct cmp{
        // 重写仿函数
        bool operator() (pair<int,int> a,pair<int,int> b)
        {
            return a.second>b.second; // 最小值优先
        }
    };
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int,int>mp;
        // 用map对每个出现的元素计数
        for(int i=0;i<nums.size();++i)
            mp[nums[i]]++;
        // 小顶堆
        priority_queue<pair<int,int>,vector<pair<int,int>>,cmp>Q;
        for(auto item : mp)
        {
            // 如果堆内元素不足k个 则入堆
            if(Q.size()<k)
            {
                Q.push(item);
            }
            // 当前元素的频次低于堆顶元素 则不入堆
            else if(item.second>Q.top().second)
            {
                Q.pop();
                Q.push(item);
            }
        }
        vector<int>ans;
        while(!Q.empty())
        {
            ans.push_back(Q.top().first);
            Q.pop();
        }
        return ans;


    }
};

时间复杂度:O(nlogk) 空间复杂度:O(n)