算法的概念
算法是計算機處理信息的本質,因為計算機程序本質上是一個算法來告訴計算機確切的步驟來執行一個指定的任務。一般地,當算法在處理信息時,會從輸入設備或數據的存儲地址讀取數據,把結果寫入輸出設備或某個存儲地址供以后再調用。
算法是獨立存在的一種解決問題的方法和思想。
對於算法而言,實現的語言並不重要,重要的是思想。
算法可以有不同的語言描述實現版本(如C描述、C++描述、Python描述等),我們現在是在用Python語言進行描述實現。
算法的五大特性
- 輸入: 算法具有0個或多個輸入
- 輸出: 算法至少有1個或多個輸出
- 有窮性: 算法在有限的步驟之后會自動結束而不會無限循環,並且每一個步驟可以在可接受的時間內完成
- 確定性:算法中的每一步都有確定的含義,不會出現二義性
- 可行性:算法的每一步都是可行的,也就是說每一步都能夠執行有限的次數完成
先來看一道題:
如果 i+j+k=1000,且 i^2+j^2=k^2(i,j,k 為自然數),如何求出所有i,j,k可能的組合?
1 #!/usr/bin/eny python 2 # -*- coding:utf-8 -*- 3 import time 4 5 a = time.time() 6 for i in range(1001): 7 for j in range(1001): 8 for k in range(1001): 9 if i + k + j == 1000 and i*i + j*j == k*k: 10 print i ,j ,k 11 12 b = time.time() 13 #輸出運行時間 14 print b-a
結果:
0 500 500 200 375 425 375 200 425 500 0 500 164.008999825
改:
#!/usr/bin/eny python # -*- coding:utf-8 -*- import time a = time.time() for i in range(1001): for j in range(1001): k = 1000 - i - j if i*i + j*j == k*k: print i ,j ,k b = time.time() print b-a
結果;
0 500 500 200 375 425 375 200 425 500 0 500 0.408999919891
算法效率衡量
執行時間反應算法效率
對於同一問題,我們給出了兩種解決算法,在兩種算法的實現中,我們對程序執行的時間進行了測算,發現兩段程序執行的時間相差懸殊(164秒相比於0.4秒),由此我們可以得出結論:實現算法程序的執行時間可以反應出算法的效率,即算法的優劣。
單靠時間值絕對可信嗎?
假設我們將第二次嘗試的算法程序運行在一台配置古老性能低下的計算機中,情況會如何?很可能運行的時間並不會比在我們的電腦中運行算法一的214.583347秒快多少。
單純依靠運行的時間來比較算法的優劣並不一定是客觀准確的!
程序的運行離不開計算機環境(包括硬件和操作系統),這些客觀原因會影響程序運行的速度並反應在程序的執行時間上。那么如何才能客觀的評判一個算法的優劣呢?
時間復雜度與“大O記法”
我們假定計算機執行算法每一個基本操作的時間是固定的一個時間單位,那么有多少個基本操作就代表會花費多少時間單位。雖然對於不同的機器環境而言,確切的單位時間是不同的,但是對於算法進行多少個基本操作(即花費多少時間單位)在規模數量級上卻是相同的,由此可以忽略機器環境的影響而客觀的反應算法的時間效率。
對於算法的時間效率,我們可以用“大O記法”來表示。
“大O記法”:對於單調的整數函數f,如果存在一個整數函數g和實常數c>0,使得對於充分大的n總有f(n)<=c*g(n),就說函數g是f的一個漸近函數(忽略常數),記為f(n)=O(g(n))。也就是說,在趨向無窮的極限意義下,函數f的增長速度受到函數g的約束,亦即函數f與函數g的特征相似。
時間復雜度:假設存在函數g,使得算法A處理規模為n的問題示例所用時間為T(n)=O(g(n)),則稱O(g(n))為算法A的漸近時間復雜度,簡稱時間復雜度,記為T(n)
如何理解“大O記法”
對於算法進行特別具體的細致分析雖然很好,但在實踐中的實際價值有限。對於算法的時間性質和空間性質,最重要的是其數量級和趨勢,這些是分析算法效率的主要部分。而計量算法基本操作數量的規模函數中那些常量因子可以忽略不計。例如,可以認為3n2和100n2屬於同一個量級,如果兩個算法處理同樣規模實例的代價分別為這兩個函數,就認為它們的效率“差不多”,都為n2級。
最壞時間復雜度
分析算法時,存在幾種可能的考慮:
- 算法完成工作最少需要多少基本操作,即最優時間復雜度
- 算法完成工作最多需要多少基本操作,即最壞時間復雜度
- 算法完成工作平均需要多少基本操作,即平均時間復雜度
對於最優時間復雜度,其價值不大,因為它沒有提供什么有用信息,其反映的只是最樂觀最理想的情況,沒有參考價值。
對於最壞時間復雜度,提供了一種保證,表明算法在此種程度的基本操作中一定能完成工作。
對於平均時間復雜度,是對算法的一個全面評價,因此它完整全面的反映了這個算法的性質。但另一方面,這種衡量並沒有保證,不是每個計算都能在這個基本操作內完成。而且,對於平均情況的計算,也會因為應用算法的實例分布可能並不均勻而難以計算。
因此,我們主要關注算法的最壞情況,亦即最壞時間復雜度。
時間復雜度的幾條基本計算規則
- 基本操作,即只有常數項,認為其時間復雜度為O(1)
- 順序結構,時間復雜度按加法進行計算
- 循環結構,時間復雜度按乘法進行計算
- 分支結構,時間復雜度取最大值
- 判斷一個算法的效率時,往往只需要關注操作數量的最高次項,其它次要項和常數項可以忽略
- 在沒有特殊說明時,我們所分析的算法的時間復雜度都是指最壞時間復雜度
常見時間復雜度
執行次數函數舉例 | 階 | 非正式術語 |
---|---|---|
12 | O(1) | 常數階 |
2n+3 | O(n) | 線性階 |
3n2+2n+1 | O(n2) | 平方階 |
5log2n+20 | O(logn) | 對數階 |
2n+3nlog2n+19 | O(nlogn) | 對數線性階 |
6n3+2n2+3n+4 | O(n3) | 立方階 |
2n | O(2n) | 指數階 |
注意,經常將log2n(以2為底的對數)簡寫成logn
常見時間復雜度之間的關系
所消耗的時間從小到大
O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)
Python內置類型性能分析
timeit模塊
timeit模塊可以用來測試一小段Python代碼的執行速度。
class timeit.Timer(stmt='pass', setup='pass', timer=<timer function>)
Timer是測量小段代碼執行速度的類。
stmt參數是要測試的代碼語句(statment);
setup參數是運行代碼時需要的設置;
timer參數是一個定時器函數,與平台有關。
timeit.Timer.timeit(number=1000000)
Timer類中測試語句執行速度的對象方法。number參數是測試代碼時的測試次數,默認為1000000次。方法返回執行代碼的平均耗時,一個float類型的秒數。
list的操作測試

1 def test1(): 2 l = [] 3 for i in range(1000): 4 l = l + [i] 5 def test2(): 6 l = [] 7 for i in range(1000): 8 l.append(i) 9 def test3(): 10 l = [i for i in range(1000)] 11 def test4(): 12 l = list(range(1000)) 13 14 from timeit import Timer 15 16 t1 = Timer("test1()", "from __main__ import test1") 17 print("concat ",t1.timeit(number=1000), "seconds") 18 t2 = Timer("test2()", "from __main__ import test2") 19 print("append ",t2.timeit(number=1000), "seconds") 20 t3 = Timer("test3()", "from __main__ import test3") 21 print("comprehension ",t3.timeit(number=1000), "seconds") 22 t4 = Timer("test4()", "from __main__ import test4") 23 print("list range ",t4.timeit(number=1000), "seconds") 24 25 # ('concat ', 1.7890608310699463, 'seconds') 26 # ('append ', 0.13796091079711914, 'seconds') 27 # ('comprehension ', 0.05671119689941406, 'seconds') 28 # ('list range ', 0.014147043228149414, 'seconds')
list內置操作的時間復雜度
dict內置操作的時間復雜度
數據結構
概念
數據是一個抽象的概念,將其進行分類后得到程序設計語言中的基本類型。如:int,float,char等。數據元素之間不是獨立的,存在特定的關系,這些關系便是結構。數據結構指數據對象中數據元素之間的關系。
Python給我們提供了很多現成的數據結構類型,這些系統自己定義好的,不需要我們自己去定義的數據結構叫做Python的內置數據結構,比如列表、元組、字典。而有些數據組織方式,Python系統里面沒有直接定義,需要我們自己去定義實現這些數據的組織方式,這些數據組織方式稱之為Python的擴展數據結構,比如棧,隊列等。
算法與數據結構的區別
數據結構只是靜態的描述了數據元素之間的關系。
高效的程序需要在數據結構的基礎上設計和選擇算法。
程序 = 數據結構 + 算法
總結:算法是為了解決實際問題而設計的,數據結構是算法需要處理的問題載體
抽象數據類型(Abstract Data Type)
抽象數據類型(ADT)的含義是指一個數學模型以及定義在此數學模型上的一組操作。即把數據類型和數據類型上的運算捆在一起,進行封裝。引入抽象數據類型的目的是把數據類型的表示和數據類型上運算的實現與這些數據類型和運算在程序中的引用隔開,使它們相互獨立。
最常用的數據運算有五種:
-
- 插入
- 刪除
- 修改
- 查找
- 排序
在程序中,經常需要將一組(通常是同為某個類型的)數據元素作為整體管理和使用,需要創建這種元素組,用變量記錄它們,傳進傳出函數等。一組數據中包含的元素個數可能發生變化(可以增加或刪除元素)。
對於這種需求,最簡單的解決方案便是將這樣一組元素看成一個序列,用元素在序列里的位置和順序,表示實際應用中的某種有意義的信息,或者表示數據之間的某種關系。
這樣的一組序列元素的組織形式,我們可以將其抽象為線性表。一個線性表是某類元素的一個集合,還記錄着元素之間的一種順序關系。線性表是最基本的數據結構之一,在實際程序中應用非常廣泛,它還經常被用作更復雜的數據結構的實現基礎。
根據線性表的實際存儲方式,分為兩種實現模型:
-
- 順序表,將元素順序地存放在一塊連續的存儲區里,元素間的順序關系由它們的存儲順序自然表示。
- 鏈表,將元素存放在通過鏈接構造起來的一系列存儲塊中
順序表的基本形式
圖a表示的是順序表的基本形式,數據元素本身連續存儲,每個元素所占的存儲單元大小固定相同,元素的下標是其邏輯地址,而元素存儲的物理地址(實際內存地址)可以通過存儲區的起始地址Loc (e0)加上邏輯地址(第i個元素)與存儲單元大小(c)的乘積計算而得,即:
Loc(ei) = Loc(e0) + c*i
故,訪問指定元素時無需從頭遍歷,通過計算便可獲得對應地址,其時間復雜度為O(1)。
如果元素的大小不統一,則須采用圖b的元素外置的形式,將實際數據元素另行存儲,而順序表中各單元位置保存對應元素的地址信息(即鏈接)。由於每個鏈接所需的存儲量相同,通過上述公式,可以計算出元素鏈接的存儲位置,而后順着鏈接找到實際存儲的數據元素。注意,圖b中的c不再是數據元素的大小,而是存儲一個鏈接地址所需的存儲量,這個量通常很小。
圖b這樣的順序表也被稱為對實際數據的索引,這是最簡單的索引結構。
順序表的結構與實現
順序表的結構
一個順序表的完整信息包括兩部分,一部分是表中的元素集合,另一部分是為實現正確操作而需記錄的信息,即有關表的整體情況的信息,這部分信息主要包括元素存儲區的容量和當前表中已有的元素個數兩項。
順序表的兩種基本實現方式
圖a為一體式結構,存儲表信息的單元與元素存儲區以連續的方式安排在一塊存儲區里,兩部分數據的整體形成一個完整的順序表對象。
一體式結構整體性強,易於管理。但是由於數據元素存儲區域是表對象的一部分,順序表創建后,元素存儲區就固定了。
圖b為分離式結構,表對象里只保存與整個表有關的信息(即容量和元素個數),實際數據元素存放在另一個獨立的元素存儲區里,通過鏈接與基本表對象關聯。
元素存儲區替換
一體式結構由於順序表信息區與數據區連續存儲在一起,所以若想更換數據區,則只能整體搬遷,即整個順序表對象(指存儲順序表的結構信息的區域)改變了。
分離式結構若想更換數據區,只需將表信息區中的數據區鏈接地址更新即可,而該順序表對象不變。
元素存儲區擴充
采用分離式結構的順序表,若將數據區更換為存儲空間更大的區域,則可以在不改變表對象的前提下對其數據存儲區進行了擴充,所有使用這個表的地方都不必修改。只要程序的運行環境(計算機系統)還有空閑存儲,這種表結構就不會因為滿了而導致操作無法進行。人們把采用這種技術實現的順序表稱為動態順序表,因為其容量可以在使用中動態變化。
擴充的兩種策略
-
每次擴充增加固定數目的存儲位置,如每次擴充增加10個元素位置,這種策略可稱為線性增長。
特點:節省空間,但是擴充操作頻繁,操作次數多。
-
每次擴充容量加倍,如每次擴充增加一倍存儲空間。
特點:減少了擴充操作的執行次數,但可能會浪費空間資源。以空間換時間,推薦的方式。
順序表的操作
增加元素
如圖所示,為順序表增加新元素111的三種方式
a. 尾端加入元素,時間復雜度為O(1)
b. 非保序的加入元素(不常見),時間復雜度為O(1)
c. 保序的元素加入,時間復雜度為O(n)
刪除元素
a. 刪除表尾元素,時間復雜度為O(1)
b. 非保序的元素刪除(不常見),時間復雜度為O(1)
c. 保序的元素刪除,時間復雜度為O(n)
Python中的順序表
Python中的list和tuple兩種類型采用了順序表的實現技術,具有前面討論的順序表的所有性質。
tuple是不可變類型,即不變的順序表,因此不支持改變其內部狀態的任何操作,而其他方面,則與list的性質類似。
list的基本實現技術
Python標准類型list就是一種元素個數可變的線性表,可以加入和刪除元素,並在各種操作中維持已有元素的順序(即保序),而且還具有以下行為特征:
-
基於下標(位置)的高效元素訪問和更新,時間復雜度應該是O(1);
為滿足該特征,應該采用順序表技術,表中元素保存在一塊連續的存儲區中。
-
允許任意加入元素,而且在不斷加入元素的過程中,表對象的標識(函數id得到的值)不變。
為滿足該特征,就必須能更換元素存儲區,並且為保證更換存儲區時list對象的標識id不變,只能采用分離式實現技術。
在Python的官方實現中,list就是一種采用分離式技術實現的動態順序表。這就是為什么用list.append(x) (或 list.insert(len(list), x),即尾部插入)比在指定位置插入元素效率高的原因。
在Python的官方實現中,list實現采用了如下的策略:在建立空表(或者很小的表)時,系統分配一塊能容納8個元素的存儲區;在執行插入操作(insert或append)時,如果元素存儲區滿就換一塊4倍大的存儲區。但如果此時的表已經很大(目前的閥值為50000),則改變策略,采用加一倍的方法。引入這種改變策略的方式,是為了避免出現過多空閑的存儲位置。
鏈表
為什么需要鏈表
順序表的構建需要預先知道數據大小來申請連續的存儲空間,而在進行擴充時又需要進行數據的搬遷,所以使用起來並不是很靈活。
鏈表結構可以充分利用計算機內存空間,實現靈活的內存動態管理。
鏈表的定義
鏈表(Linked list)是一種常見的基礎數據結構,是一種線性表,但是不像順序表一樣連續存儲數據,而是在每一個節點(數據存儲單元)里存放下一個節點的位置信息(即地址)。
單向鏈表
單向鏈表也叫單鏈表,是鏈表中最簡單的一種形式,它的每個節點包含兩個域,一個信息域(元素域)和一個鏈接域。這個鏈接指向鏈表中的下一個節點,而最后一個節點的鏈接域則指向一個空值。
- 表元素域elem用來存放具體的數據。
- 鏈接域next用來存放下一個節點的位置(python中的標識)
- 變量p指向鏈表的頭節點(首節點)的位置,從p出發能找到表中的任意節點。
單向循環鏈表
單鏈表的一個變形是單向循環鏈表,鏈表中最后一個節點的next域不再為None,而是指向鏈表的頭節點。
操作
- is_empty() 判斷鏈表是否為空
- length() 返回鏈表的長度
- travel() 遍歷
- add(item) 在頭部添加一個節點
- append(item) 在尾部添加一個節點
- insert(pos, item) 在指定位置pos添加節點
- remove(item) 刪除一個節點
- search(item) 查找節點是否存在
實現

1 #!/usr/bin/eny python 2 # -*- coding:utf-8 -*- 3 class Node(object): 4 """節點""" 5 def __init__(self, item): 6 self.item = item 7 self.next = None 8 9 10 class SinCycLinkedlist(object): 11 """單向循環鏈表""" 12 def __init__(self): 13 self._head = None 14 15 def is_empty(self): 16 """判斷鏈表是否為空""" 17 return self._head == None 18 19 def length(self): 20 """返回鏈表的長度""" 21 # 如果鏈表為空,返回長度0 22 if self.is_empty(): 23 return 0 24 count = 1 25 cur = self._head 26 while cur.next != self._head: 27 count += 1 28 cur = cur.next 29 return count 30 31 def travel(self): 32 """遍歷鏈表""" 33 if self.is_empty(): 34 return 35 cur = self._head 36 print cur.item, 37 while cur.next != self._head: 38 cur = cur.next 39 print cur.item, 40 print "" 41 42 43 def add(self, item): 44 """頭部添加節點""" 45 node = Node(item) 46 if self.is_empty(): 47 self._head = node 48 node.next = self._head 49 else: 50 #添加的節點指向_head 51 node.next = self._head 52 # 移到鏈表尾部,將尾部節點的next指向node 53 cur = self._head 54 while cur.next != self._head: 55 cur = cur.next 56 cur.next = node 57 #_head指向添加node的 58 self._head = node 59 60 def append(self, item): 61 """尾部添加節點""" 62 node = Node(item) 63 if self.is_empty(): 64 self._head = node 65 node.next = self._head 66 else: 67 # 移到鏈表尾部 68 cur = self._head 69 while cur.next != self._head: 70 cur = cur.next 71 # 將尾節點指向node 72 cur.next = node 73 # 將node指向頭節點_head 74 node.next = self._head 75 76 def insert(self, pos, item): 77 """在指定位置添加節點""" 78 if pos <= 0: 79 self.add(item) 80 elif pos > (self.length()-1): 81 self.append(item) 82 else: 83 node = Node(item) 84 cur = self._head 85 count = 0 86 # 移動到指定位置的前一個位置 87 while count < (pos-1): 88 count += 1 89 cur = cur.next 90 node.next = cur.next 91 cur.next = node 92 93 def remove(self, item): 94 """刪除一個節點""" 95 # 若鏈表為空,則直接返回 96 if self.is_empty(): 97 return 98 # 將cur指向頭節點 99 cur = self._head 100 pre = None 101 # 若頭節點的元素就是要查找的元素item 102 if cur.item == item: 103 # 如果鏈表不止一個節點 104 if cur.next != self._head: 105 # 先找到尾節點,將尾節點的next指向第二個節點 106 while cur.next != self._head: 107 cur = cur.next 108 # cur指向了尾節點 109 cur.next = self._head.next 110 self._head = self._head.next 111 else: 112 # 鏈表只有一個節點 113 self._head = None 114 else: 115 pre = self._head 116 # 第一個節點不是要刪除的 117 while cur.next != self._head: 118 # 找到了要刪除的元素 119 if cur.item == item: 120 # 刪除 121 pre.next = cur.next 122 return 123 else: 124 pre = cur 125 cur = cur.next 126 # cur 指向尾節點 127 if cur.item == item: 128 # 尾部刪除 129 pre.next = cur.next 130 131 def search(self, item): 132 """查找節點是否存在""" 133 if self.is_empty(): 134 return False 135 cur = self._head 136 if cur.item == item: 137 return True 138 while cur.next != self._head: 139 cur = cur.next 140 if cur.item == item: 141 return True 142 return False 143 144 if __name__ == "__main__": 145 ll = SinCycLinkedlist() 146 ll.add(1) 147 ll.add(2) 148 ll.append(3) 149 ll.insert(2, 4) 150 ll.insert(4, 5) 151 ll.insert(0, 6) 152 print "length:",ll.length() 153 ll.travel() 154 print ll.search(3) 155 print ll.search(7) 156 ll.remove(1) 157 print "length:",ll.length() 158 ll.travel()
雙向鏈表
一種更復雜的鏈表是“雙向鏈表”或“雙面鏈表”。每個節點有兩個鏈接:一個指向前一個節點,當此節點為第一個節點時,指向空值;而另一個指向下一個節點,當此節點為最后一個節點時,指向空值。
鏈表與順序表的對比
鏈表失去了順序表隨機讀取的優點,同時鏈表由於增加了結點的指針域,空間開銷比較大,但對存儲空間的使用要相對靈活。
鏈表與順序表的各種操作復雜度如下所示:
操作 | 鏈表 | 順序表 |
---|---|---|
訪問元素 | O(n) | O(1) |
在頭部插入/刪除 | O(1) | O(n) |
在尾部插入/刪除 | O(n) | O(1) |
在中間插入/刪除 | O(n) | O(n) |
注意雖然表面看起來復雜度都是 O(n),但是鏈表和順序表在插入和刪除時進行的是完全不同的操作。鏈表的主要耗時操作是遍歷查找,刪除和插入操作本身的復雜度是O(1)。順序表查找很快,主要耗時的操作是拷貝覆蓋。因為除了目標元素在尾部的特殊情況,順序表進行插入和刪除時需要對操作點之后的所有元素進行前后移位操作,只能通過拷貝和覆蓋的方法進行。
棧
棧(stack),有些地方稱為堆棧,是一種容器,可存入數據元素、訪問元素、刪除元素,它的特點在於只能允許在容器的一端(稱為棧頂端指標,英語:top)進行加入數據(英語:push)和輸出數據(英語:pop)的運算。沒有了位置概念,保證任何時候可以訪問、刪除的元素都是此前最后存入的那個元素,確定了一種默認的訪問順序。
由於棧數據結構只允許在一端進行操作,因而按照后進先出(LIFO, Last In First Out)的原理運作。
棧結構實現
棧可以用順序表實現,也可以用鏈表實現。
棧的操作
- Stack() 創建一個新的空棧
- push(item) 添加一個新的元素item到棧頂
- pop() 彈出棧頂元素
- peek() 返回棧頂元素
- is_empty() 判斷棧是否為空
- size() 返回棧的元素個數

1 棧結構實現 2 3 棧可以用順序表實現,也可以用鏈表實現。 4 5 棧的操作 6 7 Stack() 創建一個新的空棧 8 push(item) 添加一個新的元素item到棧頂 9 pop() 彈出棧頂元素 10 peek() 返回棧頂元素 11 is_empty() 判斷棧是否為空 12 size() 返回棧的元素個數
結果:
3
itcast
itcast
world
hello
0
隊列
隊列(queue)是只允許在一端進行插入操作,而在另一端進行刪除操作的線性表。
隊列是一種先進先出的(First In First Out)的線性表,簡稱FIFO。允許插入的一端為隊尾,允許刪除的一端為隊頭。隊列不允許在中間部位進行操作!假設隊列是q=(A1,A2,……,An),那么A1就是隊頭元素,而An是隊尾元素。這樣我們就可以刪除時,總是從A1開始,而插入時,總是在隊列最后。這也比較符合我們通常生活中的習慣,排在第一個的優先出列,最后來的當然排在隊伍最后。
隊列的實現
同棧一樣,隊列也可以用順序表或者鏈表實現。
操作
- Queue() 創建一個空的隊列
- enqueue(item) 往隊列中添加一個item元素
- dequeue() 從隊列頭部刪除一個元素
- is_empty() 判斷一個隊列是否為空
- size() 返回隊列的大小

1 #!/usr/bin/eny python 2 # -*- coding:utf-8 -*- 3 4 5 class Queue(object): 6 """隊列""" 7 def __init__(self): 8 self.items = [] 9 10 def is_empty(self): 11 return self.items == [] 12 13 def enqueue(self, item): 14 """進隊列""" 15 self.items.insert(0,item) 16 17 def dequeue(self): 18 """出隊列""" 19 return self.items.pop() 20 21 def size(self): 22 """返回大小""" 23 return len(self.items) 24 25 if __name__ == "__main__": 26 q = Queue() 27 q.enqueue("hello") 28 q.enqueue("world") 29 q.enqueue("itcast") 30 print q.size() 31 print q.dequeue() 32 print q.dequeue() 33 print q.dequeue()
結果:
3
hello
world
itcast
雙端隊列
雙端隊列(deque,全名double-ended queue),是一種具有隊列和棧的性質的數據結構。
雙端隊列中的元素可以從兩端彈出,其限定插入和刪除操作在表的兩端進行。雙端隊列可以在隊列任意一端入隊和出隊。
操作
- Deque() 創建一個空的雙端隊列
- add_front(item) 從隊頭加入一個item元素
- add_rear(item) 從隊尾加入一個item元素
- remove_front() 從隊頭刪除一個item元素
- remove_rear() 從隊尾刪除一個item元素
- is_empty() 判斷雙端隊列是否為空
- size() 返回隊列的大小
實現

1 class Deque(object): 2 """雙端隊列""" 3 def __init__(self): 4 self.items = [] 5 6 def is_empty(self): 7 """判斷隊列是否為空""" 8 return self.items == [] 9 10 def add_front(self, item): 11 """在隊頭添加元素""" 12 self.items.insert(0,item) 13 14 def add_rear(self, item): 15 """在隊尾添加元素""" 16 self.items.append(item) 17 18 def remove_front(self): 19 """從隊頭刪除元素""" 20 return self.items.pop(0) 21 22 def remove_rear(self): 23 """從隊尾刪除元素""" 24 return self.items.pop() 25 26 def size(self): 27 """返回隊列大小""" 28 return len(self.items) 29 30 31 if __name__ == "__main__": 32 deque = Deque() 33 deque.add_front(1) 34 deque.add_front(2) 35 deque.add_rear(3) 36 deque.add_rear(4) 37 print deque.size() 38 print deque.remove_front() 39 print deque.remove_front() 40 print deque.remove_rear() 41 print deque.remove_rear()
結果:

4 2 1 4 3