【问题标题】:Iterate through binary search tree to find all leaves遍历二叉搜索树以找到所有叶子
【发布时间】:2012-11-05 19:52:11
【问题描述】:

我对树很陌生,我正在尝试创建一种“叶子迭代器”。我认为它应该将所有没有.left.right 值的节点放到一个堆栈中,但我不确定如何做,或者即使它是正确的做法。我已经尝试搜索它,但是我遇到的每个示例都从转到最左边的叶子开始,然后转到 p = node.parent,并且我避免链接到节点的父节点。

我不明白我怎么能重复从根开始,穿过藤蔓,而不是一遍又一遍地访问相同的藤蔓。

编辑

我看到人们建议使用递归方法来解决这个问题,我现在同意了。但是我一直在努力寻找迭代器类方式的解决方案来做到这一点,我仍然想知道这是否可能,以及如何!

【问题讨论】:

  • 我会推荐递归而不是迭代方法。

标签: java algorithm iterator nodes binary-search-tree


【解决方案1】:

使用递归:

public void visitNode(Node node) {
    if(node.left != null) {
        visitNode(node.left);
    }
    if(node.right != null) {
        visitNode(node.right);
    }
    if(node.left == null && node.right == null) {
        //OMG! leaf!
    }
}

通过提供 root: 来启动它:

visitNode(root);

为了将其转换为Iterator<Node>,您必须将递归转换为循环,然后转换为状态遍历。不平凡,但应该会给您带来很多乐趣。

【讨论】:

  • 但是这不是唯一的好一片叶子吗?最左边?
  • 它使用系统堆栈访问所有叶子。
  • @Sti:关键字是递归。一旦它到达最左边的叶子,它就会返回并逐渐遍历整棵树。
  • @TomaszNurkiewicz 好的,所以将if()if()if() 转换为if()elseif()else() 会在递归世界中破坏交易吗?但是为了好玩,“将递归转换为循环和状态遍历”是什么意思?这听起来很有趣。
  • @Sti:尝试在所有叶子上实现Iterator,你会看到挑战。
【解决方案2】:
class Node {
    public Node left = null;
    public Node right = null;
    // data and other goodies
}
class Tree {
    public Node root = null;
    // add and remove methods, etc.
    public void visitAllLeaves(Node root) {
        // visit all leaves starting at the root
        java.util.Stack<Node> stack = new java.util.Stack<Node>();
        if (root == null) return; // check to make sure we're given a good node
        stack.push(root);
        while (!stack.empty()) {
            root = stack.pop();
            if (root.left == null && root.right == null) {
                // this is a leaf
                // do stuff here
            }
            if (root.left != null) {
                stack.push(root.left);
            }
            if (root.right != null) {
                stack.push(root.right);
            }
        }
    }
}

我不确定上面的代码是否有效,但这与需要做的事情差不多。另一个选项是javax.swing.TreeModel(半开玩笑)。

【讨论】:

    【解决方案3】:

    下面是如何实现一个只返回叶节点的迭代器,即没有左子树或右子树的节点。

    迭代器通过深度优先搜索在树中搜索叶节点,记住堆栈中搜索的当前状态并在找到叶节点时“暂停”(参见 fetchNext() 方法)。

    当客户端通过调用 next()“消费”叶子节点时,搜索将恢复。

    class Node {
      public Node left;
      public Node right;
    }
    
    class LeaveIterator implements Iterator<Node> {
      private final Stack<Node> stack = new Stack<>();
      private Node nextNode = null;
    
      public LeaveIterator(Node root) {
        if (root != null) {
          stack.push(root);
          nextNode = fetchNext();
        }
      }
    
      private void fetchNext() {
        Node next = null;
        while (!stack.isEmpty() && next == null) {
          Node node = stack.pop();
          if (node.left == null && node.right == null) {
            next = node;
          }
          if (node.right != null) {
            stack.push(node.right);
          }
          if (node.left != null) {
            stack.push(node.left);
          }
        }
        return next;
      }
    
      public boolean hasNext() {
        return nextNode != null;
      }
    
      public Node next() {
        if (!hasNext()) {
          throw new NoSuchElementException();
        }
        Node n = nextNode;
        nextNode = fetchNext();
        return n;
      }
    
      public void remove() {
        throw new UnsupportedOperationException();
      }
    }
    

    【讨论】:

    • 你能解释一下为什么这回答了这个问题吗?最好的答案不仅仅是代码!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多