中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

5.雙鏈表

發布時間:2020-05-10 22:43:43 來源:網絡 閱讀:407 作者:聽丶飛鳥說 欄目:編程語言

1.單鏈表的缺點:

(1)remove操作要從頭到尾遍歷,時間復雜度是O(n)

(2)只能單向遍歷,不能反向遍歷


2.使用雙鏈表可以克服以上兩個缺點

雙鏈表相對于單鏈表來說,雙鏈表的節點(Node)多了一個指針:

5.雙鏈表

這樣一來就能指向前一個節點,而且也可以指向后一個節點。


同樣root節點也有一個prev和next,root節點的next指向head節點,head節點的prev指向root節點,這樣就能實現一個雙端鏈表。

5.雙鏈表

循環雙端鏈表:

比如要反向遍歷的時候,都是從root節點作為一個入口,把root節點的prev反過來指向tail節點,這樣就能實現從頭向尾節點遍歷,然后從root節點的prev反過來指向上一個節點,對比正向遍歷從next指向下一個節點,這樣就實現循環雙端鏈表。


雙鏈表的屬性:

                             

                data {    root          有個根節點

                              maxsize    控制它的最大長度

                              length      記錄長度的屬性

雙鏈表

                method {    headnode    獲取頭節點的方法

                                   tailnode       獲取尾節點的方法

                                   append        最后添加新節點

                                   appendleft   在頭節點前面,根節點后面添加新節點

                                   remove        刪除節點,時間復雜度為O(1);

                                                       比如,有3個節點,要刪除中間節點,就可以讓前面和后面節點互指,最后再del掉中間的節點。

                                   iter_node     遍歷節點的操作

                                   iter_node_reverse      反向遍歷節點的操作



實現方式:

class Node(object):
    def __init__(self, value=None, prev=None, next=None):
        self.value, self.prev, self.next = value, prev, next

class CircualDoubleLinkedList(object):
    def __init__(self, maxsize=None):
        self.maxsize = maxsize
        node =Node()                        #這兩行代碼,用于構建一個根節點,
        node.next, node.prev = node, node   #這個根節點是自己指向自己的默認是一個閉環。
        self.root = node                    #把node賦值給根節點
        self.length = 0                     #長度屬性默認是0,root節點是不計算在鏈表長度里面的

    def __len__(self):
        return self.length                  #返回長度值

    def headnode(self):                     #定義頭節點
        return self.root.next               #也就是root節點的下一個節點

    def tailnode(self):                     #定義尾節點
        return self.root.prev               #也就是root節點的上一個節點

    """
        假設有一條幾個節點的鏈表,插入一個新的節點前,要先構造這個新的節點,
        然后再讓鏈表原來尾節點的next指向新節點,并且新節點的prev指向原來的
        尾節點,root節點的prev也要指向新節點,新節點的next指向root節點,
        這樣就形成了一個閉環,實現了append新增節點。
    """
    def append(self, value):
        if self.maxsize is not None \
            and len(self) > self.maxsize:       #判斷是否已經超長,如果是就報異常。
            raise Exception("The LinkedList is Full")
        node = Node(value=value)                           #構造新節點
        tailnode = self.tailnode()              #尾節點

        tailnode.next = node                    #尾節點的next指向新節點
        node.prev = tailnode                    #新節點的prev指向尾節點
        node.next = self.root                   #新節點的next指向root節點
        self.root.prev = node                   #root節點的prev指向新節點

        self.length += 1                        #最后將長度+1

    def appendleft(self, vlaue):
        if self.maxsize is not None \
            and len(self) > self.maxsize:       #判斷是否已經超長,如果是就報異常。
            raise Exception("The LinkedList is Full")
        node = Node(value=vlaue)
        if self.root.next is self.root:         #判斷這個鏈表是空的情況
            node.next = self.root
            node.prev = self.root               #新節點的next和prev都指向root節點,形成一個閉環。
            self.root.next = node               #同理,將root節點的next指向新節點
            self.root.prev = node               #將root節點的prev指向新節點
        else:                                   #否則,如果鏈表不是空的話
            headnode = self.root.next           #定義root節點的next節點是鏈表的頭節點
            node.prev = self.root               #將新節點的prev指向root節點
            node.next = headnode                #將新節點的next指向原頭節點
            headnode.prev = node                #最后將頭節點的prev指向新節點
        self.length += 1                        #鏈表長度加1

    def remove(self, node):                     #node是要刪除的節點,是O(1)的時間復雜度,注意是node不是value
        if node is self.root:                   #如果只有根節點,啥都不返回
            return
        else:                                   #否則是非根節點
            node.prev.next = node.next          #將要刪除節點的前一個節點的next指針指向要刪除節點的下一個節點
            node.next.prev = node.prev          #將要刪除節點的后一個節點的prev指針指向要刪除節點的上一個節點
        self.length -= 1                        #鏈表長度-1
        return node                             #返回刪除的節點

    def iter_node(self):                        #遍歷節點
        if self.root.next is self.root:         #防止鏈表是空的
            return
        curnode = self.root.next                #否則,不是空的,從頭開始遍歷
        while curnode.next is not self.root:    #當curnode不是尾節點
            yield curnode                       #一直把curnode節點給yield出來
            curnode = curnode.next              #更新curnode節點,讓curnode一直往下一個節點走
        yield curnode                         #最后別忘了把最后一個curnode給yield出來
                                                #因為遍歷到最后一個節點,但并沒有去yield這個節點
                                                #當while循環終止時,當前curnode已經到達了tailnode節點,
                                                #所以要把它yield出來才完整。

    def iter_node_reverse(self):
        if self.root.prev is self.root:
            return
        curnode = self.root.prev                #和正向遍歷相反,這個是tailnode節點
        while curnode.prev is not self.root:
            yield curnode
            curnode = curnode.prev              #前移
        yield curnode



#單元測試
def test_double_link_list():
    dll = CircualDoubleLinkedList()
    assert len(dll) == 0
    dll.append(0)
    dll.append(1)
    dll.append(2)
    assert list(dll) == [0, 1, 2]
    assert [node.value for node in dll.iter_node_reverse()] == [2, 1, 0]
    assert [node.value for node in dll.iter_node()] == [0, 1, 2]
    headnode = dll.headnode()           #取頭節點
    assert headnode.value == 0          #斷言頭節點的值為0,因為0是第一個被添加的
    dll.remove(headnode)                #O(1)
    assert len(dll) == 2
    assert [node.value for node in dll.iter_node()] == [1, 2]
    dll.appendleft(0)
    assert [node.value for node in dll.iter_node()] == [0, 1, 2]


執行測試:

# pytest double_link_list.py


平均時間復雜度:

循環雙端鏈表操作平均時間復雜度
cdll.append(value)O(1)
cdll.appendleft(value)O(1)
cdll.remove(node),注意這里參數是 nodeO(1)
cdll.headnode()O(1)
cdll.tailnode()O(1)


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

陆河县| 泗水县| 宁德市| 烟台市| 卢氏县| 龙泉市| 马尔康县| 荣昌县| 丰镇市| 军事| 方城县| 清水县| 舒城县| 武定县| 岢岚县| 沾化县| 黄平县| 武威市| 溧水县| 封丘县| 十堰市| 来凤县| 扬中市| 安庆市| 高邮市| 元江| 广南县| 广元市| 田阳县| 益阳市| 永新县| 陈巴尔虎旗| 南安市| 塘沽区| 临湘市| 扬中市| 横山县| 阳谷县| 万州区| 荃湾区| 福清市|