資料結構-雙向連結串列(Python實現)

浩然haoran發表於2019-07-15

資料結構在程式設計世界中一直是非常重要的一環,不管是開發還是演算法,哪怕是單純為了面試,資料結構都是必修課,今天我們介紹連結串列中的一種——雙向連結串列的程式碼實現。

好了,話不多說直接上程式碼。

雙向連結串列

首先,我們定義一個節點類:Node

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None
        self.prev = None
    def getData(self):
        return self.data

    def setData(self, data):
        self.data = data

    def getNext(self):
        return self.next

    def getPrev(self):
        return self.prev

好,我們定義了節點類,並實現了獲取、修改節點資料、獲取上一個/下一個節點的方法。

通過node = Node(10)就可以例項化一個節點啦。

接下來我們來定義連結串列類:

class TwoWayList:
    def __init__(self):
        self.head = None
        self.tail = None
        self.length = 0

好,我們定義了一個連結串列類,並設定三個屬性,head表示頭節點,tail表示尾節點,length表示連結串列長度,接下來,我們給連結串列類新增一些方法。

  • 判斷連結串列是否為空:
    def isEmpty(self):
        return self.head == None
  • 在連結串列尾部新增節點:
    def append(self, item):
        if self.length == 0:
            node = Node(item)
            self.head = node
            self.tail = node
            self.length = 1
            return
        node = Node(item)
        tail = self.tail
        tail.next = node
        node.prev = tail
        self.tail = node
        self.length += 1

新增節點的時候,我們首先要判斷連結串列是否為空,另外要注意給原本的尾節點設定next屬性,新的尾節點設定prev屬性,更新連結串列的tail和length屬性。

  • 連結串列中插入節點:
    def insert(self, index, item):
        length = self.length
        if (index<0 and abs(index)>length) or (index>0 and index>=length):
            return False
        if index < 0:
            index = index + length
        if index == 0:
            node = Node(item)
            if self.head != None:
                self.head.prev = node
            else:
                self.tail = node
            node.next = self.head
            self.head = node
            self.length += 1
            return True
        if index == length - 1:
            return self.append(item)


        node1 = self.head
        for i in range(0, index):
            node1 = node1.next
        node2 = node1.next

        node = Node(item)
        node.prex = node1
        node.next = node2
        node1.next = node
        node2.prev = node

        self.length += 1
        return True

插入節點時候,我們引數為下標index和資料item,我們預設在指定下標的後面插入新節點。

在這裡我們同樣要特殊考慮頭節點和尾結點的情況。

在執行插入時先將新節點的next、prev屬性指向相應節點,在將前後節點的next和prev指向新節點,同時注意更新連結串列的length屬性。

  • 根據節點資料獲取連結串列上的節點
    def get(self, data):
        node = self.head
        for i in range(self.length):
            if node.data == data:
                return node
            else:
                node = node.next
        else:
            return False
  • 根據下標獲取連結串列上的節點
    def getByIndex(self, index):
        if index >= self.length:
            return False
        if index == 0:
            return self.head

        now = self.head
        for i in range(self.length):
            if i == index:
                return now
            now = now.next
  • 更新指定下標節點的資料
    def setData(self, index, data):
        if index >= self.length:
            return False
        if index == 0:
            self.head.data = data

        now = self.head
        for i in range(self.length):
            if i == index:
                now.data = data
                return True
            now = now.next
  • 刪除指定下標的節點
    def remove(self, index):
        if index >= self.length:
            return False
        if index == 0:
            self.head = self.head.next
            if self.length != 1:
                self.head.prev = None
            self.length -= 1
            return True
        if index == self.length-1:
            self.tail = self.tail.prev
            self.tail.next = None
            self.length -= 1
            return True

        now = self.head
        for i in range(self.length):
            if i == index:
                now.next.prev = now.prev
                now.prev.next = now.next
                self.length -= 1
                return True
            now = now.next

注意要更新length屬性,如果刪除頭節點還要更新head屬性,如果刪除尾結點要更新tail屬性。

  • 連結串列翻轉
    def reverse(self):
        now = self.head
        last = None
        for i in range(self.length):
            last = now
            now = now.next
            tmp = last.prev
            last.prev = last.next
            last.next = tmp
        tmp = self.head
        self.head = self.tail
        self.tail = tmp
        return True

連結串列翻轉我們不光要更新tail和head屬性,還要將每一個節點上的next和prev屬性調換。

  • 清空連結串列
    def clear(self):
        self.head = None
        self.tail = None
        self.length = 0
  • 實現連結串列類的__str__方法,定義print()函式列印連結串列的方式
    def __str__(self):
        string = ''
        node = self.head
        for i in range(self.length):
            string += str(node.data) + '/'
            node = node.next
        return string

這裡我們讓print()函式列印連結串列時,從頭節點開始依次列印每個節點的資料,並用/符號分割。

好啦,一個雙向連結串列我們就定義好了,並實現了一些操作連結串列的方法,我們了來測試一下我們定義的連結串列吧~

li = TwoWayList()
li.isEmpty()
li.insert(0, 1)
li.getByIndex(0)
li.remove(0)

print(li)
li.append(1)

print(li)
li.append(2)
print(li)
li.append(4)
print(li)
li.insert(2,3)
print(li)
li.insert(3,4)

print(li)
li.remove(2)
print(li)
li.setData(2,10)
print(li)
li.reverse()
print(li)
print(li.get(2).data)
print(li.getByIndex(1).data)

執行上面的操作,檢查一下你的輸出吧,如果你有任何建議歡迎留言告訴我

相關文章