如何确定单链表是否是循环/循环的?我试图搜索,但找不到满意的解决方案。如果可能,您能否提供伪代码或 Java 实现?
例如:
1
→ 3
→ 5
→ 71
→ 45
→ 7
→ 5
,其中第二个5
实际上是列表的第三个元素。
如何确定单链表是否是循环/循环的?我试图搜索,但找不到满意的解决方案。如果可能,您能否提供伪代码或 Java 实现?
例如:
1
→ 3
→ 5
→ 71
→ 45
→ 7
→ 5
,其中第二个5
实际上是列表的第三个元素。
标准答案是在开始时采用两个迭代器,第一个递增一次,第二个递增两次。检查它们是否指向同一个对象。然后重复,直到增加两次的那个到达第一个或到达末尾。
该算法在列表中找到任何循环链接,而不仅仅是一个完整的循环。
伪代码(不是 Java,未经测试——从我的脑海中浮出水面)
bool hasCircle(List l)
{
Iterator i = l.begin(), j = l.begin();
while (true) {
// increment the iterators, if either is at the end, you're done, no circle
if (i.hasNext()) i = i.next(); else return false;
// second iterator is travelling twice as fast as first
if (j.hasNext()) j = j.next(); else return false;
if (j.hasNext()) j = j.next(); else return false;
// this should be whatever test shows that the two
// iterators are pointing at the same place
if (i.getObject() == j.getObject()) {
return true;
}
}
}
我知道的三个主要策略:
开始遍历列表并跟踪您访问过的所有节点(例如,将它们的地址存储在地图中)。您访问的每个新节点,检查您是否已经访问过它。如果您已经访问过该节点,那么显然存在一个循环。如果没有循环,你最终会到达终点。这不是很好,因为存储额外信息的空间复杂度为 O(N)。
乌龟/野兔解决方案。在列表的前面开始两个指针。第一个指针,“乌龟”每次迭代向前移动一个节点。另一个指针“Hare”每次迭代向前移动两个节点。如果没有循环,兔子和乌龟都会到达列表的末尾。如果有一个循环,野兔会在某个时候通过乌龟,当这种情况发生时,你就知道有一个循环。这是 O(1) 空间复杂度和一个非常简单的算法。
使用该算法反转一个链表。如果列表有一个循环,您将在尝试反转它时回到列表的开头。如果它没有循环,您将完成反转并结束。这是 O(1) 的空间复杂度,但算法略丑。
我计算你的节点并再次到达 *head。
使用龟兔算法。
下面的方法怎么样:
按照任何标准算法按升序对链接列表进行排序。排序前:4-2-6-1-5 排序后:1-2-4-5-6
排序后,检查每个节点数据并与链接节点的数据进行比较,如下所示:
如果(当前代码->数据>当前节点->链接->数据)即循环=真;
在任何比较中,如果排序链表的“currentnode->data”中的任何一个大于“currentcode->link->data”,则表示当前节点指向某个先前的节点(即循环);
伙计们,我没有设置来测试代码。如果这个概念有效,现在让我看看。
一个算法是:
从一个节点开始并记录它,然后遍历整个列表,直到您到达一个空指针或您开始使用的节点。
就像是:
Node start = list->head;
Node temp = start->next;
bool circular = false;
while(temp != null && temp != start)
{
if(temp == start)
{
circular = true;
break;
}
temp = temp->next;
}
return circular
这是 O(n),这几乎是你可以通过单链表获得的最好的(如果我错了,请纠正我)。
或者要查找列表中的任何循环(例如中间),您可以执行以下操作:
Node[] array; // Use a vector or ArrayList to support dynamic insertions
Node temp = list->head;
bool circular = false;
while(temp != null)
{
if(array.contains(temp) == true)
{
circular = true;
break;
}
array.insert(temp);
temp = temp->next;
}
return circular
由于动态数组的插入时间,这会有点慢。
@samoz 在我看来有答案!伪代码丢失。会是这样的
yourlist 是你的链表
allnodes = hashmap
while yourlist.hasNext()
node = yourlist.next()
if(allnodes.contains(node))
syso "loop found"
break;
hashmap.add(node)
抱歉,代码非常伪(最近做的脚本比 Java 多)
这是一个不错的站点,可以在其上复制不同的解决方案。
这是该网站上的获胜者
// Best solution
function boolean hasLoop(Node startNode){
Node slowNode = Node fastNode1 = Node fastNode2 = startNode;
while (slowNode && fastNode1 = fastNode2.next() && fastNode2 = fastNode1.next()){
if (slowNode == fastNode1 || slowNode == fastNode2) return true;
slowNode = slowNode.next();
}
return false;
}
这个解决方案就是 Robert W. Floyd 于 1967 年在“Non-deterministic Algorithms”中发表的“Floyd's Cycle-Fiding Algorithm”。它也被称为“The Tortoise and the Hare Algorithm”。
它永远不会从循环中终止,也可以在以下解决方案中完成:
bool hasCircle(List l)
{
Iterator i = l.begin(), j = l.begin();
while (true) {
// increment the iterators, if either is at the end, you're done, no circle
if (i.hasNext()) i = i.next(); else return false;
// second iterator is travelling twice as fast as first
if (j.hasNext()) j = j.next(); else return false;
if (j.hasNext()) j = j.next(); else return false;
// this should be whatever test shows that the two
// iterators are pointing at the same place
if (i.getObject() == j.getObject()) {
return true;
}
if(i.next()==j)
break;
}
}
试试这个
/* Link list Node */
结构节点 { int 数据;下一个结构节点*;};
/* 如果给定的链表是循环的,这个函数返回真,否则返回假。*/ bool isCircular(struct Node *head) { // 一个空链表是循环的 if (head == NULL) return true;
// Next of head
struct Node *node = head->next;
// This loop would stope in both cases (1) If
// Circular (2) Not circular
while (node != NULL && node != head)
node = node->next;
// If loop stopped because of circular
// condition
return (node == head);
}