優先順序佇列的實現

2021-08-21 21:37:29 字數 4034 閱讀 5926

優先順序佇列:佇列裡面的所有元素都有相應的權值,元素的刪除順序由這些權值決定。

優先順序佇列的實現一般用堆來實現其效率比一般的實現要高。

要弄清楚堆我們得先弄清楚下面的定義:

一顆大根樹(小根樹):是這樣一棵樹,其中每個節點的值都大於(小於)或等於其子節點(如果有子節點的話)的值。

大根堆:乙個大根堆(小根堆)即是大根樹(小根樹)也是完全二叉樹。

由於大根堆為完全二叉樹,所以我們能用陣列來實現,並且不用擔心浪費記憶體資源。完全二叉樹的性質之前已經講過了。

template

void maxheap::push(const t& theelement)

//位元素theelement尋找插入位置

//currentnode從新葉子向上移動

int currentnode=++heapsize;//注意這是前++

while(currentnode!=1&&heap[currentnode/2]//這裡的currentnode/2為父節點位置,完全二叉樹的性質,前面有講

heap[currentnode]=theelement;

}

以上為大根堆的插入**,大根堆是乙個父節點元素大於子節點的元素的樹,如果要在其中插入乙個元素後任然保持大根堆的性質,那麼就得將該元素插入到適當的位子,首先將該元素插入到最後乙個葉節點的位子,然後將其與父節點進行比較,如果小於父節點則插入該位置,否則交換位置,該元素成為新的父節點,然後再次與其新的父節點進行比較,直到其插入當前位置,或者成為樹根為止。一次操作最多將插入的元素變為根為止,所以最多需要樹高height次操作。

template

void maxheap::pop()

heap[currentnode]=lastelement;

}

以上是刪除大根堆中最大元素並保持大根堆性質的程式,首先刪除根元素,儲存並刪除最後乙個葉元素,然後為則最後乙個葉元素尋找其新的插入位置,首先將其 插入根位置,然後與根的子節點進行比較看其適不適合該位置,如果適合則插入該位子,否則,將適合的子節點位置與該元素進行交換,然後再判斷該元素是否適合新的位置。這個操作同插入最多消耗height時間。

template

void maxheap::initialize(t *theheap,int thesize)

heap[child/2]=rootelement;

}}

以上為大根堆的初始化程式,負責將乙個非大根堆陣列初始化為大根堆陣列。

首先處理的是最後乙個擁有子節點的節點,將其與子節點進行比較,然後交換順序,然後在處理與該節點相鄰的上乙個節點,直到根節點。需要注意的是,當某個節點擁有至少二層子節點時,每當其與子節點進行交換後都要重新考慮其子節點與其孫節點的順序。以上程式是通過乙個while迴圈進行的處理。

以上的堆結構是一種隱式資料結構,用完全二叉樹表示的堆在陣列中是隱式存在的。雖然空間和時間效率都很高但是卻並不適合用於將不同長度的數進行合併操作,下面介紹左高樹的概念。

外部節點:在一棵樹的所有葉節上新增其左孩子和右孩子(如果本身具有左或右則僅新增缺失的那乙個)新增的這部分節點稱為外部節點,其他的節點稱為內部節點。

s(x):從節點x到其子樹的外部節點的所有路徑中最短的一條。

高度優先左高樹:當且僅當其任何乙個內部節點的左孩子的s值都大於或等於右孩子的s值。

高度優先左高樹的性質:

另x為hblt的乙個內部節點,則

(1)以x為根的子樹的節點數目至少為2^s(x)-1.

(2)若以x為根的子樹有m個節點,那麼s(x)最多有log2(m+1).

(3)從x到一外部節點的最右路徑的長度為s(x)。

衍生:若一顆hblt(高度優先左高樹)同時還是大根樹或者小根樹,那麼這棵樹被稱為最大hblt和最小hblt。

重量優先左高樹:當且僅當其任何乙個內部節點的左孩子的w值都大於或者等於其右孩子的w值。若是大根樹或者小根樹,則稱為最大wblt和最小wblt.

w(x):是以節點x為根的子樹的內部節點數目,若x是外部節點,則他的重量為0,若x是內部節點則它的重量為其孩子節點的重量之和加1。(加一是因為算其本身的重量,外部節點不算重量)

template

void maxhblt::initialize(t* theelement,int thesize)

//從佇列中重複取出兩棵樹合併

for(i=1;i<=thesize-1;i++)

if(thesize>0)

root=q.front();

treesize=thesize;

}

以上為最大左高樹的初始化函式,其輸入為要進行樹化的陣列和其尺寸大小。

注意:這裡的最大左高樹並不是完全二叉樹,所以並不滿足其性質。所以這裡我們並不能用陣列進行訪問,所以我們在這裡用二叉樹節點對資料進行儲存,二叉樹節點裡面有三個資料,elment是乙個pair物件,裡面包含乙個t型資料和乙個int型資料代表以該節點為根節點的樹s值,還有兩個指標分別指向左,右子節點。

我們首先將資料存到二叉樹節點裡面,然後將這些節點裝進乙個佇列,然後每次取其中的前兩個節點進行合併成左高樹,然後將該樹的根節點push到佇列尾部,迴圈thesize-1次後佇列中將只剩下乙個左高樹節點,就是我們形成的左高樹根節點。

template

void maxhblt

::meld(binarytreenode<

pair

>*

&x,binarytreenode<

pair

>*

&x)//如果x為空,則將y作為新的樹根

//x和y都不為空,必要時交換x和y

if(x->element.secondelement.second)

swap(x,y);//在合併的時候我們一般將根較大的值放在左邊,保證大根堆的性質。

meld(x->rightchild,y);

//如有需要,交換x的子樹,然後設定x->element.first的值

if(x->element==

null)

else

}

以上為將兩個左高樹進行合併的**,初始化函式裡面使用了這個**,這個**首先判斷兩個左高樹是否為空,然後對其進行簡單的交換處理,或者不處理,如果都不為空,則首先選取合成左高樹的根節點,選取標準是誰的根節點大,誰就是新左高樹的根節點,這是為了保證形成的左高樹滿足大根樹的特點(注意不是大根堆),然後將根節點的右子樹與另乙個子樹進行合併(這裡使用了迭代演算法,且對於這種迭代我們可以先僅僅考慮最外層)如果根節點的左子樹為空,則交換左右子樹的位置,否則比較左右子樹的s值,將s值較小的那個放到右子樹的位置。

void maxhblt::meld(maxhblt& thehblt)

以上**將兩個左高樹合併,其實就是呼叫了之前的melt然後對一些變數進行改變而已。

template

void maxhblt::push(const t& theelement)

插入只是將元素初始化為節點後在使用meld函式進行合併

template

void maxhblt::pop()

刪除只是將樹的根刪除然後再將樹的左子樹和右子樹合併成乙個新的樹。

以上我們實現了最大左高樹以及大根堆的演算法,大根堆由於滿足完全二叉樹的性質,我們能用陣列直接實現這樣既節省空間,同時又很效率,但是其不能實現兩個大根堆的合併操作,所以我們又實現了最大左高樹,其的核心就是樹的合併,無論資料的刪除,插入都是利用左高樹的合併來實現的。

template

void heapsort(t a,int n)

//從堆的析構函式中儲存陣列a

heap.deactivatearray();

}

最後用了乙個deactivatearray();用來儲存陣列a,因為在heap初始化函式中將a初始化為heap所以當該函式執行完後heap即a會被刪除掉。

優先順序佇列的實現

首先優先順序佇列的概念脫胎於佇列,佇列有先進先出的概念,優先順序佇列則根據優先順序的次序從佇列中彈出元素。優先佇列的底層實現是堆,因為堆的插入時間複雜度為o logn 所以優先順序佇列的入隊操作的時間複雜度也是o logn 堆可以由動態陣列實現的。優先順序佇列中比較重要的兩個操作是插入和刪除。如下簡...

優先順序佇列(堆實現)

一 優先順序佇列定義 二 方法實現 獲得最大元素方法 去掉最大元素方法 修改優先順序方法 新增節點 三 實現 用堆實現乙個優先順序佇列 主要是新增 修改 刪除節點 節點具有唯一性 author hhf 2014年11月28日 public class priorityqueue 返回優先佇列中優先順...

Redis實現優先順序佇列

title redis實現優先順序佇列 tags 基於目前系統中存在部分非同步需求,比如匯入或者新開客戶車輛匹配vin碼等 redis中使用列表作為佇列 最關鍵提供了阻塞版本的指令blpop 新建三個佇列對應高中低優先順序 比如f6car high f6car mid f6 car low 再新建d...