算法導論第六章 優先級隊列

原文鏈接:http://blog.csdn.net/coder_xia/article/details/6627902  

如堆一樣,隊列也有2種,最大優先級隊列和最小優先級隊列。最大優先級隊列的一個應用是在一臺分時計算機上進行作業調度(終於搞到點有用的),對於最大優先級隊列,支持以下操作:

     1)INSERT(S,x)把元素x插入隊列S

     2)MAXIMUM(S):返回S中最大元素

    3)EXTRACT-MAX(S):去掉並返回S中最大元素

 4)INCRESE-KEY(S,x,key)在x位置插入值key。

     優先級隊列,用堆實現,這就是看到的必殺運用了。

    我們以82頁圖爲例


示範程序如下:

  1. //============================================================================  
  2. // Name        : prioity.cpp  
  3. // Author      : xia  
  4. // Version     : 1.0  
  5. // Copyright   : NUAA  
  6. // Description : 優先級隊列的模擬實現  
  7. //============================================================================  
  8. #include <iostream>  
  9. #include <climits> //INT_MIN  
  10. #include <vector> //vector  
  11. #include <algorithm>//for_each  
  12. using namespace std;  
  13.   
  14. int Parent(int i)  
  15. {//返回i節點的父節點  
  16.     if (i>0)  
  17.         return i/2;  
  18.     return -1;  
  19. }  
  20. void MaxHeapify(vector<int> &v ,int i ,int heap_size)  
  21. {//讓A[i]在最大堆中下降,使以i爲根的子樹成爲大頂堆  
  22.     int left=2*i; //l<-LEFT(i)  
  23.     int right = 2*i+1; //r<-RIGHT(i)  
  24.     int largest=i;  
  25.    
  26.     if ( (left <= heap_size)  && (v[left] > v[i]) )  
  27.         largest = left ;  
  28.     else  
  29.         largest = i;  
  30.     if ( (right <=heap_size ) && (v[right] > v[largest]) )  
  31.         largest = right;//從父母和自己中找出最大的  
  32.    
  33.     if (largest != i)  
  34.     {  
  35.         swap(v[i],v[largest]);//交換使i和子堆滿足堆性質,不過largest爲根的可能違反,遞歸調整  
  36.         MaxHeapify(v,largest, heap_size);  
  37.     }   
  38. }  
  39. void BuildHeap(vector<int> &v)  
  40. {//建堆  
  41.     for (int i=v.size()/2 ; i > 0 ; i--)  
  42.         MaxHeapify(v,i,v.size()-1);   
  43. }  
  44. int HeapMaximum(vector<int> A)  
  45. //返回堆上的最大元素  
  46.     return A[1];  
  47. }  
  48. int HeapExtractMax(vector<int> &A )  
  49. //去掉並返回A中最大的值  
  50.     int heap_size = A.size()-1;  
  51.     if ( heap_size <1 )  
  52.     {  
  53.         cout << " heap underflow" << endl;  
  54.         exit(EXIT_FAILURE);  
  55.     }  
  56.     int max = A[1];  
  57.     A[1] = A[heap_size];  
  58.     heap_size--;   
  59.     A.pop_back();  
  60.     MaxHeapify(A,1 ,heap_size);  
  61.     return max;  
  62. }  
  63. void HeapIncreaseKey(vector<int> &A , int i, int key)  
  64. //在i處插入值爲key的數,並調整堆  
  65.     if (key<A[i])  
  66.     {  
  67.         cout << " new key is smaller than current key " << endl;  
  68.         exit(EXIT_FAILURE);  
  69.     }  
  70.     A[i] = key;  
  71.     while ( (i>1) && (A[Parent(i)] < A[i]))  
  72.     {  
  73.         swap(A[i],A[Parent(i)]);  
  74.         i = Parent(i) ;  
  75.     }  
  76. }  
  77. void MaxHeapInsert(vector<int> &A , int key)  
  78. {  
  79.     A.push_back(INT_MIN); //僞代碼heapsize+1,且插入負無窮  
  80.     HeapIncreaseKey(A,A.size()-1,key);//第二個參數實際爲堆大小  
  81. }  
  82.   
  83. template <class T>   
  84. class Print   
  85. {  
  86.  public:   
  87.      void operator () (T& t)   
  88.      {  
  89.          cout << t << " ";   
  90.      }  
  91. };  
  92.   
  93. const int heap_size = 10; //這裏假設元素爲10個  
  94.   
  95. int main()  
  96. {  
  97.     int temp[heap_size]={16,14,10,8,7,9,3,2,4,1};  
  98.     vector<int> v(temp+0,temp+heap_size);  
  99.   
  100.     Print<int> print;  
  101.     v.insert(v.begin(),0);//插入個0,切合僞代碼  
  102.   
  103.     BuildHeap(v); //雖然我們的數組順序已經符合堆,不過常理還是要先建堆  
  104.   
  105.     cout << "初始堆V " << endl;  
  106.     for_each(v.begin()+1,v.end(),print);//遍歷輸出  
  107.     cout << endl<< endl;  
  108.   
  109.     cout <<"插入個試試 " << endl;  
  110.     HeapIncreaseKey(v,9,15);//p82圖  
  111.     for_each(v.begin()+1,v.end(),print);  
  112.     cout << endl << endl;  
  113.   
  114.     cout << "提取個" << endl;  
  115.     cout << "max = " << HeapExtractMax(v) << endl;  
  116.     for_each(v.begin()+1,v.end(),print);  
  117.     cout << endl << endl ;  
  118.   
  119.     cout << "再提取個" << endl;  
  120.     cout << "max = " << HeapExtractMax(v) << endl;  
  121.     for_each(v.begin()+1,v.end(),print);  
  122.     cout << endl << endl;  
  123.   
  124.     cout << "插入個" << endl;  
  125.     MaxHeapInsert(v,20);  
  126.     for_each(v.begin()+1,v.end(),print);  
  127.     cout << endl << endl;  
  128.   
  129.     return 0;  
  130. }  
運行結果如下:

     程序各部分的說明在源代碼中,添加說明如下:

    1、 爲了更接近僞代碼,我們將vector的0位置不用,於是left[i]=2*i,right[i]=2*i+1;

    2、雖然我們的初始數組已經符合堆概念,不過這只是巧合,對於任意數組,我們應該首先對其建堆,BuildHeap
    看起來,第二步插入,只是如書82頁的圖,對優先級進行了改變,而第五步的插入數,則更像是新到一個作業,很像作業調度吧?哈哈,堆,想不到也是高級貨。。。


     抄書上一句話,一個堆,可以在O(lgn)時間內,支持大小爲n的集合上的任意優先隊列操作。

     看到MAX-HEAP-INSERT過程,有沒有很眼熟?根據思考題6.1,其實我們建堆的時候,可以用MaxHeapInsert過程,不夠這樣建堆,感覺跟插入排序沒什麼兩樣了。

過程如下:

    

  1. void BuildMaxHeap(vector<int> &v)  
  2. {  
  3.      v.clear();  
  4.      for (int i=0 ; i<v.size() ; i++)  
  5.            MaxHeapInsert(A,v[i]);  
  6. }  

      第六章的一些想法:

      關於堆排序,個人覺得, 其實也是類似選擇排序,每次選出最大的,只是比較都是每個子,左右三個節點進行,排序中規模會減少,雖然這個與選擇是一樣,不過堆引入遞歸(插入也有遞歸,其實也快不了多少,所以堆排序快的因素不是遞歸),而且堆有劃分的想法,對每個子堆分別進行。如同快排的劃分,使得上下半部分不用進行比較,從而與選擇排序比大大減少了比較次數。

      關於優先級隊列,以前知道隊列調度,雖然可以用隊列進行調度,不過藉助堆這樣的結構去組織,清晰的畫出圖之後,發現理解會更深刻一點,也更形象。

     

       菜鳥goes on ~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章