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

在单链表中查找循环

涂选
2023-03-14

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

共有3个答案

壤驷文华
2023-03-14

您还可以使用哈希映射来查找下面的链接列表是否有循环。函数使用哈希映射来查找链接列表是否有循环

    static bool isListHaveALoopUsingHashMap(Link *headLink) {

        map<Link*, int> tempMap;
        Link * temp;
        temp = headLink;
        while (temp->next != NULL) {
            if (tempMap.find(temp) == tempMap.end()) {
                tempMap[temp] = 1;
            } else {
                return 0;
            }
            temp = temp->next;
        }
        return 1;
    }

双指针方法是最好的方法,因为时间复杂度是O(n)哈希映射所需的空间复杂度加上O(n)空间复杂度。

茅慈
2023-03-14

选择的答案给出了一个O(n*n)解,以找到循环的开始节点。这里有一个O(n)解:

一旦我们发现慢A和快B在循环中相遇,让其中一个静止不动,另一个每次继续走一步,以决定循环的周长,比如,P。

然后我们在头部放一个节点,让它走P步,在头部放另一个节点。我们每次都将这两个节点推进一步,当它们第一次相遇时,这是循环的起点。

薛霄
2023-03-14

您只需在列表中运行两个指针就可以检测到它,这个过程被称为龟兔算法,其前身是同名寓言:

  • 首先,检查列表是否为空(headnull)。如果是这样,就不存在循环,所以现在停止

考虑下面的循环,该循环从<代码> 3 /代码>开始:

head -> 1 -> 2 -> 3 -> 4 -> 5
                  ^         |
                  |         V
                  8 <- 7 <- 6

从1开始的tortoise和从2开始的hare具有以下值:

(tortoise,hare) = (1,2) (2,4) (3,6) (4,8) (5,4) (6,6)

因为它们在(6,6)处相等,而且在非循环列表中兔子应该总是在乌龟之外,这意味着你发现了一个循环。

伪代码会像这样运行:

def hasLoop (head):
  return false if head = null           # Empty list has no loop.

  tortoise = head                       # tortoise initially first element.
  hare = tortoise.next                  # Set hare to second element.

  while hare != null:                   # Go until hare reaches end.
    return false if hare.next = null    # Check enough left for hare move.
    hare = hare.next.next               # Move hare forward two.

    tortoise = tortoise.next            # Move tortoise forward one.

    return true if hare = tortoise      # Same means loop found.
  endwhile

  return false                          # Loop exit means no loop.
enddef

该算法的时间复杂度为O(n),因为访问的节点数(龟兔)与节点数成正比。

一旦知道循环中的一个节点,还有一个O(n)方法可以找到循环的起点。

在循环中找到某个元素后,让我们回到原始位置,但不确定循环的起点在哪里。

head -> 1 -> 2 -> 3 -> 4 -> 5
                  ^         |
                  |         V
                  8 <- 7 <- 6
                             \
                              x (where hare and tortoise met).

这是要遵循的过程:

  • 前进hare并将size设置为1

您可以通过以下演练看到这一点:

size  tortoise  hare  comment
----  --------  ----  -------
   6         1     1  initial state
                   7  advance hare by six
             2     8  1/7 different, so advance both together
             3     3  2/8 different, so advance both together
                      3/3 same, so exit loop

因此,3是循环的起点,并且由于这两个操作(循环检测和循环开始发现)都是O(n)并按顺序执行,因此整个过程也是O(n)

如果您想要更正式的证据证明这一点,您可以查看以下资源:

  • 关于我们姐妹网站的一个问题

如果您只是想获得对该方法的支持(不是形式证明),那么可以运行以下Python 3程序,该程序将评估其在大量大小(周期中有多少个元素)和引入(周期开始之前的元素)下的可用性。

您会发现它总是找到两个指针相交的点:

def nextp(p, ld, sz):
    if p == ld + sz:
        return ld
    return p + 1

for size in range(1,1001):
    for lead in range(1001):
        p1 = 0
        p2 = 0
        while True:
            p1 = nextp(p1, lead, size)
            p2 = nextp(nextp(p2, lead, size), lead, size)
            if p1 == p2:
                print("sz = %d, ld = %d, found = %d" % (size, lead, p1))
                break
 类似资料:
  • 本文向大家介绍在C ++中将单链表转换为循环链表,包括了在C ++中将单链表转换为循环链表的使用技巧和注意事项,需要的朋友参考一下 在本教程中,我们将讨论将单链接列表转换为循环链接列表的程序。 为此,我们将提供一个单链表。我们的任务是获取该列表的元素,并将其转换为循环链接列表。 示例 输出结果

  • 我们知道,为了检测链表中的循环,我们使用慢指针和快指针,首先用头节点初始化两个节点慢和快,然后向前两步遍历快指针,向前一步遍历慢指针 如果我们发现两个地址相等,那么如果fast==null | | fast,则存在循环。next==null则不存在循环 现在我的问题是 是否有可能在不使用快速和慢速指针的情况下检测单链表中的循环 任何想法将不胜感激。 提前感谢。

  • 在我的DSA课程期中考试中,我有一个问题: 考虑单个链表包含n个节点(n) 选择一个: a、 O(N)和O(N) B.O(1)和O(1) C.O(1)和O(N) d、 O(N)和O(1) 给出的正确答案是c。O(1)和O(N)。不过我认为正确答案是a。我知道如果N=8,从一开始就需要O(1)时间来找到第8个节点(只需返回尾部节点),但在这种情况下N 提前感谢您能提供的任何帮助。

  • 问题内容: 在SQL Server 2005中获得了此表,该表用于维护合并操作的历史记录: 列FROM_ID(int) 列TO_ID(int) 现在,我需要一个将原始FROM_ID作为输入并返回最后一个可用TO_ID的查询。 因此,例如: ID 1合并到ID 2 以后,ID 2合并为ID 3 稍后再次将ID 3合并为ID 4 因此,我要汇总的查询将作为输入(在我认为的WHERE子句中)ID 1,因

  • 本文向大家介绍如何判断单链表是否是循环链表?相关面试题,主要包含被问及如何判断单链表是否是循环链表?时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 时间复杂度:O(n) 空间复杂度:O(1) 两个指针,一个每次走一步,一个每次走两步,如果有环,两者会相遇。相遇后,让一个指针从头结点再次出发,两个指针每次都走一步,直到相遇点即为环入口。 Java 代码示例:

  • 我已为单链表创建了此节点类:  我想在名为findmax的方法中搜索具有最高键的节点。但是我想检查列表是否为空,如果为空,则返回null,否则返回具有最高密钥的节点。这就是我所做的: 我只想知道我检查列表是否为空是否正确。