// Modified BinaryTree class. I have implemented one of the required methods // for you -- see (far) below. You must complete the implementations for the // remaining methods. package MyTreePackage; import java.util.*; import java.io.*; // Needed for Assignment 5 methods 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 BinaryTreeInterface { 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); } public 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(); } public Iterator getLevelOrderIterator() { return new LevelOrderIterator(); } 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; if (!nodeStack.isEmpty()) { parent = nodeStack.peek(); if (nextNode == parent.getLeftChild()) currentNode = parent.getRightChild(); else currentNode = null; } else currentNode = null; } else { throw new NoSuchElementException(); } return nextNode.getData(); } /* 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; 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(); } } private class LevelOrderIterator implements Iterator { private QueueInterface> nodeQueue; public LevelOrderIterator() { nodeQueue = new LinkedQueue<>(); if (root != null) nodeQueue.enqueue(root); } public boolean hasNext() { return !nodeQueue.isEmpty(); } public T next() { BinaryNode nextNode; if (hasNext()) { nextNode = nodeQueue.dequeue(); BinaryNode leftChild = nextNode.getLeftChild(); BinaryNode rightChild = nextNode.getRightChild(); // Add to queue in order of recursive calls if (leftChild != null) nodeQueue.enqueue(leftChild); if (rightChild != null) nodeQueue.enqueue(rightChild); } else { throw new NoSuchElementException(); } return nextNode.getData(); } public void remove() { throw new UnsupportedOperationException(); } } // ******************************* // Assignment 5 Methods Start Here // ******************************* // I am giving you the code for this method so you can see how the recursion // works and how you can utilize Object files. public void saveInorder(String fileName) { try { ObjectOutputStream OS = new ObjectOutputStream( new FileOutputStream(fileName)); // Create the object file int n = getNumberOfNodes(); OS.writeInt(n); // output the number of nodes // Call the recursive method to output the nodes themselves RecWriteTree(OS, (BinaryNode)getRootNode()); OS.close(); } catch (IOException e) { System.out.println("Writing problem"); } } public void RecWriteTree(ObjectOutputStream OS, BinaryNode node) { if (node != null) // Base case -- do nothing for empty node { try { // Recursively output left subtree RecWriteTree(OS, (BinaryNode) node.getLeftChild()); // output data in current node OS.writeObject(node.getData()); // Recursively output right subtree RecWriteTree(OS, (BinaryNode) node.getRightChild()); } catch (IOException e) { System.out.println("Rec Writing Problem" + e); } } } }