優先佇列按照佇列的方式正常入隊,但按照優先順序出隊。有兩種實現方式:堆(二插堆、多項式堆等等)和二叉搜尋樹。這裡重點講解二叉堆,關於二叉搜尋樹的內容見這篇文章。
堆是一種特殊的完全二叉樹。大根堆:完全二叉樹的任一節點都比其孩子節點大。小根堆:完全二叉樹的任一節點都比其孩子節點小。堆的向下調整:假設根節點的左右子樹都是堆,但根節點不滿足堆的性質,可以通過一次向下調整將其變成乙個堆。因為二叉堆是完全二叉樹,一般可以用陣列來表示,這樣不會浪費空間。大根堆和小根堆的舉例如下所示:
用陣列表示的二叉堆,有如下性質:
二叉堆的時間複雜度:
python實現:heapq
import heapq
# 將array列表轉為堆的結構
heap.heapify(array)
# 彈出堆中的最小值
# 往堆中插入新值a
heapq.heapreplace(array, a)
# 獲得array中前k個最大的值
heapq.nlargest(k, array)
# 獲得array中前k個最小的值
heapq.nsmallest(k, array)
此題為leetcode第23題
合併 k 個排序鍊錶,返回合併後的排序鍊錶。
import heapq
class
solution
:def
mergeklists
(self, lists: list[listnode])-
> listnode:
head = p = listnode(0)
# 建立堆
a =for i in
range
(len
(lists)):
if lists[i]
:# 元組在heapq裡比較的機制是從元組首位0開始,即遇到相同,就比較元組下一位
# 比如(1,2), (1,3),前者比後者小。
# 這題剛好node值有重複的,同時listnode無法被比較,所以會報錯
(lists[i]
.val, i)
) lists[i]
= lists[i]
.next
while a:
p.next
= listnode(val)
p = p.
next
if lists[idx]
:(lists[idx]
.val, idx)
) lists[idx]
= lists[idx]
.next
return head.
next
此題為leetcode第215題import heapq
class
solution
:def
findkthlargest
(self, nums: list[
int]
, k:
int)
->
int:
n =len(nums)
# 建立含k個元素的小根堆
temp =
for i in
range
(k):
)# 遍歷nums裡剩下的元素,比堆頂大的話更新小根堆
for i in
range
(k, n)
: top = temp[0]
if nums[i]
> top:
heapq.heapreplace(temp, nums[i]
)# 最後結果為堆頂元素
return temp[
0]
此題為leetcode第347題
思路:首先利用雜湊表統計nums裡的元素num出現的頻率。然後建立大小為k的小根堆heap,heap列表中的元素為元組,包含num及其頻率。堆滿後,若新加的數大於堆頂元素的頻率,則heapreplace堆頂元素。最後heap裡包含的就是前k個高頻元素。
import heapq
class
solution
:def
topkfrequent
(self, nums: list[
int]
, k:
int)
-> list[
int]
:# 統計元素出現頻率
hash
=for num in nums:
hash
[num]
=hash
.get(num,0)
+1heap =
for num, freq in
hash
.items():
iflen
(heap)
== k:
if heap[0]
[0]< freq:
heapq.heapreplace(heap,
(freq, num)
)else
:(freq, num)
) res =
while heap:[1
])return res
此題為leetcode第703題
設計乙個找到資料流中第k大元素的類(class)。注意是排序後的第k大元素,不是第k個不同的元素。你的 kthlargest 類需要乙個同時接收整數 k 和整數陣列nums 的構造器,它包含資料流中的初始元素。每次呼叫 kthlargest.add,返回當前資料流中第k大的元素。
import heapq
class
kthlargest
:def
__init__
(self, k:
int, nums: list[
int]):
self.nums = nums
self.k = k
heapq.heapify(self.nums)
# 留下k個元素,即前k大的
while
len(self.nums)
> k:
defadd
(self, val:
int)
->
int:
iflen
(self.nums)
< self.k:
elif self.nums[0]
< val:
# 新的值更大則更新
heapq.heapreplace(self.nums, val)
return self.nums[
0]
資料結構與演算法 優先佇列
英雄聯盟遊戲裡面防禦塔都有乙個自動攻擊功能,小兵排著隊進入防禦塔的攻擊範圍,防禦塔先攻擊靠得最近的小兵,這時候大炮車的優先順序更高 因為系統判定大炮車對於防禦塔的威脅更大 所以防禦塔會優先攻擊大炮車。而當大炮車陣亡,剩下的全部都是普通小兵,這時候離得近的優先順序越高,防禦塔優先攻擊距離更近的小兵。優...
資料結構與演算法 複習 堆 優先佇列
插入演算法 該演算法從優先佇列的序列去觀察,比較直觀。首先把要插入的元素放在隊尾temp裡。從佇列的最後乙個元素,逐次向前尋找父節點,空位隨之移動,當到達隊頭,或者當前元素小於temp元素時,即可插入。刪除演算法 刪除最小元素,也就是最頭的元素。當我們利用 當前元素數量 1 這樣的操作刪除元素後,最...
資料結構與演算法 堆 的優先佇列
作業系統核心作業排程是優先佇列的乙個應用例項,它根據優先順序的高低而不是先到先服務的方 式來進行排程 如果最小鍵值元素擁有最高的優先順序,那麼這種優先佇列叫作公升序優先佇列 即總是先刪除最小 的元素 類似的,如果最大鍵值元素擁有最高的優先順序,那麼這種優先佇列叫作降序優先佇列 即總是先刪除最大的元素...