avatar

目录
判断一个链表是否有环

问题描述

怎么能够更高效地判断一个链表是否有环?

首先创建两个指针p1和p2(在Java里就是两个对象引用),让它们同时指向这个链表的头节点。

然后开始一个大循环,在循环体中,让指针p1每次向后移动1个节点,让指针p2每次向后移动2个节点,然后比较两个指针指向的节点是否相同。如果相同,则可以判断出链表有环,如果不同,则继续下一次循环。

复杂度分析

假设链表的节点数量为n,则该算法的时间复杂度为O(n)。

除两个指针外,没有使用任何额外的存储空间,所以空间复杂度是O(1)

代码实现

java
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
36
37
38
39
40
41
42
43
44
45
public class LinkedListCycle {

/**
* 判断是否有环
* @param head 链表头节点
*/
public static boolean isCycle(Node head) {
Node p1 = head;
Node p2 = head;
while (p2!=null && p2.next!=null){ // 【注意】
p1 = p1.next;
p2 = p2.next.next;
if(p1 == p2){
return true;
}
}
return false;
}

/**
* 链表节点
*/
private static class Node {
int data;
Node next;
Node(int data) {
this.data = data;
}
}

public static void main(String[] args) throws Exception {
Node node1 = new Node(5);
Node node2 = new Node(3);
Node node3 = new Node(7);
Node node4 = new Node(2);
Node node5 = new Node(6);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
node5.next = node2;

System.out.println(isCycle(node1));
}
}

扩展

如果链表有环,如何求出环的长?

当两个指针首次相遇,证明链表有环的时候,让两个指针从相遇点继续循环前进,并统计前进的循环次数,直到两个指针第2次相遇。此时,统计出来的前进次数就是环长。

因为指针p1每次走1步,指针p2每次走2步,两者的速度差是1步。当两个指针再次相遇时,p2比p1多走了整整1圈因此,环长 = 每一次速度差 × 前进次数 = 前进次数

参考文献

https://www.cnblogs.com/zhaoqingqing/p/11853924.html

文章作者: Yang4
文章链接: https://masteryang4.github.io/2020/08/09/%E5%88%A4%E6%96%AD%E4%B8%80%E4%B8%AA%E9%93%BE%E8%A1%A8%E6%98%AF%E5%90%A6%E6%9C%89%E7%8E%AF/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 MasterYangBlog
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论