真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

5.雙鏈表

1.單鏈表的缺點:

公司專注于為企業(yè)提供成都網(wǎng)站設(shè)計、成都網(wǎng)站建設(shè)、微信公眾號開發(fā)、商城網(wǎng)站制作,重慶小程序開發(fā),軟件按需定制等一站式互聯(lián)網(wǎng)企業(yè)服務(wù)。憑借多年豐富的經(jīng)驗,我們會仔細(xì)了解各客戶的需求而做出多方面的分析、設(shè)計、整合,為客戶設(shè)計出具風(fēng)格及創(chuàng)意性的商業(yè)解決方案,創(chuàng)新互聯(lián)公司更提供一系列網(wǎng)站制作和網(wǎng)站推廣的服務(wù)。

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

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

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

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

5.雙鏈表

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

同樣root節(jié)點也有一個prev和next,root節(jié)點的next指向head節(jié)點,head節(jié)點的prev指向root節(jié)點,這樣就能實現(xiàn)一個雙端鏈表。

5.雙鏈表

循環(huán)雙端鏈表:

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

雙鏈表的屬性:

                             

                data {    root          有個根節(jié)點

                              maxsize    控制它的最大長度

                              length      記錄長度的屬性

雙鏈表

                method {    headnode    獲取頭節(jié)點的方法

                                   tailnode       獲取尾節(jié)點的方法

                                   append        最后添加新節(jié)點

                                   appendleft   在頭節(jié)點前面,根節(jié)點后面添加新節(jié)點

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

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

                                   iter_node     遍歷節(jié)點的操作

                                   iter_node_reverse      反向遍歷節(jié)點的操作

實現(xiàn)方式:

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()                        #這兩行代碼,用于構(gòu)建一個根節(jié)點,
        node.next, node.prev = node, node   #這個根節(jié)點是自己指向自己的默認(rèn)是一個閉環(huán)。
        self.root = node                    #把node賦值給根節(jié)點
        self.length = 0                     #長度屬性默認(rèn)是0,root節(jié)點是不計算在鏈表長度里面的

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

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

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

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

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

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

    def appendleft(self, vlaue):
        if self.maxsize is not None \
            and len(self) > self.maxsize:       #判斷是否已經(jīng)超長,如果是就報異常。
            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               #新節(jié)點的next和prev都指向root節(jié)點,形成一個閉環(huán)。
            self.root.next = node               #同理,將root節(jié)點的next指向新節(jié)點
            self.root.prev = node               #將root節(jié)點的prev指向新節(jié)點
        else:                                   #否則,如果鏈表不是空的話
            headnode = self.root.next           #定義root節(jié)點的next節(jié)點是鏈表的頭節(jié)點
            node.prev = self.root               #將新節(jié)點的prev指向root節(jié)點
            node.next = headnode                #將新節(jié)點的next指向原頭節(jié)點
            headnode.prev = node                #最后將頭節(jié)點的prev指向新節(jié)點
        self.length += 1                        #鏈表長度加1

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

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

    def iter_node_reverse(self):
        if self.root.prev is self.root:
            return
        curnode = self.root.prev                #和正向遍歷相反,這個是tailnode節(jié)點
        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()           #取頭節(jié)點
    assert headnode.value == 0          #斷言頭節(jié)點的值為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]

執(zhí)行測試:

# pytest double_link_list.py

平均時間復(fù)雜度:

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

網(wǎng)站名稱:5.雙鏈表
瀏覽路徑:http://weahome.cn/article/pjspci.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部