例說資料結構&STL(七)——priority_queue

無鞋童鞋發表於2017-07-29

1 白話優先佇列(priority_queue)
  前面我們已經相繼介紹了雙向佇列和FIFO特性的佇列,這裡我們還要接觸另一個包含“佇列”稱呼的資料結構——優先佇列。其實這三個資料結構名稱看似很像,實則天差萬別,通過下面的介紹你就會有很深的體會了。
  那麼何為優先佇列呢,在優先佇列中,元素被賦予優先順序,當訪問元素時,具有最高階優先順序的元素先被訪問。即優先佇列具有最高階先出的行為特徵。所以說佇列queue可以看成是優先佇列的一個特殊情況,其中的資料優先順序別是按資料的插入時間先後排序的,這種插入時間的先後就可以看做是一種優先順序。在預設的優先佇列中,優先順序最高的先出隊。預設的int型別的優先佇列中先出隊的為佇列中較大的數。
  介紹到此,你是不是發現它有些像構建堆呢?也就是大頂堆表示優先順序最高的先出隊,而小頂堆表示優先順序別最低的先出隊。
2 STL中priority_queue實戰
 2.1 包含heap的標頭檔案
  priority_queue和queue一樣定義在同一個標頭檔案中的,另外使用一直強調的std名稱空間一定要加上,實現如下:

#include<queue>

using namespace std;

 2.2 宣告優先佇列物件
  優先佇列模板類的構造實際上有三個型別需要給出,預設構造如下:

priority_queue<int> que1;       // 普通構造,預設是大頂堆

priority_queue<int> que2(10,3);// 帶參構造初始化10個資料3

  此外我們還可以手工構造,這樣就可以定義為大頂堆還是小頂堆了,如下:

priority_queue<int, vector<int>, less<int>>    //大頂堆:表示其他都比堆頂小
priority_queue<int, vector<int>, greater<int>> //小頂堆:表示其他都比堆頂大

  所以預設情況下是less構建的大頂堆,表示其中的數越來越小。要記住,如果是要手工確認優先順序規則,那麼內部使用的容器一定也要手動加上,不可以是priority_queue<int, greater<int>>這樣定義。
  另外,上面的less和greater是定義在functional.h標頭檔案中,如果使用這樣的系統自帶功能函式一定要加上對應的標頭檔案。當然我們也可以自定義優先規則,這個後面再詳細說明。
 2.3 基本操作
  基本操作和佇列大致相同,除了佇列既可以訪問隊首也可以訪問隊尾,而優先佇列只能訪問隊首,所以訪問介面不同,其他幾乎一樣。此外優先佇列也是介面卡型別容器,所以沒有對應的迭代器功能定義。基本操作如下:

que1.empty( );  // 判斷佇列是否為空

que1.pop( );    // 刪除隊頂元素

que1.push( );   // 加入一個元素

que1.size( );   // 返回優先佇列中擁有的元素個數

que1.top( );    // 返回隊頂元素,介面和stack名一樣。而queue中是front()和back()

 2.4 自定義優先順序規則
  優先順序的規則定義常用是下面兩種方法,主要都是構建一個結構體,一種方法是在結構體中過載運算子(),而另一種是構建一個友元的函式過載運算子<。

// 自定義優先順序規則
struct cmp
{
    bool operator()(int a, int b) //過載運算子(),引數是int後面只能宣告int型別優先佇列
    {
        return a < b; //最大值優先,如果a>b就是最小值優先
    }
};

priority_queue<int,vector<int>,cmp> que; //只能是構建int型別有限佇列

  首先結構體中過載運算子型別決定了你構建優先佇列模板類型別,如果是過載運算子()中引數型別是string,則構建優先佇列只能是string型別。此外比較的大小符號決定構建最大堆還是最小堆。
  另外一種方法如下:

//定義結構,使用成員函式運算子過載<自定義優先順序1 
struct node{  
    int x;  
    bool operator < (const node &a) const {  
        return x>a.x;  // 最小值優先,<則為最大值優先  
    }  
}; 

//定義結構,使用友元函式運算子過載<自定義優先順序2 
struct node{  
    int x;  
    friend bool operator < (const node &a, const node &b) const {  
        return a.x>b.x;   // 最小值優先,<則為最大值優先  
    }  
}; 

priority_queue<node> que; // 構建node型別的優先佇列物件
node num[]={14,10,56,7,83,22,36,91,3,47}; // 建立多個結構體的物件,並且初始化資料x
for(int& i : num)
{
    que.push(i); // 依次讀進node,根據引數x優先排列
}

  成員函式和友元函式兩種表達方式都行,使用該方法則優先佇列的型別需要就是該結構體,並且優先佇列的前後順序由結構體中比較符和對應引數決定。此處需要注意,過載>號會編譯出錯,因為標準庫預設使用元素型別的<操作符來確定它們之間的優先順序關係。而且自定義優先順序與過載操作運算子型別並無直接聯絡,我們按規則行事即可。

3 小結
  上面介紹了優先佇列資料結構特點以及STL中包含的介面。由於優先佇列是基於堆完成敬意,所以其存取的時間複雜度為O(logn),n為佇列中元素的個數。
  以上是個人學習記錄,由於能力和時間有限,如果有錯誤望讀者糾正,謝謝!
  轉載請註明出處:http://blog.csdn.net/FX677588/article/details/76359337


  參考文獻:
  http://blog.csdn.net/u011240016/article/details/59266961
  http://blog.csdn.net/ac_gibson/article/details/44200411
  http://www.cnblogs.com/heqinghui/archive/2013/07/30/3225407.html

相關文章