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.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
import tester.Tester;
|
||||||
|
|
||||||
// a non-empty binary tree
|
// A non-empty binary tree.
|
||||||
abstract class BT<X> {
|
abstract class BT<X> {
|
||||||
X value;
|
X value;
|
||||||
|
|
||||||
BT(X value) { this.value = value; }
|
BT(X value) { this.value = value; }
|
||||||
|
|
||||||
// produce an iterator for the left child, or an empty iterator if one does
|
// Produce an iterator for the left child, or an empty iterator if one does
|
||||||
// not exist
|
// not exist.
|
||||||
abstract Iterator<X> leftIterator(DFTIterator<X> f);
|
abstract Iterator<X> leftIterator(DFTIterator<X> f);
|
||||||
|
|
||||||
// produce an iterator for the right child, or an empty iterator if one does
|
// Produce an iterator for the right child, or an empty iterator if one does
|
||||||
// not exist
|
// not exist.
|
||||||
abstract Iterator<X> rightIterator(DFTIterator<X> f);
|
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);
|
abstract void addChildrenToQueue(Queue<BT<X>> queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Leaf<X> extends BT<X> {
|
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); }
|
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> {
|
class Node<X> extends BT<X> {
|
||||||
@@ -46,23 +54,21 @@ class Node<X> extends BT<X> {
|
|||||||
this.right = right;
|
this.right = right;
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<X> leftIterator(DFTIterator<X> f) {
|
Iterator<X> leftIterator(DFTIterator<X> f) { return f.iterate(this.left); }
|
||||||
return this.left.leftIterator(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator<X> rightIterator(DFTIterator<X> f) {
|
Iterator<X> rightIterator(DFTIterator<X> f) {
|
||||||
return this.right.rightIterator(f);
|
return f.iterate(this.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addChildrenToQueue(Queue<BT<X>> queue) {
|
void addChildrenToQueue(Queue<BT<X>> queue) {
|
||||||
this.left.addChildrenToQueue(queue);
|
queue.add(this.left);
|
||||||
this.right.addChildrenToQueue(queue);
|
queue.add(this.right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// a depth first iterator for a BT
|
// A depth first iterator for a BT.
|
||||||
interface DFTIterator<X> extends Iterator<X> {
|
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);
|
DFTIterator<X> iterate(BT<X> x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +76,7 @@ abstract class DFT<X> implements DFTIterator<X> {
|
|||||||
BT<X> bt;
|
BT<X> bt;
|
||||||
Iterator<X> left;
|
Iterator<X> left;
|
||||||
Iterator<X> right;
|
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;
|
boolean nodeGiven;
|
||||||
|
|
||||||
DFT(BT<X> bt) {
|
DFT(BT<X> bt) {
|
||||||
@@ -83,13 +89,15 @@ abstract class DFT<X> implements DFTIterator<X> {
|
|||||||
return left.hasNext() || !nodeGiven || right.hasNext();
|
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() {
|
public X next() {
|
||||||
if (!this.hasNext()) { throw new NoSuchElementException(); }
|
if (!this.hasNext()) {
|
||||||
|
throw new NoSuchElementException("Nothing left in tree.");
|
||||||
|
}
|
||||||
return this.getNext();
|
return this.getNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
// actually get the next
|
// Get the next element.
|
||||||
abstract X getNext();
|
abstract X getNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +105,17 @@ class InOrder<X> extends DFT<X> {
|
|||||||
|
|
||||||
InOrder(BT<X> bt) { super(bt); }
|
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> {
|
class PreOrder<X> extends DFT<X> {
|
||||||
@@ -105,6 +123,16 @@ class PreOrder<X> extends DFT<X> {
|
|||||||
PreOrder(BT<X> bt) { super(bt); }
|
PreOrder(BT<X> bt) { super(bt); }
|
||||||
|
|
||||||
public DFTIterator<X> iterate(BT<X> x) { return new PreOrder<X>(x); }
|
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> {
|
class PostOrder<X> extends DFT<X> {
|
||||||
@@ -112,12 +140,177 @@ class PostOrder<X> extends DFT<X> {
|
|||||||
PostOrder(BT<X> bt) { super(bt); }
|
PostOrder(BT<X> bt) { super(bt); }
|
||||||
|
|
||||||
public DFTIterator<X> iterate(BT<X> x) { return new PostOrder<X>(x); }
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NoSuchElementException("Nothing left in tree.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// a breadth first iterator for a BT
|
// A breadth first iterator for a BT.
|
||||||
class BFT<X> implements Iterator<X> {
|
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); }
|
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