堆--優先佇列

Haskei發表於2016-11-09

1.完全二叉樹的一個父節點編號為k,那麼他的左二子的編號為2*k,右二子節點的編號為2*k+1

2.如果已知兒子(左兒子或者右兒子)的編號為x,那麼他的父節點的編號為x/2(取整除,就是計算機裡的/)

3.一棵完全二叉樹的高度為logN,即最多有logN層節點

4.最小堆是所有的父節點都比他的子節點小,最大堆是所有的父節點都比他的子節點大


5.像這樣支援插入元素和尋找元素(最大值和最小值)的資料結構成為優先佇列,如果使用普通佇列,那麼尋找最大元素就需要列舉整個佇列,時間複雜度為O(n),時間複雜度比較高,如果是已經排好序的陣列,那麼插入一個元素需要移動大量的資料,時間複雜度依舊很高,而堆就是一種優先佇列的實現,可以很好地解決這兩種操作


6.堆經常被用來求一個數列中第K大的數,只需要建立一個大小為K的最小堆,堆頂就是第K大的數(舉個例子,假設有事十個數,要求第3大的數,將前三個數建成最小堆,然後從第四個數開始,與堆頂元素比較,如果比堆頂元素大,則捨棄當前堆頂元素,而將這個新數作為堆頂,然後堆頂開始向下調整,如果比堆頂元素小,則不進入堆),同理如果求第K小的數,那麼就建一個最大堆,這種方法的時間複雜度為O(NlogK)

<span style="font-size:18px;">//該演算法用來把數從小到大排序
#include<iostream>
#include<queue>
#include<stack>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define maxn 20
#define inf 0x3f3f3f3f
using namespace std;
int h[maxn];//用來存放堆的陣列
int n;//用來儲存堆中元素的個數,也就是堆的大小

//交換堆中兩個元素的位置
void swap(int i, int j)
{
    int t=h[i];
    h[i]=h[j];
    h[j]=t;
    return;
}

void siftdown(int i)//從i開始向下調整
{
    int t,flag=1;
    while(i*2<=n && flag)//至少存在左兒子
    {
        if(h[i*2]>h[i])
            t=i*2;
        else t=i;
        
        if(i*2+1<=n)//如果存在右兒子
        {
            if(h[i*2+1]>h[t])
                t=i*2+1;
        }
        
        if(i!=t)//說明父節點不是最小的點
        {
            swap(i,t);//交換父節點和比父節點大的子節點的位置
            i=t;//更新為剛才交換的子節點的編號,方便繼續向下調整
        }
        else
            flag=0;
    }
    return;
}

void creat()
{
    for(int i=n/2;i>=1;i--)//從最後一個父節點開始向下調整
        siftdown(i);
}

void heapsort()
{
    while(n>1)
    {
        swap(1,n);
        n--;
        siftdown(1);
    }
    return;
}

int main()
{
    int num;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&h[i]);
    num=n;
    creat();//建堆
    heapsort();//堆排序
    printf("\n");
    for(int i=1;i<=num;i++)
        printf("%d ",h[i]);
    printf("\n");
    
    return 0;
        
}
/*
輸入資料
 14
 99 5 36 7 22 17 46 12 2 19 25 28 1 92
 
輸出結果
 1 2 5 7 12 17 19 22 25 28 36 46 92 99
 */</span>


相關文章