如何在二叉树中找到下一个顺序继承者?

时间:2014-03-01 13:19:26

标签: java treeset

我试图在我自己的TreeSet类中实现Iterator。 但是,我创建它的尝试仅适用于当前节点是根节点。 迭代器看起来像这样:

构造

public TreeWordSetIterator()
{
    next = root;

    if(next == null)
        return;

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

hasNext:

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

下一步:

public TreeNode next()
{
    if(!hasNext()) throw new NoSuchElementException();

    TreeNode current = next;

    next = findNext(next); // find next node

    return current;
}

FindNext中:

private TreeNode findNext(TreeNode node)
{
    if(node.right != null)
    {
        node = node.right;

        while(node.left != null)
            node = node.left;

        return node;
    }
    else
    {
        if(node.parent == null)
            return null;

        while(node.parent != null && node.parent.left != node)
            node = node.parent;

        return node;
    }
}

这很好用,直到我到达我的根节点。所以我只能遍历root的左子,而不是右。谁能给我一些关于我做错的提示?我不期待一个解决方案,只是一些提示。

问题:如果每个节点指向其父节点,左子节点和右子节点,如何找到TreeSet中的下一个节点。

提前致谢

4 个答案:

答案 0 :(得分:1)

有三种主要方法可以迭代二元树

private void inOrder(TreeNode node) {
    if(isEmpty())return;
    if(node.getLeftNode()!=null)inOrder(node.getLeftNode());
    System.out.print(node.getNodeData()+" ");
    if(node.getRightNode()!=null)inOrder(node.getRightNode());
}

private void preOrder(TreeNode node) {
    if(isEmpty())return;
    System.out.print(node.getNodeData()+" ");
    if(node.getLeftNode()!=null)preOrder(node.getLeftNode());
    if(node.getRightNode()!=null)preOrder(node.getRightNode());
}

private void postOrder(TreeNode node) {
    if(isEmpty())return;
    if(node.getLeftNode()!=null)postOrder(node.getLeftNode());
    if(node.getRightNode()!=null)postOrder(node.getRightNode());
    System.out.print(node.getNodeData()+" ");
}

//use
inOrder(root);
preOrder(root);
postOrder(root);

它很简单,你的代码对我来说真的没有意义,除了以这种方式之一进行迭代之外,还有其他的东西要做吗?

答案 1 :(得分:1)

有助于考虑Binary Search Tree的规则。假设先前返回的节点是n

  • 如果n具有正确的子树,则具有下一个值的节点将是右子树的最左侧节点。
  • 如果n没有正确的子树,那么具有下一个值的节点将是{em}左侧包含n的{​​{1}}的第一个祖先子树。

您的代码正确处理第一种情况,但不是第二种情况。考虑n是树的最左边的叶子(起始情况)的情况。 node没有合适的孩子,所以我们直接前往nodeelse有父项,因此跳过if子句。 node,因此跳过node.parent.left == node子句而不执行任何操作。最终结果是返回while。我希望你的迭代器能够永远地继续返回同一个节点。

答案 2 :(得分:0)

我认为你需要保存迭代器中的前一点,以便知道你之前的位置

这里有一些代码,但要注意它不完整,你应该自己做,它只是为了向你展示这个想法。它也没有处理根节点。

findNext(TreeNode node, TreeNode previousNode) {

  if(node.left != null && node.left != previousNode && node.right != previousNode){ //go left if not been there yet
    return node.left; 
  }
  if(node.right != null && node.right != previousNode){ //go right if not been there yet
    return node.right;
  }
  return findNext(node.parent, node); //go up and pass current node to avoid going down
}

答案 3 :(得分:0)

一个好的方法是使用堆栈来管理排序,如果你使用递归遍历(而不是试图建立一个Iterator),这就像你在SteveL的回答中所描述的那样。

当你想从左边开始时,你首先按照正确的顺序将根节点及其最左边的子节点加载到堆栈中(从根部向左下方按下)。

始终从堆栈顶部弹出下一个,然后推送其右子(如果有的话)及其最左边的子项,然后返回刚刚弹出的子项,以便它们在下一行。

通过这种方法,堆栈的顶部将始终是返回的下一个,当堆栈为空时,不再有...

在代码中:

import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Stack;

public class TreeNodeInOrderIterator<T> implements Iterator<T> {

    private final Stack<TreeNode<T>> stack;

    public TreeNodeInOrderIterator(TreeNode<T> root) {
        this.stack = new Stack<TreeNode<T>>();
        pushLeftChildren(root);
    }

    @Override
    public boolean hasNext() {
        return !stack.isEmpty();
    }

    @Override
    public T next() {
        if (!hasNext())
            throw new NoSuchElementException();
        TreeNode<T> top = stack.pop();
        pushLeftChildren(top.right);
        return top.val;
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }

    private void pushLeftChildren(TreeNode<T> cur) {
        while (cur != null) {
            stack.push(cur);
            cur = cur.left;
        }
    }

}

在此代码中,TreeNode

定义
public class TreeNode<T> {
    T val;
    TreeNode<T> left;
    TreeNode<T> right;
    TreeNode(T x) { val = x; }
}

如果你想让每个节点都知道它的父节点,那没关系,但是所有遍历都是通过使用堆栈上的内容并使用leftright子链接添加到堆栈。