堆(優先佇列)的基本操作
阿新 • • 發佈:2019-01-12
堆(優先佇列)的基本操作
堆是一棵完全二叉樹,所以可以利用陣列來實現。
以1號作為root,則對於陣列中的任意一個i,其左兒子在(2*i),右兒子在(2*i+1),父親在(i/2)。
下面以最小堆為例,實現一些基本操作:
1.堆的宣告
#define INF 0x3f3f3f3f
#define MAX 1005
int heap[MAX];
heap[0] = -INF;
int Size = 0;
2.兩個基本的操作:PercolateUp,PercolateDown
//比較父節點與子節點,若父節點大,則交換,實現子節點的上濾 void PercolateUp(int p){ while(p/2){ if(heap[p] < heap[p/2]){ swap(heap[p], heap[p/2]); p /= 2; //更新p } else break; } }
//將左右兩個兒子節點與父節點比較,若父節點大,下濾(與兒子節點交換) void PercolateDown(int p){ int len = Size; while(p*2 <= len){ if(heap[p*2] < heap[p]){ //左兒子 swap(heap[p], heap[p*2]); p *= 2; } else if(heap[p*2 + 1] < heap[p]){ //右兒子 swap(heap[p], heap[p*2 + 1]); p = (p*2)+1; } else return; } }
3.Insert
將元素先插入到末尾的下一個位置(保證為完全樹),然後逐層上濾,尋找正確的位置。
每一次上濾都需要反覆交換,但是縱觀整個過程,會發現每一步只需要將不滿足條件的父親下移,當找到正確的位置之後,再進行一步交換即可。
如果插入的元素是整個堆的最小值,則X會被一直推到堆頂。此時X大於heap[0](-INF),迴圈終止,交換。
void Insert(int x){ if(Size == MAX - 1){ cout<<"FULL"<<endl; return; } int i; //將x置於最後,然後向上調整(與他爹比較) for(i = ++Size; data[i / 2] > x; i/=2) data[i] = data[i/2]; data[i] = x; }
4.DeleteMin
//刪除堆頂的最小元,之後將最後一個節點放到1號位置,然後PercolateDown,進行調整,保持完全樹
int DeleteMin(){
int i, child;
if(Size == 0){
cout<<"Empty"<<endl;
return ERROR;
}
int MinElem = heap[1];
int LastElem = heap[Size--];
for(i = 1; i*2 < Size; i = child){
child = i*2;
//找相對較小的兒子節點
if(child != Size && heap[child + 1] < heap[child])
child++;
//percolate one level
if(Last > heap[child])
heap[i] = heap[child];
else break;
}
heap[i] = LastElem;
return MinElem;
}