Python implements default or custom priority queue

Reference article

https://blog.csdn.net/weixin_41102519/article/details/121617236
https://pythonjishu.com/python-priority/
https://blog.csdn.net/junxinwoxin/article/details/75545610

heapq module

heapq is an implementation of binary heap, which internally uses the built-in list object (2) The pop method returns the smallest element, not the largest. (1) Zero-based indexing is used; in the queue. minimum element is the , defaults to a minimum heapa[k] <= a[2k+1] and a[k] <= a[2k+2], therefore, this method, for each element in the list, it satisfiesa[0]


Insert image description here


Minimum priority queue implementation

Since the default heapq module is the minimum heap structure, you can directly use the function operations to implement the minimum priority queue function. Note that heapq is a function, and the list to be modified is one of the inputs.

Convert list to min-heap

import heapq
arr = [3, 1, 5, 7, 2, 6, 9, 3, 5]

# 将给定的列表转化为最小堆,线性时间
heapq.heapify(arr)
print("最小堆数组:{0}".format(arr))
最小堆数组:[1, 2, 5, 3, 3, 6, 9, 7, 5]

insert element

heapq.heappush(arr, 2)
print("插入新元素后:{0}".format(arr))
插入新元素后:[1, 2, 5, 3, 2, 6, 9, 7, 5, 3]

pop up minimal element

# 弹出最小元素
item0 = heapq.heappop(arr)
print("弹出元素后:{0}".format(arr))
弹出元素后:[2, 2, 5, 3, 3, 6, 9, 7, 5]

Returns the smallest element

# 返回最小元素
item1 = arr[0]
print("获取最小元素的值:{0}".format(item1))
获取最小元素的值:2

Insert new element after popup

# 弹出最小元素,并插入一个新的元素,相当于先 heappop, 再 heappush
item2 = heapq.heapreplace(arr, -2)
print("弹出的元素为:{0}".format(item2))
弹出的元素为:2
print("现在的堆结构为:{0}".format(arr))
现在的堆结构为:[-2, 2, 5, 3, 3, 6, 9, 7, 5]

Maximum priority queue implementation

Similar to the minimum priority queue, however,it does not have a built-in function for newly inserted elements:heapq.heappushYes No.

arr = [3,1,5,7,2,6,9,3,5]
heapq._heapify_max(arr)
print("最大堆数组:{0}".format(arr))
最大堆数组:[9, 7, 6, 5, 2, 3, 5, 3, 1]
# 弹出最大元素
item0 = heapq._heappop_max(arr)
print("弹出的元素为:{0}".format(item0))
print("弹出的元素后:{0}".format(arr))
# 弹出的元素为:9
# 弹出的元素后:[7, 5, 6, 3, 2, 3, 5, 1]
# 弹出最大元素,并插入一个新的元素
item1 = heapq._heapreplace_max(arr, 9)
print("弹出的元素为:{0}".format(item1))
print("现在的堆结构为:{0}".format(arr))
# 弹出的元素为:7
# 现在的堆结构为:[9, 5, 6, 3, 2, 3, 5, 1]

So, if it is a simplenumeric queue, you must use theinsertion operation If , you can use the minimum priority queue instead, but is inserted in front of the value. Just add a negative sign.


Complex structure of priority queue

tuple type

q = []
heapq.heappush(q, (2, 'code'))
heapq.heappush(q, (1, 'eat'))
heapq.heappush(q, (3, 'sleep'))
heapq.heappush(q, (2, 'play'))
heapq.heappush(q, (3, "debug"))
q1 = [x for x in q]
while q:
    next_item = heapq.heappop(q)
    print(next_item)

(1, 'eat')
(2, 'code')
(2, 'play')
(3, 'debug')
(3, 'sleep')
# 返回最小的 n 个元素,相当于 sorted(iterable, key=key)[:n]
n_smallest = heapq.nsmallest(3, q1, key=lambda x: x[0])
print("最小的3个元素:{0}".format(n_smallest))
最小的3个元素:[(1, 'eat'), (2, 'code'), (2, 'play')]
# 返回最大的 n 个元素,相当于 sorted(iterable, key=key, reverse=True)[:n]
n_largest = heapq.nlargest(3, q1, key=lambda x: x[1])
print("最大的3个元素:{0}".format(n_largest))
最大的3个元素:[(3, 'sleep'), (2, 'play'), (1, 'eat')]

Linked list pointers and other types

If it is a linked list pointer and you need to compare the size by the value of the element pointed to by the pointer, you can use the following method.
Method 1:
Directly The disadvantage of this method is that it completely abandons pointers. If you want to use pointers to obtain other properties of elements, it will not work. For example, employees are sorted by salary and want to get their names. Of course, you can also use They are all added to the tuple, but it is very troublesome.

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

heap = []
arr = [ListNode(1), ListNode(5), ListNode(2), ListNode(4),ListNode(8), ListNode(5), ListNode(3), ListNode(4)]
for i in range(len(arr)):
    if arr[i] :
        #先按链表的值排序,如果值相同就按插入先后顺序排序
        heapq.heappush(heap, (arr[i].val, i))
print(heap)
[(1, 0), (4, 3), (2, 2), (4, 7), (8, 4), (5, 5), (3, 6), (5, 1)]

Method 2: Directly activate the class definition

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
    # __repr__和__lt__都要修改
    def __repr__(self):
        return str(self.val)
    def __lt__(self, other):
        return self.val < other.val
       
heap = []
arr = [ListNode(1), ListNode(5), ListNode(2), ListNode(4),ListNode(8), ListNode(5), ListNode(3), ListNode(4)]
for ln in arr:
    heapq.heappush(heap,ln)
print(heap)
[1, 4, 2, 4, 8, 5, 3, 5]

PriorityQueue module

The priority queue defined by this module uses the heapq module internally, so its time complexity is the same as that of heapq.

When all elements of an object are comparable, by default they are sorted according to the first element of the object in the queue. The smaller the object, the higher the priority and the higher it is ranked. When the first elements are the same, the sizes of subsequent elements are compared in order to sort.

Since PriorityQueue inherits from the Queue class, the usage of many functions can be directly referred to the functions in the Queue class.

The time complexity of Python priority queue insertion and deletion is logn, and the get() method returns the smallest element by default.

grammar:

q = queue.PriorityQueue()
q.put([priority, value])
q.put([priority1, value1])

Example 1:

import queue
q = queue.PriorityQueue()
q.put(1) #添加元素
q.get()  #删除元素
1

Example:2:

import queue
q = queue.PriorityQueue()
q.put([1, 'HaiCoder'])   # 1是级别最高的
q.put([40, 1024])
q.put([3, 'Python'])
q.put([5, True])
if __name__ == '__main__':
    while not q.empty():  # 不为空时候执行
        print("get data =", q.get())

get data = [1, 'HaiCoder']
get data = [3, 'Python']
get data = [5, True]
get data = [40, 1024]

Example 3:

from queue import PriorityQueue as PQ
pq = PQ()
pq.put((1, 'a'))
pq.put((2, 'c'))
pq.put((2, 'b'))
pq.put((2, 'b'))
print(pq.queue)
[(1, 'a'), (2, 'b'), (2, 'b'), (2, 'c')]
item0 = pq.get() 
print(item0)
(1, 'a')
print(pq.queue)
[(2, 'b'), (2, 'b'), (2, 'c')]

print(pq.qsize())
优先队列的尺寸:  3

while not pq.empty():
    print(pq.get())
(2, 'b')
(2, 'b')
(2, 'c')

print(pq.queue)
[]

Implement your own priority queue

In the process of object-oriented programming, we usually combine some individual functions or variables into an object, and then prioritize them. For example, we now have many types of cars. The cars have names and prices, as well as some operating methods. When we prioritize car objects according to price, because the custom objects are incomparable, an error will be reported when prioritizing. So for those custom objects, we need to override the priority queue method to implement it.

Since PriorityQueue is also implemented based on heapq, our custom priority queue can be implemented directly based on the heapq module.

Customize the My_PriorityQueue class based on the heapq module

This method is more cumbersome and not as simple as custom comparison operators.

Example 1:

import heapq

class My_PriorityQueue(object):
    def __init__(self):
        self._queue = []
        self._index = 0

    def push(self, item, priority):
        """
        队列由 (priority, index, item) 形式组成
        priority 增加 "-" 号是因为 heappush 默认是最小堆
        index 是为了当两个对象的优先级一致时,按照插入顺序排列
        """
        heapq.heappush(self._queue, (-priority, self._index, item))
        self._index += 1

    def pop(self):
        """
        弹出优先级最高的对象
        """
        return heapq.heappop(self._queue)[-1]

    def qsize(self):
        return len(self._queue)

    def empty(self):
        return True if not self._queue else False

class Car(object):
    def __init__(self, name, value):
        self.name = name
        self.value = value

    def __repr__(self):
        return "{0} -- {1}".format(self.name, self.value)

if __name__ == "__main__":
    car1 = Car("BMW", 45)
    car2 = Car("Maybach", 145)
    car3 = Car("Bugatti", 85)
    car4 = Car("Cadillac", 78)
    car5 = Car("Maserati", 85)
    pq = My_PriorityQueue()
    pq.push(car1, car1.value)
    pq.push(car2, car2.value)
    pq.push(car3, car3.value)
    pq.push(car4, car4.value)
    pq.push(car5, car5.value)
    print("队列大小:{0}".format(pq.qsize()))
    # 弹出元素
    while not pq.empty():
        print(pq.pop())
        
队列大小:5
Maybach -- 145
Bugatti -- 85
Maserati -- 85
Cadillac -- 78
BMW -- 45

Example 2:

from heapq import heappush, heappop
class PriorityQueue:
    def __init__(self):
        self._queue = []

    def put(self, item, priority):
        heappush(self._queue, (priority, item))

    def get(self):
        return heappop(self._queue)

q = PriorityQueue()
q.put('world', 2)
q.put('hello', 1)
>>>q.get()[1]
hello
>>>q.get()[1]
world

Modify the element that makes get() return the largest value:

from heapq import heappush, heappop
class PriorityQueue:
    def __init__(self):
        self._queue = []

    def put(self, item, priority):
        heappush(self._queue, (-priority, item))

    def get(self):
        return heappop(self._queue)

q = PriorityQueue()
q.put('world', 2)
q.put('hello', 1)
>>>q.get()[1]
world
>>>q.get()[1]
hello

Custom comparison operator

has oneNumber类, which has two attributes: val1 and val2
. The size of the objects needs to be compared according to the following rules :
(1) First, compare according to the value of val2. The larger the value of val2, the larger the object size; < /span>, the larger the object size will be. are the same, the larger the value of
(2) When the values ​​of val2val1

from queue import Queue, PriorityQueue

class Number:
    def __init__(self, val1, val2):
        self.val1 = val1
        self.val2 = val2
    
    def __eq__(self, other):
        if self is other:
            return True
        if hasattr(other, 'val1') and hasattr(other, 'val2'):
            return self.val1 == other.val1 and self.val2 == other.val2
    
    def __gt__(self, other):
        if self.val2 == other.val2:
            return self.val1 > other.val1
        else:
            return self.val2 > other.val2
    
    def __ge__(self, other):
        if self.val2 == other.val2:
            return self.val1 >= other.val1
        else:
            return self.val2 > other.val2

Minimum priority queue (default)

(1) Use the PriorityQueue class:

q = PriorityQueue()
q.put(Number(10, 99))
q.put(Number(6, 99))
q.put(Number(3, 100))
q.put(Number(6, 100))

while not q.empty():
    cur = q.get()
    print(cur.val1, cur.val2)

# 输出
6 99
10 99
3 100
6 100

(2) Use the heapq module:

l = []
l.append(Number(10, 99))
l.append(Number(6, 99))
l.append(Number(3, 100))
l.append(Number(6, 100))
heapq.heapify(l)

while l:
    item = heapq.heappop(l)
    print(item.val1, item.val2)

# 输出
6 99
10 99
3 100
6 100

maximum priority queue

Here we need to negate the comparison operator when defining it, that is, modify __gt__ and __ge__:

    def __gt__(self, other): # 大于
        if self.val2 == other.val2:
            # 这里本应该是self.val1 > other.val1,但要取反
            return self.val1 < other.val1 # 取反
        else:
        	# 这里本应该是self.val2 > other.val2,但要取反
            return self.val2 < other.val2 # 取反
    
    def __ge__(self, other): # 大于等于
        if self.val2 == other.val2:
            # 与上面的一样,取反
            return self.val1 <= other.val1 # 取反
        else:
        	# 与上面的一样,取反
            return self.val2 < other.val2 # 取反

(1) Use the PriorityQueue class:

q = PriorityQueue()
q.put(Number(10, 99))
q.put(Number(6, 99))
q.put(Number(3, 100))
q.put(Number(6, 100))

while not q.empty():
    cur = q.get()
    print(cur.val1, cur.val2)

# 输出
6 100
3 100
10 99
6 99

(2) Use the heapq module:

l = []
l.append(Number(10, 99))
l.append(Number(6, 99))
l.append(Number(3, 100))
l.append(Number(6, 100))
heapq.heapify(l)

while l:
    item = heapq.heappop(l)
    print(item.val1, item.val2)

# 输出
6 100
3 100
10 99
6 99

Guess you like

Origin blog.csdn.net/weixin_44123362/article/details/130002240