import java.util.Iterator; import java.util.NoSuchElementException; import StackAndQueuePackage.*; // Needed by tree iterators /** A class that implements the ADT binary tree. @author Frank M. Carrano @author Timothy M. Henry @version 4.0 */ public class BinaryTree implements { private BinaryNode root; public BinaryTree() { root = null; } public BinaryTree(T rootData) { root = new BinaryNode<>(rootData); } public BinaryTree(T rootData, BinaryTree leftTree, BinaryTree rightTree) { privateSetTree(rootData, leftTree, rightTree); } public void setTree(T rootData) { root = new BinaryNode<>(rootData); } public void setTree(T rootData, BinaryTreeInterface leftTree, BinaryTreeInterface rightTree) { privateSetTree(rootData, (BinaryTree)leftTree, (BinaryTree)rightTree); } private void privateSetTree(T rootData, BinaryTree leftTree, BinaryTree rightTree) { root = new BinaryNode<>(rootData); if ((leftTree != null) && !leftTree.isEmpty()) { root.setLeftChild(leftTree.root); } if ((rightTree != null) && !rightTree.isEmpty()) { if (rightTree != leftTree) { root.setRightChild(rightTree.root); } else { root.setRightChild(rightTree.root.copy()); } } if ((leftTree != null) && (leftTree != this)) { leftTree.clear(); } if ((rightTree != null) && (rightTree != this)) { rightTree.clear(); } } public T getRootData() { if (isEmpty()) { throw new EmptyTreeException(); } else { return root.getData(); } } public boolean isEmpty() { return root == null; } public void clear() { root = null; } protected void setRootData(T rootData) { root.setData(rootData); } protected void setRootNode(BinaryNode rootNode) { root = rootNode; } protected BinaryNode getRootNode() { return root; } public int getHeight() { return root.getHeight(); } public int getNumberOfNodes() { return root.getNumberOfNodes(); } public Iterator getPreorderIterator() { return new PreorderIterator(); } public Iterator getInorderIterator() { return new InorderIterator(); } public Iterator getPostorderIterator() { return new PostorderIterator(); } private class PreorderIterator implements Iterator { private StackInterface> nodeStack; public PreorderIterator() { nodeStack = new LinkedStack>(); if (root != null) nodeStack.push(root); } public boolean hasNext() { return !nodeStack.isEmpty(); } public T next() { BinaryNode nextNode; if (hasNext()) { nextNode = nodeStack.pop(); BinaryNode leftChild = nextNode.getLeftChild(); BinaryNode rightChild = nextNode.getRightChild(); // Push into stack in reverse order of recursive calls if (rightChild != null) nodeStack.push(rightChild); if (leftChild != null) nodeStack.push(leftChild); } else { throw new NoSuchElementException(); } return nextNode.getData(); } public void remove() { throw new UnsupportedOperationException(); } } public void iterativePreorderTraverse() { StackInterface> nodeStack = new LinkedStack<>(); if (root != null) nodeStack.push(root); BinaryNode nextNode; while (!nodeStack.isEmpty()) { nextNode = nodeStack.pop(); BinaryNode leftChild = nextNode.getLeftChild(); BinaryNode rightChild = nextNode.getRightChild(); // Push into stack in reverse order of recursive calls if (rightChild != null) nodeStack.push(rightChild); if (leftChild != null) nodeStack.push(leftChild); System.out.print(nextNode.getData() + " "); } } private class InorderIterator implements Iterator { private StackInterface> nodeStack; private BinaryNode currentNode; public InorderIterator() { nodeStack = new LinkedStack>(); currentNode = root; } public boolean hasNext() { return !nodeStack.isEmpty() || (currentNode != null); } public T next() { BinaryNode nextNode = null; // Find leftmost node with no left child while (currentNode != null) { nodeStack.push(currentNode); currentNode = currentNode.getLeftChild(); } // Get leftmost node, then move to its right subtree if (!nodeStack.isEmpty()) { nextNode = nodeStack.pop(); assert nextNode != null; // Since nodeStack was not empty // before the pop currentNode = nextNode.getRightChild(); } else throw new NoSuchElementException(); return nextNode.getData(); } public void remove() { throw new UnsupportedOperationException(); } } public void iterativeInorderTraverse() { StackInterface> nodeStack = new LinkedStack<>(); BinaryNode currentNode = root; while (!nodeStack.isEmpty() || (currentNode != null)) { // Find leftmost node with no left child while (currentNode != null) { nodeStack.push(currentNode); currentNode = currentNode.getLeftChild(); } // Visit leftmost node, then traverse its right subtree if (!nodeStack.isEmpty()) { BinaryNode nextNode = nodeStack.pop(); assert nextNode != null; // Since nodeStack was not empty // before the pop System.out.print(nextNode.getData() + " "); currentNode = nextNode.getRightChild(); } } } private class PostorderIterator implements Iterator { private StackInterface> nodeStack; private BinaryNode currentNode; public PostorderIterator() { nodeStack = new LinkedStack>(); currentNode = root; } public boolean hasNext() { return !nodeStack.isEmpty() || (currentNode != null); } public T next() { boolean foundNext = false; BinaryNode leftChild, rightChild, nextNode = null; // Find leftmost leaf while (currentNode != null) { nodeStack.push(currentNode); leftChild = currentNode.getLeftChild(); if (leftChild == null) { currentNode = currentNode.getRightChild(); } else { currentNode = leftChild; } } // Stack is not empty either because we just pushed a node, or // it wasn't empty to begin with since hasNext() is true. // But Iterator specifies an exception for next() in case // hasNext() is false. if (!nodeStack.isEmpty()) { nextNode = nodeStack.pop(); // nextNode != null since stack was not empty before pop BinaryNode parent = null; //Option 1: Use if-else if (!nodeStack.isEmpty()) { parent = nodeStack.peek(); if (nextNode == parent.getLeftChild()) { currentNode = parent.getRightChild(); } else { currentNode = null; } } else { currentNode = null; } /* //Option 2: Use try-catch try { parent = nodeStack.peek(); if (nextNode == parent.getLeftChild()) currentNode = parent.getRightChild(); else currentNode = null; } catch(EmptyStackException e) { currentNode = null; } */ } else { throw new NoSuchElementException(); } return nextNode.getData(); } public void remove() { throw new UnsupportedOperationException(); } } }