【问题标题】:Count number of nodes in a linked list that may be circular计算可能是循环的链表中的节点数
【发布时间】:2009-09-18 00:17:07
【问题描述】:

这就是问题所在,它来自 Sedgwick 的优秀 Algorithms in Java (q 3.54)

给定一个指向单链表中不包含空链接的节点的链接(即每个节点要么链接到自身,要么链接到列表中的另一个节点)确定不同节点的数量,而无需修改任何节点且不再使用而不是恒定的内存空间。

你是怎么做到的?使用兔子和乌龟算法扫描一次列表以确定它是否以任何方式循环,然后再次扫描以找出列表变为圆形的位置,然后再次扫描计算到该位置的节点数?对我来说听起来有点暴力,我想还有更优雅的解决方案。

【问题讨论】:

    标签: algorithm linked-list


    【解决方案1】:

    tortoise and hare algorithm 可以为您提供循环长度和循环开始前的节点数(分别为λ和μ)。

    【讨论】:

    • 哈哈,我正在根据我的洞察力设计一个精心设计的答案,即龟兔赛跑所需的步数提供了有关周期长度的信息,我应该什么时候”我刚刚查过了。
    • +1。但是你的算法的时间复杂度是多少?求循环 O(lambda + u),求循环长度 O(lambda),求颈长 O(lambda * u)。总体而言,假设 N = min(lambda,u),它仍然是 O(N^2)。有没有比二次方更好的方法?
    • @Akusete:什么?该算法在 O(λ+μ) 时间内给你 λ 和 μ,答案是 λ+μ。
    【解决方案2】:

    最优雅的解决方案是弗洛伊德的寻环算法:http://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare

    它在 O(N) 时间内运行,只需要恒定数量的内存。

    【讨论】:

      【解决方案3】:

      看看这个:Puzzle: Loop in a Linked List

      指针标记:在实践中,链接 列表是使用 C 结构实现的 至少有一个指针;这样的结构 在 C 中应为 4 字节对齐。所以 最低有效两位为零。 在遍历列表时,您可以 “标记”一个指针被遍历 翻转最低有效位。一种 第二次遍历是为了清除这些 位。

      【讨论】:

      • 问题表明您应该“确定不同节点的数量而不修改任何节点”。即使这不是必需的,这个解决方案也有异味,因为它过于依赖实现细节并且与语言无关。
      • @Jason:谁在乎?我更喜欢一种 fast 算法(适合我的环境),而不是适用于更多语言的算法。我并不是说这个答案描述了一种快速算法,只是说一般来说,算法的性能比可移植性更重要。
      • @Jason,是的,它会临时修改节点。无论如何,我知道这不是最好的解决方案,但我认为这是一个有趣的解决方案。
      • 是的。我们使用那些底部的两位来实现按需指针的延迟加载!但那是另一回事了。
      【解决方案4】:

      只要记住你去过哪里,如果你来到同一个节点,那就结束了。

      尝试将条目存储在二叉树中,您将拥有 O(N*log(N)) 时间和 O(N) 空间复杂度

      编辑

      如果您不按指数顺序存储每个链接,则可以使用 Log(N) 空间复杂性。这意味着您存储第 1、第 2、第 4、第 8、第 16,然后如果您被击中,则必须从该点继续。这个时间复杂度是 N*Log(n)^2

      【讨论】:

      • 但你只能使用常量空间
      • log(N) 几乎是恒定的空间 100 个条目应该足以满足世界上每个磁盘/内存的需求:D
      • @ralu:抱歉,O(log N) 不接近 O(1) 空间。远非如此。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-03
      • 1970-01-01
      • 2019-12-16
      • 2021-06-01
      相关资源
      最近更新 更多