有环链表如何高效的判断是否有环,以及在何处产生环?
采用2个指针不同步数(步数小的每次1步,步数大的每次2步),步数大的如果能够与步数小的相遇则必然存在环。

![]()
![]()
相遇后的情况如图,假设相遇后步数大的回绕环遍历了n遍,步数小的肯定一遍也没遍历完,假设第一段距离为a,第2段距离为c,第3段距离为b
则有(a+c)*2 = a+n(b+c)+c,转换后得 a = n(b+c) - c,也就是说,从出发点出发,移动a的距离,刚好等于相遇点出发移动n个整圈减c的距离,这个点刚好就是环产生的点,由此可以设置2个指针,分别从根节点与相遇点出发,第一次相遇的地方则是环产生的点。
完成证明后,代码较为简单,如下
package com.xhb.algorithms;
public class MyLinkedList {
private LinkListNode<Integer> root = new LinkListNode<Integer>(null, null);
private int length;
private int point;
/**
* @param args
*/
public static void main(String[] args) {
MyLinkedList list = new MyLinkedList(10045, 232);
System.out.println(list.isHasRound());
System.out.println("the point cut obj is " + list.getCutPoint());
}
/**
* 初始化一个环链表
*/
private MyLinkedList(int length, int point) {
this.length = length;
this.point = point;
LinkListNode<Integer> current = this.root;
for (int i = 1; i <= this.length - 1; i++) {
current = current.next(new LinkListNode<Integer>(new Integer(i),
null));
}
if (this.point < 0) {
current.next(null);
} else {
LinkListNode<Integer> pointObj = this.root;
for (int i = 0; i < point; i++) {
pointObj = pointObj.next();
}
current.next(pointObj);
}
}
public Integer getCutPoint() {
LinkListNode<Integer> seekPoint = this.getSeekPoint();
System.out.println(seekPoint.data());
LinkListNode<Integer> a = this.root;
while (true) {
a = a.next();
seekPoint = seekPoint.next();
if (a == seekPoint) {
return a.data();
}
// System.out.println(a.data() +"," + seekPoint.data());
}
}
private LinkListNode<Integer> getSeekPoint() {
LinkListNode<Integer> a = this.root;
LinkListNode<Integer> b = this.root;
a = a.next();
b = b.next().next();
while (true) {
a = a.next();
b = b.next();
if (b == null) {
return null;
}
if (a == b && b != null) {
return b;
}
b = b.next();
if (b == null) {
return null;
}
if (a == b && b != null) {
return b;
}
}
}
public boolean isHasRound() {
return this.getSeekPoint() != null;
}
}
class LinkListNode<T> {
private LinkListNode<T> next = null;
private T data;
public LinkListNode(T data, LinkListNode<T> next) {
this.data = data;
this.next = next;
}
public LinkListNode<T> next() {
return next;
}
public LinkListNode<T> next(LinkListNode<T> next) {
this.next = next;
return next;
}
public T data() {
return this.data;
}
@Override
public String toString() {
return data.toString();
}
}

- 大小: 15.9 KB
分享到:
相关推荐
这些代码可能包含上述操作的示例,有助于学习和掌握循环链表的实现细节。 总之,循环链表是C++编程中一个重要的数据结构,理解和熟练掌握其原理和操作,对于提升编程能力、解决实际问题具有重要意义。通过实践和...
在面试中,还可能被问到两个无环链表是否相交的问题。一个常见的方法是分别遍历两个链表并计算它们的长度,然后将较长链表先移动(长度差)的步数,之后两个指针同步移动,当两个指针指向同一个节点时,即找到了交点...
6. **测试和调试**:`cycle_floyd_test.c`可能包含了各种测试用例,对`cycle_floyd.c`中的函数进行调用,以确保在不同情况下的正确性,包括无环链表、有环链表以及环的位置和大小变化的情况。 这个实现不仅展示了...
2. **判断单向链表中是否带有环链表** - 检测链表环可以通过使用两个指针,一个快指针每次移动两步,慢指针每次移动一步。如果链表有环,快指针最终会追上慢指针;若无环,则快指针会到达链表尾部。 3. **寻找倒数...
在Java编程中,链表是一种常见的数据结构,用于存储一系列有序的元素。在这个问题中,我们面临的是...最后,测试代码部分应该包含各种情况,如无环链表、有环链表、单个节点链表以及空链表,以验证我们的实现是否正确。
- (b) 该关系表示了一个有环链表,b指向c,c不指向d,而是b指向d,形成了一个环,依然是线性结构。 - (c) 该关系表示了一个有向图,d有两个入边和一个出边,不属于简单的线性结构。 2. **时间复杂度**: - 时间...
* 另一种方法,把问题转换成有环链表,找环的起始节点。O(n) O(1) lc142 * 二分查找,每次看一边数字的个数, O(nlog(n)) O(1) * Tips:剑指offer原题 */ RoadMap :soccer_ball: :basketball: :hamburger: ...
另一种方法,把问题转换成有环链表,找环的起始节点。O(n) O(1) lc142 * 二分查找,每次看一边数字的个数, O(nlog(n)) O(1) * Tips:剑指offer原题 */ RoadMap :soccer_ball: :basketball: :hamburger: LeetCode ...