【问题标题】:Big O for this recursive algorithm这个递归算法的大 O
【发布时间】:2011-01-19 03:28:44
【问题描述】:

我做了以下涉及二进制堆结构的算法:

Algorithm: heapMinimum(node)
Input    : Position n
Output   : Sequence minList; containing the postions that hold the minimum value

1. minList <-- sequence
2. if parent(node) == NULL // current node is the root of the tree
3.   minList.insertLast(node)
4. if (leftchild(node).element() == node.element())
5.   concat(heapMinimum(leftchild(node), minList))
6. if(right(node).element() == node.element())
7.   concat(heapMinimum(rightChild(node), minList))
8. return minList

算法所做的基本上是遍历给定其根的二叉堆,以查找并存储保存最小值(即与根的值匹配的值)的节点。

现在,我无法以大 O 表示法计算算法的运行时间。我感到困惑的原因是因为用于遍历每个节点的左右子节点的递归。

concat 外,所有操作都以恒定时间运行,O(1)。但是我该如何计算这种递归解决方案的运行时间呢?

【问题讨论】:

标签: algorithm heap big-o tree-traversal


【解决方案1】:

对我来说看起来像 O(N),其中 N 是元素的数量。如果您的堆只包含相等的元素,则将遍历所有元素。另外,为什么不是 concat O(1)?只要您“连接”数字,它也应该是 O(1)。但是,如果 concat 以某种方式是 O(N) (从您的伪代码看起来是这样 - 但是您应该重新考虑是否真的需要连接两个返回的列表),那么总时间将为 O(N2 sup>) 最坏的情况。

【讨论】:

  • 嗯,我认为concat 的原因是线性时间O(n),因为它与两个输入序列的大小成正比增长。您认为我应该使用什么结构来使其达到恒定时间?
  • 只需使用堆大小的向量,或链表来节省空间。这样就不需要 concat,您只需将递归调用的结果附加到列表的末尾即可。
【解决方案2】:

我假设您在谈论二进制堆?

根据堆属性的定义,你应该只递归直到你找到一个大于根的元素。但是,您还必须确定树的当前级别上的其他元素都不与根的大小相同。本质上,这会产生这样的规则:一旦遇到大于根的堆元素,就不需要递归到元素的子元素。

但是,在最坏的情况下,每个元素都可能等于根。在这种情况下,您必须检查整个堆,这会产生 O(n) 时间,其中 n 是堆中的元素数。

所以要回答你的问题,它是 O(n)

【讨论】:

  • 正如 IVlad 指出的,如果你的 concat 不是 O(1),那么你使用了错误的数据结构来存储它。在这种情况下,一个简单的链表可以工作,一个可调整大小的数组(如向量)也可以。对于大型堆,每次在 concat 列表上运行的惩罚可能非常低效。如果 concat 操作不是 O(1),因为它存储的数据的性质(例如,每个元素都是一个序列),那么您需要使用不同的变量对其进行计数。示例:O(n * k) 其中 n = 堆大小,k = 最长序列大小。
  • 所以concat 例如,基于数组的加倍策略向量将花费恒定时间将两个向量连接在一起?
  • @Andreas 正如我所指出的,计算取决于您希望存储的数据类型。从插入操作到您的列表的角度来看,它应该是 O(1) (意味着您每次想要连接时都不会遍历整个列表)。 concat 下的具体操作可能不是 O(1),因此需要使用不同的变量来计算这个操作。如果可能,您希望将该向量初始化为具有足够大的大小来容纳所有数据。为了节省空间,您改为使用链表。是不是更清楚一点?
  • 如果我理解正确的话,他在存储位置,所以应该使用整数链表,这意味着绝对是 O(1)。
【解决方案3】:

正如其他人所提到的,如果你的 concat() 是 O(1) [如果不是,你可以这样做] 那么你的算法在输出大小上是 O(N)。

但是,如果您使用 concat() 来复制您的列表(取决于系统,这可能很容易意外地做到),那么最坏的情况是输出大小为 O(N^2)。导致这种行为的一种情况是,当您的最小节点深入到树中时,您的 concat() 会不断复制每个级别的列表。

请注意,此深度受堆深度的限制,因此如果您的树是平衡的,那么最坏的情况也是数据结构大小的 O(M log M)。您可以看到这一点,因为最大副本数是树的深度。

【讨论】:

    【解决方案4】:

    我想您的解决方案中存在错误。 第一次检查:

    如果父(节点)== NULL

    必须删除,但必须添加对 node != NULL 的检查。

    此外,我建议使用列表作为附加参数,您将在其中放置答案。 所以,这就是我的实现:

    Algorithm: heapMinimum(node, minList)
    if (node != NULL)
    {
       if (minList.empty() || minList.getFirst().element() == node.element())
       {
          minList.insertLast(node)
    
          heapMinimum(left(node),  minList)
          heapMinimum(right(node), minList)
       }
    }
    

    假设向列表中添加一个元素需要 O(1),我们得到该函数需要 O(k),其中 k 是堆中最小值的数量。

    享受吧。

    【讨论】:

      猜你喜欢
      • 2016-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-29
      • 1970-01-01
      • 1970-01-01
      • 2016-03-18
      相关资源
      最近更新 更多