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)

运行结果:

带环单链表


无环单链表

原文地址:https://www.cnblogs.com/miao-study/p/11477450.html

时间: 2024-10-08 02:23:05

1.6带环单链表的相关文章

带环单链表

判断单链表是否带环: 定义两个快慢指针,快指针每次走两步,慢指针每次走一步,然后判断是否两个指针相遇.若相遇,则带环. 设慢指针走过的路程为s,则快指针走过的路程即为2s. 设从环头结点到环的入口点的距离为a. 设从环的入口点到两指针相遇点的距离为x. 设环的长度为m.快指针走了n圈. 由数学关系式可得:s = a + x    2s = a + n*m + x; 则  n*m = a + x; a = n*m - x; 求环的入口点方法:定义连个指针,一个指针从环的头结点开始走,另一个指针则从

Python与数据结构[0] -> 链表[0] -> 单链表与带表头单链表的 Python 实现

单链表 / Linked List 目录 单链表 带表头单链表 链表是一种基本的线性数据结构,在C语言中,这种数据结构通过指针实现,由于存储空间不要求连续性,因此插入和删除操作将变得十分快速.下面将利用Python来完成单链表的实现. 1 单链表 不带表头的单链表通常形式如下, node_1 -> node_2 -> node_3 -> node_4 完整代码 1 class Node: 2 def __init__(self, val=None, nxt=None): 3 self.v

求有环单链表中的环长、环起点、链表长

1.判断单链表是否有环 使用两个slow, fast指针从头开始扫描链表.指针slow 每次走1步,指针fast每次走2步.如果存在环,则指针slow.fast会相遇:如果不存在环,指针fast遇到NULL退出. 就是所谓的追击相遇问题: 2.求有环单链表的环长 在环上相遇后,记录第一次相遇点为Pos,之后指针slow继续每次走1步,fast每次走2步.在下次相遇的时候fast比slow正好又多走了一圈,也就是多走的距离等于环长. 设从第一次相遇到第二次相遇,设slow走了len步,则fast走

寻找带环的链表的柄长

试题:给定一个带环的链表,找出环起点.比如:A -> B -> C -> D -> E -> C (C为环形起点)写一个程序找出环起点C. ListNode结构如下,请实现 ListNode* find_circle_beginning(ListNode* head);函数,返回环的起点. struct ListNode { char val; ListNode* next; }; 答案: 1.先用快指针(每次走两步)和慢指针(每次走一步),遍历链表,当两个指针相遇时,说明该

1.11判断两个无环单链表是否相交

判断两个无环单链表是否交叉 题目描述: 如上图,这两个链表相交于结点5,要求判断两个链表是否相交,如果相交,找出相交处的结点. 解题思路: 方法一:Hash 法 如上图所示,如果两个链表相交,那么它们一定会有公共的结点,由于结点的地址或引用可以作为结点的唯一标识,因此,可以通过判断两个链表中的结点是否有相同的地址或引用来判断链表是否相交. 方法二:首尾相接法 将这两个链表首尾相连(例如把链表headl尾结点链接到head2的头指针),然后检测这个链表是否存在环,如果存在,则两个链表相交,而环入口

有环单链表

单链表有环的情况如上图所示,循环链表也属于有环的链表. 这里我们使用追逐法判断一个链表是否有环:设置两个指针slow和fast从头节点开始,slow每次移动一个节点,fast每次移动两个节点,如果fast遇到了NULL则表明链表没有环,停止循环.如果链表有环的话,那么这两个指针总会在某个位置相遇,相遇后停止循环.代码如下: 1 //追逐法判断链表是否有环 2 bool has_loop(){ 3 Node<Type> *fast=head,*slow=head; 4 //fast一定是走在前面

leetcode链表--6、linked-list-cycle-ii(有环单链表环的入口结点)

题目描述 Given a linked list, return the node where the cycle begins. If there is no cycle, returnnull. Follow up: Can you solve it without using extra space? 解题思路: 1.确定环中结点的数目(快慢指针确定环中结点,然后遍历到下一次到该节点确定数目n) 2.一个指针先走n步,一个指针指向头结点 3.然后两个指针一起走 4.相遇点为入口点 1 /*

判断单链表是否有环以及环的连接点

给定一个单链表,只给出头指针h: 1.如何判断是否存在环? 2.如何知道环的长度? 3.如何找出环的连接点在哪里? 4.带环链表的长度是多少? 解法: 1.对于问题1,使用追赶的方法,设定两个指针slow.fast,从头指针开始,每次分别前进1步.2步.如存在环,则两者相遇:如不存在环,fast遇到NULL退出. 2.对于问题2,记录下问题1的碰撞点p,slow.fast从该点开始,再次碰撞所走过的操作数就是环的长度s. 3.问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分

如何判断单链表是否存在环

原文:http://blog.csdn.net/liuxialong/article/details/6555850 如何判断单链表是否存在环 给定一个单链表,只给出头指针h: 1.如何判断是否存在环? 2.如何知道环的长度? 3.如何找出环的连接点在哪里? 4.带环链表的长度是多少? 解法: 1.对于问题1,使用追赶的方法,设定两个指针slow.fast,从头指针开始,每次分别前进1步.2步.如存在环,则两者相遇:如不存在环,fast遇到NULL退出. 2.对于问题2,记录下问题1的碰撞点p,