LinkedTree.java

Download
1/*2 * LinkedTree.java3 *4 * Computer Science S-22, Harvard University5 */6 7import java.util.*;8 9/*10 * LinkedTree - a class that represents a binary tree containing data11 * items with integer keys.  If the nodes are inserted using the12 * insert method, the result will be a binary search tree.13 */14public class LinkedTree {15    // An inner class for the nodes in the tree16    private class Node {17        private int key;         // the key field18        private LLList data;     // list of data values for this key19        private Node left;       // reference to the left child/subtree20        private Node right;      // reference to the right child/subtree21        22        private Node(int key, Object data){23            this.key = key;24            this.data = new LLList();25            this.data.addItem(data, 0);26            this.left = null;27            this.right = null;28        }29    }30    31    // the root of the tree as a whole32    private Node root;33    34    public LinkedTree() {35        root = null;36    }37    38    /*39     * Prints the keys of the tree in the order given by a preorder traversal.40     * Invokes the recursive preorderPrintTree method to do the work.41     */42    public void preorderPrint() {43        if (root != null) {44            preorderPrintTree(root);      45        }46        System.out.println();47    }48    49    /*50     * Recursively performs a preorder traversal of the tree/subtree51     * whose root is specified, printing the keys of the visited nodes.52     * Note that the parameter is *not* necessarily the root of the 53     * entire tree. 54     */55    private static void preorderPrintTree(Node root) {56        System.out.print(root.key + " ");57        if (root.left != null) {58            preorderPrintTree(root.left);59        }60        if (root.right != null) {61            preorderPrintTree(root.right);62        }63    }64    65    /*66     * Prints the keys of the tree in the order given by a postorder traversal.67     * Invokes the recursive postorderPrintTree method to do the work.68     */69    public void postorderPrint() {70        if (root != null) {71            postorderPrintTree(root);      72        }73        System.out.println();74    }75    76    /*77     * Recursively performs a postorder traversal of the tree/subtree78     * whose root is specified, printing the keys of the visited nodes.79     * Note that the parameter is *not* necessarily the root of the 80     * entire tree. 81     */82    private static void postorderPrintTree(Node root) {83        if (root.left != null) {84            postorderPrintTree(root.left);85        }86        if (root.right != null) {87            postorderPrintTree(root.right);88        }89        System.out.print(root.key + " ");90    }91    92    /*93     * Prints the keys of the tree in the order given by an inorder traversal.94     * Invokes the recursive inorderPrintTree method to do the work.95     */96    public void inorderPrint() {97        if (root != null) {98            inorderPrintTree(root);      99        }100        System.out.println();101    }102    103    /*104     * Recursively performs an inorder traversal of the tree/subtree105     * whose root is specified, printing the keys of the visited nodes.106     * Note that the parameter is *not* necessarily the root of the 107     * entire tree. 108     */109    private static void inorderPrintTree(Node root) {110        if (root.left != null) {111            inorderPrintTree(root.left);112        }113        System.out.print(root.key + " ");114        if (root.right != null) {115            inorderPrintTree(root.right);116        }117    }118    119    /* 120     * Inner class for temporarily associating a node's depth121     * with the node, so that levelOrderPrint can print the levels122     * of the tree on separate lines.123     */124    private class NodePlusDepth {125        private Node node;126        private int depth;127        128        private NodePlusDepth(Node node, int depth) {129            this.node = node;130            this.depth = depth;131        }132    }133    134    /*135     * Prints the keys of the tree in the order given by a136     * level-order traversal.137     */138    public void levelOrderPrint() {139        LLQueue<NodePlusDepth> q = new LLQueue<NodePlusDepth>();140        141        // Insert the root into the queue if the root is not null.142        if (root != null) {143            q.insert(new NodePlusDepth(root, 0));144        }145        146        // We continue until the queue is empty.  At each step,147        // we remove an element from the queue, print its value,148        // and insert its children (if any) into the queue.149        // We also keep track of the current level, and add a newline150        // whenever we advance to a new level.151        int level = 0;152        while (!q.isEmpty()) {153            NodePlusDepth item = q.remove();154            155            if (item.depth > level) {156                System.out.println();157                level++;158            }159            System.out.print(item.node.key + " ");160            161            if (item.node.left != null) {162                q.insert(new NodePlusDepth(item.node.left, item.depth + 1));163            }164            if (item.node.right != null) {165                q.insert(new NodePlusDepth(item.node.right, item.depth + 1));166            }167        }168        System.out.println();169    }170    171    /*172     * Searches for the specified key in the tree.173     * If it finds it, it returns the list of data items associated with the key.174     * Invokes the recursive searchTree method to perform the actual search.175     */176    public LLList search(int key) {177        Node n = searchTree(root, key);178        if (n == null) {179            return null;180        } else {181            return n.data;182        }183    }184    185    /*186     * Recursively searches for the specified key in the tree/subtree187     * whose root is specified. Note that the parameter is *not*188     * necessarily the root of the entire tree.189     */190    private static Node searchTree(Node root, int key) {191        if (root == null) {192            return null;193        } else if (key == root.key) {194            return root;195        } else if (key < root.key) {196            return searchTree(root.left, key);197        } else {198            return searchTree(root.right, key);199        }200    }201    202    /*203     * Inserts the specified (key, data) pair in the tree so that the204     * tree remains a binary search tree.205     */206    public void insert(int key, Object data) {207        // Find the parent of the new node.208        Node parent = null;209        Node trav = root;210        while (trav != null) {211            if (trav.key == key) {212                trav.data.addItem(data, 0);213                return;214            }215            parent = trav;216            if (key < trav.key) {217                trav = trav.left;218            } else {219                trav = trav.right;220            }221        }222        223        // Insert the new node.224        Node newNode = new Node(key, data);225        if (parent == null) {    // the tree was empty226            root = newNode;227        } else if (key < parent.key) {228            parent.left = newNode;229        } else {230            parent.right = newNode;231        }232    }233    234    /*235     * FOR TESTING: Processes the integer keys in the specified array from 236     * left to right, adding a node for each of them to the tree. 237     * The data associated with each key is a string based on the key.238     */239    public void insertKeys(int[] keys) {240        for (int i = 0; i < keys.length; i++) {241            insert(keys[i], "data for key " + keys[i]);242        }243    }244    245    /*246     * Deletes the node containing the (key, data) pair with the247     * specified key from the tree and return the associated data item.248     */249    public LLList delete(int key) {250        // Find the node to be deleted and its parent.251        Node parent = null;252        Node trav = root;253        while (trav != null && trav.key != key) {254            parent = trav;255            if (key < trav.key) {256                trav = trav.left;257            } else {258                trav = trav.right;259            }260        }261        262        // Delete the node (if any) and return the removed data item.263        if (trav == null) {   // no such key    264            return null;265        } else {266            LLList removedData = trav.data;267            deleteNode(trav, parent);268            return removedData;269        }270    }271    272    /*273     * Deletes the node specified by the parameter toDelete.  parent274     * specifies the parent of the node to be deleted. 275     */276    private void deleteNode(Node toDelete, Node parent) {277        if (toDelete.left != null && toDelete.right != null) {278            // Case 3: toDelete has two children.279            // Find a replacement for the item we're deleting -- as well as 280            // the replacement's parent.281            // We use the smallest item in toDelete's right subtree as282            // the replacement.283            Node replaceParent = toDelete;284            Node replace = toDelete.right;285            while (replace.left != null) {286                replaceParent = replace;287                replace = replace.left;288            }289            290            // Replace toDelete's key and data with those of the 291            // replacement item.292            toDelete.key = replace.key;293            toDelete.data = replace.data;294            295            // Recursively delete the replacement item's old node.296            // It has at most one child, so we don't have to297            // worry about infinite recursion.298            deleteNode(replace, replaceParent);299        } else {300            // Cases 1 and 2: toDelete has 0 or 1 child301            Node toDeleteChild;302            if (toDelete.left != null) {303                toDeleteChild = toDelete.left;304            } else {305                toDeleteChild = toDelete.right;  // null if it has no children306            }307            308            if (toDelete == root) {309                root = toDeleteChild;310            } else if (toDelete.key < parent.key) {311                parent.left = toDeleteChild;312            } else {313                parent.right = toDeleteChild;314            }315        }316    }317}