Advertisement
Guest User

LinkedTree.java

a guest
Nov 22nd, 2019
199
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.00 KB | None | 0 0
  1. import java.util.*;
  2.  
  3. /*
  4. * LinkedTree - a class that represents a binary tree containing data
  5. * items with integer keys. If the nodes are inserted using the
  6. * insert method, the result will be a binary search tree.
  7. */
  8. public class LinkedTree {
  9. // An inner class for the nodes in the tree
  10. private class Node {
  11. private int key; // the key field
  12. private LLList data; // list of data values for this key
  13. private Node left; // reference to the left child/subtree
  14. private Node right; // reference to the right child/subtree
  15. private Node parent; // reference to the parent. NOT YET MAINTAINED!
  16.  
  17. private Node(int key, Object data) {
  18. this.key = key;
  19. this.data = new LLList();
  20. this.data.addItem(data, 0);
  21. this.left = null;
  22. this.right = null;
  23. this.parent = null;
  24. }
  25. }
  26.  
  27. // the root of the tree as a whole
  28. private Node root;
  29.  
  30. public LinkedTree() {
  31. root = null;
  32. }
  33.  
  34. /*
  35. * Prints the keys of the tree in the order given by a preorder traversal.
  36. * Invokes the recursive preorderPrintTree method to do the work.
  37. */
  38. public void preorderPrint() {
  39. if (root != null) {
  40. preorderPrintTree(root);
  41. }
  42. System.out.println();
  43. }
  44.  
  45. /*
  46. * Recursively performs a preorder traversal of the tree/subtree whose root is
  47. * specified, printing the keys of the visited nodes. Note that the parameter is
  48. * *not* necessarily the root of the entire tree.
  49. */
  50. private static void preorderPrintTree(Node root) {
  51. System.out.print(root.key + " ");
  52. if (root.left != null) {
  53. preorderPrintTree(root.left);
  54. }
  55. if (root.right != null) {
  56. preorderPrintTree(root.right);
  57. }
  58. }
  59.  
  60. /*
  61. * Prints the keys of the tree in the order given by a postorder traversal.
  62. * Invokes the recursive postorderPrintTree method to do the work.
  63. */
  64. public void postorderPrint() {
  65. if (root != null) {
  66. postorderPrintTree(root);
  67. }
  68. System.out.println();
  69. }
  70.  
  71. /*
  72. * Recursively performs a postorder traversal of the tree/subtree whose root is
  73. * specified, printing the keys of the visited nodes. Note that the parameter is
  74. * *not* necessarily the root of the entire tree.
  75. */
  76. private static void postorderPrintTree(Node root) {
  77. if (root.left != null) {
  78. postorderPrintTree(root.left);
  79. }
  80. if (root.right != null) {
  81. postorderPrintTree(root.right);
  82. }
  83. System.out.print(root.key + " ");
  84. }
  85.  
  86. /*
  87. * Prints the keys of the tree in the order given by an inorder traversal.
  88. * Invokes the recursive inorderPrintTree method to do the work.
  89. */
  90. public void inorderPrint() {
  91. if (root != null) {
  92. inorderPrintTree(root);
  93. }
  94. System.out.println();
  95. }
  96.  
  97. /*
  98. * Recursively performs an inorder traversal of the tree/subtree whose root is
  99. * specified, printing the keys of the visited nodes. Note that the parameter is
  100. * *not* necessarily the root of the entire tree.
  101. */
  102. private static void inorderPrintTree(Node root) {
  103. if (root.left != null) {
  104. inorderPrintTree(root.left);
  105. }
  106. System.out.print(root.key + " ");
  107. if (root.right != null) {
  108. inorderPrintTree(root.right);
  109. }
  110. }
  111.  
  112. /*
  113. * Inner class for temporarily associating a node's depth with the node, so that
  114. * levelOrderPrint can print the levels of the tree on separate lines.
  115. */
  116. private class NodePlusDepth {
  117. private Node node;
  118. private int depth;
  119.  
  120. private NodePlusDepth(Node node, int depth) {
  121. this.node = node;
  122. this.depth = depth;
  123. }
  124. }
  125.  
  126. /*
  127. * Prints the keys of the tree in the order given by a level-order traversal.
  128. */
  129. public void levelOrderPrint() {
  130. LLQueue<NodePlusDepth> q = new LLQueue<NodePlusDepth>();
  131.  
  132. // Insert the root into the queue if the root is not null.
  133. if (root != null) {
  134. q.insert(new NodePlusDepth(root, 0));
  135. }
  136.  
  137. // We continue until the queue is empty. At each step,
  138. // we remove an element from the queue, print its value,
  139. // and insert its children (if any) into the queue.
  140. // We also keep track of the current level, and add a newline
  141. // whenever we advance to a new level.
  142. int level = 0;
  143. while (!q.isEmpty()) {
  144. NodePlusDepth item = q.remove();
  145.  
  146. if (item.depth > level) {
  147. System.out.println();
  148. level++;
  149. }
  150. System.out.print(item.node.key + " ");
  151.  
  152. if (item.node.left != null) {
  153. q.insert(new NodePlusDepth(item.node.left, item.depth + 1));
  154. }
  155. if (item.node.right != null) {
  156. q.insert(new NodePlusDepth(item.node.right, item.depth + 1));
  157. }
  158. }
  159. System.out.println();
  160. }
  161.  
  162. /*
  163. * Searches for the specified key in the tree. If it finds it, it returns the
  164. * list of data items associated with the key. Invokes the recursive searchTree
  165. * method to perform the actual search.
  166. */
  167. public LLList search(int key) {
  168. Node n = searchTree(root, key);
  169. if (n == null) {
  170. return null;
  171. } else {
  172. return n.data;
  173. }
  174. }
  175.  
  176. /*
  177. * Recursively searches for the specified key in the tree/subtree whose root is
  178. * specified. Note that the parameter is *not* necessarily the root of the
  179. * entire tree.
  180. */
  181. private static Node searchTree(Node root, int key) {
  182. if (root == null) {
  183. return null;
  184. } else if (key == root.key) {
  185. return root;
  186. } else if (key < root.key) {
  187. return searchTree(root.left, key);
  188. } else {
  189. return searchTree(root.right, key);
  190. }
  191. }
  192.  
  193. /*
  194. * Inserts the specified (key, data) pair in the tree so that the tree remains a
  195. * binary search tree.
  196. */
  197. public void insert(int key, Object data) {
  198. // Find the parent of the new node.
  199. Node parent = null;
  200. Node trav = root;
  201. while (trav != null) {
  202. if (trav.key == key) {
  203. trav.data.addItem(data, 0);
  204. return;
  205. }
  206. parent = trav;
  207. if (key < trav.key) {
  208. trav = trav.left;
  209. } else {
  210. trav = trav.right;
  211. }
  212. }
  213.  
  214. // Insert the new node.
  215. Node newNode = new Node(key, data);
  216. if (parent == null) { // the tree was empty
  217. root = newNode;
  218. } else if (key < parent.key) {
  219. parent.left = newNode;
  220. } else {
  221. parent.right = newNode;
  222. }
  223. }
  224.  
  225. /*
  226. * FOR TESTING: Processes the integer keys in the specified array from left to
  227. * right, adding a node for each of them to the tree. The data associated with
  228. * each key is a string based on the key.
  229. */
  230. public void insertKeys(int[] keys) {
  231. for (int i = 0; i < keys.length; i++) {
  232. insert(keys[i], "data for key " + keys[i]);
  233. }
  234. }
  235.  
  236. /*
  237. * Deletes the node containing the (key, data) pair with the specified key from
  238. * the tree and return the associated data item.
  239. */
  240. public LLList delete(int key) {
  241. // Find the node to be deleted and its parent.
  242. Node parent = null;
  243. Node trav = root;
  244. while (trav != null && trav.key != key) {
  245. parent = trav;
  246. if (key < trav.key) {
  247. trav = trav.left;
  248. } else {
  249. trav = trav.right;
  250. }
  251. }
  252.  
  253. // Delete the node (if any) and return the removed data item.
  254. if (trav == null) { // no such key
  255. return null;
  256. } else {
  257. LLList removedData = trav.data;
  258. deleteNode(trav, parent);
  259. return removedData;
  260. }
  261. }
  262.  
  263. /*
  264. * Deletes the node specified by the parameter toDelete. parent specifies the
  265. * parent of the node to be deleted.
  266. */
  267. private void deleteNode(Node toDelete, Node parent) {
  268. if (toDelete.left != null && toDelete.right != null) {
  269. // Case 3: toDelete has two children.
  270. // Find a replacement for the item we're deleting -- as well as
  271. // the replacement's parent.
  272. // We use the smallest item in toDelete's right subtree as
  273. // the replacement.
  274. Node replaceParent = toDelete;
  275. Node replace = toDelete.right;
  276. while (replace.left != null) {
  277. replaceParent = replace;
  278. replace = replace.left;
  279. }
  280.  
  281. // Replace toDelete's key and data with those of the
  282. // replacement item.
  283. toDelete.key = replace.key;
  284. toDelete.data = replace.data;
  285.  
  286. // Recursively delete the replacement item's old node.
  287. // It has at most one child, so we don't have to
  288. // worry about infinite recursion.
  289. deleteNode(replace, replaceParent);
  290. } else {
  291. // Cases 1 and 2: toDelete has 0 or 1 child
  292. Node toDeleteChild;
  293. if (toDelete.left != null) {
  294. toDeleteChild = toDelete.left;
  295. } else {
  296. toDeleteChild = toDelete.right; // null if it has no children
  297. }
  298.  
  299. if (toDelete == root) {
  300. root = toDeleteChild;
  301. } else if (toDelete.key < parent.key) {
  302. parent.left = toDeleteChild;
  303. } else {
  304. parent.right = toDeleteChild;
  305. }
  306. }
  307. }
  308.  
  309. /* Returns a preorder iterator for this tree. */
  310. public LinkedTreeIterator preorderIterator() {
  311. return new PreorderIterator();
  312. }
  313.  
  314. /*
  315. * inner class for a preorder iterator IMPORTANT: You will not be able to
  316. * actually use objects from this class to perform a preorder iteration until
  317. * you have modified the LinkedTree methods so that they maintain the parent
  318. * fields in the Nodes.
  319. */
  320. private class PreorderIterator implements LinkedTreeIterator {
  321. private Node nextNode;
  322.  
  323. private PreorderIterator() {
  324. // The traversal starts with the root node.
  325. nextNode = root;
  326. }
  327.  
  328. public boolean hasNext() {
  329. return (nextNode != null);
  330. }
  331.  
  332. public int next() {
  333. if (nextNode == null) {
  334. throw new NoSuchElementException();
  335. }
  336.  
  337. // Store a copy of the key to be returned.
  338. int key = nextNode.key;
  339.  
  340. // Advance nextNode.
  341. if (nextNode.left != null) {
  342. nextNode = nextNode.left;
  343. } else if (nextNode.right != null) {
  344. nextNode = nextNode.right;
  345. } else {
  346. // We've just visited a leaf node.
  347. // Go back up the tree until we find a node
  348. // with a right child that we haven't seen yet.
  349. Node parent = nextNode.parent;
  350. Node child = nextNode;
  351. while (parent != null && (parent.right == child || parent.right == null)) {
  352. child = parent;
  353. parent = parent.parent;
  354. }
  355.  
  356. if (parent == null) {
  357. nextNode = null; // the traversal is complete
  358. } else {
  359. nextNode = parent.right;
  360. }
  361. }
  362.  
  363. return key;
  364. }
  365. }
  366.  
  367. /*
  368. * "wrapper method" for the recursive depthInTree() method from PS 7, Problem 4
  369. */
  370. public int depth(int key) {
  371. if (root == null) { // root is the root of the entire tree
  372. return -1;
  373. }
  374.  
  375. return depthInTree(key, root);
  376. }
  377.  
  378. /*
  379. * original version of the recursive depthInTree() method from PS 7, Problem 4.
  380. * You will write a more efficient version of this method.
  381. */
  382. private static int depthInTree(int key, Node root) {
  383. if (key == root.key) {
  384. return 0;
  385. }
  386.  
  387. if (root.left != null) {
  388. int depthInLeft = depthInTree(key, root.left);
  389. if (depthInLeft != -1) {
  390. return depthInLeft + 1;
  391. }
  392. }
  393.  
  394. if (root.right != null) {
  395. int depthInRight = depthInTree(key, root.right);
  396. if (depthInRight != -1) {
  397. return depthInRight + 1;
  398. }
  399. }
  400.  
  401. return -1;
  402. }
  403.  
  404. public static void main(String[] args) {
  405. System.out.println("--- Testing depth()/depthInTree() from Problem 4 ---");
  406. System.out.println();
  407. System.out.println("(0) Testing on tree from Problem 3, depth of 28 node");
  408. try {
  409. LinkedTree tree = new LinkedTree();
  410. int[] keys = { 44, 35, 53, 23, 48, 62, 28, 57, 80 };
  411. tree.insertKeys(keys);
  412.  
  413. int results = tree.depth(28);
  414. System.out.println("actual results:");
  415. System.out.println(results);
  416. System.out.println("expected results:");
  417. System.out.println(3);
  418. System.out.print("MATCHES EXPECTED RESULTS?: ");
  419. System.out.println(results == 3);
  420. } catch (Exception e) {
  421. System.out.println("INCORRECTLY THREW AN EXCEPTION: " + e);
  422. }
  423.  
  424. System.out.println(); // include a blank line between tests
  425.  
  426. /*
  427. * Add at least two unit tests for each method from Problem 6. Test a variety of
  428. * different cases. Follow the same format that we have used above.
  429. */
  430.  
  431. }
  432. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement