:一種支持插入,刪除,查詢最值的數據結構,是一顆完全二叉樹,實際上就是一個優先隊列priority_queue,這裏我們用數組的實現這個堆
大根堆:樹中的任意一個節點的權值都小於等於其父節點
小根堆:樹中的任意一個節點的權值都大於等於其父節點
如何實現堆
直接用一個數組來保存二叉堆, 逐層的從左到右依次編號,將此編號作爲節點在數組中存儲的位置。所以,父親點編號等於子節點編號除以2,左子節點編號等於父節點編號乘以2,又子節點等於父節點編號乘2加1

堆的基本操作
1求集合中的最小值:h[ 1 ]
2.插入一個數:h[++n] = x;up(n); //up函數將x向上調整,找到x的位置,保證堆的有序性
3.刪除最小值:h[1] = h[n–];down(1) //down函數,將x向下調整,找到x的位置,保證堆的有序性
4.刪除任意一個元素:h[x] = h[n–];down(x);up(x);//因爲不確定x的大小,所以可能是向上調整,也可能是向下調整,這倆個函數雖然都寫上了,但實際上只會執行一個,
5.修改任意一個元素:h[k] = x;down(k);up(k)//跟4同理
時間複雜度:與堆的高度有關,所以是O(logN)
代碼如下:

題目描述

輸入一個長度爲n的整數數列,從小到大輸出前m小的數。

輸入格式

第一行包含整數n和m。
第二行包含n個整數,表示整數數列。

輸出格式

共一行,包含m個整數,表示整數數列中前m小的數。

數據範圍

1≤m≤n≤105,
1≤數列中元素≤109

輸入樣例:

5 3
4 5 1 3 2

輸出樣例:

1 2 3

#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int h[N], n ,m;
void down(int p) //向上調整
{
    int s = 2 * p;  //子節點
    while(s <= n){
        if(s < n && h[s] > h[s + 1])s++;  //找到左右子節點的最小值
        if(h[s] < h[p]){  //如果子節點比父節點小
            swap(h[s], h[p]);  //則交換
            p = s;   //繼續向下調整
            s = 2 * p;
        }
        else break;
    }
}
void up(int p)  //向上調整,
{
    while(p > 1){ 
        if(h[p] < h[p / 2]){  //如果子節點小於父節點
            swap(h[p], h[p / 2]);  //則交換
            p /= 2;  //繼續向上調整
        }
        else break;
    }
}
int main()
{
    cin>> n >> m;
    for(int i = 1; i <= n; i++)
        cin >> h[i];
    for(int i = n / 2; i >= 1; i--)down(i);
    while(m--){
        cout << h[1] << ' ';
        h[1] = h[n--];
        down(1);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章