Java 二叉树的顺序迭代器

Java 二叉树的顺序迭代器,java,algorithm,iterator,binary-tree,nodes,Java,Algorithm,Iterator,Binary Tree,Nodes,如何编写一个Java迭代器(即需要next和hasNext方法),它取二叉树的根,并以的顺序以的方式迭代二叉树的节点?这是非常直接的,因为在遍历过程中,如果有左子级,则访问左子级,然后访问根节点,那么正确的孩子: visit_node(node) if node.left: visit_node(node.left) // visit the root node if node.right: visit_node(node.right) 图表: a /

如何编写一个Java迭代器(即需要
next
hasNext
方法),它取二叉树的根,并以的顺序以的方式迭代二叉树的节点?

这是非常直接的,因为在遍历过程中,如果有左子级,则访问左子级,然后访问根节点,那么正确的孩子:

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

为了获得迭代器的下一个条目“nextEntry()”,我查看了粘贴在下面的
java.util.TreeMap
中的片段。简单地说,我要说的是首先确保根节点不为null,否则返回null。如果不为空,则查看右侧节点(如果不为空)。然后访问左侧(如果不是null),并在while循环中重复访问该左侧,直到达到null。如果原始右侧节点为null,则不访问所有节点,而是访问父节点(如果该节点不为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;
    }
}
public final boolean hasNext(){
返回下一步!=null;
}
最终树映射条目nextEntry(){
TreeMap.条目e=下一个;
if(e==null | | e.key==fenceKey)
抛出新的NoTouchElementException();
if(m.modCount!=expectedModCount)
抛出新的ConcurrentModificationException();
next=后继(e);
最后返回=e;
返回e;
}
静态树映射条目后续项(条目t){
如果(t==null)
返回null;
else if(t.right!=null){
条目p=t.右;
while(p.left!=null)
p=p.左;
返回p;
}否则{
条目p=t.parent;
输入ch=t;
while(p!=null&&ch==p.right){
ch=p;
p=p.parent;
}
返回p;
}
}

子树的第一个元素始终是最左边的元素。元素后的下一个元素是其右子树的第一个元素。如果元素没有正确的子元素,则下一个元素是元素的第一个正确祖先。如果元素既没有正确的子元素也没有正确的祖先元素,那么它是最右边的元素,也是迭代中的最后一个元素

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

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
没有父对象,因此我们无法进一步向上移动。我们来自最右边的节点,已经完成了迭代
但在编写迭代器(例如,需要
next
hasNext
方法的Java迭代器)时,如何合并这样的递归方法?@PaulSeangwongree:您可以始终按顺序将节点添加到其他集合中。@ChrisDargis有效率吗?是的,我有。请公布你的答案,如果与我的解释相同或更好,这可能是公认的答案。它实际上在与jdk打包的TreeMap.java文件中声明代码是适当的。如果是这样的话,我会说2400行中约有30行是出于教育目的的合理使用。我确实发表了我的答案。不确定抄本是否有助于理解……我同意合理使用政策,我是说很容易忽略归因。事实上,我知道了。我明白你的意思,假设是用户粘贴代码编写的是合理的。我不确定我自己是否可以编写一个二叉树数据结构,但我使用了树映射,并注意到相关的源代码比我预期的要简单得多。我认为抄本很有用。我很喜欢你的a-g树,看到了同一事物的两个实现。我没有在我的答案中发布有效的迭代器是有原因的,所以OP必须自己做。给出这样的答案对任何人都没有好处。@HunterMcMillen说得好。然而,无论如何,这不是一个复制粘贴的东西。必须至少更改一行;-)但我承认这不是故意的。我的重点是可读性,而不是正确性。我甚至没有测试;-)如果你没有父指针怎么办?@Vic那么你需要某种类型的堆栈。由于Java没有生成器/协同路由(除非Java8引入了它们),因此必须使用显式堆栈。只要记住列表中的父母列表,然后在你想上升的时候弹出一个。但是你失去了根的引用……我认为问题很清楚,如果你知道什么是二叉树并且有解析它们的经验。我认为这是一个真正的问题。它应该被关闭,因为它太宽了。这是一个真正的问题。我真的无法理解SO中的一些主持人。我发现这个答案比下面的答案更有用: