【问题标题】:Retrieving a Binary-Tree node's depth non-recursively以非递归方式检索二叉树节点的深度
【发布时间】:2010-11-03 15:50:30
【问题描述】:

谁能指出一种在不使用递归的情况下获取二叉树(不是平衡树或 BST)中节点深度的方法?理想情况下使用 Java/C/C#

节点表示为:

class Node
{
  Node Left;
  Node Right;
  string Value;
  int Depth;
}

我的第一个想法是使用带有 FIFO 列表的 Level Order,但我在检测级别何时发生变化时遇到了困难,尤其是对于不平衡的树。

【问题讨论】:

  • 递归必须是最简单的方法,你想避免它的原因是什么?
  • 深度场是距根的距离,还是距最远的孩子的距离?
  • Kirschstein:有理由避免在资源有限的平台(例如嵌入式系统)上进行递归调用。通常需要具有恒定内存占用的非递归算法。
  • @Binary Worrier:啊,我明白了。谢谢
  • 我在 SO 上阅读的递归帖子给出的建议是递归应该用于最多 10 个级别。一棵完整树中的 10 个级别是 1024 个项目,所以我很好奇你会如何做更多(我假设其他基于二叉树的树会使用,尽管总是平衡的)

标签: recursion binary-tree non-recursive


【解决方案1】:

您可以使用堆栈实现任何递归方法,这就是递归的工作方式。想象一下你的递归函数看起来像

function int getDepth (Node head, string val)
{
    if (head == NULL)
        return -1;

    if (val == head.Value)
        return head.Depth;

    return MAX(getDepth(head.Left, val), getDepth(head.Right, val);
}

非递归函数看起来像

function int getDepth (Node head, string val)
{
    Stack s = new Stack();

    s.push(head);

    while(s.count > 0)
    {
        Node temp = s.pop();

        if (temp != NULL)
        {
            if (s.Value == val)
                return s.Depth;
            else
            {
                s.push(temp.Left);
                s.push(temp.Right);
            }
        }

    }


    return -1;
}

编辑:

这个函数设置每个节点的深度

function void setDepth (Node head)
{
    Stack s = new Stack();

    head.Depth = 0;
    s.push(head);

    while(s.count > 0)
    {
        Node temp = s.pop();

        if (temp != NULL)
        {
            if (temp.Left != NULL)
            {
                temp.Left.Depth = temp.Depth + 1;
                s.push(temp.Left);
            }

            if (temp.Right != NULL)
            {
                temp.Right.Depth = temp.Depth + 1;
                s.push(temp.Right);
            }
        }

    }

}

【讨论】:

  • 我也在设置深度之后
  • +1 为答案。必须有更好的方法来获取深度,而不需要每个节点都具有 Depth 属性,对吧?
  • @RepoMan 是的。您可以将递归函数更改为函数 int getDepth (Node head, string val, int depth)。将 depth+1 传递给递归调用。
【解决方案2】:

我假设您的意思是填写节点上的深度值,和/或找到最大深度。一种方法是使用两个列表,并按照建议执行级别顺序。它类似于:

int level=0;
List<Node> currentLevel = new List<Node>{root};
while(currentLevel.Count != 0)
{
  List<Node> nextLevel = new List<Node>{};
  foreach(Node node in currentLevel)
  {
    if(node.Right!=null) nextLevel.Add(node.Right);
    if(node.Left != null) nextLevel.Add(node.Left);
    node.Depth=level;
  }
  level++;
  currentLevel=nextLevel;
}

基本上,您枚举给定级别上的每个节点,然后找到下一个级别的每个节点;直到你用完节点/级别。显然,List 可以替换为几乎任何列表,如数据结构(链表、队列等)。 'level' 的最后一个值是最大深度 + 1。我怀疑。

基于重新阅读问题的另一个澄清;如果您正在搜索具有特定值的节点,并且想要找到它的深度,您可以更改 foreach 循环以包含“if(node.Value==searchValue) return level;”。而且,从技术上讲,如果您正在搜索特定值,则不应执行级别顺序遍历,而应使用相关的二叉树属性(例如 val

【讨论】:

    【解决方案3】:

    我认为这是一个更简单的解决方案。如果数据结构允许任意数量的孩子,那么这个解决方案也可以很容易地针对这种情况进行修改:

    int getDepthNoRecursion(Node n) {
      if(n == null) {
        return 0;
      }
      int retval = 0;
      n.depth = 1;
      Stack s = new Stack();
      s.push(n);
      while(!s.isEmpty()) {
        Node n = (Node) s.pop();
        int currDepth = n.depth;
        if(currDepth > retval) {
          retval = currDepth;
        }
        if(n.left != null) {
          n.left.depth = currDepth + 1;
          s.push(n.left);
        }
        if(n.right != null) {
          n.right.depth = currDepth + 1;
          s.push(n.right);
        }
      }
      return retval;
    }
    class Node {
      Node left;
      Node right;
      int depth = 0;
    }
    

    【讨论】:

      【解决方案4】:

      这是我想出的最有效的解决方案 (C++)。诀窍是使用第二个队列来存储当前级别的所有节点的子节点。这适用于平衡和不平衡的二叉树。

      template <class T>
      struct TreeNode {
        TreeNode<T>* left_;
        TreeNode<T>* right_;
        T* data_;
      };
      
      template <class T>
      int find_depth( const TreeNode<T>* root ) {   
        if ( root == NULL ) return 0;
        int depth = 0;
        std::queue<const TreeNode<T>*>* q1 = new std::queue<const TreeNode<T>*>;
        std::queue<const TreeNode<T>*>* q2 = new std::queue<const TreeNode<T>*>;
        q1->push( root );
        while ( !q1->empty() ) {
          // At the top of the outer loop q1 contains a complete horizontal level of the tree                                                                                  
          depth++;
      
          // Swap the queue pointers to avoid any deep copies                                                                                                                  
          std::queue<const TreeNode<T>*>* tmpQ = q2;
          q2 = q1;
          q1 = tmpQ;
      
          // Iterate over this level, inserting all children into q1                                                                                                           
          while( !q2->empty() ) {
            const TreeNode<T>* node = q2->front();
            if ( node->left_ != NULL ) q1->push( node->left_ );
            if ( node->right_ != NULL ) q1->push( node->right_ );
            q2->pop();
          }
        }
        delete q1;
        delete q2;
        return depth;
      }
      

      【讨论】:

        猜你喜欢
        • 2012-01-26
        • 2015-04-08
        • 2012-10-10
        • 1970-01-01
        • 2014-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多