1.為何要實現優先級隊列這種數據結構
考慮實際中的問題,某個夜間門診只有一個接診醫生,在接診病人時的次序自然是按照隊列的FIFO(先進先出)的原則進行實行。但是這是有一個傷口出血的病人自然是要比平常感冒的病人要先被接診,而相對於一個心臟病突發的病人更是需要把他放置在更高的優先級。
在計算機系統中,運行程序也是遵循某個優先級關系。在一批待處理的進程中,系統總是將優先級更高的進程優先傳遞給CPU進行處理。
這些問題都需要運用到優先級隊列這種數據結構。
2.優先級隊列所要實現的基本接口
根據以上接口,可知要實現的三種方法要控制在一個良好的復雜度。
1.若采用向量vector來實現優先級隊列
其插入可以采用在尾部插入的vector::put_back(const T& e) - 復雜度為O(1)
其get_max需要遍歷整個向量才能得出最高優先級詞條 - 其復雜度為O(n)
而del_max則更是需要get_max后再進行刪除 - 其復雜也可達O(n)
2.若采用有序的向量sorted_vector來實現優先級隊列
固然其查找和刪除都可以在向量的尾部進行 - 其復雜度僅僅只有O(1)
但是其插入操作為了保證有序插入 - 需要進行二分查找(O(logn)) - 而插入操作涉及元素的移動也可達O(n)復雜度
3.若采用鏈表list進行實現優先級隊列
其插入操作固然可以達到O(1)
但是其get_max和del_max接口都需要對最高優先級的元素進行查找,其復雜度都可達O(n)
----------------即使采用有序化的鏈表
其get_max接口和del_max接口都可在把首節點設為最高優先級的情況下,復雜度為O(1)
但是其插入操作則不得在有序的查找下進行O(n) + O(1) - O(n)復雜度
4.繼而考慮采用平衡二叉搜索樹(BBST) - AVL樹、splay樹、red_black樹
可以相信其三種操作都是可以在O(logn)復雜度下實現
但是優先級隊列只需維護隊列中優先級最高的元素即可 - BBST則需要維護這種全序,未免顯得有些殺雞用牛刀
3.以上實現方法都不能在效率和成本上比較好的實現,考慮采用—以向量為形,完全二叉樹為神—來實現優先級隊列
3.1 完全二叉樹
從根節點到倒數第二層構成的是一個滿二叉樹(2^h-1 - 1個節點),最后一層可能不滿
也可看作平衡因子非負的AVL樹,平衡因子為0,左子樹為滿二叉樹時 // 平衡因子為1,右子樹為滿二叉樹時
3.2 向量之形
其存儲的形式是以一個動態分配的可擴充數組來實現的,將有20個節點的完全二叉樹存儲為向量其對應形式可視為:
3.3 完全二叉樹之神
根據宏定義可將向量中秩所對應的元素確定子父關系
#define Parent(i) ( ( ( i ) - 1 ) >> 1 ); //某個節點的父親的秩必為其( rank - 1 )/ 2
#define Lchild(i) ( 1 + ( ( i ) << 1 ) ); //某個節點存在左孩子其左孩子的秩為其 ( rank * 2 ) + 1 - 為奇數
#define Rchild(i) ( ( 1 + ( i ) ) << 1 ); //某個節點存在右孩子其右孩子的秩為其 ( rank + 1 ) * 2 - 為偶數
為了對優先級隊列中優先級高的詞條進行快速處理,規定完全二叉樹還要滿足堆序性
即其H( i ) <= H( Parent( i ) ) - 從而保證最大元始終在根節點處 - 即向量中秩為0所對應的詞條