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}
Node root
Field defined at line 32.
LinkedTree()
Constructor defined at line 34.
preorderPrint()
Method defined at line 42.
preorderPrintTree(root)
Method defined at line 55.
postorderPrint()
Method defined at line 69.
postorderPrintTree(root)
Method defined at line 82.
inorderPrint()
Method defined at line 96.
inorderPrintTree(root)
Method defined at line 109.
levelOrderPrint()
Method defined at line 138.
search(key)
Method defined at line 176.
searchTree(root, key)
Method defined at line 190.
insert(key, data)
Method defined at line 206.
insertKeys(keys)
Method defined at line 239.
delete(key)
Method defined at line 249.
deleteNode(toDelete, parent)
Method defined at line 276.