笨辦法學 Python · 續 練習 15:棧和隊列

練習 15:棧和隊列

原文:Exercise 15: Stacks and Queues

譯者:飛龍

協議:CC BY-NC-SA 4.0

自豪地采用谷歌翻譯

當處理數據結構時,你將經常遇到類似于另一種結構的結構。Stack類似于練習13中的SingleLinkedList,以及Queue類似于練習14中的DoubleLinkedList,唯一區別是StackQueue限制了可能的操作,以簡化它們的使用方式。這有助于減少缺陷,因為你不能意外地像Queue那樣使用Stack并導致問題。在Stack中,節點被“壓入”“棧頂”,然后從頂部“彈出”。在隊列中,節點壓入“尾部”,之后從“頭部”彈出。這些操作都是SingleLinkedListDoubleLinkedList的簡化,其中Stack只允許pushpop操作,Queue只允許shiftunshift

譯者注:實際上是pushunshift

當可視化堆棧時,你應該想到你的地板上的一堆書。想像我在書架上的那種很重的藝術書,如果我堆疊了20個,可能會重約100磅。當你為這些書構建棧的時候,你不能抬起整個棧,并且把書放在底部,對吧?不,你把書放在棧的頂部。你把它放在那兒,但我們也可以使用“推”描述這個動作。如果你想從棧中獲取一本書,你可能會抬起一些書,然后抓住一本書,但是最終你可能要從頂部拿出一些書,才能獲取底部得數。你可以從頂部抬起每本書,或者在我們的例子中,我們會說“從頂部彈出一本書”。

如果你想像在銀行排隊,隊列有“頭部”和“尾部”,可視化隊列是最簡單的。通常有一個繩索迷宮,它的末尾有一個入口,出口處是檢票員。你可以通過進入這條繩索迷宮的“尾部”進入隊列,我們??稱之為shift,因為這是Queue數據結構中的常見編程屬于。一旦你進入銀行(隊列),你不能越過等候線然后離開,否則其余的人會生氣。所以你必須等待,隨著你前面的每個人都離開了等候線(對你而言是unshift),你離“頭部”更近了。一旦你達到了頭部,那么你可以退出,我們稱之為unshift

很多時候,你可以找到數據結構的真實世界示例,來幫助你可視化其工作原理。你現在應該花點時間來繪制這些場景,或者實際上得到書籍的棧并測試這些操作。你可以找到與StackQueue類似的其他真實情況嗎?

挑戰練習

我現在打算讓你做一個基于代碼的挑戰練習,并且從它們的描述中實現數據結構。在這個挑戰中,你首先需要使用這里的起始代碼,以及你從練習 13 中了解的SingleLinkedList,實現Stack數據結構。完成之后,你將嘗試從零開始實現Queue數據結構。

StackNode節點類幾乎和SingleLinkedListNode相同,而事實上我只是復制過來并更名:

class StackNode(object):

    def __init__(self, value, nxt):
        self.value = value
        self.next = nxt

    def __repr__(self):
        nval = self.next and self.next.value or None
        return f"[{self.value}:{repr(nval)}]"

Stack控制類和SingleLinkedList十分類似,除了我使用top代替了first。這樣匹配Stack的概念。

class Stack(object):

    def __init__(self):
        self.top = None

    def push(self, obj):
        """Pushes a new value to the top of the stack."""

    def pop(self):
        """Pops the value that is currently on the top of the stack."""

    def top(self):
        """Returns a *reference* to the first item, does not remove."""

    def count(self):
        """Counts the number of elements in the stack."""

    def dump(self, mark="----"):
        """Debugging function that dumps the contents of the stack."""

現在你的挑戰是實現Stack,并為其執行測試,類似于在練習 13 中進行的測試。請確保你的測試涵蓋了每一個操作,你可以以任何方式。記住,盡管如此,堆棧的push操作必須在頂部,所以有到頂部的鏈接。

一旦你使Stack正常工作,你應該實現Queue,但它基于DoubleLinkedList。(譯者注:其實單鏈表也行,因為只有尾部彈出的操作比較困難。你可以在尾部插入,在頭部彈出。)Stack中的內容應該與SingleLinkedList基本內部結構相同,只需更改允許的功能。Queue也一樣。花點時間來繪制隊列的工作原理,然后弄清楚它如何限制DoubleLinkedList。一旦你完成了,創建你的隊列。

破壞它

破壞這些數據結構僅僅是不要維持約束。看看如果一個操作無法使用正確的尾部會發生什么。

你可能還注意到,它有“偏移一位”的持久性錯誤。在我的設計中,當結構為空時,我設置了self.top = None。這意味著當你達到 0 個元素時,你必須對self.top做一些特殊處理。一個替代方法是使self.top總是指向一個StackNode(偽造的頭節點),并假設當你有這個最后的元素時,結構是空的。嘗試它,看看它如何改變你的實現。這樣會更容易出錯還是更不容易出錯?

深入學習

這些數據結構有很多操作是非常低效的。回顧你為每個數據結構編寫的代碼,并嘗試猜測哪些函數最慢。一旦你有了想法,嘗試解釋為什么他們可能很慢。研究其他人對這些數據結構的看法。在練習 18 和 19 中,你將學習對這些數據結構進行一些性能分析并進行調整。

最后,你真的需要實現一個全新的數據結構嗎,還是簡單地“包裝” SingleLinkedListDoubleLinkedList數據結構?這如何改變你的設計?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 棧 棧的英文單詞是Stack,它代表一種特殊的線性表,這種線性表只能在固定一端(通常認為是線性表的尾端)進行插入,...
    Jack921閱讀 1,523評論 0 5
  • 練習42:棧和隊列 原文:Exercise 42: Stacks and Queues 譯者:飛龍 到現在為止,你...
    布客飛龍閱讀 518評論 0 36
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,373評論 25 708
  • 細雨太湖白,軒窗任意開。朦朧江左秀,水墨畫中來。 注:江左即江南。 圖原創 文原創
    深谷留風閱讀 354評論 13 24
  • 最近笑來老師的天天用英語在搞年中復盤,我想了想,投不投稿先放一邊,要不自己趁著這個機會也盤點盤點這半年的英語學習情...
    JYQC66閱讀 1,879評論 0 0