我试图在我自己的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中的下一个节点。
提前致谢
答案 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
没有合适的孩子,所以我们直接前往node
。 else
有父项,因此跳过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; }
}
如果你想让每个节点都知道它的父节点,那没关系,但是所有遍历都是通过使用堆栈上的内容并使用left
和right
子链接添加到堆栈。