/** @file BinaryTree.java @author Morgan McGuire, morgan@cs.brown.edu @created 2002-09-17 @edited 2002-09-17 */ public class BinaryTree { protected Node root = null; public BinaryTree(Node root) { this.root = root; } public void setRoot(Node n) { root = n; } public Node getRoot() { return root; } /** Returns null if not found. */ public Node get(int key) { Node node = root; while (node != null) { if (key == node.key) { return node; } else if (key > node.key) { node = node.right; } else if (key < node.key) { node = node.left; } } return null; } public void insert(int key) { insert(new Node(key)); } public void insert(Node node) { if (node == null) { return; } if (root == null) { root = node; return; } Node parent = null; Node current = root; while (current != null) { parent = current; if (current.key == node.key) { // Already in the set return; } if (node.key < current.key) { current = current.left; } else { current = current.right; } } // current is now null if (node.key < parent.key) { parent.setLeft(node); } else { parent.setRight(node); } } /** Does nothing if they key is not present. */ public void delete(int key) { delete(get(key)); } public void delete(Node node) { // Based on Tree-Delete, CLR page 253 if (node == null) { // Not in set return; } Node y = null; if (node.isLeaf()) { // The node has no children; just replace it with null replace(node, null); } else if (node.left == null) { // Replace this node with its right child. // There is no left child. replace(node, node.right); } else if (node.right == null) { // Replace this node with its left child. // There is no right child. replace(node, node.left); } else { // The node has children. Replace it with its successor. // The successor might have children of its own, however. Node r = getSuccessor(node); Node x = null; // Grab the first non-null child of r (if there is one). if (r.left == null) { x = r.right; } else { x = r.left; } // Replace r with its child replace(r, x); // Replace the node with its successor if (node.left == r) { node.left = null; } else if (node.right == r) { node.right = null; } replace(node, r); r.setLeft(node.left); r.setRight(node.right); } node.left = null; node.right = null; node.parent = null; } /** Next larger key */ public Node getSuccessor(Node node) { // Based on Tree-Successor, CLR page 249 if (node == null) { return null; } if (node.right != null) { return getMinimum(node.right); } Node y = node.parent; while ((y != null) && (node != y.right)) { node = y; y = node.parent; } return y; } public Node getMinimum() { return getMinimum(root); } public Node getMinimum(Node node) { // Based on Tree-Minimum, CLR page 248 if (node == null) { return null; } while (node.left != null) { node = node.left; } return node; } /** Replaces one subtree with another, ensuring that the root pointer is maintained. */ private void replace(Node oldNode, Node newNode) { if (oldNode.isRoot()) { root = newNode; if (newNode != null) { newNode.parent = null; } } else { oldNode.parent.replaceChild(oldNode, newNode); } } /** Perform a binary tree rotation about this node's parent... that is, replace the parent with this node and move the affected children so the binary search tree property is maintained. */ public void rotate(int key) { rotate(get(key)); } public void rotate(Node n) { if (n == null) { return; } System.out.println("Rotating " + n.key); // Parent Node p = n.parent; // Grandparent Node g = (p != null) ? p.parent : null; if (n.isRoot()) { // Rotating the root does nothing return; } final boolean wasLeft = n.isLeft(); if (g != null) { // Make the grandparent point at the node. g.replaceChild(p, n); } else { // No grandparent; this node is the new tree root. root = n; n.parent = null; } if (wasLeft) { p.setLeft(n.right); n.setRight(p); } else { p.setRight(n.left); n.setLeft(p); } } /** Ensures that the tree hasn't been corruped; here for debugging purposes. */ public void debugCheckIntegrity() { checkIntegrity(root, -1, 1000); } private void checkIntegrity(Node n, int min, int max) { if (n != null) { if (! (n.isRoot() || n.isLeft() || n.isRight())) { throw new Error("Integrity violation: " + n.key); } if (n.isRoot() && (root != n)) { throw new Error("Integrity violation: " + n.key + " thinks it is the root"); } if ((n.key >= max) || (n.key <= min)) { throw new Error("Integrity violation: " + n.key + " is not between " + min + " and " + max); } checkIntegrity(n.left, min, n.key); checkIntegrity(n.right, n.key, max); } } }