如何在没有额外内存的情况下在O(n)时间内遍历二叉树

时间:2009-04-05 09:35:12

标签: algorithm data-structures binary-tree

给定一个带整数的二叉树,Left&右指针,如何在O(n)时间和O(1)额外内存(没有堆栈/队列/递归)中遍历树?

This guy给出了一个解决方案,该解决方案不是将当前路径编码为整数的O(n)总时间(因此适用于深度有限的树)。

我正在寻找经典解决方案

(SPOILER)

编码子节点中每个节点的父节点。

5 个答案:

答案 0 :(得分:6)

任何好的算法手册都会有这个算法,例如在Knuth(TAOCP I.2.3.1遍历二叉树,练习21)。但是,由于此算法会修改树,因此必须在多线程环境中使用 extreme 警告。

您也可以使用线程树(参见Knuth)。

答案 1 :(得分:3)

主要思想类似于列表反转算法,基于指针(在人类目前已知的所有语言中)的事实,有一个超级丑陋的黑客攻击(从理论的角度来看,可能是作弊) ,0模式4为整数。

这个想法是你可以将树上路径上的指针翻转到指向上方。问题是 - 当你离开时,这就是你从列表反演算法中转移的地方 回溯你需要知道左点或右点是否向上;那时我们使用黑客。

伪代码如下:

current = root->left
next = current
while (current != null) {
  next = current->left
  current->left = static_cast<int>(prev) + 1 // ugly hack.
  current = next
}
status = done
while (current != root or status != done) {
  if (status = done) {
     if (static_cast<u32>(current->left) %4 = 1) {
         next = static_cast<u32>(current->left) -1
         current->left = prev
         status = middle
     }
     else {
         next = current->right
         current->right = prev
         status = done
     }
     prev = current
     current = next
  }
  else if (status == left) {
     if (current->left) {
       prev = current->left
       current->left = static_cast<u32>(next) +1
       next = current
     }
     else
       status = middle
  }
  else if (status == right) {
     if (current->right) {
        prev = current->right;
        current ->right = next;
        next = current
     }
     else
       status = done
  }
  else {// status == middle
     work_on_node(current)
     status = right
  }
}

答案 2 :(得分:1)

那家伙的算法很有意思,但需要指出的是,它需要O(log n)额外的空间来遍历具有n个节点的二叉树。空间要求必须以位而不是字节来衡量 - 通常在使用Big Oh表示法时它们会崩溃成相同的东西,但是这样的情况指出了为什么区分这一点很重要。

要看到这一点,请询问如何使用单个整数存储(在32位平台上)遍历具有2 ^ 32-1个节点的树。

答案 3 :(得分:0)

使用O(1)存储来记住“最后一个节点访问”指针。您可以将其初始化为0或某个未知值。

要遍历树,请从根节点开始。 查看节点的两个子节点。如果“上次访问的节点”等于RIGHT节点,则转到父节点。如果“上次访问”等于LEFT节点,则步进到右侧节点。其他步骤到左节点。

重复直到你走完整棵树。 唯一真正的聪明之处在于使用一个变量来记住你来自哪里,以便决定下一步该去哪里。这使得遍历具有确定性。

你最终会采取O(n)步骤。您将访问每个中间节点三次,每个叶子一次,所以您仍然是O(N)。存储是O(1)。

答案 4 :(得分:0)

这是另一种解决方案

http://sites.google.com/site/debforit/efficient-binary-tree-traversal-with-two-pointers

但是我想知道是否有一种方法可以在像Java那样没有真正意义上的指针的语言中做到这一点。