欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python中的優(yōu)先隊列(priority?queue)和堆(heap)

 更新時間:2022年09月28日 09:39:52   作者:笨笨的蛋  
這篇文章主要介紹了Python中的優(yōu)先隊列(priority?queue)和堆(heap),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

隊列和優(yōu)先隊列(Priority Queue)

隊列是一種可以完成插入和刪除的數(shù)據(jù)結(jié)構(gòu)。普通隊列是先進先出(FIFO), 即先插入的先被刪除。

然而在某些時候我們需要按照任務的優(yōu)先級順序來決定出隊列的順序,這個時候就需要用到優(yōu)先級隊列了。優(yōu)先隊列是一種可以完成插入和刪除最小元素的數(shù)據(jù)結(jié)構(gòu)

python中有現(xiàn)成的優(yōu)先隊列類可以調(diào)用。

代碼示例

from queue import Queue   # 隊列,F(xiàn)IFO
from queue import PriorityQueue  #優(yōu)先級隊列,優(yōu)先級高的先輸出
###############隊列(Queue)的使用,/python中也可是用列表(list)來實現(xiàn)隊列###############
q = Queue(maxsize) 	#構(gòu)建一個隊列對象,maxsize初始化默認為零,此時隊列無窮大
q.empty()		#判斷隊列是否為空(取數(shù)據(jù)之前要判斷一下)
q.full()		#判斷隊列是否滿了
q.put()			#向隊列存放數(shù)據(jù)
q.get()			#從隊列取數(shù)據(jù)
q.qsize()		#獲取隊列大小,可用于判斷是否滿/空
###用法示例:
>>> q = Queue(3)
>>> for i in range(3):
>>>	q.put(i)
>>> q.full()
True
>>> while not q.empty():
>>> 	print(q.get())
0
1
2
###############優(yōu)先隊列(PriorityQueue)的使用###############
"""
隊列的變體,按優(yōu)先級順序(最低優(yōu)先)檢索打開的條目。
條目通常是以下格式的元組:
插入格式:q.put((priority number, data))
特點:priority number 越小,優(yōu)先級越高
其他的操作和隊列相同
"""
>>> q = PriorityQueue()
>>> q.put((2, "Lisa"))
>>> q.put((1, "Lucy"))
>>> q.put((0, "Tom"))
>>> i = 0
>>> while i < q.qsize():
>>> 	print(q.get())
(0,"Tom")
(1,"Lucy")
(2,"Lisa")
#可見并沒有按照輸入的順序輸出的,而是按照優(yōu)先級順序輸出的
#優(yōu)先獨隊列的實質(zhì)是

堆(heap)

看完上面的示例我們也許會有疑惑,優(yōu)先隊列是如何來實現(xiàn)的了?

----------優(yōu)先隊列的實質(zhì)是每次插入時按照一定的規(guī)則插入,刪除時直接找到最小的那個元素彈出即可。插入和彈出最壞情況下的時間復雜度都是O(LogN)

下面我們就來介紹實現(xiàn)優(yōu)先隊列的一種數(shù)據(jù)結(jié)構(gòu)——堆(heap)。

簡介

堆的實質(zhì)是一個完全二叉樹(除最底層外,其余層都是滿二叉樹,且最底層的節(jié)點從左往右順序排列)。 堆主要分為大頂堆小頂堆兩種

1.大頂堆:每個分支的根節(jié)點都大于等于其子節(jié)點。(ki >= k2i)and (ki >= k2i+1)

2.小頂堆:每個分支的根節(jié)點都小于等于其子節(jié)點。(ki <= k2i)and (ki <= k2i+1)

所以堆中的第i個元素的父親是floor(i/2)(向下取整), 第i個元素的左右孩子分別是2i2i+1

堆的根節(jié)點要從1開始計算,不能從0開始計算。(假如從零開始i=2時其父親節(jié)點為floor(2/2)=1, 顯然是錯誤的)

初始化構(gòu)建堆

將一個有k個元素的數(shù)組構(gòu)成一個大頂堆或者小頂堆。時間復雜度O(n)$

核心思路:從下往上,從右往左,且每次都從第floor(k/2)個元素開始進行調(diào)整依次遞減直到根節(jié)點

1.從floor(k/2)個元素開始進行調(diào)整,調(diào)整完畢,則i--;
    #調(diào)整節(jié)點,每次只調(diào)整該根節(jié)點以下的子樹
    while i <= k
        1.1 找出左右孩子中最大的那個
        1.2 該節(jié)點和較大的那個子節(jié)點比較,
                如果父節(jié)點較大,break
                如果子節(jié)點較大,記錄子節(jié)點的索引,把子節(jié)點的值給父節(jié)點
        1.3 將上面較大的那個字節(jié)點作為新的父節(jié)點開始一輪循環(huán)
    循環(huán)結(jié)束后,將父節(jié)點的值放到他應該去的子節(jié)點的位置上

例如有如下數(shù)組

把其轉(zhuǎn)化成完全二叉樹的形式就是

該數(shù)組一共有9個元素,所以從i = floor(9/2)=4 個元素開始,第4個元素是6, 其右孩子9最大,將6和9交換完成一次調(diào)整.

i=3,第三個元素是8,8比左右孩子都大,不用交換

i=2,此時的子樹是:第二個元素是2,而此時以2為根節(jié)點的子樹如下左圖。交換過程為: a).2與9交換,此時的根節(jié)點就到了2現(xiàn)在的位置 (下中圖)。b).2與7交換。 c)交換完成,本次調(diào)整完畢

i=1,此時的父節(jié)點就是整棵樹的根節(jié)點,而此時整棵樹的狀態(tài)是下圖所示

a). 5和9交換,此時5到了9的位置(下左圖) b). 5和7交換,5到了7的位置(下中圖) c).最后5和6交換,完成調(diào)整。


經(jīng)過以上的floor(k/2)次的調(diào)整之后,由一個無序數(shù)組初始化構(gòu)建大頂堆就完成了

堆的插入(節(jié)點上?。?/h3>

時間復雜度O(log(k+1))

我們之前由一個無序數(shù)組構(gòu)造了一個大頂堆,那么現(xiàn)在我們要插入一個新的元素該怎么辦了,如下圖,如果直接在最末尾插入,則破壞了堆的結(jié)構(gòu),所以還需要按進行調(diào)整。

調(diào)整規(guī)則:由于其他子樹的順序都已經(jīng)調(diào)整完畢,所以只需要調(diào)整根節(jié)點到插入節(jié)點所在的子路即可。

如下圖所示。(a)將11與4調(diào)整,(b)將11與7調(diào)整,©再將11與9調(diào)整。最后得到調(diào)整完畢的結(jié)果。

堆的刪除(節(jié)點下浮)

時間復雜度O(log(k-1))

由于堆是隊列結(jié)構(gòu),只能從堆中刪除堆頂?shù)脑?。移除堆頂元素之后,之前的完全二叉樹就變成來兩個子樹,次數(shù)最方便的做法就是用堆的最后一個節(jié)點來填補取走的堆頂元素,并將堆的實際元素個數(shù)減1。但是這樣做以后又不滿足堆的定義了,還是要進行調(diào)整。

調(diào)整規(guī)則:從根節(jié)點開始逐層向下調(diào)整即可。


(a).將5與8調(diào)換,(b)調(diào)整完成,刪除完畢

堆的應用

之間講過的利用堆(python中是小頂堆)來實現(xiàn)優(yōu)先隊列

利用堆求Top k:

假如現(xiàn)在有1億個數(shù)據(jù)要求其中前十個最小的元素。最笨方法就是對所有數(shù)據(jù)進行排序,然后找出前十個最小的,即使使用快排,也需要O(NlogN)的時間復雜度。假如利用大頂堆的話–先利用前10個數(shù)據(jù)構(gòu)造一個大頂堆,然后順序遍歷數(shù)組與大頂堆頂點比較,假如比大于等于頂點直接刪除,否則就刪除堆頂點并插入新的節(jié)點,最后堆里面的元素就是最小的前是個元素。這樣求出來的時間復雜度為Nlog(k)

假如要求前十個最大的元素,那就要使用小頂堆來實現(xiàn)

最后放上python手動實現(xiàn)將數(shù)組轉(zhuǎn)化為大頂堆和小頂堆的代碼

class Heap:
	def __init__(self, _list):
		self._list = _list
		self.k = len(_list)
		
	def _bigHeapAdjuest(self, j):
		temp = self._list[j] #存放當前雙親節(jié)點的值,j代表當前節(jié)點的位置
		i = 2*j  			 #j的左孩子
		while i <= self.k:
			if i < self.k and self._list[i] < self._list[i+1]:  #i==n時由于只有一個子節(jié)點,所以沒有比較的必要
				i += 1
			#與雙親比較,如果雙親大則跳過
			#如果雙親小,就把大的給雙親
			if temp >= self._list[i]:
				break                 			#沒有必要修整
			self._list[j] = self._list[i]       #元素交換
			j = i                               #j記錄著temp應該去的位置,由于這個位置的節(jié)點發(fā)生了變動,所以需要再次調(diào)整
			i *= 2             					#接著找該節(jié)點的左孩子
		self._list[j] = temp	
	
    def _smallheapAdjuest(self, j):
        temp = self._list[i] #父節(jié)點
        i = 2*j  #左孩子
        while i <= self.k:
            if i < self.k and self._list[i] > self._list[i+1]:    #找最小的那個孩子
                i += 1
            #構(gòu)建小頂堆,小于父節(jié)點的都要上浮
            if self._list[i] >= temp:
                break
            self._list[j] = self._list[i]  #子節(jié)點交給父節(jié)點
            j= i    #記錄父節(jié)點應該去的索引位置
            i *= 2
        self._list[j] = temp
	
	def heapSort(self):
		self._list.insert(0, -1) 
		s = self.length // 2  
		#構(gòu)建大頂堆
		for j in range(s, 0, -1):
			self._bigHeapAdjuest(j) 
		#構(gòu)建小頂堆
			for j in range(s, 0, -1):
			self._SmallheapAdjuest(j) 
		

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • python爬蟲指南之xpath實例解析(附實戰(zhàn))

    python爬蟲指南之xpath實例解析(附實戰(zhàn))

    在進行網(wǎng)頁抓取的時候,分析定位html節(jié)點是獲取抓取信息的關(guān)鍵,目前我用的是lxml模塊,下面這篇文章主要給大家介紹了關(guān)于python爬蟲指南之xpath實例解析的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • python中的逆序遍歷實例

    python中的逆序遍歷實例

    今天小編就為大家分享一篇python中的逆序遍歷實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • Python實現(xiàn)簡單的猜單詞

    Python實現(xiàn)簡單的猜單詞

    這篇文章主要為大家詳細介紹了Python實現(xiàn)簡單的猜單詞,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • Appium自動化測試實現(xiàn)九宮格解鎖

    Appium自動化測試實現(xiàn)九宮格解鎖

    本文主要介紹了Appium自動化測試實現(xiàn)九宮格解鎖,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • python 讀取二進制 顯示圖片案例

    python 讀取二進制 顯示圖片案例

    這篇文章主要介紹了python 讀取二進制 顯示圖片案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-04-04
  • typing.Dict和Dict的區(qū)別及它們在Python中的用途小結(jié)

    typing.Dict和Dict的區(qū)別及它們在Python中的用途小結(jié)

    當在 Python 函數(shù)中聲明一個 dictionary 作為參數(shù)時,我們一般會把 key 和 value 的數(shù)據(jù)類型聲明為全局變量,而不是局部變量。,這篇文章主要介紹了typing.Dict和Dict的區(qū)別及它們在Python中的用途小結(jié),需要的朋友可以參考下
    2023-06-06
  • python使用正則表達式(Regular Expression)方法超詳細

    python使用正則表達式(Regular Expression)方法超詳細

    這篇文章主要介紹了python使用正則表達式(Regular Expression)方法超詳細,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • opencv實現(xiàn)圖像校正

    opencv實現(xiàn)圖像校正

    這篇文章主要為大家詳細介紹了opencv實現(xiàn)圖像校正,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • Python面向?qū)ο蠡A(chǔ)入門之設(shè)置對象屬性

    Python面向?qū)ο蠡A(chǔ)入門之設(shè)置對象屬性

    這篇文章主要給大家介紹了關(guān)于Python面向?qū)ο蠡A(chǔ)入門之設(shè)置對象屬性的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-12-12
  • 使用Python?Cupy模塊加速大規(guī)模數(shù)值計算實例深究

    使用Python?Cupy模塊加速大規(guī)模數(shù)值計算實例深究

    Cupy是一個基于NumPy的庫,專門設(shè)計用于在GPU上進行高性能計算,它提供了與NumPy相似的API,因此用戶可以很容易地將現(xiàn)有的NumPy代碼遷移到Cupy上,從而充分利用GPU的并行計算能力
    2023-12-12

最新評論