• 1.6带环单链表


    检测单链表中是否有环

    方法一:蛮力法

    定义一个集合用来存放结点的引用,并将其初始化为空,从链表的头结点开始向后遍历,每遍历到一个结点就判断集合中是否有这个结点的引用,如果没有,说明这个结点是第一次访问,还没有形成环,那么将这个结点的引用添加到集合中去。如果在集合中找到了同样的结点,那么说明这个结点已经被访问过了,于是就形成了环。这种方法的时间复杂度为O(n),空间复杂度也为O(n)。

    方法二 : 快慢指针遍历法

    定义两个指针fast(快)与slow(慢),二者的初始值都指向链表头,指针slow每次前进一步,指针fast每次前进两步,两个指针同时向前移动,快指针每移动一次都要跟慢指针比较,如果快指针等于慢指针,就证明这个链表是带环的链表。

    找出环的入口处并解环

    如果单链表有环,那么按照上述方法二的思路,当走得快的指针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即可解环。

    代码实现:

    # -*-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)
    

    运行结果:

    带环单链表


    无环单链表

  • 相关阅读:
    [设计模式]在CodeDom代码生成中使用Decorator模式实现类型创建
    【翻译】防腐层:面向领域驱动设计的更为稳健的系统集成方案
    EntityFramework之领域驱动设计实践【后续篇】:基于EF 4.3.1 Code First的领域驱动设计实践案例
    Apworks框架中各种仓储实现的性能基准测试与结果对比
    CQRS架构中同步服务的一种实现方式
    在Visual Studio 2010中创建多项目(解决方案)模板【三】
    Microsoft NLayerApp案例理论与实践 应用层
    在Visual Studio 2010中创建多项目(解决方案)模板【二】
    小猫奥斯卡
    测试一下又拍网图片外链
  • 原文地址:https://www.cnblogs.com/miao-study/p/11477450.html
Copyright © 2020-2023  润新知