当前位置: 首页 > 知识库问答 >
问题:

在单链表中查找循环,而不使用慢指针和快指针

方光华
2023-03-14

我们知道,为了检测链表中的循环,我们使用慢指针和快指针,首先用头节点初始化两个节点慢和快,然后向前两步遍历快指针,向前一步遍历慢指针
如果我们发现两个地址相等,那么如果fast==null | | fast,则存在循环。next==null则不存在循环

现在我的问题是
是否有可能在不使用快速和慢速指针的情况下检测单链表中的循环

任何想法将不胜感激。
提前感谢。

共有2个答案

斜烈
2023-03-14

当然可以。最直观的方法是遍历每个节点并检查您是否访问过该节点。如果您之前访问过此节点,这意味着存在一个循环,并且此特定节点是循环的开始。

要检查您是否早些时候访问过这个节点,您可以维护一个哈希集,它允许您以O(1)时间复杂度检查元素的存在。检查下面的伪代码。

时间复杂度-O(n)

空间复杂度-O(n)

boolean isCyclic(Node head){
  HashSet<Node> set = new HashSet<Node>();    
  while(head != NULL){
    if(set.contains(head))
       return true;
    set.add(head)
    head = head.next  
  }
  return false;
}
郗唯
2023-03-14

至少还有另外两种解决方案。

O(n^2)解决方案是跟踪节点编号。在每个节点上,返回头部并计算到达当前节点所需的next操作数。如果在执行nnext操作之前到达第n个节点,则列表中有一个循环。即:

// assuming head is not null, and head doesn't point to itself
nodeNumber = 1
current = head.next
while (current != null)
{
    p = head
    counter = 0
    while (p != current && counter < nodeNumber)
    {
        p = p.next
        counter = counter + 1
    }
    if (p != current)
        there's a loop
    nodeNumber = nodeNumber + 1
}

一种破坏性的方法是在运行时反转链接。如果链表中有一个循环,那么当指针等于null时,它将位于根。即:

if (head == null) || (head.next == null)
    no loop

prev = head
current = head.next
while (current != null)
{
    // save next position
    next = current.next
    // reverse the link
    current.next = prev
    // and move to the next node
    prev = current
    current = next
}
if (prev == head)
    there is a loop

这样做的缺点是,如果列表中有循环,则会将其销毁。如果没有循环,可以返回列表并反转链接。

 类似资料:
  • 问题内容: 我正在努力理解为什么我的代码处于一种状态而不是另一种状态。自从我讲完指针已经有一段时间了,所以我可能会生锈! 基本上,我有一个用于将对象存储在内存中的具有功能的存储库结构。 因此,它所做的全部工作就是将RW互斥锁锁定在其上,并将指针添加到由标识符引用的映射中。 然后,我得到了一个功能,该功能将基本上遍历这些对象的一部分,并将它们全部存储在存储库中。 上面的方法不起作用,看起来一开始一切

  • 如何检测单个链表是否有循环??如果有循环,则如何找到循环的起始点,即循环开始的节点。

  • 所以我有一个堆栈,它允许典型的Push和Pop函数。我很难理解这一切实际上是如何在代码方面工作的。我在这里看到了这篇文章,最佳答案中的图片/图表,展示了列表是如何被“推”下来的,你指向最新的元素。我有一个 它挂接到结构“节点” 我如何结合一个推拉与"节点*下一步;"?最难理解的是我将如何真正做到这一点。我知道它最初指向空,然后如果我推一个2,4,6,它将是6,4,2,#。掌握如何实际使用链表中的指

  • 我试图创建一个包含两个参数的节点的单链表。每当我使用尾指针加入另一个节点时,头指针将取与新节点相同的值。 我确信指针指向相同的内存位置或类似的东西,但我不确定如何修复这个问题。 我想使用这个函数创建一个单链接列表,其中头节点指向列表中的第一个元素,尾节点指向列表中的最后一个元素。当前代码将生成表示最后添加的元素的两个变量。

  • 我试图了解下面创建单链表的代码是如何使用双指针工作的。 我理解在函数push()中使用双指针的目的,它允许您更改指针headRef在函数中指向的内容。但是,在函数constructList()中,我不理解以下行是如何工作的: 最初lastPtrRef将指向指向NULL的head。在对推送()的第一次调用中,在构造列表()中的for循环中,head指向的值发生了变化(它指向包含值1的新节点)。因此,