1. 程式人生 > >堆(優先佇列)的基本操作

堆(優先佇列)的基本操作

堆(優先佇列)的基本操作

堆是一棵完全二叉樹,所以可以利用陣列來實現。

以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;
}