什么是一个有效的algorithm来找出一个单链表是否是循环的/循环的?
我怎样才能find一个单链表是循环/循环的? 我试图search,但找不到一个令人满意的解决scheme。 如果可能的话,你能提供一个伪代码还是Java实现?
例如:
1
→ 3
→ 5
→ 71
→ 45
→ 7
→ 5
,其中第二个5
实际上是列表的第三个元素。
标准答案是在开始时带两个迭代器,第一个递增一个,第二个递增两个迭代器。 检查它们是否指向相同的对象。 然后重复,直到增加两倍的那个击中第一个或结束。
该algorithm在列表中find任何循环链接,而不仅仅是一个完整的循环。
伪代码(不是Java,未经testing – 脱离我的头顶)
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; } } }
一个叫做Floydalgorithm的简单algorithm是有两个指针a和b,它们都从链表的第一个元素开始。 然后在每一步你增加一次和B两次。 重复,直到你到达列表的末尾(无循环),或者a == b(链表包含一个循环)。
另一种algorithm是布伦特algorithm 。
我所知道的三个主要策略是:
-
开始遍历列表并跟踪您访问的所有节点(例如,将地址存储在地图中)。 你访问的每个新节点,检查你是否已经访问过它。 如果你已经访问过这个节点,那显然是一个循环。 如果没有一个循环,你会最终达到目的。 这不是很好,因为存储额外信息是O(N)空间的复杂性。
-
龟/兔子的解决scheme。 在列表的前面开始两个指针。 第一个指针“Tortoise”每次迭代前进一个节点。 另一个指针“Hare”每次迭代前进两个节点。 如果没有循环,兔子和乌龟都将达到列表的最后。 如果有一个循环,兔子会在某一时刻通过乌龟,当发生这种情况时,你知道有一个循环。 这是O(1)空间的复杂性和一个非常简单的algorithm。
-
使用algorithm来反转链接列表。 如果列表中有一个循环,则在尝试将其反转的同时,将返回到列表的开头。 如果它没有循环,你将完成倒转,并结束。 这是O(1)的空间复杂度,但略微丑陋的algorithm。
我算你的节点,再次到达头部。
以下方法如何:
按照任何标准algorithm升序排列链接列表。 sorting前:4-2-6-1-5sorting后:1-2-4-5-6
一旦sorting,检查每个节点的数据,并与链接节点的数据进行比较,如下所示:
if(currentcode-> data> currentnode-> link-> data)即circular = true;
在任何比较中,如果任何“currentnode-> data”大于“currentcode-> link-> data”,则表示当前节点指向某个前一个节点(即圆形)。
伙计们,我没有设置testing代码。现在让我来看看这个概念的工作。
使用龟兔赛跑algorithm 。
@samoz有我的观点的答案! 伪代码丢失。 会是这样的
你的名单是你的链表
allnodes = hashmap while yourlist.hasNext() node = yourlist.next() if(allnodes.contains(node)) syso "loop found" break; hashmap.add(node)
对不起,代码是非常伪(最近做更多的脚本,然后Java)
从一个节点开始logging,然后遍历整个列表,直到到达空指针或开始的节点。
就像是:
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),这几乎是最好的,你将能够得到一个单一的链表(纠正我,如果我错了)。
或者在列表中find任何周期(例如中间),可以这样做:
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
由于dynamic数组的插入时间,这会稍微慢一些。
这是一个不错的网站,可以复制不同的解决scheme。
find循环单链表
这是该网站的赢家
// 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; }
这个解决scheme是Robert F. Floyd于1967年在“Non-deterministic Algorithms”中发表的“Floyd循环寻找algorithm”,它也被称为“龟和兔子algorithm”。
algorithm是:
- 将指针存储到第一个节点
- 遍历列表,比较每个节点指针和这个指针
- 如果遇到一个NULL指针,那么它的循环链表就不是
- 如果在遍历时遇到第一个节点,那么它是一个循环链表
它永远不会从循环中终止,它也可以在以下解决scheme中完成:
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 */
struct Node {int data; struct Node * next; };
/ *如果给定链表是循环的,则此函数返回true,否则返回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);
}