堆:一種支持插入,刪除,查詢最值的數據結構,是一顆完全二叉樹,實際上就是一個優先隊列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;
}