[英]Pre-order/Post-order iterative traversal of n-ary tree using Iterator pattern
[英]Post-order iterator in trees
我正在嘗試為后訂單創建一個Iterator
實現,但我處於低迷狀態。 我能夠獲得有序和預購實施,但我似乎無法獲得后訂購。 如果你們能指出我正確的方向並給我一些提示,那就太棒了。
這是我的有序類:
public class InOrderIterator<T> implements Iterator<T> {
private final Deque<BinaryTreeNode<T>> stack;
private BinaryTreeNode<T> current;
public InOrderIterator(BinaryTreeNode<T> root){
stack = new LinkedList<BinaryTreeNode<T>>();
this.current = root;
}
@Override
public boolean hasNext() {
return (!stack.isEmpty() || current != null);
}
@Override
public T next() {
while (current != null) {
stack.push(current);
if (current.hasLeftChild())
current = current.getLeftChild();
else
current = null;
}
current = stack.pop();
BinaryTreeNode<T> node = current;
if (current.hasRightChild())
current = current.getRightChild();
else
current = null;
return node.getData();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
以下是預購、內購和后購的說明:
預購
為了
下單
我用谷歌搜索了一個二叉樹后序迭代器實現,但找不到一個好的。 所以我使用兩個堆棧實現了我的。
public class BinaryTreePostorderIterator implements Iterator<Integer> {
private TreeNode root;
private Stack<TreeNode> nodes;
private Stack<Boolean> expanded;
public BinaryTreePostorderIterator(TreeNode root) {
this.root = root;
nodes = new Stack<>();
expanded = new Stack<>();
if (root != null) {
nodes.push(root);
expanded.push(false);
}
}
@Override
public Integer next() {
if (!hasNext()) {
throw new NoSuchElementException("End reached");
}
expanded.pop();
return nodes.pop().val;
}
@Override
public boolean hasNext() {
if (nodes.isEmpty()) {
return false;
}
while (!expanded.peek()) {
expanded.pop();
expanded.push(true);
TreeNode node = nodes.peek();
if (node.right != null) {
nodes.push(node.right);
expanded.push(false);
}
if (node.left != null) {
nodes.push(node.left);
expanded.push(false);
}
}
return true;
}
public static void main(String[] args) {
TreeNode root = new TreeNode(5);
root.left = new TreeNode(3);
root.left.right = new TreeNode(4);
root.left.left = new TreeNode(2);
root.right = new TreeNode(7);
root.right.right = new TreeNode(8);
root.right.left = new TreeNode(6);
BinaryTreePostorderIterator pi = new BinaryTreePostorderIterator(root);
while (pi.hasNext()) {
System.out.println(pi.next());
}
}
}
實現這一點的一種相當普遍的方法是從遞歸算法開始,並將其轉換為具有顯式堆棧的迭代算法。 然后,您在遞歸算法中找到將輸出數據的點,並在那里暫停計算(在本例中,通過從advance()
方法返回,並確保堆棧處於良好狀態以供下一次調用advance()
)。
我的遞歸算法(我使用 Java 8 和一個不同的Node
類,但它是相同的)是:
private void postorder(Node<V> node, Consumer<V> c) {
// step 0
if (node == null) {
return; // pop
}
postorder(node.left, onTraverse); // push
// step 1
postorder(node.right, onTraverse); // push
// step 2
c.accept(node.data);
// pop
}
它變成了以下迭代器:
class PostorderIterator<V> implements Iterator<V> {
class Frame {
int step;
Node<V> node;
public Frame(Node<V> node) {
this.node = node;
step = 0;
}
}
Stack<Frame> st = new Stack<>();
boolean ready;
V result;
public PostorderIterator(Node<V> node) {
st.push(new Frame(node));
}
private V advance() {
while (!st.isEmpty()) {
Frame f = st.peek();
switch (f.step) {
case 0:
if (f.node == null) {
st.pop(); // return
} else {
f.step = 1;
st.push(new Frame(f.node.left)); // ~postorder(node.left, ...)
}
break;
case 1:
f.step = 2;
st.push(new Frame(f.node.right)); // ~postorder(node.right, ...)
break;
case 2:
st.pop(); // ~return
return f.node.data;
default:
throw new RuntimeException();
}
}
return null;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public boolean hasNext() {
if (!ready) {
result = advance();
ready = true;
}
return result != null;
}
@Override
public V next() {
if (!ready) {
result = advance();
ready = true;
}
if (result == null) {
throw new NoSuchElementException();
}
ready = false;
return result;
}
}
這種方法可能比必要的要笨拙一些,但是擁有一個顯式的Frame
保存您的局部變量、參數以及您在代碼中的位置,應該是更清晰算法的一個不錯的起點。
我只是玩了一下后序迭代器..這就是我想出的:
class PostOrderIterator
implements Iterator<T> {
private Stack<Node<T>> stack;
private Node<T> prev;
public PostOrderIterator() {
this.stack = new Stack<>();
recurse(root);
this.prev = this.stack.peek();
}
private void recurse(Node<T> node) {
if(node == null) {
return;
}
while(node != null) {
stack.push(node);
node = node.left;
}
recurse(stack.peek().right);
}
@Override
public boolean hasNext() {
return !stack.isEmpty();
}
@Override
public T next() {
if(stack.peek().right != this.prev) {
recurse(stack.peek().right);
}
Node<T> next = stack.pop();
this.prev = next;
return next.value;
}
}
基本上,主要思想是您應該考慮初始化過程如何將要打印的第一項放在堆棧頂部,而堆棧的其余部分則跟隨遞歸會觸及的節點。 剩下的就會變得容易得多。
此外,從設計的角度來看, PostOrderIterator
是一個內部類,通過樹類的一些工廠方法作為Iterator<T>
公開。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.