如何检测链表中的循环?假设您在Java中有一个链表结构。它由节点组成:class Node {
Node next;
// some user data}每个节点都指向下一个节点,最后一个节点除外。假设列表有可能包含一个循环 - 即最终的节点,而不是具有空值,具有对列表中之前的节点之一的引用。什么是最好的写作方式boolean hasLoop(Node first)true如果给定的Node是带循环的列表的第一个,它将返回,false否则?你怎么写,这需要一个恒定的空间和合理的时间?
3 回答
慕无忌1623718
TA贡献1744条经验 获得超4个赞
您可以使用Floyd的循环寻找算法,也称为乌龟和野兔算法。
我们的想法是对列表进行两次引用,并以不同的速度移动它们。按1节点向前移动一个,按节点向前移动另一个2。
如果链表有一个循环,他们肯定会遇到。
否则两个引用(或它们
next)中的任何一个都将成为null。
实现该算法的Java函数:
boolean hasLoop(Node first) {
if(first == null) // list does not exist..so no loop either
return false;
Node slow, fast; // create two references.
slow = fast = first; // make both refer to the start of the list
while(true) {
slow = slow.next; // 1 hop
if(fast.next != null)
fast = fast.next.next; // 2 hops
else
return false; // next node null => no loop
if(slow == null || fast == null) // if either hits null..no loop
return false;
if(slow == fast) // if the two ever meet...we must have a loop
return true;
}}
泛舟湖上清波郎朗
TA贡献1818条经验 获得超3个赞
以下是快速/慢速解决方案的改进,可正确处理奇数长度列表并提高清晰度。
boolean hasLoop(Node first) {
Node slow = first;
Node fast = first;
while(fast != null && fast.next != null) {
slow = slow.next; // 1 hop
fast = fast.next.next; // 2 hops
if(slow == fast) // fast caught up to slow, so there is a loop
return true;
}
return false; // fast reached null, so the list terminates}
侃侃无极
TA贡献2051条经验 获得超10个赞
对于Turtle和Rabbit的替代解决方案,并不像我暂时更改列表那样好:
我们的想法是走在列表中,并在您前进时将其反转。然后,当您第一次到达已经访问过的节点时,其下一个指针将指向“向后”,从而导致迭代first再次继续,在此处终止。
Node prev = null;Node cur = first;while (cur != null) {
Node next = cur.next;
cur.next = prev;
prev = cur;
cur = next;}boolean hasCycle = prev == first && first != null && first.next != null;// reconstruct the listcur = prev;prev = null;while (cur != null) {
Node next = cur.next;
cur.next = prev;
prev = cur;
cur = next;}return hasCycle;测试代码:
static void assertSameOrder(Node[] nodes) {
for (int i = 0; i < nodes.length - 1; i++) {
assert nodes[i].next == nodes[i + 1];
}}public static void main(String[] args) {
Node[] nodes = new Node[100];
for (int i = 0; i < nodes.length; i++) {
nodes[i] = new Node();
}
for (int i = 0; i < nodes.length - 1; i++) {
nodes[i].next = nodes[i + 1];
}
Node first = nodes[0];
Node max = nodes[nodes.length - 1];
max.next = null;
assert !hasCycle(first);
assertSameOrder(nodes);
max.next = first;
assert hasCycle(first);
assertSameOrder(nodes);
max.next = max;
assert hasCycle(first);
assertSameOrder(nodes);
max.next = nodes[50];
assert hasCycle(first);
assertSameOrder(nodes);}添加回答
举报
0/150
提交
取消
