Adds tree iterators based on CPS defunctionalization
parent
70e2911852
commit
84161ab2ed
|
@ -0,0 +1,386 @@
|
||||||
|
package net.abhinavsarkar.algorist;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
class TreeIerators {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Tree<String> tree =
|
||||||
|
new Tree<>(new Tree<>(new Tree<>(null, "x", null), "a", null),
|
||||||
|
"b",
|
||||||
|
new Tree<>(new Tree<>(null, "o", null), "c", new Tree<>(null, "r", null)));
|
||||||
|
|
||||||
|
// InOrderIterator
|
||||||
|
InOrderIterator.iterateRecursive(tree, System.out::print);
|
||||||
|
System.out.println("\tInOrderIterator.iterateRecursive");
|
||||||
|
|
||||||
|
|
||||||
|
InOrderIterator.iterateCPS(tree, System.out::print, () -> {});
|
||||||
|
System.out.println("\tInOrderIterator.iterateCPS");
|
||||||
|
|
||||||
|
|
||||||
|
InOrderIterator.iterateDefCPS(tree, System.out::print, null);
|
||||||
|
System.out.println("\tInOrderIterator.iterateDefCPS");
|
||||||
|
|
||||||
|
InOrderIterator.iterate(tree, System.out::print, null);
|
||||||
|
System.out.println("\tInOrderIterator.iterate");
|
||||||
|
|
||||||
|
InOrderIterator<String> inOrderIterator = new InOrderIterator<>(tree);
|
||||||
|
while (inOrderIterator.hasNext()) {
|
||||||
|
System.out.print(inOrderIterator.next());
|
||||||
|
}
|
||||||
|
System.out.println("\tInOrderIterator");
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
// PreOrderIterator
|
||||||
|
PreOrderIterator.iterateRecursive(tree, System.out::print);
|
||||||
|
System.out.println("\tPreOrderIterator.iterateRecursive");
|
||||||
|
|
||||||
|
PreOrderIterator.iterateCPS(tree, System.out::print, () -> {});
|
||||||
|
System.out.println("\tPreOrderIterator.iterateCPS");
|
||||||
|
|
||||||
|
PreOrderIterator.iterateDefCPS(tree, System.out::print, null);
|
||||||
|
System.out.println("\tPreOrderIterator.iterateDefCPS");
|
||||||
|
|
||||||
|
PreOrderIterator.iterate(tree, System.out::print, null);
|
||||||
|
System.out.println("\tPreOrderIterator.iterate");
|
||||||
|
|
||||||
|
PreOrderIterator<String> preOrderIterator = new PreOrderIterator<>(tree);
|
||||||
|
while (preOrderIterator.hasNext()) {
|
||||||
|
System.out.print(preOrderIterator.next());
|
||||||
|
}
|
||||||
|
System.out.println("\tPreOrderIterator");
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
PostOrderIterator.iterateRecursive(tree, System.out::print);
|
||||||
|
System.out.println("\tPostOrderIterator.iterateRecursive");
|
||||||
|
|
||||||
|
// PostOrderIterator
|
||||||
|
PostOrderIterator.iterateCPS(tree, System.out::print, () -> {});
|
||||||
|
System.out.println("\tPostOrderIterator.iterateCPS");
|
||||||
|
|
||||||
|
PostOrderIterator.iterateDefCPS(tree, System.out::print, null);
|
||||||
|
System.out.println("\tPostOrderIterator.iterateDefCPS");
|
||||||
|
|
||||||
|
PostOrderIterator.iterate(tree, System.out::print, null);
|
||||||
|
System.out.println("\tPostOrderIterator.iterate");
|
||||||
|
|
||||||
|
PostOrderIterator<String> postOrderIterator = new PostOrderIterator<>(tree);
|
||||||
|
while (postOrderIterator.hasNext()) {
|
||||||
|
System.out.print(postOrderIterator.next());
|
||||||
|
}
|
||||||
|
System.out.println("\tPostOrderIterator");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class Tree<T> {
|
||||||
|
Tree<T> left;
|
||||||
|
T content;
|
||||||
|
Tree<T> right;
|
||||||
|
|
||||||
|
Tree(Tree<T> left, T content, Tree<T> right) {
|
||||||
|
this.left = left;
|
||||||
|
this.content = content;
|
||||||
|
this.right = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return content.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class InOrderIterator<T> implements Iterator<T> {
|
||||||
|
|
||||||
|
private static class Cont<T> {
|
||||||
|
Tree<T> tree;
|
||||||
|
Cont<T> next;
|
||||||
|
|
||||||
|
Cont(Tree<T> tree, Cont<T> next) {
|
||||||
|
this.tree = tree;
|
||||||
|
this.next = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> void iterateRecursive(Tree<T> tree, Consumer<T> action) {
|
||||||
|
if (tree != null) {
|
||||||
|
iterateRecursive(tree.left, action);
|
||||||
|
action.accept(tree.content);
|
||||||
|
iterateRecursive(tree.right, action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> void iterateCPS(Tree<T> tree, Consumer<T> action, Runnable cont) {
|
||||||
|
if (tree != null) {
|
||||||
|
iterateCPS(tree.left, action, () -> {
|
||||||
|
action.accept(tree.content);
|
||||||
|
iterateCPS(tree.right, action, cont);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cont.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> void iterateDefCPS(Tree<T> tree, Consumer<T> action, Cont<T> cont) {
|
||||||
|
if (tree != null) {
|
||||||
|
iterateDefCPS(tree.left, action, new Cont<>(tree, cont));
|
||||||
|
} else {
|
||||||
|
if (cont != null) {
|
||||||
|
action.accept(cont.tree.content);
|
||||||
|
iterateDefCPS(cont.tree.right, action, cont.next);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> void iterate(Tree<T> tree, Consumer<T> action, Cont<T> cont) {
|
||||||
|
while (true) {
|
||||||
|
if (tree != null) {
|
||||||
|
cont = new Cont<>(tree, cont);
|
||||||
|
tree = tree.left;
|
||||||
|
} else {
|
||||||
|
if (cont != null) {
|
||||||
|
action.accept(cont.tree.content);
|
||||||
|
tree = cont.tree.right;
|
||||||
|
cont = cont.next;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tree<T> tree;
|
||||||
|
private Cont<T> cont;
|
||||||
|
|
||||||
|
InOrderIterator(Tree<T> tree) {
|
||||||
|
this.tree = tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return tree != null || cont != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T next() {
|
||||||
|
while (hasNext()) {
|
||||||
|
if (tree != null) {
|
||||||
|
cont = new Cont<>(tree, cont);
|
||||||
|
tree = tree.left;
|
||||||
|
} else {
|
||||||
|
if (cont != null) {
|
||||||
|
T content = cont.tree.content;
|
||||||
|
tree = cont.tree.right;
|
||||||
|
cont = cont.next;
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new NoSuchElementException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PreOrderIterator<T> implements Iterator<T> {
|
||||||
|
|
||||||
|
private static class Cont<T> {
|
||||||
|
Tree<T> tree;
|
||||||
|
Cont<T> next;
|
||||||
|
|
||||||
|
Cont(Tree<T> tree, Cont<T> next) {
|
||||||
|
this.tree = tree;
|
||||||
|
this.next = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> void iterateRecursive(Tree<T> tree, Consumer<T> action) {
|
||||||
|
if (tree != null) {
|
||||||
|
action.accept(tree.content);
|
||||||
|
iterateRecursive(tree.left, action);
|
||||||
|
iterateRecursive(tree.right, action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> void iterateCPS(Tree<T> tree, Consumer<T> action, Runnable cont) {
|
||||||
|
if (tree != null) {
|
||||||
|
action.accept(tree.content);
|
||||||
|
iterateCPS(tree.left, action, () -> iterateCPS(tree.right, action, cont));
|
||||||
|
} else {
|
||||||
|
cont.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> void iterateDefCPS(Tree<T> tree, Consumer<T> action, Cont<T> cont) {
|
||||||
|
if (tree != null) {
|
||||||
|
action.accept(tree.content);
|
||||||
|
iterateDefCPS(tree.left, action, tree.right != null ? new Cont<>(tree.right, cont) : cont);
|
||||||
|
} else {
|
||||||
|
if (cont != null) {
|
||||||
|
iterateDefCPS(cont.tree, action, cont.next);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> void iterate(Tree<T> tree, Consumer<T> action, Cont<T> cont) {
|
||||||
|
while (true) {
|
||||||
|
if (tree != null) {
|
||||||
|
action.accept(tree.content);
|
||||||
|
if (tree.right != null) {
|
||||||
|
cont = new Cont<>(tree.right, cont);
|
||||||
|
}
|
||||||
|
tree = tree.left;
|
||||||
|
} else {
|
||||||
|
if (cont != null) {
|
||||||
|
tree = cont.tree;
|
||||||
|
cont = cont.next;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tree<T> tree;
|
||||||
|
private Cont<T> cont;
|
||||||
|
|
||||||
|
PreOrderIterator(Tree<T> tree) {
|
||||||
|
this.tree = tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return tree != null || cont != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T next() {
|
||||||
|
while (hasNext()) {
|
||||||
|
if (tree != null) {
|
||||||
|
T content = tree.content;
|
||||||
|
if (tree.right != null) {
|
||||||
|
cont = new Cont<>(tree.right, cont);
|
||||||
|
}
|
||||||
|
tree = tree.left;
|
||||||
|
return content;
|
||||||
|
} else {
|
||||||
|
if (cont != null) {
|
||||||
|
tree = cont.tree;
|
||||||
|
cont = cont.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new NoSuchElementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class PostOrderIterator<T> implements Iterator<T> {
|
||||||
|
|
||||||
|
static class Cont<T> {
|
||||||
|
Tree<T> tree;
|
||||||
|
boolean isRight;
|
||||||
|
Cont<T> next;
|
||||||
|
|
||||||
|
Cont(Tree<T> tree, boolean isRight, Cont<T> next) {
|
||||||
|
this.tree = tree;
|
||||||
|
this.next = next;
|
||||||
|
this.isRight = isRight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> void iterateRecursive(Tree<T> tree, Consumer<T> action) {
|
||||||
|
if (tree != null) {
|
||||||
|
iterateRecursive(tree.left, action);
|
||||||
|
iterateRecursive(tree.right, action);
|
||||||
|
action.accept(tree.content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> void iterateCPS(Tree<T> tree, Consumer<T> action, Runnable cont) {
|
||||||
|
if (tree != null) {
|
||||||
|
iterateCPS(tree.left, action, () -> iterateCPS(tree.right, action, () -> {
|
||||||
|
action.accept(tree.content);
|
||||||
|
cont.run();
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
cont.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static <T> void iterateDefCPS(Tree<T> tree, Consumer<T> action, Cont<T> cont) {
|
||||||
|
if (cont == null && tree == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tree != null) {
|
||||||
|
cont = new Cont<>(tree, false, cont);
|
||||||
|
iterateDefCPS(tree.left, action, tree.right != null ? new Cont<>(tree.right, true, cont) : cont);
|
||||||
|
} else {
|
||||||
|
if (!cont.isRight) {
|
||||||
|
action.accept(cont.tree.content);
|
||||||
|
}
|
||||||
|
iterateDefCPS(cont.isRight ? cont.tree : null, action, cont.next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T> void iterate(Tree<T> tree, Consumer<T> action, Cont<T> cont) {
|
||||||
|
while (tree != null || cont != null) {
|
||||||
|
if (tree != null) {
|
||||||
|
cont = new Cont<>(tree, false, cont);
|
||||||
|
cont = tree.right != null ? new Cont<>(tree.right, true, cont) : cont;
|
||||||
|
tree = tree.left;
|
||||||
|
} else {
|
||||||
|
if (!cont.isRight) {
|
||||||
|
action.accept(cont.tree.content);
|
||||||
|
tree = null;
|
||||||
|
} else {
|
||||||
|
tree = cont.tree;
|
||||||
|
}
|
||||||
|
cont = cont.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tree<T> tree;
|
||||||
|
private Cont<T> cont;
|
||||||
|
|
||||||
|
PostOrderIterator(Tree<T> tree) {
|
||||||
|
this.tree = tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return tree != null || cont != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T next() {
|
||||||
|
while (hasNext()) {
|
||||||
|
if (tree != null) {
|
||||||
|
cont = new Cont<>(tree, false, cont);
|
||||||
|
cont = tree.right != null ? new Cont<>(tree.right, true, cont) : cont;
|
||||||
|
tree = tree.left;
|
||||||
|
} else {
|
||||||
|
T content = null;
|
||||||
|
if (!cont.isRight) {
|
||||||
|
content = cont.tree.content;
|
||||||
|
tree = null;
|
||||||
|
} else {
|
||||||
|
tree = cont.tree;
|
||||||
|
}
|
||||||
|
cont = cont.next;
|
||||||
|
if (content != null) {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new NoSuchElementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue