佇列的Python實現與例項分析
佇列是隻有一端可以進行插入操作,而另一端可以進行刪除操作的有序線性儲存結構,滿足先進先出的約束。
生活中典型的例項就是排隊,先到的人排在前面,可先得到服務,後到的人排在後面,並且不能插隊。
計算機應用中典型的例項就是印表機,先發送的列印任務可以先被執行,之後的都要排隊等候
Python實現
在 Python 中,和棧一樣,同樣可以用列表作為佇列的底層實現,只需要確定列表的哪一端作為佇列的頭,也即刪除操作端,哪一端作為佇列的尾,也即插入操作端。同時,把佇列抽象為類,佇列的先進先出操作實現為類的方法
假定隊尾在列表中的位置為 0。這允許我們使用列表上的插入函式向隊尾新增新元素。彈出操作可用於刪除隊首的元素(列表的最後一個元素)。這樣入隊的複雜度為 O(n),出隊為 O(1)。如果隊尾和隊首在列表中的位置換一下,則入隊的複雜度為 O(1),出隊為 O(n)。
以下為按照前面一種方式的佇列的Python實現
Queue 實現一個佇列類,可通過 Queue() 建立一個空佇列
is_empty 操作判斷佇列是否為空
enqueue 操作將新元素插入到列尾
dequeue 操作將彈出並刪除隊首的元素
size 操作返回佇列的大小
class Queue:
def __init__(self):
self.items=[]
def is_empty(self):
return self.items==[]
def enqueue(self,item):
self.items.insert(0 ,item)
def dequeue(self):
return self.items.pop()
def size(self):
return len(self.items)
以上為佇列的最簡單實現,對比棧的實現,可以看出兩者非常相像,只在插入操作上有所不同。
應用例項
約瑟夫問題:n個人圍成一個圈,每個人分別標註為1、2、…、n,要求從1號從1開始報數,報到k的人出圈,接著下一個人又從1開始報數,如此迴圈,直到只剩最後一個人時,該人即為勝利者。
解約瑟夫問題的一種方法是模擬這個過程,模擬的載體可以是佇列,也可以是連結串列,下面就用列隊來模擬這個過程
迴圈報數的過程可以看作是一個先報數先出的過程,用佇列來模擬時,將當前報數的人彈出,如果報的不是k時,再插入到隊尾,從而得以迴圈,如果報的是k,則拋棄。直至剩下最後一個人。
下面是在生成 Queue 類的基礎下,Python 解決約瑟夫問題的一個例項程式碼,以實際人名來模擬n個人,報數為7時刪除,輸出最後的勝利者。
#約瑟夫問題模擬函式
def circle(k,nameList):
queue1=Queue()
for i in range(len(nameList)): #將名字列表逐個插入佇列
queue1.enqueue(nameList[i])
i=1
while queue1.size()!=1:
temp=queue1.dequeue() #叫到哪個將哪個彈出
if i!=k:
queue1.enqueue(temp) #不是第k個再插入
else :
i=0 #是第k個重新計數
i+=1
return queue1.dequeue()
#主函式
if __name__=='__main__':
nameList=["Bill","David","Susan","Jane","Kent","Brad"]
print(circle(7,nameList))
#輸出結果
Kent