This commit is contained in:
2025-02-04 23:56:39 -05:00
parent 677f82fc8a
commit ac99c97961

View File

@@ -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);
}
} }