【數據結構】——雙向鏈表,使用Python創建一個簡單的雙向鏈表(詳解)

雙向鏈表

雙向鏈表有兩個指針域,一個指向前驅結點,一個指向後繼結點

 

創建一個結點類:

因爲是雙向鏈表,所以需要前後相通,就是比單鏈表多了一個前驅指針

數據域data、前驅指針pre,後繼指針next

class Node(object):
    """創建一個結點類"""

    def __init__(self, data):
        self.data = data
        self.pre = None
        self.next = None

創建一個創建雙向鏈表的類:

判斷是否爲空、獲取長度、遍歷鏈表、查找指定結點是否存在,這些函數和單鏈表的一樣

(只是最簡單的方法一樣,雙向鏈表還有其它方法遍歷或者查找指定結點)

class CreateDoubleLinkedList(object):
    """創建一個創建雙向鏈表的類"""

    def __init__(self):
        self.head = None

    def is_empty(self):
        """判斷雙向鏈表是否爲空鏈表"""
        return self.head is None

    def length(self):
        """獲取雙向鏈表的長度"""
        cur = self.head
        count = 0
        while cur is not None:
            count += 1
            cur = cur.next
        return count

    def traversal(self):
        """遍歷雙向鏈表"""
        cur = self.head
        if self.is_empty():
            print("鏈表爲空!")
            return
        while cur is not None:
            print(cur.data)
            cur = cur.next
        
    def node_is_exist(self, data):
        """查找指定結點是否存在"""
        cur = self.head
        while cur is not None:
            if cur.data == data:
                return True
            else:
                cur = cur.next
        return False   

在頭部添加結點:

插入的大體過程和單鏈表很相似,只是在插入結點的過程中,我們需要注意的就是:每個結點都有兩個指針,都需要設置正確的指向。

def add_first(self, data):
    """在頭部添加結點"""
    node = Node(data)
    if self.is_empty():
        self.head = node
    else:
        # 新結點向後指向頭結點
        node.next = self.head
        # 頭結點向前指向新結點
        self.head.pre = node
        # 將頭結點的稱號給新結點
        self.head = node

在尾部添加結點:

def add_last(self, data):
    """在尾部添加結點"""
    node = Node(data)
    if self.is_empty():
        self.head = node
    else:
        cur = self.head
        # 指針移動到尾部
        while cur.next is not None:
            cur = cur.next
        # 尾結點的後繼指針指向新結點
        cur.next = node
        # 新結點的前驅指針指向尾結點
        node.pre = cur

在指定位置添加結點:

def insert_node(self, index, data):
    """在指定位置添加結點"""
    if index < 0 or index > self.length():
        print("結點位置錯誤!")
        return False
    elif index == 0:
        self.add_first(data)
    elif index == self.length():
        self.add_last(data)
    else:
        node = Node(data)
        cur = self.head
        pres = None
        count = 0
        # 移動到要添加的位置
        while count < index:
            pres = cur
            cur = cur.next
            count += 1
        # 新結點和它前面的結點互指
        pres.next = node
        node.pre = pres
        # 新結點和它後面的結點互指
        node.next = cur
        cur.pre = node

刪除指定結點:

當鏈表不爲空的時候,我們需要考慮三種情況:

  1. 要刪除是是頭結點
  2. 要刪除的是尾結點
  3. 要刪除的是中間任意結點

(需要注意的就是:每個結點都需要改變兩個指針鏈)

def remove_node(self, data):
    """刪除指定結點"""
    if self.is_empty():
        print("刪除失敗,鏈表爲空!")
        return False
    elif data == self.head.data:
        self.head.next.pre = None
        self.head = self.head.next
    else:
        cur = self.head
        # 移動到要刪除結點的位置
        while cur.data != data:
            cur = cur.next
        # 當前結點的後繼結點爲空,說明是尾結點
        if cur.next is None:
            cur.pre.next = None
            cur.pre = None
        else:
            cur.pre.next = cur.next
            cur.next.pre = cur.pre

假如我們只斷掉了一根指針鏈,會怎麼樣?

就比如這樣寫(以上面刪除尾結點的代碼爲例):

# 當前結點的後繼結點爲空,說明是尾結點
        if cur.next is None:
            cur.pre.next = None
            # 將尾結點指向前驅結點的那個指針鏈留着
            # cur.pre = None
            # 打印一下被刪掉的尾結點的前驅結點數據 
            print("測試:", cur.pre.data)

如果尾結點已經被刪掉了,那麼cur指向爲空,最後print那一行,空類型是沒有前驅結點pre屬性的,測試運行之後,肯定會報錯。

但是因爲我們只刪掉了一個指針鏈,所以測試結果還是會打印出:被刪除掉結點的前驅結點數據,因爲被刪除結點的前驅指針鏈沒有被斷掉。

接下來我們正向遍歷一次鏈表,發現:沒有被剛纔刪除的結點數據,爲什麼?因爲向右的指針鏈已經被斷掉了,遍歷不到它,我們以爲被它被刪除掉了,其實沒有。

所以:雙向鏈表必須要端兩根指針鏈,才能徹底刪除掉。

(可以自行寫一個反向遍歷的函數,看一看效果)

主函數測試:

if __name__ == '__main__':
    lists = CreateDoubleLinkedList()
    lists.add_last(3)
    lists.add_first(2)
    lists.add_first(1)
    lists.add_last(5)
    lists.insert_node(3, 4)
    lists.traversal()
    print("鏈表是否爲空:", lists.is_empty())
    print("獲取鏈表長度:", lists.length())
    print("改結點是否存在:", lists.node_is_exist(2))
    lists.remove_node(1)
    lists.remove_node(5)
    print("刪除結點之後的遍歷:")
    lists.traversal()

測試結果截圖:

完整代碼:

class Node(object):
    """創建一個結點類"""

    def __init__(self, data):
        self.data = data
        self.pre = None
        self.next = None


class CreateDoubleLinkedList(object):
    """創建一個創建雙向鏈表的類"""

    def __init__(self):
        self.head = None

    def is_empty(self):
        """判斷雙向鏈表是否爲空鏈表"""
        return self.head is None

    def length(self):
        """獲取雙向鏈表的長度"""
        cur = self.head
        count = 0
        while cur is not None:
            count += 1
            cur = cur.next
        return count

    def traversal(self):
        """遍歷雙向鏈表"""
        cur = self.head
        if self.is_empty():
            print("鏈表爲空!")
            return
        while cur is not None:
            print(cur.data)
            cur = cur.next

    def node_is_exist(self, data):
        """查找指定結點是否存在"""
        cur = self.head
        while cur is not None:
            if cur.data == data:
                return True
            else:
                cur = cur.next
        return False

    def add_first(self, data):
        """在頭部添加結點"""
        node = Node(data)
        if self.is_empty():
            self.head = node
        else:
            # 新結點向後指向頭結點
            node.next = self.head
            # 頭結點向前指向新結點
            self.head.pre = node
            # 將頭結點的稱號給新結點
            self.head = node

    def add_last(self, data):
        """在尾部添加結點"""
        node = Node(data)
        if self.is_empty():
            self.head = node
        else:
            cur = self.head
            # 指針移動到尾部
            while cur.next is not None:
                cur = cur.next
            # 尾結點的後繼指針指向新結點
            cur.next = node
            # 新結點的前驅指針指向尾結點
            node.pre = cur

    def insert_node(self, index, data):
        """在指定位置添加結點"""
        if index < 0 or index > self.length():
            print("結點位置錯誤!")
            return False
        elif index == 0:
            self.add_first(data)
        elif index == self.length():
            self.add_last(data)
        else:
            node = Node(data)
            cur = self.head
            pres = None
            count = 0
            # 移動到要添加的位置
            while count < index:
                pres = cur
                cur = cur.next
                count += 1
            # 新結點和它前面的結點互指
            pres.next = node
            node.pre = pres
            # 新結點和它後面的結點互指
            node.next = cur
            cur.pre = node

    def remove_node(self, data):
        """刪除指定結點"""
        if self.is_empty():
            print("刪除失敗,鏈表爲空!")
            return False
        elif data == self.head.data:
            self.head.next.pre = None
            self.head = self.head.next
        else:
            cur = self.head
            # 移動到要刪除結點的位置
            while cur.data != data:
                cur = cur.next
            # 當前結點的後繼結點爲空,說明是尾結點
            if cur.next is None:
                cur.pre.next = None
                cur.pre = None
            else:
                cur.pre.next = cur.next
                cur.next.pre = cur.pre


if __name__ == '__main__':
    lists = CreateDoubleLinkedList()
    lists.add_last(3)
    lists.add_first(2)
    lists.add_first(1)
    lists.add_last(5)
    lists.insert_node(3, 4)
    lists.traversal()
    print("鏈表是否爲空:", lists.is_empty())
    print("獲取鏈表長度:", lists.length())
    print("改結點是否存在:", lists.node_is_exist(2))
    lists.remove_node(1)
    lists.remove_node(5)
    print("刪除結點之後的遍歷:")
    lists.traversal()

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章