數(shù)據(jù)結(jié)構(gòu) | 優(yōu)先隊(duì)列


_文{}_\equiv{}_{\nabla \Delta \nabla \Delta \nabla \Delta} {}^{皮}{}_{實(shí)}{}^{樂}{}_{觀} ^思_考 ^有{}_{人^{生}}{}^{才_{有}}{}_{精^{彩}}
^{\star\star}{}^\equiv{}^{水土七口刀} {}_{生}{}^{活}{}_{閱}{}^{讀} ^運(yùn)_動(dòng) _有{}^{興_{趣}}{}_{才^{有}}{}^{人_{生}}


優(yōu)先隊(duì)列

復(fù)雜度:

  • 使用堆時(shí),優(yōu)先隊(duì)列插入和刪除元素的復(fù)雜度都是O(log2n)
  • 另一種描述方法是采用有序線性表,當(dāng)元素按遞增次序排列,使用鏈表時(shí)則按遞減次序排列,這兩種描述方法的刪除時(shí)間均為( 1 ),插入操作所需時(shí)間為(n).

定義

  • 普通的隊(duì)列是一種先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu),元素在隊(duì)列尾追加,而從隊(duì)列頭刪除。在優(yōu)先隊(duì)列中,元素被賦予優(yōu)先級。當(dāng)訪問元素時(shí),具有最高優(yōu)先級的元素最先刪除。優(yōu)先隊(duì)列具有最高級先出 (first in, largest out)的行為特征。通常采用堆數(shù)據(jù)結(jié)構(gòu)來實(shí)現(xiàn)。

常見方法

  • Create ( ):創(chuàng)建一個(gè)空的優(yōu)先隊(duì)列
  • Size ( ):返回隊(duì)列中的元素?cái)?shù)目
  • Max ( ):返回具有最大優(yōu)先權(quán)的元素
  • Insert (x):將x插入隊(duì)列
  • DeleteMax (x):從隊(duì)列中刪除具有最大優(yōu)先權(quán)的元素,并將該元素返回至x

實(shí)現(xiàn)方法

  • is_empty:檢查隊(duì)列是否沒有元素。
  • insert_with_priority:使用關(guān)聯(lián)的優(yōu)先級向隊(duì)列添加元素。
  • pull_highest_priority_element / get_minimum_element(pop_element):從隊(duì)列中刪除具有最高優(yōu)先級的元素,并將其返回。
  • peek(find-max / find-min)返回最高優(yōu)先級元素但不修改隊(duì)列,此操作及其O(1)性能對于許多優(yōu)先級隊(duì)列應(yīng)用程序至關(guān)重要。
  • 更高級的實(shí)現(xiàn)可能支持更復(fù)雜的操作,例如檢查前幾個(gè)最高或最低優(yōu)先級元素,清除隊(duì)列,清除隊(duì)列子集,執(zhí)行批量插入,將兩個(gè)或多個(gè)隊(duì)列合并為一個(gè),增加優(yōu)先級任何元素等。

python實(shí)現(xiàn)

#CSDN-bebr實(shí)現(xiàn)
class Heap_Pri_Queue(object):
    def __init__(self, elems=[]):
        self._elems = list(elems)
        if self._elems:
            self.buildheap()

    def is_empty(self):
        return self._elems is []

    def peek(self):   #取出堆頂元素,但不刪除
        if self.is_empty():
            raise HeapPriQueueError("in pop")
        return self._elems[0]

    def enqueue(self, e):   #在末尾增加一個(gè)元素
        self._elems.append(e)  # 此時(shí),總的元素的長度增加了1位
         self.siftup(e, len(self._elems) - 1)

    def siftup(self, e, last):  # 向上篩選
         elems, i, j = self._elems, last, (last - 1) // 2  # j為last位置的父結(jié)點(diǎn)
         while i > 0 and e < elems[j]:  # 如果需要插入的元素小于當(dāng)前的父結(jié)點(diǎn)的值
             elems[i] = elems[j]  # 則將父結(jié)點(diǎn)的值下放到其子結(jié)點(diǎn)中去
             i, j = j, (j - 1) // 2  # 更新i為當(dāng)前父結(jié)點(diǎn)的位置,j更新為當(dāng)前父結(jié)點(diǎn)的父結(jié)點(diǎn)的位置
         elems[i] = e  # 如果i已經(jīng)更新為0了,直接將e的值賦給位置0.或者需要插入的元素
                         # 大于當(dāng)前父結(jié)點(diǎn)的值,則將其賦給當(dāng)前父結(jié)點(diǎn)的子結(jié)點(diǎn)

     def dequeue(self):
        if self.is_empty():
            raise HeapPriQueueError("in pop")
        elems = self._elems
        e0 = elems[0]  # 根結(jié)點(diǎn)元素
         e = elems.pop()  # 將最后一個(gè)元素彈出,作為一個(gè)新的元素經(jīng)過比較后找到插入的位置,以維持棧序
         if len(elems) > 0:
            self.siftdown(e, 0, len(elems))
        return e0

     def siftdown(self, e, begin, end):  # 向下篩選
         elems, i, j = self._elems, begin, begin * 2 + 1  # j為i的左子結(jié)點(diǎn)
         while j < end:
            if j + 1 < end and elems[j] > elems[j + 1]:  # 如果左子結(jié)點(diǎn)大于右子結(jié)點(diǎn)
                j += 1  # 則將j指向右子結(jié)點(diǎn),將j指向較小元素的位置
             if e < elems[j]:  # j已經(jīng)指向兩個(gè)子結(jié)點(diǎn)中較小的位置,
                break  # 如果插入元素e小于j位置的值,則為3者中最小的
             elems[i] = elems[j]  # 能執(zhí)行到這一步的話,說明j位置元素是三者中最小的,則將其上移到父結(jié)點(diǎn)位置
             i, j = j, j * 2 + 1  # 更新i為被上移為父結(jié)點(diǎn)的原來的j的位置,更新j為更新后i位置的左子結(jié)點(diǎn)
         elems[i] = e  # 如果e已經(jīng)是某個(gè)子樹3者中最小的元素,則將其賦給這個(gè)子樹的父結(jié)點(diǎn)
                        # 或者位置i已經(jīng)更新到葉結(jié)點(diǎn)位置,則將e賦給這個(gè)葉結(jié)點(diǎn)。

      def buildheap(self):
        end = len(self._elems)
        for i in range(end // 2 - 1, -1, -1):  # 初始位置設(shè)置為end//2 - 1。 如果end=len(elems)-1,則初始位置為(end+1)//2-1.
            #            print(self._elems[i])
            self.siftdown(self._elems[i], i, end)

if __name__ == "__main__":
    temp = Heap_Pri_Queue([5, 6, 8, 1, 2, 4, 9])
    print(temp._elems)
    temp.dequeue()
    print(temp._elems)
    temp.enqueue(0)
    print(temp._elems)
    print(temp.peek())

python headq實(shí)現(xiàn)簡單優(yōu)先隊(duì)列

#CSDN-bebr實(shí)現(xiàn)
from heapq import *
class Heap_Pri_Queue(object):
    def __init__(self, heap=[]):
        self.heap = heap
        heapify(self.heap)

    def enqueue(self, val):
        heappush(self.heap, val)

    def dequeue(self):
        return heappop(self.heap)

if __name__ == "__main__":
    lst = [5, 6, 8, 1]
    heap = Heap_Pri_Queue(lst)
    print(heap.dequeue()) #1
    heap.enqueue(3)
    print(heap.heap)  #[3, 5, 8, 6]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容