如何查找单个链接列表是否为循环/循环?我试图搜索但找不到满意的解决方案。如果可能,您能提供伪代码或Java实现吗?
例如:
1
→3
→5
→71
→45
→7
→5
,其中第二个5
实际上是列表的第三个元素。
答案 0 :(得分:76)
标准答案是在开始时使用两个迭代器,将第一个迭代器递增一次,将第二个迭代器递增两次。检查它们是否指向同一个对象。然后重复,直到增加两次的那个击中第一个或到达结尾。
此算法在列表中找到任何循环链接,而不仅仅是它是一个完整的圆圈。
伪代码(不是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;
}
}
}
答案 1 :(得分:14)
一个名为Floyd's algorithm的简单算法是有两个指针a和b,它们都从链表中的第一个元素开始。然后在每一步增加一次和两次b。重复直到你到达列表的末尾(没有循环),或者a == b(链表包含一个循环)。
另一种算法是Brent's algorithm。
答案 2 :(得分:8)
我所知道的三个主要策略:
开始遍历列表并跟踪您访问过的所有节点(例如,将地址存储在地图中)。您访问的每个新节点,检查您是否已访问过它。如果您已经访问过节点,那么显然有一个循环。如果没有循环,你最终会达到目的。这不是很好,因为存储额外信息的O(N)空间复杂度。
The Tortoise / Hare解决方案。在列表的前面开始两个指针。第一个指针“Tortoise”每次迭代向前移动一个节点。另一个指针,“Hare”每次迭代向前移动两个节点。如果没有循环,野兔和乌龟都将到达列表的末尾。如果有一个循环,野兔会在某个时刻通过乌龟,当发生这种情况时,你知道有一个循环。这是O(1)空间复杂度和非常简单的算法。
使用算法反转链接列表。如果列表有一个循环,那么在尝试反转它时,你最终会回到列表的开头。如果它没有循环,你将完成倒转并结束。这是O(1)空间复杂度,但算法稍微丑陋。
答案 3 :(得分:4)
我算你的节点再次到达*头。
答案 4 :(得分:2)
答案 5 :(得分:2)
以下方法如何:
按照任何标准算法按升序对链接列表进行排序。 排序前:4-2-6-1-5 排序后:1-2-4-5-6
排序后,检查每个节点数据并与链接节点的数据进行比较,如下所示:
if(currentcode-> data> currentnode-> link-> data) 即circular = true;
在任何比较中,如果“currentnode-> data”中的任何一个对于已排序的链接列表大于“currentcode-> link-> data”,则表示当前节点指向某个先前的节点(即循环);
伙计们,我没有设置测试代码。如果这个概念有效,请告诉我。
答案 6 :(得分:1)
算法是:
答案 7 :(得分:0)
从一个节点开始并记录它,然后遍历整个列表,直到到达空指针或您开始使用的节点。
类似的东西:
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
由于动态数组的插入时间,这会慢一点。
答案 8 :(得分:0)
@samoz在我的观点中有答案!伪代码丢失。会像
您的列表是您的链接列表
allnodes = hashmap
while yourlist.hasNext()
node = yourlist.next()
if(allnodes.contains(node))
syso "loop found"
break;
hashmap.add(node)
抱歉,代码非常伪(最近编写java脚本)
答案 9 :(得分:0)
这是一个不同的解决方案可以复制的好网站。
这是该网站的获胜者
// 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;
}
这个解决方案是“弗洛伊德的 循环寻找算法“已发布 在“非确定性算法”中的 罗伯特W.弗洛伊德在1967年。它也是 被称为“乌龟和野兔” 算法”。
答案 10 :(得分:0)
它永远不会从循环终止,也可以在以下解决方案中完成:
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;
}
}
答案 11 :(得分:0)
试试这个
/* Link list Node */
struct Node { int数据; struct Node * next; };
/ *如果给定链接,则此函数返回true list是循环的,否则为false。 * / 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);
}