堆的定義
堆結構是一種陣列物件,可以被視為一顆完全二叉樹。樹中的每個節點與陣列中存放該節點中值的那個元素相對應。
由上圖不難看出 fa
ther
(i)=
⌊i/2
⌋ le
ftch
ild(
i)=i
∗2 r
ight
chil
d(i)
=i∗2
+1當然也可以用位運算來加快速度 fa
ther
(i)=
⌊i>>1⌋
leftchi
ld(i
)=i<<1
由於i*2一定為偶數(i∈n+),所以i<<1|1等價於i*2+1. ri
ghtc
hild
(i)=
i<<1|
1 堆的性質
n個關鍵字序列l[1…n]稱為堆,當且僅當該序列滿足:堆的操作1. l(i)<=l(2i)且l(i)<=l(2i+1)或
2. l(i)>=l(2i)且l(i)>=l(2i+1)
滿足第乙個條件的成為小根堆(即每個結點值小於它的左右孩子結點值),滿足第二個新增的成為大根堆(即每個結點值大於它的左右孩子結點值)。
1.向堆中加入乙個元素(push),並保持堆的有序演算法分析2.從隊中刪除乙個元素(pop),並保持堆的有序
3.查詢最小/最大值(top).
插入乙個元素:1.在堆尾加入乙個元素,把這個節點設定為當前結點具體實現2.維護——
比較當前結點和它的父結點的大小,小於父結點的話就交換它們的值,一直交換直到當前結點大於等於它的父結點(小根堆),大根堆相反。
刪除乙個元素
1.把堆的最後乙個結點(heap[size])放到根的位置上(將根結點覆蓋),pa指向根結點,size–。
2.根結點沒有兒子就return;否則,取兒子中最小的乙個與其比較,比子結點大就交換它們的值,pa指向子結點。(小根堆,大根堆則是取兒子中最大的比較,比子結點小就交換)
查詢最小、最大值
就是堆頂元素
插入操作
刪除操作void push(int d)//向堆heap中插入d
}//或者是使用stl裡面堆的維護操作:
void put(int d)
查詢void pop()
}//使用stl:
void pop(int d)
當然以上操作也可以使用優先佇列容器(priority_queue)int
get()
洛谷上關於小根堆的測試
手寫堆:
優先佇列容器:#include#include#includeusing namespace std;
const
int n=1000000+121;
int size,n,heap[n];
void swap(int &a,int &b)
void put(int d)
}void pop()
}int
get()
int main()
else
if(a==2)
printf("%d\n",get());
else pop();}}
堆的經典例題:#include
#include
#include//要用stl的佇列或者優先佇列的話不要忘了這個標頭檔案
#include
using
namespace
std;
//定義乙個優先佇列h,greater<>表示為小根堆
//vector<>是向量,動態陣列的一種,所佔記憶體隨插入元素的增加而增加
priority_queue
,greater >h;
int main()
else
if(a==2)
printf("%d\n",h.top());//堆頂元素
else h.pop();//彈出}}
洛谷:p1090 合併果子
洛谷:p1631 序列合併
洛谷:p3378 【模板】小根堆
openjudge: 3.7 集合問題
利用堆之優先佇列
利用上一節的最大堆,中間省略了很多該刪和修改的東西,總是時學習演算法嗎 懶了一些啊,o o include include struct heap int paraent int i int leftchild int i int rightchild int i void max heap int...
優先佇列《堆》
1.模型 兩個基本操作 insert等價enqueue deletemin刪除最小者 dequeue 2.簡單的實現 1 簡單鍊錶 遍歷刪除min或者排序刪除min 2 使用二叉查詢樹。反覆除去min會使得樹不平衡,並且bst還支援許多不需要的操作。3.二叉堆 優先佇列的實現普遍使用二叉堆,堆有兩個...
優先佇列 堆
印表機列印作業一般是放在佇列中的。如果按照先來先列印的順序,有乙個100頁的列印任務,那麼會讓後面短小的任務等待很長時間。更合理的做法也許是最後處理最耗時的列印任務,不管它是不是最後提交上來的。在多使用者作業系統中,作業系統讓哪個程式使用cpu,是需要決定從佇列裡面選擇的。一般做法是從隊頭獲得程式,...