二进制树的有序迭代器

时间:2012-10-12 01:11:03

标签: java algorithm iterator binary-tree nodes

如何编写Java迭代器(即需要nexthasNext方法),它取二叉树的根并在 in-中遍历二叉树的节点订购时尚?

3 个答案:

答案 0 :(得分:39)

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

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

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没有父母,所以我们无法继续前进。我们来自最右边的节点,我们已经完成了迭代。

答案 1 :(得分:2)

为了获得迭代器的下一个条目'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;
    }
}

答案 2 :(得分:-1)

这是非常直接的,对于有序遍历你访问左边的孩子,如果有一个,然后是根节点,然后是右边的孩子:

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