用有序二叉堆實現優先佇列
阿新 • • 發佈:2019-02-07
優先佇列
優先佇列要提供並實現兩個操作
- 刪除並返回最大元素
- 插入元素
優先佇列的實現
優先佇列的實現採用有序二叉堆形式,採用連結串列或堆疊也可實現,但時間複雜度較高。這裡不再贅述。
有序二叉堆的特點
- 所有根結點必定不小於其兩個葉子節點
- 如果某個節點對應的陣列下標為k,則其根節點為k/2,其葉子節點為2k和2k+1
- 有序二叉堆通過陣列實現,採用陣列a[N+1]描述有序二叉堆中第一個到最後一個節點(陣列元素a[0]不使用,從a[1]開始)。
- 如圖所示:
有序二叉堆的主要操作
- 上浮
當插入新元素到堆中時,先將該元素置於陣列末尾,再上浮至正確節點 - 下沉
當移除
public class MaxPQ<T extends Comparable<T>>{
private T[] a;
private int index= 0;//指向末尾元素
private int N;//記錄陣列的大小
public MaxPQ(int size){
N = size;
a = (T[])new Comparable[](size + 1);
}
//插入新元素到堆中
public void insert(T item){
//插入前檢測陣列是否需要擴容
if (index >= N * 0.75) {
resize(a);
N = a.length;
}
//指標指向新的末尾元素
a[++index] = item;
//上浮至正確節點位置
swim(index);
}
private void swim(int k){
while(k > 1 && a[k] > a[k/2 ]){
swap(k, k/2);
k = k / 2;//每上浮一次,k要變為其父節點位置
}
}
//從堆中移除最大元素
private T removeMax(){
T max = a[1];
a[1] = a[index];//將末尾元素當作新的根節點
a[index] = null;//防止物件遊離
index--;
sink(1);//將根節點元素下沉至正確位置
return max;
}
private T sink(int k){
while(k* 2 < N){
int j = 2 * k;//j記錄葉子節點位置
if (a[j] < a[j+1]) {j++};//j移動到兩個葉子節點中較大的那個
if (a[k] > a[j]) {break};//如果父節點大於葉子節點,說明位置已找到,跳出迴圈
swap(k, j);//否則將父節點和葉子節點交換
k = j;
}
}
//陣列擴容函式
private void resize(T[] a){
T[] temp = (T[])new Object[N * 2];
for (int i = 0; i < a.length; i++) {
temp[i] = a[i];
}
a = temp;
}
}