<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
和棧一樣,佇列是一種特殊的線性表,特殊之處在於它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作。佇列是一種操作受限制的線性表,進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。佇列中沒有元素時,稱為空佇列。
基本FIFO佇列 先進先出 FIFO即First in First Out,先進先出。
呼叫queue.Queue
from queue import Queue fifo_queue = Queue() fifo_queue.put(1) # 隊尾插入新元素 fifo_queue.put(2) fifo_queue.put(3) print(fifo_queue.queue) print(fifo_queue.get()) # 隊頭取出元素 print(fifo_queue.queue)
連結串列實現
class LNode(object): def __init__(self, item, next_=None): self.item = item self.next = next_ class FIFOQueue(object): def __init__(self): """初始化""" self.head = None self.rear = None def is_empty(self): """判斷是否為空""" return self.head is None def size(self): """獲取佇列長度""" cur = self.head count = 0 while True: count += 1 if cur == self.rear: break cur = cur.next return count def travel(self): """遍歷佇列""" if self.is_empty(): print('queue is empty') return else: cur = self.head while True: print(cur.item, end='') if cur.next: print(',', end='') if cur == self.rear: break cur = cur.next print('') def push(self, val): """隊尾插入新元素""" p = LNode(val) if self.is_empty(): self.head = p self.rear = p else: self.rear.next = p self.rear = self.rear.next def get(self): """獲取隊頭元素""" if self.is_empty(): print('queue is empty') return else: e = self.head.item self.head = self.head.next return e if __name__ == '__main__': FIFOQueue = FIFOQueue() FIFOQueue.push(1) FIFOQueue.push(2) FIFOQueue.push(3) FIFOQueue.push(4) FIFOQueue.travel() # 1,2,3,4 print(FIFOQueue.get()) # 1 print(FIFOQueue.get()) # 2 FIFOQueue.travel() # 3,4
list實現
# list 實現 class FIFOQueue(object): def __init__(self): self.queue = list() def size(self): return len(self.queue) def travel(self): print(self.queue) def push(self, val): self.queue.append(val) def get(self): return self.queue.pop(0) if __name__ == '__main__': FIFOQueue = FIFOQueue() FIFOQueue.push(1) FIFOQueue.push(2) FIFOQueue.push(3) FIFOQueue.push(4) FIFOQueue.travel() # 1,2,3,4 print(FIFOQueue.get()) # 1 print(FIFOQueue.get()) # 2 FIFOQueue.travel() # 3,4
LIFO即Last in First Out,後進先出。與棧的類似,在隊尾進行插入和刪除操作。
呼叫queue.LifoQueue
from queue import LifoQueue lifo_queue = LifoQueue() lifo_queue.put(1) # 隊尾插入新元素 lifo_queue.put(2) lifo_queue.put(3) print(lifo_queue.queue) print(lifo_queue.get()) # 隊尾取出元素 print(lifo_queue.queue)
連結串列實現
將連結串列頭部作為佇列尾部,在連結串列頭部進行插入和刪除操作。
class LNode(object): def __init__(self, item, next_=None): self.item = item self.next = next_ class LIFOQueue(object): def __init__(self): """初始化""" self.head = None def is_empty(self): """判斷是否為空""" return self.head is None def size(self): """獲取佇列長度""" cur = self.head count = 0 while cur: count += 1 cur = cur.next return count def travel(self): """遍歷佇列""" travel_list = [] cur = self.head while cur: travel_list.append(cur.item) cur = cur.next travel_list.reverse() print(travel_list) def push(self, val): """頭部插入""" self.head = LNode(val, self.head) def get(self): """獲取隊頭元素""" if self.is_empty(): print('queue is empty') return else: e = self.head.item self.head = self.head.next return e if __name__ == '__main__': LIFOQueue = LIFOQueue() LIFOQueue.push(1) LIFOQueue.push(2) LIFOQueue.push(3) LIFOQueue.push(4) LIFOQueue.travel() # 1,2,3,4 print(LIFOQueue.get()) # 4 print(LIFOQueue.get()) # 3 LIFOQueue.travel() # 1,2
List實現
# list 實現 class LIFOQueue(object): def __init__(self): self.queue = list() def size(self): return len(self.queue) def travel(self): print(self.queue) def push(self, val): self.queue.append(val) def get(self): return self.queue.pop() if __name__ == '__main__': LIFOQueue = LIFOQueue() LIFOQueue.push(1) LIFOQueue.push(2) LIFOQueue.push(3) LIFOQueue.push(4) LIFOQueue.travel() # 1,2,3,4 print(LIFOQueue.get()) # 4 print(LIFOQueue.get()) # 3 LIFOQueue.travel() # 1,2
雙端佇列(deque,全名 double-ended queue),是一種具有佇列和棧的性質的資料結構。雙端佇列中的元素可以從兩端彈出,其限定插入和刪除操作在表的兩端進行。雙端佇列可以在佇列任意一端入隊和出隊。
呼叫collections .deque
collections 是 python 內建的一個集合模組,裡面封裝了許多集合類,其中佇列相關的集合只有一個:deque。
deque 是雙邊佇列(double-ended queue),具有佇列和棧的性質,在 list 的基礎上增加了移動、旋轉和增刪等。
deque(maxlen=3),通過maxlen引數,可以建立固定長度的佇列,當新元素加入佇列且佇列已滿,會自動從另一端移除首個元素。不指定maxlen,得到無界限的佇列。
from collections import deque d = deque([]) d.append('a') # 在最右邊新增一個元素,此時 d=deque('a') print(d) d.appendleft('b') # 在最左邊新增一個元素,此時 d=deque(['b', 'a']) print(d) d.extend(['c', 'd']) # 在最右邊新增所有元素,此時 d=deque(['b', 'a', 'c', 'd']) print(d) d.extendleft(['e', 'f']) # 在最左邊新增所有元素,此時 d=deque(['f', 'e', 'b', 'a', 'c', 'd']) print(d) d.pop() # 將最右邊的元素取出,返回 'd',此時 d=deque(['f', 'e', 'b', 'a', 'c']) print(d) d.popleft() # 將最左邊的元素取出,返回 'f',此時 d=deque(['e', 'b', 'a', 'c']) print(d) d.rotate(-2) # 向左旋轉兩個位置(正數則向右旋轉),此時 d=deque(['a', 'c', 'e', 'b']) print(d)
雙向連結串列實現
class DLNode(object): def __init__(self, item, prior_=None, next_=None): self.item = item self.prior = prior_ self.next = next_ class DQueue(object): def __init__(self): self.head = None # 頭指標 self.rear = None # 尾製造 def is_empty(self): return self.head is None def length(self): if self.is_empty(): print('queue is empty') return else: cur = self.head count = 0 while True: count += 1 if cur == self.rear: break cur = cur.next return count def travel(self): """遍歷佇列""" if self.is_empty(): print('queue is empty') return else: cur = self.head while True: print(cur.item, end='') if cur.next: print(',', end='') if cur == self.rear: break cur = cur.next print('') def push_rear(self, val): """隊尾插入元素""" p = DLNode(val) if self.is_empty(): self.head = p self.rear = p else: self.rear.next = p p.prior = self.rear self.rear = self.rear.next def push_head(self, val): """隊頭插入元素""" p = DLNode(val) if self.is_empty(): self.head = p self.rear = p else: p.next = self.head self.head.prior = p self.head = p def pop_rear(self): """獲取隊尾元素""" if self.is_empty(): print('queue is empty') return else: p = self.rear self.rear = self.rear.prior self.rear.next = None return p.item def pop_head(self): """獲取隊頭元素""" if self.is_empty(): print('queue is empty') return else: e = self.head.item self.head = self.head.next return e if __name__ == '__main__': DQueue = DQueue() DQueue.push_head(1) DQueue.push_head(2) DQueue.push_head(3) DQueue.travel() # 3,2,1 DQueue.push_rear('a') DQueue.push_rear('b') DQueue.travel() # 3,2,1,a,b print(DQueue.pop_head()) # 3 print(DQueue.pop_rear()) # b print(DQueue.pop_rear()) # a DQueue.travel() # 2,1
list實現
class DQueue: """雙端佇列""" def __init__(self): self.queue = [] def push_head(self, val): """從隊頭加入一個元素""" self.queue.insert(0, val) def push_rear(self, val): """從隊尾加入一個元素""" self.queue.append(val) def pop_head(self): """從隊頭刪除一個元素""" return self.queue.pop(0) def pop_rear(self): """從隊尾刪除一個元素""" return self.queue.pop() def is_empty(self): """是否為空""" return self.queue == [] def size(self): """佇列長度""" return len(self.queue) def travel(self): print(self.queue) if __name__ == "__main__": DQueue = DQueue() DQueue.push_head(1) DQueue.push_head(2) DQueue.push_head(3) DQueue.travel() # [3, 2, 1] DQueue.push_rear('a') DQueue.push_rear('b') DQueue.travel() # [3, 2, 1, 'a', 'b'] print(DQueue.pop_head()) # 3 print(DQueue.pop_rear()) # b print(DQueue.pop_rear()) # a DQueue.travel() # [2, 1]
優先順序佇列是一種容器型資料結構,它能管理一隊記錄,並按照排序欄位(例如一個數位型別的權重值)為其排序。由於是排序的,所以在優先順序佇列中你可以快速獲取到最大的和最小的值。
可以認為優先順序佇列是一種修改過的普通佇列:普通佇列依據記錄插入的時間來獲取下一個記錄,而優先順序佇列依據優先順序來獲取下一個記錄,優先順序取決於排序欄位的值。
優先順序佇列常用來解決排程問題,比如給緊急的任務更高的優先順序。以作業系統的任務排程為例:高優先順序的任務(比如實時遊戲)應該先於低優先順序的任務(比如後臺下載軟體更新)執行。
呼叫queue.PriorityQueue
在 Python 中,內建的標準庫提供了兩種實現優先佇列的資料結構,分別是 heapq 模組和 PriorityQueue 模組,
最小優先順序佇列
更小的值具有更高的優先順序,也就是會被最先輸出
# 優先順序佇列 from queue import PriorityQueue as PQ Pqueue = PQ() Pqueue.put((1, 'a')) Pqueue.put((3, 'c')) Pqueue.put((2, 'b')) Pqueue.put((2, 'd')) Pqueue.put((5, 'e')) print(Pqueue.queue) # [(1, 'a'), (2, 'd'), (2, 'b'), (3, 'c'), (5, 'e')] while not Pqueue.empty(): print(Pqueue.get()) # (1, 'a') # (2, 'b') # (2, 'd') # (3, 'c') # (5, 'e')
最大優先順序佇列
更大的值具有更高的優先順序,也就是會被最先輸出。
from queue import PriorityQueue as PQ Pqueue = PQ() Pqueue.put((-1, 'a')) Pqueue.put((-3, 'c')) Pqueue.put((-2, 'b')) Pqueue.put((-2, 'd')) Pqueue.put((-5, 'e')) print(Pqueue.queue) # [(-5, 'e'), (-3, 'c'), (-2, 'b'), (-1, 'a'), (-2, 'd')] while not Pqueue.empty(): print(Pqueue.get()) # (-5, 'e') # (-3, 'c') # (-2, 'b') # (-2, 'd') 當兩個物件的優先順序一致時,按照插入順序排列 # (-1, 'a')
基於 heapq 實現
heapq 涉及到另一種資料結構“堆”,用heapq 實現優先順序佇列,也是基於最小堆,最大堆實現,這些在後面“堆”再一起研究下。
import heapq class PriorityQueue(object): def __init__(self): self._queue = [] # self._index = 0 def push(self, item, priority): """ 佇列由 (priority, index, item) 形式組成 priority 預設是最小優先順序,增加 "-" 實現最大優先順序, index 是為了當兩個物件的優先順序一致時,按照插入順序排列 """ heapq.heappush(self._queue, (-priority, 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 if __name__ == '__main__': PQueue = PriorityQueue() PQueue.push('a', 1) PQueue.push('c', 3) PQueue.push('b', 2) PQueue.push('d', 2) PQueue.push('e', 5) PQueue.push('f', 1) while not PQueue.empty(): print(PQueue.pop()) # e c b d a f
在之前實現的佇列時,都為固定佇列長度,都建立無限佇列,當佇列空間有限時,插入和刪除元素會有問題呢?
假定用長度為6的陣列,表示長度為6的佇列。佇列中已經有三個元素a1、a2、a3。
如果新插入元素,只需要在隊尾插入便可,在下標3的位置插入新元素a4,入佇列的時間複雜度O(1)。
如果刪除元素,當a1出佇列後,其後面的a2、a3、a4則需要向前移動一個位置,就好日常排隊時,當前麵人離開,後面的隊伍都往前移動一步,所以出佇列的時間複雜度為O(n)。
這種效率顯然是不可以接受的,那麼能不能不讓所有成員都往前挪一位呢?
所以在原來的基礎上,加入兩個變數front、rear分別儲存隊頭和隊尾的下標。
此時front =0 ,rear = 3。
當有新元素插入隊尾時,rear = rear+1。
當有元素出佇列時,front = front + 1
這樣一來,似乎不將後面所有成員往前挪,只需維護一下front的指向(front += 1)就可以保證隊首,但是,當遇到下面這情況時,就存在“假溢位”的情況。
將a2、a3都出佇列,此時front = 3,在將a6插入佇列,此時rear = 6。
此時,佇列長度為3,佇列未滿,再將a7插入佇列時,就會報錯陣列越界,但是此時陣列空間未滿,前面0、1、2都空著,這種現象稱為“假溢位”。
雖然這種方法不用移動元素,但是卻造成空間上的浪費。可以看出此時陣列是還有空間去容納新元素a7的,因此我們需要將前面浪費的空間重新利用起來,減少空間的浪費,這就是迴圈佇列的意義所在了。
1.迴圈佇列包括兩個指標(其實就是兩個整數型變數,因為在這裡有指示作用,所以這裡理解為指標), front 指標指向隊頭元素, rear 指標指向隊尾元素的下一個位置。
2.rear和front互相追趕著,這個追趕過程就是佇列新增和刪除的過程,如果rear追到head說明佇列滿了,如果front追到rear說明佇列為空。
3,rear和front位置的移動,關鍵在於% (取模運算),這樣就防止rear和front 超過maxsize。
網上最常看到的實現程式碼
class SqQueue(object): def __init__(self, maxsize): self.queue = [None] * maxsize self.maxsize = maxsize self.front = 0 self.rear = 0 # 返回當前佇列的長度 def QueueLength(self): return (self.rear - self.front + self.maxsize) % self.maxsize # 如果佇列未滿,則在隊尾插入元素,時間複雜度O(1) def EnQueue(self, data): if (self.rear + 1) % self.maxsize == self.front: print("The queue is full!") else: self.queue[self.rear] = data # self.queue.insert(self.rear,data) self.rear = (self.rear + 1) % self.maxsize # 如果佇列不為空,則刪除隊頭的元素,時間複雜度O(1) def DeQueue(self): if self.rear == self.front: print("The queue is empty!") else: data = self.queue[self.front] self.queue[self.front] = None self.front = (self.front + 1) % self.maxsize return data # 輸出佇列中的元素 def ShowQueue(self): for i in range(self.maxsize): print(self.queue[i],end=',') print(' ')
這有個bug,由於 self.rear = (self.rear + 1) % self.maxsize 這會造成一個空間的浪費!! 可以執行下程式碼看看。
所以自己寫了一段程式碼,直接使用現有元素個數cnt 與 maxsize 比較來判斷是否為空?是否已滿?
class CycleQueue(object): def __init__(self, maxsize): self.queue = [None] * maxsize self.maxsize = maxsize self.front = 0 self.rear = 0 self.cnt = 0 def is_empty(self): return self.cnt == 0 def is_full(self): return self.cnt == self.maxsize def push(self, val): if self.is_full(): print("The queue is full!") return if self.is_empty(): self.queue[self.rear] = val self.cnt += 1 else: self.rear = (self.rear + 1) % self.maxsize self.queue[self.rear] = val self.cnt += 1 def pop(self): if self.is_empty(): print("The queue is empty!") return val = self.queue[self.front] self.queue[self.front] = None self.front = (self.front + 1) % self.maxsize self.cnt -= 1 return val def travel(self): travel_list = [self.queue[(self.front + i) % self.maxsize] for i in range(self.cnt)] print(travel_list) def size(self): return self.cnt if __name__ == '__main__': CycleQueue = CycleQueue(6) CycleQueue.push('a1') CycleQueue.push('a2') CycleQueue.push('a3') CycleQueue.push('a4') CycleQueue.push('a5') CycleQueue.travel() # ['a1', 'a2', 'a3', 'a4', 'a5'] CycleQueue.push('a6') CycleQueue.travel() # ['a1', 'a2', 'a3', 'a4', 'a5', 'a6'] CycleQueue.pop() CycleQueue.push('a7') CycleQueue.travel() # ['a2', 'a3', 'a4', 'a5', 'a6', 'a7'] CycleQueue.pop() CycleQueue.pop() CycleQueue.push('a8') CycleQueue.travel() # ['a4', 'a5', 'a6', 'a7', 'a8']
到此這篇關於Python常用佇列全面詳細梳理的文章就介紹到這了,更多相關Python常用佇列內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45