More
This commit is contained in:
@@ -1,39 +1,47 @@
|
||||
package traversal;
|
||||
|
||||
import java.sql.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Queue;
|
||||
import tester.Tester;
|
||||
|
||||
// a non-empty binary tree
|
||||
// A non-empty binary tree.
|
||||
abstract class BT<X> {
|
||||
X value;
|
||||
|
||||
BT(X value) { this.value = value; }
|
||||
|
||||
// produce an iterator for the left child, or an empty iterator if one does
|
||||
// not exist
|
||||
// Produce an iterator for the left child, or an empty iterator if one does
|
||||
// not exist.
|
||||
abstract Iterator<X> leftIterator(DFTIterator<X> f);
|
||||
|
||||
// produce an iterator for the right child, or an empty iterator if one does
|
||||
// not exist
|
||||
// Produce an iterator for the right child, or an empty iterator if one does
|
||||
// not exist.
|
||||
abstract Iterator<X> rightIterator(DFTIterator<X> f);
|
||||
|
||||
// add this node's children, if they exist, to the queue (left then right)
|
||||
// Add this node's children, if they exist, to the queue (left then right).
|
||||
abstract void addChildrenToQueue(Queue<BT<X>> queue);
|
||||
}
|
||||
|
||||
class Leaf<X> extends BT<X> {
|
||||
Iterator<X> leftIterator(DFTIterator<X> f) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
Iterator<X> rigtIterator(DFTIterator<X> f) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
void addChildrenToQueue(Queue<BT<X>> queue) { queue.add(this); }
|
||||
|
||||
Leaf(X value) { super(value); }
|
||||
|
||||
Iterator<X> leftIterator(DFTIterator<X> f) {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
Iterator<X> rightIterator(DFTIterator<X> f) {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
void addChildrenToQueue(Queue<BT<X>> queue) {
|
||||
// Leaves have no children. Nothing to do.
|
||||
}
|
||||
}
|
||||
|
||||
class Node<X> extends BT<X> {
|
||||
@@ -46,23 +54,21 @@ class Node<X> extends BT<X> {
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
Iterator<X> leftIterator(DFTIterator<X> f) {
|
||||
return this.left.leftIterator(f);
|
||||
}
|
||||
Iterator<X> leftIterator(DFTIterator<X> f) { return f.iterate(this.left); }
|
||||
|
||||
Iterator<X> rightIterator(DFTIterator<X> f) {
|
||||
return this.right.rightIterator(f);
|
||||
return f.iterate(this.right);
|
||||
}
|
||||
|
||||
void addChildrenToQueue(Queue<BT<X>> queue) {
|
||||
this.left.addChildrenToQueue(queue);
|
||||
this.right.addChildrenToQueue(queue);
|
||||
queue.add(this.left);
|
||||
queue.add(this.right);
|
||||
}
|
||||
}
|
||||
|
||||
// a depth first iterator for a BT
|
||||
// A depth first iterator for a BT.
|
||||
interface DFTIterator<X> extends Iterator<X> {
|
||||
// produce a depth first traversal iterator for the given BT
|
||||
// Produce a depth first traversal iterator for the given BT.
|
||||
DFTIterator<X> iterate(BT<X> x);
|
||||
}
|
||||
|
||||
@@ -70,7 +76,7 @@ abstract class DFT<X> implements DFTIterator<X> {
|
||||
BT<X> bt;
|
||||
Iterator<X> left;
|
||||
Iterator<X> right;
|
||||
// has the top-level value of bt been iterated over yet
|
||||
// Whether the top-level value of the BT has been iterated over yet.
|
||||
boolean nodeGiven;
|
||||
|
||||
DFT(BT<X> bt) {
|
||||
@@ -83,13 +89,15 @@ abstract class DFT<X> implements DFTIterator<X> {
|
||||
return left.hasNext() || !nodeGiven || right.hasNext();
|
||||
}
|
||||
|
||||
// check that there is a next element, wraps the getNext method
|
||||
// Check that there's a next element, wraps getNext().
|
||||
public X next() {
|
||||
if (!this.hasNext()) { throw new NoSuchElementException(); }
|
||||
if (!this.hasNext()) {
|
||||
throw new NoSuchElementException("Nothing left in tree.");
|
||||
}
|
||||
return this.getNext();
|
||||
}
|
||||
|
||||
// actually get the next
|
||||
// Get the next element.
|
||||
abstract X getNext();
|
||||
}
|
||||
|
||||
@@ -97,7 +105,17 @@ class InOrder<X> extends DFT<X> {
|
||||
|
||||
InOrder(BT<X> bt) { super(bt); }
|
||||
|
||||
public DFTIterator<X> iterate(BT<X> x) { return new InOrder<X>(x); }
|
||||
public DFTIterator<X> iterate(BT<X> x) { return new InOrder<>(x); }
|
||||
|
||||
X getNext() {
|
||||
// Left, root, right.
|
||||
if (this.left.hasNext()) return this.left.next();
|
||||
else if (!this.nodeGiven) {
|
||||
this.nodeGiven = true;
|
||||
return this.bt.value;
|
||||
} else if (this.right.hasNext()) return this.right.next();
|
||||
throw new NoSuchElementException("Nothing left in tree.");
|
||||
}
|
||||
}
|
||||
|
||||
class PreOrder<X> extends DFT<X> {
|
||||
@@ -105,6 +123,16 @@ class PreOrder<X> extends DFT<X> {
|
||||
PreOrder(BT<X> bt) { super(bt); }
|
||||
|
||||
public DFTIterator<X> iterate(BT<X> x) { return new PreOrder<X>(x); }
|
||||
|
||||
X getNext() {
|
||||
// Root, left, right.
|
||||
if (!this.nodeGiven) {
|
||||
this.nodeGiven = true;
|
||||
return this.bt.value;
|
||||
} else if (this.left.hasNext()) return this.left.next();
|
||||
else if (this.right.hasNext()) return this.right.next();
|
||||
throw new NoSuchElementException("Nothing left in tree.");
|
||||
}
|
||||
}
|
||||
|
||||
class PostOrder<X> extends DFT<X> {
|
||||
@@ -112,12 +140,177 @@ class PostOrder<X> extends DFT<X> {
|
||||
PostOrder(BT<X> bt) { super(bt); }
|
||||
|
||||
public DFTIterator<X> iterate(BT<X> x) { return new PostOrder<X>(x); }
|
||||
|
||||
X getNext() {
|
||||
// Left, right, root.
|
||||
if (this.left.hasNext()) return this.left.next();
|
||||
else if (this.right.hasNext()) return this.right.next();
|
||||
else if (!this.nodeGiven) {
|
||||
this.nodeGiven = true;
|
||||
return this.bt.value;
|
||||
}
|
||||
|
||||
// a breadth first iterator for a BT
|
||||
throw new NoSuchElementException("Nothing left in tree.");
|
||||
}
|
||||
}
|
||||
|
||||
// A breadth first iterator for a BT.
|
||||
class BFT<X> implements Iterator<X> {
|
||||
|
||||
Queue<BT<X>> queue = new LinkedList<BT<X>>();
|
||||
Queue<BT<X>> queue = new LinkedList<>();
|
||||
|
||||
BFT(BT<X> bt) { queue.add(bt); }
|
||||
|
||||
public boolean hasNext() { return !queue.isEmpty(); }
|
||||
|
||||
public X next() {
|
||||
if (!this.hasNext())
|
||||
throw new NoSuchElementException("Nothing left in tree.");
|
||||
|
||||
// Returns & removes the head of the queue.
|
||||
BT<X> current = queue.remove();
|
||||
|
||||
// Add the childred of the current node to the queue.
|
||||
current.addChildrenToQueue(queue);
|
||||
|
||||
// Return the value of the current node.
|
||||
return current.value;
|
||||
}
|
||||
}
|
||||
|
||||
class TreeFinder {
|
||||
// Know the first element of the preorder list will be the root node of the
|
||||
// tree. Assuming node values are unique, you can then locate that node in
|
||||
// the inorder list. The nodes on the left of it will be on the left
|
||||
// subtree, the ones to the right on the right. Repeat the process on the
|
||||
// subtreees.
|
||||
|
||||
// Learned you can do static methods with a type like this :).
|
||||
static <T> BT<T> find(ArrayList<T> inorder, ArrayList<T> preorder) {
|
||||
int inorderRootIdx = inorder.indexOf(preorder.getFirst());
|
||||
System.out.println(inorderRootIdx);
|
||||
System.out.println(preorder);
|
||||
System.out.println(inorder);
|
||||
return findHelper(inorder, preorder, inorderRootIdx, 0);
|
||||
}
|
||||
|
||||
static <T> BT<T> findHelper(
|
||||
ArrayList<T> inorder, ArrayList<T> preorder, int inorderRootIdx,
|
||||
int preorderIdx
|
||||
) {
|
||||
System.out.println(inorderRootIdx);
|
||||
System.out.println(preorder);
|
||||
System.out.println(inorder);
|
||||
// If the lists are almost empty, it's a leaf.
|
||||
if (inorder.size() == 1 && preorder.size() == 1) {
|
||||
System.out.println("leaf");
|
||||
return new Leaf<>(inorder.getFirst());
|
||||
}
|
||||
|
||||
T val = preorder.getFirst();
|
||||
System.out.println("Node " + val);
|
||||
|
||||
// Get left side.
|
||||
ArrayList<T> leftInorder =
|
||||
new ArrayList<>(inorder.subList(0, inorderRootIdx));
|
||||
ArrayList<T> leftPreorder =
|
||||
new ArrayList<>(preorder.subList(preorderIdx + 1, preorder.size()));
|
||||
int leftInorderRootIdx = leftInorder.indexOf(leftPreorder.getFirst());
|
||||
|
||||
// Set left tree.
|
||||
BT<T> leftTree = findHelper(
|
||||
leftInorder, leftPreorder, leftInorderRootIdx, preorderIdx
|
||||
);
|
||||
|
||||
// Get right side.
|
||||
ArrayList<T> rightInorder =
|
||||
new ArrayList<>(inorder.subList(inorderRootIdx + 1, inorder.size())
|
||||
);
|
||||
ArrayList<T> rightPreorder =
|
||||
new ArrayList<>(preorder.subList(preorderIdx + 1, preorder.size()));
|
||||
int rightInorderRootIdx =
|
||||
rightInorder.indexOf(rightPreorder.getFirst());
|
||||
|
||||
// Set right tree.
|
||||
BT<T> rightTree =
|
||||
findHelper(rightInorder, rightPreorder, rightInorderRootIdx);
|
||||
|
||||
return new Node<>(val, leftTree, rightTree);
|
||||
}
|
||||
}
|
||||
|
||||
class Examples {
|
||||
BT<Integer> tree;
|
||||
void init() {
|
||||
tree = new Node<>(
|
||||
1, new Node<>(2, new Leaf<>(4), new Leaf<>(5)), new Leaf<>(3)
|
||||
);
|
||||
}
|
||||
|
||||
void testInorder(Tester t) {
|
||||
init();
|
||||
Iterator<Integer> inorder = new InOrder<>(tree);
|
||||
t.checkExpect(inorder.hasNext(), true);
|
||||
t.checkExpect(inorder.next(), 4);
|
||||
t.checkExpect(inorder.next(), 2);
|
||||
t.checkExpect(inorder.next(), 5);
|
||||
t.checkExpect(inorder.next(), 1);
|
||||
t.checkExpect(inorder.next(), 3);
|
||||
t.checkExpect(inorder.hasNext(), false);
|
||||
t.checkException(
|
||||
new NoSuchElementException("Nothing left in tree."), inorder, "next"
|
||||
);
|
||||
}
|
||||
|
||||
void testPreorder(Tester t) {
|
||||
init();
|
||||
Iterator<Integer> preorder = new PreOrder<>(tree);
|
||||
t.checkExpect(preorder.next(), 1);
|
||||
t.checkExpect(preorder.next(), 2);
|
||||
t.checkExpect(preorder.next(), 4);
|
||||
t.checkExpect(preorder.next(), 5);
|
||||
t.checkExpect(preorder.next(), 3);
|
||||
}
|
||||
|
||||
void testPostorder(Tester t) {
|
||||
init();
|
||||
Iterator<Integer> postorder = new PostOrder<>(tree);
|
||||
t.checkExpect(postorder.next(), 4);
|
||||
t.checkExpect(postorder.next(), 5);
|
||||
t.checkExpect(postorder.next(), 2);
|
||||
t.checkExpect(postorder.next(), 3);
|
||||
t.checkExpect(postorder.next(), 1);
|
||||
}
|
||||
|
||||
void testBreadthFirst(Tester t) {
|
||||
init();
|
||||
Iterator<Integer> breadth = new BFT<>(tree);
|
||||
t.checkExpect(breadth.hasNext(), true);
|
||||
t.checkExpect(breadth.next(), 1);
|
||||
t.checkExpect(breadth.next(), 2);
|
||||
t.checkExpect(breadth.next(), 3);
|
||||
t.checkExpect(breadth.next(), 4);
|
||||
t.checkExpect(breadth.next(), 5);
|
||||
t.checkExpect(breadth.hasNext(), false);
|
||||
t.checkException(
|
||||
new NoSuchElementException("Nothing left in tree."), breadth, "next"
|
||||
);
|
||||
}
|
||||
|
||||
void testTreeFinder(Tester t) {
|
||||
init();
|
||||
|
||||
Iterator<Integer> inorder = new InOrder<>(tree);
|
||||
Iterator<Integer> preorder = new PreOrder<>(tree);
|
||||
|
||||
ArrayList<Integer> inorderList = new ArrayList<>();
|
||||
ArrayList<Integer> preorderList = new ArrayList<>();
|
||||
|
||||
while (inorder.hasNext()) inorderList.add(inorder.next());
|
||||
while (preorder.hasNext()) preorderList.add(preorder.next());
|
||||
|
||||
BT<Integer> found = TreeFinder.find(inorderList, preorderList);
|
||||
|
||||
t.checkExpect(found, tree);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user