如何判断单向链表是否为环形的?我尝试过搜索但未找到令人满意的解决方案。如果可以的话,能否提供伪代码或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)的空间复杂度来存储额外信息。
Tortoise/Hare解法。在列表前面启动两个指针。第一个指针“乌龟”每次迭代向前移动一个节点。另一个指针“兔子”每次迭代向前移动两个节点。如果没有循环,兔子和乌龟都将到达链表末尾。如果存在循环,兔子将在某个时候超过乌龟,当发生这种情况时,您就知道存在循环。这是O(1)的空间复杂度和一个相当简单的算法。
使用反转链接列表的算法。如果列表有一个循环,您将在尝试反转它时回到列表开头。如果它没有循环,您将完成反转并到达链表末尾。这是O(1)的空间复杂度,但是算法略微丑陋。
如果你要计算节点数,并回到*头部。
以下是一种可能的解决方法:
按照标准算法将链表按升序排序。 排序前:4-2-6-1-5 排序后:1-2-4-5-6
一旦排序完成,检查每个节点数据并与链接节点的数据进行比较,如下所示:
if(currentcode->data > currentnode->link->data) 即循环=真;
在任何比较中,如果已排序的链接列表中“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;
}