1. 程式人生 > >數據結構_二叉樹Ⅲ——堆與優先隊列

數據結構_二叉樹Ⅲ——堆與優先隊列

最大 info 否則 但我 com urn med 小根堆 父親

堆(Heap)


堆是一種完全二叉樹,只是是用數組的形式表示二叉樹而已

它其實是利用完全二叉樹的結構來維護一組數據

例如這樣一棵完全二叉樹:

技術分享圖片

它用堆的形式表現就是這樣的:

技術分享圖片

當然,一般的堆每個元素都是數字呢(不然小根堆與大根堆就沒辦法實現了呢)

大根堆與小根堆

顧名思義,大根堆/小根堆就是保證根節點是所有數據中最大/小,並且盡力讓小的節點在上方

例如下面這個二叉樹就是一個小根堆呢

技術分享圖片

(借鑒某書圖片)

那如何將任意一個堆調整至大根堆/小根堆呢?

  1. 從上向下調整

    讓當前結點與它的左右孩子進行比較,哪個比較小就和它交換,更新詢問節點的下標為被交換的孩子節點下標,否則退出。

    void heapdown(int
    i) //傳入一個需要向下調整的結點編號i { int t,flag=0;//flag用來標記是否需要繼續向下調整 //當i結點有兒子的時候(其實是至少有左兒子的情況下)並且有需要繼續調整的時候循環需執行 while(i*2<=n&&flag==0) { //首先判斷他和他左兒子的關系,並用t記錄值較小的結點編號 if(h[i]>h[i*2]) t=i*2; else t=i; //如果他有右兒子的情況下,再對右兒子進行討論 if(i*2+1<=n) {
    //如果右兒子的值更小,更新較小的結點編號 if(h[t]>h[ i*2+1]) t=i*2+1; } //如果發現最小的結點編號不是自己,說明子結點中有比父結點更小的 if(t!=i) { swap(t,i); i=t;//更新i為剛才與它交換的兒子結點的編號,便於接下來繼續向下調整 } else flag=1;//則否說明當前的父結點已經比兩個子結點都要小了,不需要在進行調整了 } return; }
  2. 從下向上調整

    讓當前結點和它的父親節點比較,若比父親節點小就交換,然後將當前詢問的節點下標更新為原父親節點下標,否則退出。 

    void heapup(int i) //傳入一個需要向上調整的結點編號i
    {
       int flag=0; //用來標記是否需要繼續向上調整
       if(i==1)  return; //如果是堆頂,就返回,不需要調整了    
       while(i!=1&&flag==0)
       {
           //判斷是否比父結點的小 
           if(h[i]<h[i/2])
               swap(i,i/2);//交換他和他爸爸的位置 
           else flag=1;//表示已經不需要調整了,當前結點的值比父結點的值要大 
           i=i/2; //這句話很重要,更新編號i為它父結點的編號,從而便於下一次繼續向上調整 
       }
       return;
    }

優先隊列


優先隊列其實是在普通隊列的基礎上增加了每個元素的優先性(值)

眾所周知,普通隊列是遵循元素先進先出的原則,進隊只能從前面進,出隊只能出最後一個

而優先隊列不再遵循先入先出的原則,而是分為兩種情況:

最大優先隊列,無論入隊順序,當前最大的元素優先出隊。

最小優先隊列,無論入隊順序,當前最小的元素優先出隊。

例如說下面的這個優先隊列出隊就需要出8這個元素

技術分享圖片

但這種算法的時間復雜度並不理想

如果只用線性數據結構的話,入隊和出隊的時間復雜度都是O(n)

但我們如果通過二叉堆的方式,每次上浮最大的或最小的

這時出隊和入隊操作都只需要O(logn)的時間復雜度了

但從來不用STL的本蒟蒻只能用結構體而不會queue的操作QAQ

數據結構_二叉樹Ⅲ——堆與優先隊列