學習軌道
/
Python
Python
/
練習
/
簡易鏈結串列
簡易鏈結串列

簡易鏈結串列

簡單

簡介

你在一間音樂串流公司工作。

你的任務是為你的音樂播放器應用程式打造播放清單功能。

說明

寫一個音樂播放器應用程式的原型。

在這個原型中,每首歌只用一個數字來代表。 給定一段數字範圍(也就是歌曲 ID),請建立一個單向鏈結串列。

給定一個單向鏈結串列,你應該要能反轉這個串列,讓歌曲以相反的順序播放。

Note

鏈結串列是電腦科學中一種基礎的資料結構,常用來實作其他資料結構。

最簡單的鏈結串列是單向鏈結串列。 這表示每個元素(或稱「節點」)都包含資料,以及某個指向串列中下一個節點的東西。

如果你想更深入了解鏈結串列,可以看看這篇文章,裡面用很棒的圖解說明了這個概念。

這個練習在 Python 中的結構

雖然stacks和queues可以用lists、collections.deque、queue.LifoQueue和multiprocessing.Queue來實作,但這個練習預期的是以 自製的 單向鏈結串列實作的「後進先出」(LIFO)堆疊:


以鏈結串列實作堆疊的示意圖。最左側是一個虛線邊框的圓形,名為 New_Node,有兩條虛線箭頭指向右方。New_Node 標示著「(becomes head) - New_Node - next = node_6」。上方那條虛線箭頭標示為「push」,指向右上方的 Node_6。Node_6 標示著「(current) head - Node_6 - next = node_5」。下方那條虛線箭頭標示為「pop」,指向一個寫著「gets removed on pop()」的方塊。Node_6 有一條實線箭頭指向右方的 Node_5,Node_5 標示著「Node_5 - next = node_4」。Node_5 有一條實線箭頭指向右方的 Node_4,Node_4 標示著「Node_4 - next = node_3」。這個模式一直持續到 Node_1,Node_1 標示著「(current) tail - Node_1 - next = None」。Node_1 有一條虛線箭頭指向右方一個寫著「None」的節點。


這不應該與使用動態陣列的LIFO堆疊混為一談,後者底層可能使用list、queue或array。 以動態陣列為基礎的stacks有不同的head位置,以及不同的時間複雜度(Big-O)與記憶體佔用量。


以陣列/動態陣列實作堆疊的示意圖。最右側是一個虛線邊框的方塊,名為 New_Node,有兩條虛線箭頭指向左方。New_Node 標示著「(becomes head) -  New_Node」。上方那條虛線箭頭標示為「append」,指向左上方的 Node_6。Node_6 標示著「(current) head -  Node_6」。下方那條虛線箭頭標示為「pop」,指向一個虛線外框、寫著「gets removed on pop()」的方塊。Node_6 有一條實線箭頭指向左方的 Node_5。Node_5 有一條實線箭頭指向左方的 Node_4。這個模式一直持續到 Node_1,Node_1 標示著「(current) tail - Node_1」。


有幾個考量點可以參考這兩篇 Stack Overflow 問答:以陣列為基礎與以鏈結串列為基礎的堆疊與佇列,以及陣列堆疊、鏈結堆疊與堆疊之間的差異。 關於鏈結串列、LIFO堆疊,以及 Python 中其他抽象資料型態(ADT)的更多細節:


Python 中的類別

Python 中「正統」的鏈結串列實作通常需要一個或多個classes。 如果想好好認識classes,請參閱 classes 與搭配的練習 ellens-alien-game,或是 Python 官方教學的類別章節。


Python 中的特殊方法

這個練習的測試會對你的LinkedList呼叫len()。 為了讓len()能運作,你需要建立__len__特殊方法。 關於在 Python 中實作特殊方法或「dunder」方法的細節,請參閱 Python 文件:基本物件自訂 與 Python 文件:object.len(self)。


建立疊代器

若要支援對你的LinkedList進行迴圈或反轉,你需要實作__iter__特殊方法。 實作細節請參閱為類別實作疊代器。


自訂與引發例外

有時候,你的程式碼需要同時自訂與raise例外。 這麼做時,你應該總是在其中加上有意義的錯誤訊息,指出錯誤的來源是什麼。 這會讓你的程式碼更容易閱讀,對除錯也有很大的幫助。

自訂例外可以透過新的例外類別來建立(詳情請參閱classes),這些類別通常是Exception的子類別。

如果你知道錯誤來源會是某種例外_型別_的衍生物,可以選擇繼承 Exception 類別底下的其中一種built in error types。 引發錯誤時,你還是應該附上有意義的訊息。

這個練習要求你建立一個_自訂例外_,在鏈結串列為空時引發/「拋出」它。 只有當你自訂適當的例外、raise這些例外,並加上適當的錯誤訊息時,測試才會通過。

若要自訂一般的_例外_,請建立一個繼承自Exception的class。 引發自訂例外並附上訊息時,請將訊息寫成exception型別的引數:

# subclassing Exception to create EmptyListException
class EmptyListException(Exception):
    """Exception raised when the linked list is empty.

    message: explanation of the error.

    """
    def __init__(self, message):
        self.message = message

# raising an EmptyListException
raise EmptyListException("The list is empty.")
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
Python Exercism

準備好開始 簡易鏈結串列 了嗎?

註冊 Exercism,透過 17 個概念146 個練習 和真人引導來學習並精通 Python,全部免費。