1.6帶環單鏈表

檢測單鏈表中是否有環

方法一:蠻力法

定義一個集合用來存放結點的引用,並將其初始化爲空,從鏈表的頭結點開始向後遍歷,每遍歷到一個結點就判斷集合中是否有這個結點的引用,若是沒有,說明這個結點是第一次訪問,尚未造成環,那麼將這個結點的引用添加到集合中去。若是在集合中找到了一樣的結點,那麼說明這個結點已經被訪問過了,因而就造成了環。這種方法的時間複雜度爲O(n),空間複雜度也爲O(n)。node

方法二 : 快慢指針遍歷法

定義兩個指針fast(快)與slow(慢),兩者的初始值都指向鏈表頭,指針slow每次前進一步,指針fast每次前進兩步,兩個指針同時向前移動,快指針每移動一次都要跟慢指針比較,若是快指針等於慢指針,就證實這個鏈表是帶環的鏈表。app

找出環的入口處並解環

若是單鏈表有環,那麼按照上述方法二的思路,當走得快的指針fast與走得慢的指針slow相遇時,slow 指針確定沒有遍歷完鏈表,而fast指針己經在環內循環了n圈 (n>=1)。若是slow 指針走了s步,則fast指針走了2s步,fast步數還等於s加上在環上多轉的n圈,假設環長爲r,則知足以下關係表達式:
2s = s +or
由此能夠獲得 : s=nr
設整個鏈表長爲L,入口環與相遇點距離爲x,起點到環入口點的距離爲a。則知足以下關係表達式:
a+x=nr
a+x=(n-1)r+r=(n-l)r+L-a
a=(n-l)r+(L-ax)
(L-a-x)爲相遇點到環入口點的距離,從鏈表頭到環入口點的距離=(n-l)*環長+相遇點到環入口 點的長度,因而從鏈表頭與相遇點分別設一個指針,每次各走一步,兩個指針一定相遇,且相遇第一點爲環入口點。將相遇點指針的前一個節點的next域設成None便可解環。oop

代碼實現:

# -*-coding:utf-8-*- 
"""
@Author  : 圖南
@Software: PyCharm
@Time    : 2019/9/6 15:28
"""


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


# 構造單鏈表
def con_link(s, k):
    head = Node()
    cur = head
    nums = list(map(int, s.split(' ')))
    k = int(k)
    for num in nums:
        node = Node(num)
        cur.next = node
        cur = node
    tmp = head
    if k != 0:
        for i in range(k):
            tmp = tmp.next
        cur.next = tmp
    return head


# 打印單鏈表(用到方法一中的思想)
def print_link(head):
    if head is None or head.next is None:
        return None
    flag = []
    cur = head.next
    while cur:
        if cur not in flag:
            flag.append(cur)
            print(cur.data, end=' ')
            cur = cur.next
        else:
            print(cur.data, end=' ')
            break
    print()


# 判斷鏈表中是否有環
def isLoop(head):
    if head is None or head.next is None:
        return None
    fast = head.next
    slow = head.next
    while True:
        try:
            fast = fast.next.next
            slow = slow.next
        except Exception:
            print("該鏈表中沒有環!")
            print_link(head)
            return False, head
        if fast == slow:
            print("該鏈表中有環!")
            print_link(head)
            return True, fast


# 查找環的入點口,並解環
def findLoopNode(head, fast):
    cur = head.next
    pre = None
    while cur != fast:
        pre = fast
        cur = cur.next
        fast = fast.next
    print(cur.data)
    # 解環並打印鏈表
    pre.next = None
    print_link(head)


if __name__ == '__main__':
    nums = input('鏈表:')
    # 輸入環的入口點,若爲0則鏈表中無環
    k = input('環的入點口:')
    head = con_link(nums, k)
    f, fast = isLoop(head)
    if f:
        findLoopNode(head, fast)

運行結果:

帶環單鏈表


無環單鏈表

3d

相關文章
相關標籤/搜索