1.6python如何检测一个较大单链表是否有环

题目描述:

单链表有环指的是单链表中某个结点的next指针域指向的是链表中在它之前的某一个结点,这样在链表的尾部形成一个环形结构。如何判断单链表是否有环存在?

方法:

1. 蛮力法
定义一个HashSet来存放结点的引用,并将其初始化为空,从链表的头结点开始遍历,每遍历到一个结点就判断HashSet中是否有这个结点的引用。如果没有,说明这个点是第一次访问,还没有形成环,那么将这个结点的引用添加到指针HashSet中;如果在HashSet中找到了同样的结点,那么说明这个结点已经被访问过了,于是就形成了环。这种方法的时间复杂度为O(n),空间复杂度也为O(n)
2. 快慢指针遍历法
定义两个指针 fast 和 slow ,二者的初始值都指向链表头,指针 slow 每次前进一步,指针 fast 每次前进两步,两个指针同时向前移动,快指针每移动一次都要跟慢指针比较,如果快指针等于慢指针,就证明这两个链表是带环的单向链表;否则证明这个链表不是带环的循环链表。实现代码见后面引申部分。

引申:

如果链表存在环,那么如何找出环的入口点?

思路:
当链表有环的时候,如果知道环的入口点,那么在需要遍历链表或释放链表所占空间的时候方法将会非常简单,下面主要介绍查找链表环入口点的思路:
如果单链表有环,那么按照上述方法二的思路,当走的快的指针 fast 与走的慢的指针 slow 相遇时,slow 指针肯定没有遍历完链表,而 fast 指针已经在环内循环了n ( n>=1 ) 圈。如果 slow 指针走了 s 步,则 fast 指针走了 2s 步( fast 步数还等于 s 加上在环上多转的 n 圈),设环的长度为 r,则满足下述关系表达式:
2s = s + nr,即得到 s = nr
设整个链表长度为 L ,入口环与相遇点距离 x,起点到环入口点的距离为 a,则满足下列关系表达式:
a + x = nr
a + x = (n-1)r +r = (n-1)r + L - a
a = (n-1)r + (L - a - x)
(L-a-x)为相遇点到环入口点的距离,从链表头到环入口点的距离=(n-1)*环长+相遇点到环入口点的长度,于是从链表头与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点

算法性能分析:
这种方法只需要对链表进行一次遍历,因此,时间复杂度为O(n);
另外由于只需要几个指针变量来保存结点的地址信息,所以空间复杂度为O(1)

实现代码如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time    : 2020/1/16 21:35
# @Author  : buu
# @Software: PyCharm
# @Blog    :https://blog.csdn.net/weixin_44321080
class LNode:
    def __init__(self, data=None, next=None):
        self.data = data
        self.next = next


def ConstructList():
    """
    构造一个带环的单链表
    :return: 链表的头结点
    """
    i = 1
    head = LNode()
    tmp = None
    cur = head
    while i < 8:
        tmp = LNode(i)
        cur.next = tmp
        cur = tmp
        i += 1
    cur.next = head.next.next.next  # 构造环
    return head


def isLoop(head):
    """
    判断单链表是否有环
    :param head: 头结点
    :return: None: 无环,否则返回slow与fast相遇点的结点;
    """
    if head is None or head.next is None:
        return None
    slow = head.next
    fast = head.next  # 初始时fast与slow都指向链表的第一个结点
    while fast is not None and fast.next is not None:
        slow = slow.next
        fast = fast.next.next
        if slow == fast:
            return slow
    return None


def findLoopNode(head, meetNode):
    """
    找出环的入口点
    :param head: 头结点
    :param meetNode: 快慢指针相遇的结点
    :return: None:无环,否则返回slow与fast指针相遇点的结点
    """
    first = head.next
    second = meetNode
    while first != second:
        first = first.next
        second = second.next
    return first


if __name__ == '__main__':
    head = ConstructList()
    cur = head.next
    i = 0
    print('lindedList:', end=' ')
    while i < 7:
        print(cur.data, end='->')
        cur = cur.next
        i += 1
    print(cur.data, end='')
    meetNode = isLoop(head)
    loopNode = None
    if meetNode != None:
        print('\nhas loop!')
        loopNode = findLoopNode(head, meetNode)
        print('entry:' + str(loopNode.data))
    else:
        print('no loop!')

结果:
在这里插入图片描述
end

发布了76 篇原创文章 · 获赞 2 · 访问量 2577

猜你喜欢

转载自blog.csdn.net/weixin_44321080/article/details/104010975
今日推荐