資料結構-練習 12 堆以及最優隊列的實現

來源:互聯網
上載者:User

堆排序是最重要的排序演算法之一,在平時的開發以及面試中經常會用到。堆的特點是:

        1,有一顆完全二叉樹構成,1;

         2,可分為最大堆和最小堆。最大堆的意思就是:任何根節點的資料不小於左右孩子節點的資料;反之,最小堆的意思就是任何節點的資料不大於左右孩子節點的資料;

         3,堆排序的演算法複雜度為O(NlgN),比冒泡和插入快,究其原因在於堆只維護局部最大或最小。

         4,堆的儲存用數組實現,按層儲存,1;

                                          

                                                       儲存在數組裡:

                                                   

                                                         圖 1

  下面分四部分講解堆,分別為:堆的插入,刪除,以及堆排序,最後是堆化的優先隊列。

  一,堆的插入

  堆的插入只能在最後一個位置插入, 2。只能在黑色圈的地方插入。插入以後,必須進行更新,以保持堆的性質,即根資料最大或是最小。更新的思路:從插入節點到根節點,依次比較更新,直到滿足條件(本列子就是:根資料小於左右孩子)。

                                                                大致原理解:

關鍵代碼如下:

            注意的是:左孩子和右孩子的順序分別為2i+1,2i+2。結合上面的流程圖,插入的過程為:從下往上依次比較,重新調整堆的結構。

void MinHeapFixup(int* a, int i)  {      int j, temp;           temp = a[i];      j = (i - 1) / 2;      //父結點      while (j >= 0 && i != 0)      {          if (a[j] <= temp)              break;                    a[i] = a[j];     //把較大的子結點往下移動,替換它的子結點          i = j;          j = (i - 1) / 2;      }      a[i] = temp;  }  void MinHeapAddNumber(int* a, int n, int nNum)  {      a[n] = nNum;      MinHeapFixup(a, n);  }  

二,堆的刪除

記住只能刪除最頂部的元素,再把最低端的元素放到最頂端,從上往下依次更新整個堆。如下:

void MinHeapFixdown(int a[], int i, int n)  {      int j, temp;        temp = a[i];      j = 2 * i + 1;      while (j < n)      {          if (j + 1 < n && a[j + 1] < a[j]) //如果存在有孩子,比較左右孩子的大小            j++;            if (a[j] >= temp)              break;            a[i] = a[j];             i = j;          j = 2 * i + 1;      }      a[i] = temp;  }  void MinHeapDeleteNumber(int a[], int n)  {  std::swap(a[0], a[n - 1]);      MinHeapFixdown(a, 0, n - 1);  }  

總結:刪除,只能刪除頭結點,然後從上往下依次調整堆;插入,只能在末端插入,然後從下往上依次調整堆。三,堆化數組,採用插入的思想從下往上依次調整堆即可。此時調整每一個非葉子節點即可。關鍵代碼如下:

void MakeMinHeap(int* a, int n)  {      for (int i = n / 2 - 1; i >= 0; i--)      MinHeapFixdown(a, i, n);  }  
測試:結合圖形中的資料,我們示範一遍:
int main(){int a[8]={9,7,5,6,8,4,10};cout<<"原始數組裡的資料為:";for(int i=0;i<7;++i)cout<<a[i]<<" ";cout<<endl<<"堆化後的數組為:";    MakeMinHeap(a, 7);for(int i=0;i<7;++i)cout<<a[i]<<" ";    cout<<endl<<"增加一個資料3後的數組為:";    MinHeapAddNumber(a,7,3);    for(int i=0;i<8;++i)cout<<a[i]<<" ";    MinHeapDeleteNumber(a,8);   cout<<endl<<"刪除頂點後的資料為:";   for(int i=0;i<7;++i)cout<<a[i]<<" ";    return 0;}

我們自然要問:維護一個堆結構的意義何在?至少有兩個目的:堆排序和優先隊列。四 ,堆排序。思想:既然我們可以每次取出頂點的資料,取到的資料又是最小資料,根據此思想,我們可以把數組裡的資料全部取完後得到的資料就是有順序的了。不過跟歸併排序一樣,空間複雜度增加了,必須有一個數組去接受。測試:

int b[8];    for(int i=0;i<8;++i){b[i]=a[0];    MinHeapDeleteNumber(a,8-i);}for(int i=0;i<8;++i)cout<<b[i]<<" ";

我們知道,任何演算法都得用時間複雜度計算一下,否則,演算法沒什麼意義。由於按樹堆化,樹高lgN,最壞情況下,每層計算N次,所以複雜度為:O(NlgN),跟歸併一樣。最優隊列:最優隊列是每次都彈出資料的最大或是最小值。每次進隊列後,都要一次更新操作。每次出隊列都要一次刪除操作。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.