【问题标题】:In-order iterator for binary tree [closed]二叉树的有序迭代器[关闭]
【发布时间】:2012-10-02 18:52:22
【问题描述】:

如何编写一个 Java 迭代器(即需要 nexthasNext 方法),它以二叉树的根为根,并以 按顺序 遍历二叉树的节点> 时尚?

【问题讨论】:

  • 如果你知道什么是二叉树并且有解析它们的经验,我认为这个问题已经很清楚了。
  • 我认为这是一个真正的问题。它可能应该被关闭,因为它太宽泛了。
  • 这是一个真正的问题。 SO中的一些版主实在看不懂。
  • 我发现这个答案比以下答案更有帮助:stackoverflow.com/a/2942598/1599699

标签: java algorithm iterator binary-tree nodes


【解决方案1】:

子树的第一个元素总是最左边的。元素之后的下一个元素是其右子树的第一个元素。如果元素没有右子元素,则下一个元素是元素的第一个右祖先。如果元素既没有右子元素也没有右祖先元素,则它是最右边的元素,并且是迭代中的最后一个元素。

我希望我的代码是人类可读的并且涵盖所有情况。

public class TreeIterator {
    private Node next;

    public TreeIterator(Node root) {
        next = root;
        if(next == null)
            return;

        while (next.left != null)
           next = next.left;
    }

    public boolean hasNext(){
        return next != null;
    }

    public Node next(){
        if(!hasNext()) throw new NoSuchElementException();
        Node r = next;

        // If you can walk right, walk right, then fully left.
        // otherwise, walk up until you come from left.
        if(next.right != null) {
            next = next.right;
            while (next.left != null)
                next = next.left;
            return r;
        }

        while(true) {
            if(next.parent == null) {
                next = null;
                return r;
            }
            if(next.parent.left == next) {
                next = next.parent;
               return r;
            }
            next = next.parent;
        }
     }
 }

考虑以下树:

     d
   /   \
  b     f
 / \   / \
a   c e   g
  • 第一个元素是“完全离开根”
  • a 没有右孩子,所以下一个元素是“直到你从左边来”
  • b 确实有一个右孩子,所以迭代 b 的右子树
  • c 没有正确的孩子。它的父级是b,已经遍历过了。下一个父级是d,还没有遍历完,就到此为止吧。
  • d 有一个右子树。它最左边的元素是e
  • ...
  • g 没有右子树,所以向上走。 f 已被访问,因为我们是从右边来的。 d 已被访问。 d 没有父级,所以我们不能更进一步。我们来自最右边的节点,我们已经完成了迭代。

【讨论】:

  • 我没有在我的答案中发布有效的迭代器是有原因的,所以 OP 必须自己做。给出这样的答案对任何人都没有好处。
  • @HunterMcMillen 好点。但是,无论如何,这不是复制和粘贴的事情。至少要更改一行;-) 但我承认这不是故意的。我的重点是可读性,而不是正确性。我什至没有测试它;-)
  • 如果没有父指针怎么办?
  • @Vic 那么你需要一堆东西。由于 Java 没有生成器/协程(除非 Java 8 引入了它们),因此必须使用显式堆栈。只需记住列表中的父母列表,然后在您想上的时候弹出一个。
  • 这个答案的一个问题是每个TreeNode都需要存储父节点,否则我们需要通过单独存储父节点的路线或使用堆栈形成迭代器。
【解决方案2】:

为了获取迭代器的下一个条目“nextEntry()”,我查看了粘贴在下面的java.util.TreeMap 的 sn-ps。用简单的英语,我会说你首先确保根节点不为空,否则返回空。如果不是,则访问正确的节点(如果它不为空)。然后访问左边(如果不是 null)并在 while 循环中反复访问左边,直到达到 null。如果原始右节点为空,那么如果不为空,则访问父节点。现在进入一个 while 循环,您可以在其中访问父节点,直到它为 null 或者您当前访问的节点的右(子)节点等于您的最后一个位置。现在返回您正在使用的任何条目。如果所有这些选项都失败,则返回(原始)根节点。 'HasNext()' 仅检查您返回的“下一个条目”是否为空。

public final boolean hasNext() {
     return next != null;
}

final TreeMap.Entry<K,V> nextEntry() {
    TreeMap.Entry<K,V> e = next;
    if (e == null || e.key == fenceKey)
        throw new NoSuchElementException();
    if (m.modCount != expectedModCount)
        throw new ConcurrentModificationException();
    next = successor(e);
    lastReturned = e;
    return e;
}

static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
    if (t == null)
        return null;
    else if (t.right != null) {
        Entry<K,V> p = t.right;
        while (p.left != null)
            p = p.left;
        return p;
    } else {
        Entry<K,V> p = t.parent;
        Entry<K,V> ch = t;
        while (p != null && ch == p.right) {
            ch = p;
            p = p.parent;
        }
        return p;
    }
}

【讨论】:

  • 是的,我做到了。请发表您的答案,如果与我的解释相同或更好,这可能是公认的答案。它实际上在与 jdk 打包的 TreeMap.java 文件中声明代码是专有的。如果是这样的话,我会说 2400 行中的大约 30 行是出于教育目的而合理使用的。
  • 我确实发布了我的答案。
  • 不确定转录是否有助于理解...
  • 我同意合理使用政策,我是说很容易忽略归属。事实上,我做到了。
  • 我明白你的意思,假设用户粘贴代码编写它是合理的。我不确定自己是否可以编写二叉树数据结构,但我使用了 TreeMaps 并注意到相关源比我预期的要简单得多。我认为转录是有帮助的。我确实喜欢您的 a-g 树,并且看到了同一事物的两个实现。
【解决方案3】:

这很简单,对于按顺序遍历,如果有左孩子,则访问左孩子,然后是根节点,然后是右孩子:

visit_node(node)
   if node.left: visit_node(node.left)
   // visit the root node
   if node.right: visit_node(node.right)

图表:

     a 
   /   \        (in-order traversal would give bac)
  b     c

【讨论】:

  • 但是在编写迭代器时(例如,需要nexthasNext 方法的Java 迭代器),如何合并这样的递归方法?
  • @PaulSeangwongree:您始终可以按顺序获取节点并将它们添加到其他集合中。
  • @ChrisDargis 有效率吗?
猜你喜欢
  • 2016-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-06
  • 1970-01-01
  • 2011-02-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多