python實(shí)現(xiàn)堆棧與隊(duì)列的方法
創(chuàng)新互聯(lián)專(zhuān)業(yè)為企業(yè)提供黔江網(wǎng)站建設(shè)、黔江做網(wǎng)站、黔江網(wǎng)站設(shè)計(jì)、黔江網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、黔江企業(yè)網(wǎng)站模板建站服務(wù),十載黔江做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
本文實(shí)例講述了python實(shí)現(xiàn)堆棧與隊(duì)列的方法。分享給大家供大家參考。具體分析如下:
1、python實(shí)現(xiàn)堆棧,可先將Stack類(lèi)寫(xiě)入文件stack.py,在其它程序文件中使用from stack import Stack,然后就可以使用堆棧了。
stack.py的程序:
代碼如下:class Stack():
def __init__(self,size):
self.size=size;
self.stack=[];
self.top=-1;
def push(self,ele): #入棧之前檢查棧是否已滿(mǎn)
if self.isfull():
raise exception("out of range");
else:
self.stack.append(ele);
self.top=self.top+1;
def pop(self): # 出棧之前檢查棧是否為空
if self.isempty():
raise exception("stack is empty");
else:
self.top=self.top-1;
return self.stack.pop();
def isfull(self):
return self.top+1==self.size;
def isempty(self):
return self.top==-1;
再寫(xiě)一個(gè)程序文件,stacktest.py,使用棧,內(nèi)容如下:
代碼如下:#!/usr/bin/python
from stack import Stack
s=Stack(20);
for i in range(3):
s.push(i);
s.pop()
print s.isempty();
2、python 實(shí)現(xiàn)隊(duì)列:
復(fù)制代碼代碼如下:class Queue():
def __init__(self,size):
self.size=size;
self.front=-1;
self.rear=-1;
self.queue=[];
def enqueue(self,ele): #入隊(duì)操作
if self.isfull():
raise exception("queue is full");
else:
self.queue.append(ele);
self.rear=self.rear+1;
def dequeue(self): #出隊(duì)操作
if self.isempty():
raise exception("queue is empty");
else:
self.front=self.front+1;
return self.queue[self.front];
def isfull(self):
return self.rear-self.front+1==self.size;
def isempty(self):
return self.front==self.rear;
q=Queue(10);
for i in range(3):
q.enqueue(i);
print q.dequeue();
print q.isempty();
希望本文所述對(duì)大家的Python程序設(shè)計(jì)有所幫助。
“?!?/p>
和
“隊(duì)列”
是數(shù)據(jù)結(jié)構(gòu),與具體的語(yǔ)言無(wú)關(guān)。
1.隊(duì)列先進(jìn)先出,棧先進(jìn)后出。
2.
對(duì)插入和刪除操作的"限定"。
棧是限定只能在表的一端進(jìn)行插入和刪除操作的線性表。
隊(duì)列是限定只能在表的一端進(jìn)行插入和在另一端進(jìn)行刪除操作的線性表。
從"數(shù)據(jù)結(jié)構(gòu)"的角度看,它們都是線性結(jié)構(gòu),即數(shù)據(jù)元素之間的關(guān)系相同。但它們是完全不同的數(shù)據(jù)類(lèi)型。除了它們各自的基本操作集不同外,主要區(qū)別是對(duì)插入和刪除操作的"限定"。
棧和隊(duì)列是在程序設(shè)計(jì)中被廣泛使用的兩種線性數(shù)據(jù)結(jié)構(gòu),它們的特點(diǎn)在于基本操作的特殊性,棧必須按"后進(jìn)先出"的規(guī)則進(jìn)行操作,而隊(duì)列必須按"先進(jìn)先出"
的規(guī)則進(jìn)行操作。和線性表相比,它們的插入和刪除操作受更多的約束和限定,故又稱(chēng)為限定性的線性表結(jié)構(gòu)。
3.遍歷數(shù)據(jù)速度不同。棧只能從頭部取數(shù)據(jù)
也就最先放入的需要遍歷整個(gè)棧最后才能取出來(lái),而且在遍歷數(shù)據(jù)的時(shí)候還得為數(shù)據(jù)開(kāi)辟臨時(shí)空間,保持?jǐn)?shù)據(jù)在遍歷前的一致性隊(duì)列怎不同,他基于地址指針進(jìn)行遍歷,而且可以從頭或尾部開(kāi)始遍歷,但不能同時(shí)遍歷,無(wú)需開(kāi)辟臨時(shí)空間,因?yàn)樵诒闅v的過(guò)程中不影像數(shù)據(jù)結(jié)構(gòu),速度要快的多
棧(stack)是限定只能在表的一端進(jìn)行插入和刪除操作的線性表。
隊(duì)列(queue)是限定只能在表的一端進(jìn)行插入和在另一端進(jìn)行刪除操作的線性表。
從"數(shù)據(jù)結(jié)構(gòu)"的角度看,它們都是線性結(jié)構(gòu),即數(shù)據(jù)元素之間的關(guān)系相同。但它們是完全不同的數(shù)據(jù)類(lèi)型。除了它們各自的基本操作集不同外,主要區(qū)別是對(duì)插入和刪除操作的"限定"。
棧和隊(duì)列是在程序設(shè)計(jì)中被廣泛使用的兩種線性數(shù)據(jù)結(jié)構(gòu),它們的特點(diǎn)在于基本操作的特殊性,棧必須按"后進(jìn)先出"的規(guī)則進(jìn)行操作,而隊(duì)列必須按"先進(jìn)先出"的規(guī)則進(jìn)行操作。和線性表相比,它們的插入和刪除操作受更多的約束和限定,故又稱(chēng)為限定性的線性表結(jié)構(gòu)。
Queue 叫隊(duì)列,是數(shù)據(jù)結(jié)構(gòu)中的一種,基本上所有成熟的編程語(yǔ)言都內(nèi)置了對(duì) Queue 的支持。
Python 中的 Queue 模塊實(shí)現(xiàn)了多生產(chǎn)者和多消費(fèi)者模型,當(dāng)需要在多線程編程中非常實(shí)用。而且該模塊中的 Queue 類(lèi)實(shí)現(xiàn)了鎖原語(yǔ),不需要再考慮多線程安全問(wèn)題。
該模塊內(nèi)置了三種類(lèi)型的 Queue,分別是 class queue.Queue(maxsize=0) , class queue.LifoQueue(maxsize=0) 和 class queue.PriorityQueue(maxsize=0) 。它們?nèi)齻€(gè)的區(qū)別僅僅是取出時(shí)的順序不一致而已。
Queue 是一個(gè) FIFO 隊(duì)列,任務(wù)按照添加的順序被取出。
LifoQueue 是一個(gè) LIFO 隊(duì)列,類(lèi)似堆棧,后添加的任務(wù)先被取出。
PriorityQueue 是一個(gè)優(yōu)先級(jí)隊(duì)列,隊(duì)列里面的任務(wù)按照優(yōu)先級(jí)排序,優(yōu)先級(jí)高的先被取出。
如你所見(jiàn),就是上面所說(shuō)的三種不同類(lèi)型的內(nèi)置隊(duì)列,其中 maxsize 是個(gè)整數(shù),用于設(shè)置可以放入隊(duì)列中的任務(wù)數(shù)的上限。當(dāng)達(dá)到這個(gè)大小的時(shí)候,插入操作將阻塞至隊(duì)列中的任務(wù)被消費(fèi)掉。如果 maxsize 小于等于零,則隊(duì)列尺寸為無(wú)限大。
向隊(duì)列中添加任務(wù),直接調(diào)用 put() 函數(shù)即可
put() 函數(shù)完整的函數(shù)簽名如下 Queue.put(item, block=True, timeout=None) ,如你所見(jiàn),該函數(shù)有兩個(gè)可選參數(shù)。
默認(rèn)情況下,在隊(duì)列滿(mǎn)時(shí),該函數(shù)會(huì)一直阻塞,直到隊(duì)列中有空余的位置可以添加任務(wù)為止。如果 timeout 是正數(shù),則最多阻塞 timeout 秒,如果這段時(shí)間內(nèi)還沒(méi)有空余的位置出來(lái),則會(huì)引發(fā) Full 異常。
當(dāng) block 為 false 時(shí),timeout 參數(shù)將失效。同時(shí)如果隊(duì)列中沒(méi)有空余的位置可添加任務(wù)則會(huì)引發(fā) Full 異常,否則會(huì)直接把任務(wù)放入隊(duì)列并返回,不會(huì)阻塞。
另外,還可以通過(guò) Queue.put_nowait(item) 來(lái)添加任務(wù),相當(dāng)于 Queue.put(item, False) ,不再贅述。同樣,在隊(duì)列滿(mǎn)時(shí),該操作會(huì)引發(fā) Full 異常。
從隊(duì)列中獲取任務(wù),直接調(diào)用 get() 函數(shù)即可。
與 put() 函數(shù)一樣, get() 函數(shù)也有兩個(gè)可選參數(shù),完整簽名如下 Queue.get(block=True, timeout=None) 。
默認(rèn)情況下,當(dāng)隊(duì)列空時(shí)調(diào)用該函數(shù)會(huì)一直阻塞,直到隊(duì)列中有任務(wù)可獲取為止。如果 timeout 是正數(shù),則最多阻塞 timeout 秒,如果這段時(shí)間內(nèi)還沒(méi)有任務(wù)可獲取,則會(huì)引發(fā) Empty 異常。
當(dāng) block 為 false 時(shí),timeout 參數(shù)將失效。同時(shí)如果隊(duì)列中沒(méi)有任務(wù)可獲取則會(huì)立刻引發(fā) Empty 異常,否則會(huì)直接獲取一個(gè)任務(wù)并返回,不會(huì)阻塞。
另外,還可以通過(guò) Queue.get_nowait() 來(lái)獲取任務(wù),相當(dāng)于 Queue.get(False) ,不再贅述。同樣,在隊(duì)列為空時(shí),該操作會(huì)引發(fā) Empty 異常。
Queue.qsize() 函數(shù)返回隊(duì)列的大小。注意這個(gè)大小不是精確的,qsize() 0 不保證后續(xù)的 get() 不被阻塞,同樣 qsize() maxsize 也不保證 put() 不被阻塞。
如果隊(duì)列為空,返回 True ,否則返回 False 。如果 empty() 返回 True ,不保證后續(xù)調(diào)用的 put() 不被阻塞。類(lèi)似的,如果 empty() 返回 False ,也不保證后續(xù)調(diào)用的 get() 不被阻塞。
如果隊(duì)列是滿(mǎn)的返回 True ,否則返回 False 。如果 full() 返回 True 不保證后續(xù)調(diào)用的 get() 不被阻塞。類(lèi)似的,如果 full() 返回 False 也不保證后續(xù)調(diào)用的 put() 不被阻塞。
queue.Queue() 是 FIFO 隊(duì)列,出隊(duì)順序跟入隊(duì)順序是一致的。
queue.LifoQueue() 是 LIFO 隊(duì)列,出隊(duì)順序跟入隊(duì)順序是完全相反的,類(lèi)似于棧。
優(yōu)先級(jí)隊(duì)列中的任務(wù)順序跟放入時(shí)的順序是無(wú)關(guān)的,而是按照任務(wù)的大小來(lái)排序,最小值先被取出。那任務(wù)比較大小的規(guī)則是怎么樣的呢。
注意,因?yàn)榱斜淼谋容^對(duì)規(guī)則是按照下標(biāo)順序來(lái)比較的,所以在沒(méi)有比較出大小之前 ,隊(duì)列中所有列表對(duì)應(yīng)下標(biāo)位置的元素類(lèi)型要一致。
好比 [2,1] 和 ["1","b"] 因?yàn)榈谝粋€(gè)位置的元素類(lèi)型不一樣,所以是沒(méi)有辦法比較大小的,所以也就放入不了優(yōu)先級(jí)隊(duì)列。
然而對(duì)于 [2,1] 和 [1,"b"] 來(lái)說(shuō)即使第二個(gè)元素的類(lèi)型不一致也是可以放入優(yōu)先級(jí)隊(duì)列的,因?yàn)橹恍枰容^第一個(gè)位置元素的大小就可以比較出結(jié)果了,就不需要比較第二個(gè)位置元素的大小了。
但是對(duì)于 [2,1] 和 1 [2,"b"] 來(lái)說(shuō),則同樣不可以放入優(yōu)先級(jí)隊(duì)列,因?yàn)樾枰容^第二個(gè)位置的元素才可以比較出結(jié)果,然而第二個(gè)位置的元素類(lèi)型是不一致的,無(wú)法比較大小。
綜上,也就是說(shuō), 直到在比較出結(jié)果之前,對(duì)應(yīng)下標(biāo)位置的元素類(lèi)型都是需要一致的 。
下面我們自定義一個(gè)動(dòng)物類(lèi)型,希望按照年齡大小來(lái)做優(yōu)先級(jí)排序。年齡越小優(yōu)先級(jí)越高。
本章節(jié)介紹了隊(duì)列以及其常用操作。因?yàn)殛?duì)列默認(rèn)實(shí)現(xiàn)了鎖原語(yǔ),因此在多線程編程中就不需要再考慮多線程安全問(wèn)題了,對(duì)于程序員來(lái)說(shuō)相當(dāng)友好了。
在 Python 中定義 Celery 的時(shí)候,我們要引入 Broker,中文翻譯過(guò)來(lái)就是“中間人”的意思。在工頭(生產(chǎn)者)提出任務(wù)的時(shí)候,把所有的任務(wù)放到 Broker 里面,在 Broker 的另外一頭,一群碼農(nóng)(消費(fèi)者)等著取出一個(gè)個(gè)任務(wù)準(zhǔn)備著手做。這種模式注定了整個(gè)系統(tǒng)會(huì)是個(gè)開(kāi)環(huán)系統(tǒng),工頭對(duì)于碼農(nóng)們把任務(wù)做的怎樣是不知情的。所以我們要引入 Backend 來(lái)保存每次任務(wù)的結(jié)果。這個(gè) Backend 也是存儲(chǔ)任務(wù)的信息用的,只不過(guò)這里存的是那些任務(wù)的返回結(jié)果。我們可以選擇只讓錯(cuò)誤執(zhí)行的任務(wù)返回結(jié)果到 Backend,這樣我們?nèi)』亟Y(jié)果,便可以知道有多少任務(wù)執(zhí)行失敗了。
其實(shí)現(xiàn)架構(gòu)如下圖所示:
可以看到,Celery 主要包含以下幾個(gè)模塊:
celery可以通過(guò)pip自動(dòng)安裝。
broker 可選擇使用RabbitMQ/redis,backend可選擇使用RabbitMQ/redis/MongoDB。RabbitMQ/redis/mongoDB的安裝請(qǐng)參考對(duì)應(yīng)的官方文檔。
------------------------------rabbitmq相關(guān)----------------------------------------------------------
官網(wǎng)安裝方法:
啟動(dòng)管理插件:sbin/rabbitmq-plugins enable rabbitmq_management 啟動(dòng)rabbitmq:sbin/rabbitmq-server -detached
rabbitmq已經(jīng)啟動(dòng),可以打開(kāi)頁(yè)面來(lái)看看 地址:
用戶(hù)名密碼都是guest 。進(jìn)入可以看到具體頁(yè)面。 關(guān)于rabbitmq的配置,網(wǎng)上很多 自己去搜以下就ok了。
------------------------------rabbitmq相關(guān)--------------------------------------------------------
項(xiàng)目結(jié)構(gòu)如下:
使用前,需要三個(gè)方面:celery配置,celery實(shí)例,需執(zhí)行的任務(wù)函數(shù),如下:
Celery 的配置比較多,可以在 官方配置文檔: 查詢(xún)每個(gè)配置項(xiàng)的含義。
當(dāng)然,要保證上述異步任務(wù)and下述定時(shí)任務(wù)都能正常執(zhí)行,就需要先啟動(dòng)celery worker,啟動(dòng)命令行如下:
需 啟動(dòng)beat ,執(zhí)行定時(shí)任務(wù)時(shí), Celery會(huì)通過(guò)celery beat進(jìn)程來(lái)完成。Celery beat會(huì)保持運(yùn)行, 一旦到了某一定時(shí)任務(wù)需要執(zhí)行時(shí), Celery beat便將其加入到queue中. 不像worker進(jìn)程, Celery beat只需要一個(gè)即可。而且為了避免有重復(fù)的任務(wù)被發(fā)送出去,所以Celery beat僅能有一個(gè)。
命令行啟動(dòng):
如果你想將celery worker/beat要放到后臺(tái)運(yùn)行,推薦可以扔給supervisor。
supervisor.conf如下: