`
xp9802
  • 浏览: 1204922 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

检测单向链表是否存在环

 
阅读更多

问题描述:在单向链表中,每个结点都包含一个指向下一个结点的指针,最后一个结点的这个指针被设置为空。但如果把最后一个结点的指针指向链表中存在的某个结点,就会形成一个环,在顺序遍历链表的时候,程序就会陷入死循环。我们的问题就是,如何检测一个链表中是否有环,如果检测到环,如何确定环的入口点(即求出环长,环前面的链长)。

一种比较耗空间的做法是,从头开始遍历链表,把每次访问到的结点(或其地址)存入一个集合(hashset)或字典(dictionary),如果发现某个结点已经被访问过了,就表示这个链表存在环,并且这个结点就是环的入口点。这需要O(N)空间和O(N)时间,其中N是链表中结点的数目。

如果要求只是用O(1)空间、O(N)时间,应该怎么处理呢?

其实很简单,想象一下在跑道上跑步:两个速度不同的人在操场跑道上一圈一圈地跑,他们总会有相遇的时候。因此我们只需要准备两个指针,同时从链表头出发,一个每次往前走一步,另一个每次往前走两步。如果链表没有环,那么经过一段时间,第二个(速度较快的)指针就会到达终点;但如果链表中有环,两个指针就会在环里转圈,并会在某个时刻相遇。

大家也许会问,这两个指针要在环里转多少圈才能相遇呢?会不会转几千几万圈都无法相遇?实际上,第一个(速度慢的)指针在环里转满一圈之前,两个指针必然相遇。不妨设环长为L,第一个指针P1第一次进入环时,第二个指针P2在P1前方第a个结点处(0 < a < L),设经过x次移动后两个指针相遇,那么应该有0 + x = a + 2x (mod L),显然x = L - a。下面这张图可以清晰地表明这种关系,经过x = L - a次移动,P1向前移动了L - a个位置(相当于后退了a),到达P1′处,而P2向前移动了2L - 2a个位置(相当于后退了2a),到达P2′处,显然P1′和P2′是同一点。

慢指针(P1)转一周之内,必然与快指针(P2)相遇

在知道链表内有环后,求环长是一件非常简单的事情,只要从刚才那个相遇点开始,固定P2,继续移动P1,直到P1与P2再次相遇,所经过的步数就是环长。

怎么求环前面那段子链的长度呢?很简单,让P1和P2都回到链表起点,然后让P2先往前走L次(每次往前走一步),然后P1和P2再同时往前走,当它们再次相遇时,P1所走的步数就是环前面的子链长度。

算法示意:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
def CheckRing(head):
  l1 = 0  # length of the chain before the ring
  l2 = 0  # length of the ring

  # Check if there is a ring.
  pos1 = head
  pos2 = head
  while pos2 and pos2.next:
    pos1 = pos1.next
    pos2 = pos2.next.next
    l1 += 2
    if pos2 and pos1 == pos2:
      l2 = 1
      break
  if not l2:
    if pos2: l1 += 1
    return (l1, l2)  # l2 should be 0

  # Calc the length of the ring.
  pos1 = pos2.next
  while pos1 != pos2:
    pos1 = pos1.next
    l2 += 1

  # Calc the length of the chain before the ring.
  l1 = 0
  pos1 = head
  pos2 = head
  for i in xrange(l2):
    pos2 = pos2.next
  while pos1 != pos2:
    pos1 = pos1.next
    pos2 = pos2.next
    l1 += 1
  return (l1, l2)

转载 http://www.gocalf.com/blog/circle-of-link-list.html

分享到:
评论

相关推荐

    算法:给定一个链表,判断链表中是否存在环

    快慢指针算法是一种用于检测链表中是否存在环的有效方法,也称为“龟兔赛跑”算法。这种方法使用两个指针,一个快指针(每次移动两步),一个慢指针(每次移动一步)。 - **初始化**:将快慢指针都指向链表头结点。...

    python判断单向链表是否包括环,若包含则计算环入口的节点实例分析

    本篇文章将深入探讨如何判断单向链表是否包含环,并在存在环的情况下计算环的入口节点。 判断链表中是否存在环的典型方法是使用快慢指针。快慢指针的初始位置都是链表的头节点。快指针每次移动两个节点,而慢指针...

    实用单向链表的基本操作函数24个C语言版

    13. **判断链表是否有环**:使用快慢指针(Floyd's Cycle-Finding Algorithm)来检测链表中是否存在环。 14. **找到环的起始节点**:如果链表有环,可以进一步找到环的起始节点。 15. **节点交换**:交换链表中两...

    双指针法判断链表有环-Java 版

    如果链表中存在环,那么快指针最终会追上慢指针。 在这段代码中,Node类定义了链表的节点,LinkedList类包含一个head节点,代表链表的头。hasCycle方法实现了环检测的逻辑。在Main类中,我们创建了一个链表,并故意...

    编程判断两个链表是否相交

    本篇文章将详细探讨如何判断两个单向链表是否相交的问题,以及相应的解决方案。 #### 问题背景 在实际应用中,尤其是在大型系统开发过程中,可能会遇到两个链表相交的情况。例如,当两个链表共享部分节点时,如果不...

    实验二 链表基本操作的实现

    8. 判断链表环:通过快慢指针(一个每次移动一步,另一个每次移动两步)来检测链表是否存在环。 在完成实验过程中,你可能需要用到C、C++或Python等编程语言。对于这些语言,了解如何声明和操作指针是至关重要的。...

    快慢指针法判断单链表有环

    如果链表中存在环,那么快指针最终会追上慢指针。 Node类定义了链表的节点,LinkedList类包含一个head节点,代表链表的头。hasCycle方法实现了环检测的逻辑。在Main类中,我们创建了一个链表,并故意引入了一个环...

    链表 简单 链表 操作

    8. **判断链表环**:检测链表中是否存在环,可以使用快慢指针(Floyd判圈法)。 在C和C++中实现这些操作,主要涉及指针操作和内存管理。由于链表节点在内存中可能分散,因此需要注意内存泄漏问题,适时释放不再使用...

    1_12313212313链表.7z

    7. **链表的环形检测**:判断链表是否有环,可以使用快慢指针(Floyd判圈法),快指针每次前进两步,慢指针每次前进一步,如果存在环,它们最终会在环内相遇。 8. **链表的排序**:链表可以使用各种排序算法进行...

    js代码-FindFirstNodeJS 寻找链表的头节点,每个节点,有 id 和 nextId 两个属性,nextId 表示指向节点 id。现在请实现一个办法寻找该链表的头节点。 PS. 考虑一下链表环状,以及节点不在链表内等异常情况,出现异常时,打印异常消息即可。

    如果链表存在环,两个指针最终会在环内相遇。如果遇到环,需要跳出循环并返回`head`,因为在这种情况下,没有明确的头节点。 4. **检查异常情况**: 如果遍历完成后栈为空,说明输入的节点数组为空,应打印异常消息...

    数据结构笔试面试汇总.doc

    **解题思路**:根据题目要求,我们需要设计一个算法来判断单向链表是否包含环,并且该算法需要满足内存使用量是固定的,不会随着链表长度的变化而变化。常见的解决方案有两种:快慢指针法和哈希表法。但由于题目要求...

    LinkedListProblems

    4. 判断链表环:检测链表中是否存在环。 5. 反转链表:反转整个链表。 6. 删除重复节点:移除链表中的重复节点,保持原始顺序。 解决这些问题需要理解链表的内在工作原理,并熟练运用递归、迭代等算法设计技巧。在...

    2_链表_求la和lb的交集_源码.zip

    链表分为单向链表和双向链表,其中单向链表只能向前遍历,而双向链表则可以向前或向后遍历。 求两个链表的交集是一个常见的编程问题,通常有以下几种解决方法: 1. **双指针法**:如果链表长度已知或可以预先计算...

    计算机语言c++

    ### 如何判断链表中是否存在环 在链表数据结构中,判断链表中是否存在环是一个常见的问题。给定的代码示例通过使用快慢指针的方法来检测环的存在。具体步骤如下: 1. 首先检查链表是否为空或仅包含一个节点,如果...

    常考的数据结构题_面试常用

    **解决方法**:通常采用快慢指针的方法来检测链表中是否存在环。具体步骤如下: 1. **定义两个指针**:`p1` 和 `p2`,初始都指向链表的头部。 2. **移动指针**:`p1` 每次移动一步,而 `p2` 每次移动两步。 3. **...

    腾讯校园招聘笔试题技术类C语言.pdf

    8. **判断单向链表是否有环**: - 使用快慢指针(Floyd算法),快指针每次移动两个节点,慢指针每次移动一个节点。如果存在环,快指针最终会追上慢指针;若不存在环,快指针会先到达链表尾部。 9. **判断字符串...

    java程序员最可能被考到的面试题.pdf,这是一份不错的文件

    - 检测链表环:同样使用双指针,一个每步走一个节点,另一个每步走两个节点,相遇则存在环。 - 找到链表倒数第三个元素:用两个指针,先让一个指针走三步,然后两个一起走,当先走的指针到末尾时,另一个指针指向...

    数据结构面试大全

    一种常用且较为高效的算法是使用“快慢指针”方法来检测链表中是否存在环。具体步骤如下: 1. **初始化两个指针** `p1` 和 `p2`,并让它们都指向链表头节点 `head`。 2. **移动指针**:在每一轮循环中,`p1` 向前...

    数据结构笔试面试题目汇总

    本篇文章将围绕链表这一核心数据结构,讨论如何判断单向链表是否存在环路,并提供一种算法实现。此外,还将探讨C语言中的指针操作,通过标准库函数的源代码来加深理解。 1. **链表环路检测**: 在单向链表中,环路...

    0722_部分解题.rar

    5. **环形链表**:检测链表中是否存在环,如Floyd判圈法(快慢指针)或使用栈进行模拟。 6. **合并两个有序链表**:将两个已排序的链表合并成一个有序链表。这通常通过比较两个链表的当前节点并选择较小的一个来...

Global site tag (gtag.js) - Google Analytics