1. 程式人生 > >【模板】堆

【模板】堆

int algorithm mage 有一個 tor n) long long 小根堆 \n

?堆是一種特殊的完全二叉樹。以小根堆為例,這種完全二叉樹有一個特點,就是它的父節點都比子節點小。符合這樣特點的二叉樹,我們也稱為最小堆。

?反之,如果所有父節點都比子節點要大,這樣的完全二叉樹稱為大根堆,或最大堆。

?(若是最小堆,則最小的數在堆頂/樹根。)


按一般意義來講,一個堆的父節點的優先級都比子節點高。

堆有兩種基本的寫法



1.手寫堆

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#define leftson (cur<<1)
#define rightson (cur<<1|1)
#define father (cur>>1)
#define int long long
#define MAXN 1000000+10
int n=0,m;
int heap[MAXN];
namespace self
{
    #define int long long
    void swap(int h[],int x,int y)
    {
        int t; t=h[x]; h[x]=h[y]; h[y]=t;
        return;
    }
    using namespace self;
    void siftdown(int h[],int i)
    {
        int t;
        bool flag=0;
        while (i*2<=n && flag==0)
        {
            if (h[i]>h[i*2])
            t=i*2;
            else t=i;
            if (i*2+1<=n)
            {
                if(h[t]>h[i*2+1])
                t=i*2+1;
            }
            if (t!=i)
            {
                swap(heap,t,i);
                i=t;
            }
            else flag=1;
        }
        return;
    }
}
using namespace self;
void down(int cur)
{
    int t;
    bool flag=0;
    while (leftson<=n&&(!flag))
    {
        if (heap[cur]>heap[leftson])
        {
            t=leftson;
        }
        else t=cur;
        if (rightson<=n)
        {
            if (heap[t]<heap[rightson])
            {
                t=rightson;
            }
        }
        if (t!=cur)
        {
            swap(heap,t,cur);
            cur=t;
        }
        else flag=1;
    }
}
void up(int cur)
{
    bool flag=0;
    if (cur==1) return;
    while (cur!=1&&(!flag))
    {
        if (heap[cur]<heap[father])
        {
            swap(heap,cur,father);
        }
        else flag=1;
        cur=father;
    }
    return;
}
signed main()
{
    scanf("%lld",&m);
    int q;
    while (m--)
    {
        scanf("%lld",&q);
        if (q==1)
        {
            n++;
            scanf("%lld",&heap[n]);
            up(n);
            continue;
        }
        if (q==2)
        {
            printf("%lld\n",heap[1]);
            continue;
        }
        if (q==3)
        {
            heap[1]=heap[n];
            n--;
            siftdown(heap,1);
        }
    }
    return 0;
}

無良無分析式玄學代碼


2.STL 堆:優先隊列


?隊列是一種先進先出(FIFO)式的數據結構。優先隊列與其不同的地方是,優先隊列存儲的時候,會將(定義的)優先級較大的元素放在較小的元素之前。也就是說優先級最大的元素放在隊頭。 那麽這裏就和堆有了共同點:優先級大的放在隊前/堆高層。
大根堆的定義:
queue< int >q;


小根堆的定義:
priority_queue< int,vector< int >,greater< int > >q;


一個優先隊列的操作:


技術分享圖片

小根堆基本操作代碼

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
using namespace std;
priority_queue<int,vector<int>,greater<int> >q;
int main()
{
    int n;
    scanf("%d",&n);
    int x;
    while(n--)
    {
        scanf("%d",&x);
        if (x==1)//命令1 在堆中加入一個數
        {
            scanf("%d",&x);
            q.push(x);
            continue;
        }
        if (x==2)//命令2 輸出當前序列中最小數
        {
            printf("%d\n",q.top());
            continue;
        }
        if (x==3)//命令3 刪除當前序列中最小數
        q.pop();
    }
    return 0;
}

【模板】堆