1. 程式人生 > >資料結構(二)雙向連結串列的的分析與python程式碼實現

資料結構(二)雙向連結串列的的分析與python程式碼實現

概念

       每個節點有兩個連結:一個指向前一個節點,當此節點為第一個節點時,指向空值;而另一個指向下一個節點,當此節點為最後一個節點時,指向空值。

特點:
        節點包含三個域,一個元素域,兩個連結域(前驅和後繼),第0個節點沒有前驅,最後一個節點沒有後繼,在單鏈表的基礎上,增加向前指向的考慮。

結構

python程式碼實現 

class Node(object):
    """實現雙向連結串列節點"""
    def __init__(self, item):
        # item存放資料元素
        self.item = item
        # next代表後一個節點
        self.next = None
        # prev代表前一個節點
        self.prev = None


class DoubleLinkList(object):
    """雙向連結串列"""
    def __init__(self):
        # 表示首節點
        self.head = None

    # 連結串列是否為空
    def is_empty(self):
        return self.head is None

    # 連結串列長度
    def length(self):

        # cur初始時指向頭節點
        cur = self.head
        n = 0
        # 當未到達尾節點None時
        while cur is not None:
            n += 1
            # 將cur後移一個節點
            cur =cur.next

        return n

    # 遍歷整個連結串列
    def travel(self):
        cur = self.head
        while cur is not None:
            print(cur.item, end='-')
            cur = cur.next
        # 輸出連結串列
        print()


    # 連結串列頭部新增元素
    def add(self, item):
        # 呼叫Node類,例項node物件
        node = Node(item)

        # 先讓新增加的節點next指向原首節點
        node.next = self.head
        # 然後讓head指向新節點
        self.head = node
        # 原首節點存在時,原首節點向前指向新節點,實現雙向
        if node.next is not None:
            node.next.prev = node



    # 連結串列尾部新增元素
    def append(self, item):

        # 若連結串列為空,則直接在頭部新增
        if self.is_empty():
            self.add(item)
            return
        # 1、連結串列不為空,需要遍歷查詢尾節點
        cur = self.head
        while cur.next is not None:
            cur = cur.next

        # 至此cur指向當前連結串列的尾節點
        # 2、讓cur的next指向新節點
        node = Node(item)
        cur.next = node
        # 3、新節點向前指向cur
        node.prev = cur

    # 指定位置新增元素
    def insert(self, pos, item):
        # 需要對新增的位置進行分類討論
        # 如果新增位置<=0,則直接在頭部新增
        if pos <= 0:
            self.add(item)
        # 位置大於連結串列長度,則直接新增到尾部
        elif pos >= self.length():
            self.append(item)
        else:
            # 1 遍歷查詢待插入位置的前一個節點cur
            cur = self.head
            for i in range(pos-1):
                cur = cur.next
            # 至此,cur指向的就是待插入位置的前一個節點
            # 2 新節點的next指向cur的next
            node = Node(item)
            node.next = cur.next
            # 3 cur的next指向新節點
            cur.next = node
            # 4 新節點的後繼節點向前指向新節點(雙向,向前)
            node.next.prev = node
            # 5 新節點向前指向cur(雙向,向前)
            node.prev = cur

    # 刪除節點
    def remove(self, item):
        # 思路:讓待刪節點的pre(前節點)next指向待刪節點的next
        cur = self.head
        # 1 找到待刪節點並記錄前一個節點
        while cur is not None:
            # 待刪節點不存在也就不用刪了,若存在
            if cur.item == item:
                # 2 若cur有前驅節點則:cur的前驅節點指向cur的後繼節點,越過待刪節點
                if cur.prev is not None:
                    cur.prev.next = cur.next
                # 否則(待刪節點是第0個節點),head指向待刪節點的next
                else:
                    self.head = cur.next
                # 3 若cur有後繼節點,則cur的後繼節點向前指向cur的前驅節點(越過待刪節點)
                if cur.next is not None:
                    cur.next.prev = cur.prev

                return
            cur = cur.next


    # 查詢某個節點是否存在
    def search(self, item):
        cur = self.head
        while cur is not None:
            if cur.item == item:
                return True
            cur = cur.next

        # 沒有找到
        return False


# 測試程式碼
if __name__ == '__main__':
    dl = DoubleLinkList()
    dl.add(1)
    dl.add(2)
    dl.add(3)
    dl.travel()
    # 結果3-2-1-
    dl.append("abc")
    dl.append("def")
    dl.append("ghi")
    dl.travel()
    # 結果3-2-1-abc-def-ghi-
    dl.insert(-1, "xx")
    dl.insert(99, "yy")
    dl.insert(3, "zz")
    dl.travel()
    # 結果xx-3-2-zz-1-abc-def-ghi-yy-
    dl.remove("xx")
    dl.remove("yy")
    dl.remove(1)
    dl.remove(90)
    dl.travel()
    # 結果3-2-zz-abc-def-ghi-
    print(dl.search(3))
    # 結果True
    print(dl.search("zz"))
    # 結果True
    print(dl.search(380))
    # 結果False

複雜度

頭部新增O(1),尾部新增O(n),指定位置新增O(n),

刪除節點:

若cur有前驅節點則:cur的前驅節點指向cur的後繼節點 O(n),否則:head指向cur的後繼節點 O(1)