我有以下代码用于检测链表中的循环:
public Class Node {
Object data;
Node next = null;
}
boolean containCycle() {
boolean retVal = true;
Node head = this;
Node slower = head;
Node faster = head;
if(faster != null && faster.next != null) {
faster = faster.next;
} else { // there is only one element or zero element
retVal = false;
}
if (faster.next != null) {
faster = faster.next;
} else { // there are only 2 elements
retVal = false;
}
while (slower != faster && slower != null && faster != null) {
faster = (faster.next != null && faster.next.next != null) ? faster.next.next : null;
slower = (slower.next != null) ? slower.next : null;
}
if (slower == faster) {
retVal = true;
System.out.printf("The two pointers meet at: %d\n", faster.data);
} else {
retVal = false;
}
if (retVal) { // this is the part for detecting where the loop begins
slower = head;
while(slower.next != faster.next) {
slower = slower.next;
faster = faster.next;
}
System.out.println("The cycle starts at: " + slower.data);
}
return retVal;
}
此代码运行良好,直到我实际开始检测循环开始的位置,我在代码中注释了这一点。不知何故,这会遇到无限循环。
我怀疑这与Java中的引用传递有某种关系?我在检测循环时更新了head
所指的值吗?我真的没有想法。请帮忙!
答案 0 :(得分:0)
我不知道确切的算法,但您可以使用以下方法找到会面点。
让我们将节点越来越快地称为会合点。
有两个指针,一个从头开始,另一个从会面点开始。
并记住从头到会点需要遍历的节点数(让我们将此计为a
)和
会合点到会合点的下一个节点。 (让我们称之为b
)
现在这两个计数中的差异|a-b|
代表了共同的部分 - 正确吗? (即在循环开始和慢速和更快的会合点之间的部分。)
所以现在再次重新开始。重新设置两个指针,一个指向头部,另一个指向点+ 1。
例如,如果a>b
,则从头部|a-b|
移动指针,否则将指针移动到会议点+ 1 |a-b|
次。
现在将两个指针移动到他们相遇。
另一种解释这个的方法
因为您要查找的内容类似于您有两个链接列表并且它们在某个节点合并并且您需要标识该节点的情况。 你所拥有的只是两个链表的起点。
所以你从head1开始计算到列表末尾。 接下来,你从head2开始计算到列表末尾。
计算长度中的差异。增加较长的路径差异时间。然后开始从较短路径头部和差异开始移动指针直到两个指针相遇。
这与你在其他情况下所做的基本相同。