概念

單鏈表的一個變形是單向迴圈連結串列,連結串列中最後一個節點的next域不再為None,而是指向連結串列的頭節點。

節點包含兩個域:元素域和連結域(下一個節點),尾節點next指向第0個節點,當連結串列只有一個節點時,自己的next指向自己,基於單鏈表的基礎上,增加考慮首節點和尾節點的情況。

結構

python程式碼實現

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

class CycleLinkList(object):
    def __init__(self):
        self.head = None


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


    def length(self):
        """連結串列長度"""
        if self.is_empty():
            return 0
        cur = self.head
        n = 1
        while cur.next != self.head:
            n += 1
            cur = cur.next
        # 至此除了尾節點外,所有節點都被數了一次

        return n

    def travel(self):
        """遍歷整個連結串列"""
        if self.is_empty():
            return

        cur = self.head
        while cur.next != self.head:
            print(cur.item,end="->")
            cur = cur.next
        # 至此,cur指向尾節點,cur本身還未被列印
        print(cur.item)


    def add(self, item):
        """連結串列頭部新增元素"""
        node = Node(item)
        # 若沒有尾節點(連結串列為空),head指向新節點,新節點next指向自己
        if self.is_empty():
            self.head = node
            node.next = node
        else:
            # 1 找到尾節點cur
            cur = self.head
            while cur.next != self.head:
                cur = cur.next
            # 至此,cur指向尾節點
            #2 新節點next指向原首節點
            node.next = self.head
            #3 head指向新節點
            self.head = node
            #4 尾節點next指向新節點
            cur.next = node



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

        # 若連結串列為空,則直接頭部新增
        if self.is_empty():
            self.add(item)
            return

        # 1 遍歷查詢尾節cur
        cur = self.head
        while cur.next != self.head:
            cur = cur.next
        # 至此cur指向當前連結串列的尾節點
        # 2 cur的next指向新節點
        node = Node(item)
        cur.next = node
        # 3 新節點next指向首節點
        node.next = self.head


    def insert(self, pos, item):
        """指定位置新增元素"""
        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

    def remove(self, item):
        """刪除節點"""
        if self.is_empty():
            return
        cur = self.head
        pre = None
        # 1 遍歷查詢找到待刪節點並記錄前一個節點
        while cur.next != self.head:
            if cur.item == item:
                # 2 若有前一個節點,pre的next指向cur的next
                if pre is not None:
                    pre.next = cur.next
                else:
                    # 否則(待刪節點是首節點),
                    # 1)遍歷查詢尾節點tail
                    tail = self.head
                    while tail.next != self.head:
                        tail = tail.next
                    # 2) head指向cur的next
                    self.head = cur.next
                    # 3) tail的next指向head
                    tail.next = self.head
                return
            pre = cur
            cur = cur.next
        # 至此cur指向尾節點,尾節點還未判斷是否是待刪節點
        # 3 判斷尾節點是否是待刪節點
        if cur.item == item:
            # 若有前一個節點,pre的next指向cur的next
            if pre is not None:
                pre.next = cur.next
            # 否則(待刪節點是連結串列唯一節點),head指向None
            else:
                self.head = None

    def search(self, item):
        """查詢節點是否存在"""
        if self.is_empty():
            return False

        cur = self.head
        while cur.next != self.head:
            if cur.item == item:
                return True
            cur = cur.next
        # 至此,除了尾節點外所有節點都找過了,還沒找到
        # 判斷尾節點是否是待查節點
        if cur.item == item:
            return True
        return  False

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

複雜度

迴圈連結串列頭部新增O(n),迴圈連結串列尾部新增O(n),迴圈連結串列中間位置新增O(n),迴圈連結串列刪除O(n)。