咱們從四個簡單但重要的概念開始研究數據結構。棧,隊列,deques(雙向隊列), 列表是一類數據的容器,它們數據元素之間的順序由添加或刪除的順序決定。一旦一個數據元素被添加,它相對於先後元素一直保持該位置不變。諸如此類的數據結構被稱爲線性數據結構。web
線性數據結構有兩端,有時被稱爲左右,某些狀況被稱爲先後。你也能夠稱爲頂部和底部,名字都不重要。將兩個線性數據結構區分開的方法是添加和移除元素的方式,特別是添加和移除元素的位置。例如一些結構容許從一端添加元素,另外一些容許從另外一端移除元素。瀏覽器
概念:棧(有時稱爲「後進先出棧」)是一個元素的有序集合,其中添加移除新元素總髮生在同一端。這一端一般稱爲「頂部」。與頂部對應的端稱爲「底部」。棧的底部很重要,由於在棧中靠近底部的元素是存儲時間最長的。最近添加的元素是最早會被移除的。這種排序原則有時被稱爲 LIFO,後進先出。它基於在集合內的時間長度作排序。較新的項靠近頂部,較舊的項靠近底部。數據結構
案例:棧的例子很常見。幾乎全部的自助餐廳都有一堆托盤或盤子,你從頂部拿一個,就會有一個新的托盤給下一個客人。想象桌上有一堆書, 只有頂部的那本書封面可見,要看到其餘書的封面,只有先移除他們上面的書。app
棧的分析與應用:測試
- 分析:和棧相關的最有用的想法之一來自對它的觀察。假設從一個乾淨的桌面開始,如今把書一本本疊起來,你在構造一個棧。考慮下移除一本書會發生什麼。移除的順序跟剛剛被放置的順序相反。棧之因此重要是由於它能反轉項的順序。插入跟刪除順序相反。網站
- 應用:每一個 web 瀏覽器都有一個返回按鈕。當你瀏覽網頁時,這些網頁被放置在一個棧中(實際是網頁的網址)。你如今查看的網頁在頂部,你第一個查看的網頁在底部。若是按‘返回’按鈕,將按相反的順序瀏覽剛纔的頁面。ui
棧的抽象數據類型應該由如下結構和操做定義。棧操做以下: url
代碼實現:spa
Python 中的列表類提供了有序集合機制和一組方法。例如,若是咱們有列表 [2,5,3,6,7,4],咱們只須要肯定列表的哪一端將被認爲是棧的頂部。一旦肯定,可使用諸如 append 和 pop 的列表方法來實現操做。設計
# 建立棧 class Stack(): def __init__(self): self.items = [] # 入棧(壓棧) def push(self,item): self.items.append(item) # 出棧 def pop(self): return self.items.pop() # 棧指針回到棧頂部 def peek(self): return len(self.items) - 1 # 判斷棧是否爲空,空返回Ture,不然爲False def isEmpty(self): return self.items == [] # 獲取棧長度 def size(self): return len(self.items)
測試應用:
from basic.stack import Stack s=Stack() print(s.isEmpty()) s.push(4) s.push('dog') print(s.peek()) s.push(True) print(s.size()) print(s.isEmpty()) s.push(8.4) print(s.pop()) print(s.pop()) print(s.size())
模擬網站url地址存放機制:
s = Stack()
# 點擊進入一個新的網頁 def getRequest(url): s.push(url) # 查看當前網頁 def showCurenrUrl(): print('當前頁面展現的url:'+s.pop()) # 回退到前一個網頁 def back(): print('回退按鈕點擊後顯示的url:',s.pop()) getRequest('www.1.com') getRequest('www.2.com') getRequest('www.3.com') showCurenrUrl() back() back()
# 結果:>>>
當前頁面展現的url:www.3.com 回退按鈕點擊後顯示的url: www.2.com 回退按鈕點擊後顯示的url: www.1.com
概念:deque(也稱爲雙端隊列)是與隊列相似的項的有序集合。它有兩個端部,首部和尾部,而且項在集合中保持不變。
特性:deque 特殊之處在於添加和刪除項是非限制性的。能夠在前面或後面添加新項。一樣,能夠從任一端移除現有項。在某種意義上,這種混合線性結構提供了單個數據結構中的棧和隊列的全部能力。
注意:即便 deque 能夠擁有棧和隊列的許多特性,它不須要由那些數據結構強制的 LIFO 和 FIFO 排序。這取決於你如何持續添加和刪除操做。
Deque的抽象數據類型應該由如下結構和操做定義。其中元素能夠從首部或尾部的任一端添加和移除。Deque操做以下:
建立雙端隊列:
# 建立雙端隊列 class Dequeue(): def __init__(self): self.items = [] # 從隊列頭部插入數據 def addFont(self,item): self.items.insert(0,item) # 從隊列尾部插入數據 def addRear(self,item): self.items.append(item) # 隊頭取出元素 def removeFont(self): return self.items.pop() # 隊尾取元素 def removeRear(self): return self.items.pop(0) # 獲取隊列長度 def size(self): return len(self.items)
隊列測試:
q = Dequeue()
q.addFont(1) q.addFont(2) q.addFont(3) # print(q.removeFont()) # print(q.removeFont()) # print(q.removeFont()) print(q.removeRear()) print(q.removeRear()) print(q.removeRear()) # 結果>>> 3 2 1
迴文檢測:設計程序,檢測一個字符串是否爲迴文。
迴文:迴文是一個字符串,讀取首尾相同的字符,例如,radar toot madam
。
分析:該問題的解決方案將使用 deque 來存儲字符串的字符。咱們從左到右處理字符串,並將每一個字符添加到 deque 的尾部。在這一點上,deque 像一個普通的隊列。然而,咱們如今能夠利用 deque 的雙重功能。 deque 的首部保存字符串的第一個字符,deque 的尾部保存最後一個字符。咱們能夠直接刪除並比較首尾字符,只有當它們匹配時才繼續。若是能夠持續匹配首尾字符,咱們最終要麼用完字符,要麼留出大小爲 1 的deque,取決於原始字符串的長度是偶數仍是奇數。在任一狀況下,字符串都是迴文。
class Dequeue(): def __init__(self): self.items = [] def addFront(self,item): self.items.insert(0,item) def addRear(self,item): self.items.append(item) def removeFront(self): return self.items.pop() def removeRear(self): return self.items.pop(0) def size(self): return len(self.items) def isHuiWen(s): de = Dequeue() ex = True for sr in s: de.addFront(sr) while de.size() > 1: if de.removeFront() != de.removeRear(): ex = False break return ex print(isHuiWen("abcba"))
實驗規則:燙手山芋遊戲介紹:6個孩子圍城一個圈,排列順序孩子們本身指定。第一個孩子手裏有一個燙手的山芋,須要在計時器計時1秒後將山芋傳遞給下一個孩子,依次類推。規則是,在計時器每計時7秒時,手裏有山芋的孩子退出遊戲。該遊戲直到剩下一個孩子時結束,最後剩下的孩子獲勝。請使用隊列實現該遊戲策略,排在第幾個位置最終會獲勝。
分析:
代碼實現:
q = Queue()
kids = ['A','B','C','D','E','F'] # 進隊列(循環隊列) for kid in kids: q.enqueue(kid) # 隊列中剩最後一個孩子則跳出循環,孩子獲勝 while q.size() > 1: # 內層循環是用來將手裏有山芋的孩子排在隊頭 # 每次計時器到時,刪除當前孩子,則指針指向的下一個孩子位置 # 每次計時,循環隊列 for i in range(6): # 刪除隊列最後一個孩子 kid = q.dequeue() # 刪除的孩子從新添加在隊首位置,實現隊列循環 q.enqueue(kid) # 6s計時到時,刪除最後一個孩子,指針指向下一個孩子 q.dequeue() # 打印最後獲勝的孩子 print(q.dequeue()) # 孩子E獲勝,留下的最後一個孩子 # 結果>>>E
隊列的抽象數據類型應該由如下結構和操做定義。隊列操做以下:
class Queue(): def __init__(self): self.items = [] # 隊列插入元素(左端) def enqueue(self,item): self.items.insert(0,item) # 隊列刪除元素(右端) def dequeue(self): return self.items.pop() # 判斷隊列是否爲空,空返回True,不然返回False def isEmpty(self): return self.items == [] # 返回隊列長度 def size(self): return len(self.items)
隊列測試:
>>> q.size()
3
>>> q.isEmpty() False >>> q.enqueue(8.4) >>> q.dequeue() 4 >>> q.dequeue() 'dog' >>> q.size() 2