Python算法應用實戰之隊列詳解

隊列是一種先進先出(First-In-First-Out,FIFO)的數據結構。隊列被用在不少地方,好比提交操做系統執行的一系列進程、打印任務池等,一些仿真系統用隊列來模擬銀行或雜貨店裏排隊的顧客。下面就介紹了Python中隊列的應用實戰,須要的能夠參考。前端

隊列(queue)python

隊列是先進先出(FIFO, First-In-First-Out)的線性表,在具體應用中一般用鏈表或者數組來實現,隊列只容許在後端(稱爲rear)進行插入操做,在前端(稱爲front)進行刪除操做,隊列的操做方式和堆棧相似,惟一的區別在於隊列只容許新數據在後端進行添加(摘錄維基百科)。算法

如圖所示後端

隊列的接口數組

一個隊列至少須要以下接口:數據結構

 

接口 描述
add(x) 入隊
delete() 出隊
clear() 清空隊列
isEmpty() 判斷隊列是否爲空
isFull() 判斷隊列是否未滿
length() 隊列的當前長度
capability() 隊列的容量

 

然而在Python中,可使用collections模塊下的deque函數,deque函數提供了隊列全部的接口,那麼先讓我門看看隊列deque函數提供了那些API把:app

collections.deque是雙端隊列,即左右兩邊都是可進可出的函數

 

方法 描述
append(x) 在隊列的右邊添加一個元素
appendleft(x) 在隊列的左邊添加一個元素
clear() 從隊列中刪除全部元素
copy() 返回一個淺拷貝的副本
count(value) 返回值在隊列中出現的次數
extend([x..]) 使用可迭代的元素擴展隊列的右側
extendleft([x..]) 使用可迭代的元素擴展隊列的右側
index(value, [start, [stop]]) 返回值的第一個索引,若是值不存在,則引起ValueError。
insert(index, object) 在索引以前插入對象
maxlen 獲取隊列的最大長度
pop() 刪除並返回最右側的元素
popleft() 刪除並返回最左側的元素
remove(value) 刪除查找到的第一個值
reverse() 隊列中的全部元素進行翻轉
rotate() 向右旋轉隊列n步(默認n = 1),若是n爲負,向左旋轉。

 

如今咱們在Python中測試下這些個API的使用吧。學習

入隊操做測試

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
>>> from collections import deque
# 建立一個隊列
>>> q = deque([ 1 ])
>>> q
deque([ 1 ])
# 往隊列中添加一個元素
>>> q.append( 2 )
>>> q
deque([ 1 , 2 ])
# 往隊列最左邊添加一個元素
>>> q.appendleft( 3 )
>>> q
deque([ 3 , 1 , 2 ])
# 同時入隊多個元素
>>> q.extend([ 4 , 5 , 6 ])
>>> q
deque([ 3 , 1 , 2 , 4 , 5 , 6 ])
# 在最左邊同時入隊多個元素
>>> q.extendleft([ 7 , 8 , 9 ])
>>> q
deque([ 9 , 8 , 7 , 3 , 1 , 2 , 4 , 5 , 6 ])

出隊操做

?
1
2
3
4
5
6
7
8
9
10
# 刪除隊列中最後一個
>>> q.pop()
6
>>> q
deque([ 9 , 8 , 7 , 3 , 1 , 2 , 4 , 5 ])
# 刪除隊列中最左邊的一個元素
>>> q.popleft()
9
>>> q
deque([ 8 , 7 , 3 , 1 , 2 , 4 , 5 ])

其餘的API

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 清空隊列
>>> q
deque([ 8 , 7 , 3 , 1 , 2 , 4 , 5 ])
>>> q.clear()
>>> q
deque([])
# 判斷隊列是否爲空
>>> not q
True
# 獲取隊列最大長度
>>> q = deque([ 1 , 2 ], 10 )
>>> q.maxlen
10
# 查看某個元素出現的次數
>>> q.extend([ 1 , 2 , 1 , 1 ])
>>> q.count( 1 )
4
# 查看當前隊列長度
>>> len (q)
6
# 判斷隊列是否滿了
>>> q.maxlen = = len (q)
False
# 隊列元素反轉
>>> q = deque([ 1 , 2 , 3 , 4 , 5 ], 5 )
>>> q.reverse()
>>> q
deque([ 5 , 4 , 3 , 2 , 1 ], maxlen = 5 )
# 查看元素對應的索引
>>> q.index( 1 )
4
# 刪除匹配到的第一個元素
>>> q
deque([ 5 , 4 , 3 , 2 , 1 ], maxlen = 5 )
>>> q.remove( 5 )
>>> q
deque([ 4 , 3 , 2 , 1 ], maxlen = 5 )
# 元素位置進行旋轉
>>> q
deque([ 4 , 3 , 2 , 1 ], maxlen = 5 )
>>> q.rotate( 2 )
>>> q
deque([ 2 , 1 , 4 , 3 ], maxlen = 5 )
>>> q.rotate( 1 )
>>> q
deque([ 3 , 2 , 1 , 4 ], maxlen = 5 )
# 使用負數
>>> q.rotate( - 1 )
>>> q
deque([ 2 , 1 , 4 , 3 ], maxlen = 5 )

實例

二項式係數

題目

編寫程序,求二項式係數表中(楊輝三角)第K層系列數

?
1
2
3
4
5
1
  1 1
  1 2 1
1 3 3 1
......

思路

  1. 把第K行的係數存儲在隊列中
  2. 依次出隊K層的係數(每行最後一個1不出隊),並推算K+1層係數,添加到隊尾,最後在隊尾添加一個1,便變成了k+1行。

解決代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/use/bin/env python
# _*_ coding:utf-8 _*_
from collections import deque
def yanghui(k):
  """
  :param k: 楊輝三角中第幾層
  :return: 第K層的係數
  """
  q = deque([ 1 ]) # 建立一個隊列,默認從1開始
  for i in range (k): # 迭代要查找的層數
  for _ in range (i): # 循環須要出隊多少次
   q.append(q.popleft() + q[ 0 ]) # 第一個數加上隊列中第二個數並賦值到隊列末尾
  q.append( 1 ) # 每次查找結束後都須要在隊列最右邊添加個1
  return list (q)
result = yanghui( 3 )
print (result)

劃分無衝突子集

題目

某動物園搬家,要運走N種動物,老虎與獅子放在一塊兒會你們,大象與犀牛放在一個籠子會打架,野豬和野狗放在一個籠子裏會打架,如今須要咱們設計一個算法,使得裝進同一個籠子的動物互相不打架。

思路

  1. 把全部動物按次序入隊
  2. 建立一個籠子(集合),出隊一個動物,若是和籠子內動物無沖沖突則添加到該籠子,有衝突則添加到隊尾,等待進入新籠子
  3. 因爲隊列先進先出的特性,若是當前出隊動物的index不大於前一個出隊動物的index,說明當前隊列中全部動物已經嘗試過進入且進入不了當前籠子,此時建立信的籠子(集合)

解決代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/use/bin/env python
# _*_ coding:utf-8 _*_
from collections import deque
def division(m, n):
  """
  :param m: 衝突關係矩陣
  :param n: 幾種動物
  :return: 返回一個棧,棧內包含了全部的籠子
  """
  res = [] # 建立一個棧
  q = deque( range (n)) # 初始化隊列,裏面放着動物的序號
  pre = n # 前一個動物的下標
  while q:
  cur = q.popleft() # 從隊頭出隊一個動物
  if pre > = cur: # 是否須要建立籠子
   res.append([]) # 建立一個籠子
  # 當前的動物是否與籠子內的動物有衝突
  for a in res[ - 1 ]: # 迭代棧中最頂層的籠子
   if m[cur][a]: # 有衝突
   q.append(cur) # 從新放入隊列的尾部
   break
  else : # 當前動物和當前籠子中的全部動物沒衝突
   res[ - 1 ].append(cur) # 當前動物放入最上面的籠子中
  pre = cur # 當前變成以前的
  return res
N = 9
R = { # 衝突對應關係表
  ( 1 , 4 ), ( 4 , 8 ), ( 1 , 8 ), ( 1 , 7 ),
  ( 8 , 3 ), ( 1 , 0 ), ( 0 , 5 ), ( 1 , 5 ),
  ( 3 , 4 ), ( 5 , 6 ), ( 5 , 2 ), ( 6 , 2 ), ( 6 , 4 ),
}
M = [[ 0 ] * N for _ in range (N)] # 沖洗關係矩陣M,0表明不衝突
for i, j in R:
  M[i][j] = M[j][i] = 1 # 1表明衝突
result = division(M, N)
print (result)

數字變換

題目

對於一對正整數a,b,對a只能進行加1,減1,乘2操做,問最少對a進行幾回操做能獲得b?

例如:

  1. a=3,b=11: 能夠經過322-1,3次操做獲得11;
  2. a=5,b=8:能夠經過(5-1)*2,2次操做獲得8;

思路

本題用廣度優先搜索,尋找a到b狀態遷移最短路徑,對於每一個狀態s,能夠轉換到撞到s+1,s-1,s*2:

  1. 把初始化狀態a入隊;
  2. 出隊一個狀態s,而後s+1,s-1,s*2入隊;
  3. 反覆循環第二步驟,直到狀態s爲b;

解決代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/use/bin/env python
# _*_ coding:utf-8 _*_
from collections import deque
def atob(a, b):
  """
  :param a: 開始的數字
  :param b: 最終轉換以後的數字
  :return: 最小匹配的次數
  """
  q = deque([(a, 0 )]) # a=當前數字,0=操做的次數
  checked = {a} # 已經檢查過的數據
  while True :
  s, c = q.popleft()
  if s = = b:
   break
  if s < b: # 要計算的數小於計算以後的數字
   if s + 1 not in checked: # 若是要計算的數字+1不在已檢查過的數據集合中
   q.append((s + 1 , c + 1 )) # 要計算的數+1,轉換次數+1
   checked.add(s + 1 ) # 把計算過的數添加到checked集合中
   if s
相關文章
相關標籤/搜索