線性數據結構---隊列,棧 隨筆

咱們從四個簡單但重要的概念開始研究數據結構。棧,隊列,deques(雙向隊列), 列表是一類數據的容器,它們數據元素之間的順序由添加或刪除的順序決定。一旦一個數據元素被添加,它相對於先後元素一直保持該位置不變。諸如此類的數據結構被稱爲線性數據結構。web

  線性數據結構有兩端,有時被稱爲左右,某些狀況被稱爲先後。你也能夠稱爲頂部和底部,名字都不重要。將兩個線性數據結構區分開的方法是添加和移除元素的方式,特別是添加和移除元素的位置。例如一些結構容許從一端添加元素,另外一些容許從另外一端移除元素。瀏覽器

 

 

 

概念:棧(有時稱爲「後進先出棧」)是一個元素的有序集合,其中添加移除新元素總髮生在同一端。這一端一般稱爲「頂部」。與頂部對應的端稱爲「底部」。棧的底部很重要,由於在棧中靠近底部的元素是存儲時間最長的。最近添加的元素是最早會被移除的。這種排序原則有時被稱爲 LIFO,後進先出。它基於在集合內的時間長度作排序。較新的項靠近頂部,較舊的項靠近底部。數據結構

  案例:棧的例子很常見。幾乎全部的自助餐廳都有一堆托盤或盤子,你從頂部拿一個,就會有一個新的托盤給下一個客人。想象桌上有一堆書, 只有頂部的那本書封面可見,要看到其餘書的封面,只有先移除他們上面的書。app

棧的分析與應用:測試

   - 分析:和棧相關的最有用的想法之一來自對它的觀察。假設從一個乾淨的桌面開始,如今把書一本本疊起來,你在構造一個棧。考慮下移除一本書會發生什麼。移除的順序跟剛剛被放置的順序相反。棧之因此重要是由於它能反轉項的順序。插入跟刪除順序相反。網站

   - 應用:每一個 web 瀏覽器都有一個返回按鈕。當你瀏覽網頁時,這些網頁被放置在一個棧中(實際是網頁的網址)。你如今查看的網頁在頂部,你第一個查看的網頁在底部。若是按‘返回’按鈕,將按相反的順序瀏覽剛纔的頁面。ui

Python實現棧

棧的抽象數據類型應該由如下結構和操做定義。棧操做以下: url

  • Stack() 建立一個空的新棧。 它不須要參數,並返回一個空棧。
  • push(item)將一個新項添加到棧的頂部。它須要 item 作參數並不返回任何內容。
  • pop() 從棧中刪除頂部項。它不須要參數並返回 item 。棧被修改。
  • peek() 從棧返回頂部項,但不會刪除它。不須要參數。 不修改棧。
  • isEmpty() 測試棧是否爲空。不須要參數,並返回布爾值。
  • size() 返回棧中的 item 數量。不須要參數,並返回一個整數。

  代碼實現: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存放機制)

  模擬網站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 特殊之處在於添加和刪除項是非限制性的。能夠在前面或後面添加新項。一樣,能夠從任一端移除現有項。在某種意義上,這種混合線性結構提供了單個數據結構中的棧和隊列的全部能力。

  注意:即便 deque 能夠擁有棧和隊列的許多特性,它不須要由那些數據結構強制的 LIFO 和 FIFO 排序。這取決於你如何持續添加和刪除操做。

Python實現Deque

  Deque的抽象數據類型應該由如下結構和操做定義。其中元素能夠從首部或尾部的任一端添加和移除。Deque操做以下:

    • Deque() 建立一個空的新 deque。它不須要參數,並返回空的 deque。
    • addFront(item) 將一個新項添加到 deque 的首部。它須要 item 參數 並不返回任何內容。
    • addRear(item) 將一個新項添加到 deque 的尾部。它須要 item 參數並不返回任何內容。
    • removeFront() 從 deque 中刪除首項。它不須要參數並返回 item。deque 被修改。
    • removeRear() 從 deque 中刪除尾項。它不須要參數並返回 item。deque 被修改。
    • isEmpty() 測試 deque 是否爲空。它不須要參數,並返回布爾值。
    • size() 返回 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
複製代碼

Python實現隊列

  隊列的抽象數據類型應該由如下結構和操做定義。隊列操做以下:

    • Queue() 建立一個空的新隊列。 它不須要參數,並返回一個空隊列。
    • enqueue(item) 將新項添加到隊尾。 它須要 item 做爲參數,並不返回任何內容。
    • dequeue() 從隊首移除項。它不須要參數並返回 item。 隊列被修改。
    • isEmpty() 查看隊列是否爲空。它不須要參數,並返回布爾值。
    • size() 返回隊列中的項數。它不須要參數,並返回一個整數。
複製代碼






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
相關文章
相關標籤/搜索