Advertisement
Guest User

Untitled

a guest
Sep 23rd, 2019
132
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.57 KB | None | 0 0
  1. import java.util.Objects;
  2.  
  3. /**
  4. * Implementation of an AVL Tree.
  5. *
  6. * @author Magnus Nielsen (magnus.nielsen@liu.se)
  7. * Partially based on existing C++-laborations by Tommy Olsson and Filip Strömbäck.
  8. */
  9. public class AVLTree<T extends Comparable<T>> {
  10.  
  11. private AVLTreeNode<T> root;
  12.  
  13. /**
  14. * Default constructor.
  15. */
  16. public AVLTree() {
  17. root = null;
  18. }
  19.  
  20. public void insert(T data) {
  21. if (root == null) {
  22. root = new AVLTreeNode<>(data);
  23. } else {
  24. try {
  25. root = root.insert(data);
  26. } catch (AVLTreeException e) {
  27. System.out.println(e.getMessage());
  28. }
  29. }
  30. }
  31.  
  32. /**
  33. * Remove the node which contains the key.
  34. *
  35. * @param key - Generic parameter with the key value which to remove from the tree.
  36. */
  37. public void remove(T key) {
  38. throw new AVLTreeException("Remove needs to be implemented!");
  39. }
  40.  
  41. /**
  42. * Check if the tree contains a node with the key.
  43. *
  44. * @param key - Generic key value for which to search.
  45. * @return boolean, true if the key exists in the tree, false otherwise.
  46. */
  47. public boolean member(T key) {
  48. return root.find(key) != null;
  49. }
  50.  
  51. /**
  52. * Look up the key in the tree, returns the element if it exists.
  53. *
  54. * @param key - Generic value for which to search.
  55. * @return the element containing (or equalling) the key.
  56. */
  57. public T find(T key) {
  58. if (root == null) {
  59. throw new AVLTreeException("Value not found in the tree!");
  60. }
  61. AVLTreeNode<T> tmp = root.find(key);
  62. if (tmp == null) {
  63. throw new AVLTreeException("Value not found in the tree!");
  64. }
  65. return tmp.element;
  66. }
  67.  
  68. /**
  69. * Find the smallest element in the tree.
  70. *
  71. * @return the element containing the smallest value in the tree.
  72. */
  73. public T findMin() {
  74. if (root == null) {
  75. throw new AVLTreeException("Cannot find a smallest element in an empty tree!");
  76. }
  77. return root.findMin().element;
  78. }
  79.  
  80. /**
  81. * Find the largest element in the tree.
  82. *
  83. * @return the element containing the largest value in the tree.
  84. */
  85. public T findMax() {
  86. if (root == null) {
  87. throw new AVLTreeException("Cannot find a largest element in an empty tree!");
  88. }
  89. return root.findMax().element;
  90. }
  91.  
  92. /**
  93. * Check if the tree is empty.
  94. *
  95. * @return boolean, true if empty and false otherwise.
  96. */
  97. public boolean empty() {
  98. return root == null;
  99. }
  100.  
  101. /**
  102. * Clear the tree.
  103. */
  104. public void clear() {
  105. root = root.clear();
  106. }
  107.  
  108. /**
  109. * Swap trees x and y with each other.
  110. *
  111. * @param x - first tree to swap.
  112. * @param y - second tree to swap.
  113. */
  114. public void swap(AVLTree<T> x, AVLTree<T> y) {
  115. x.swap(y);
  116. }
  117.  
  118. /**
  119. * Swap this tree with another.
  120. *
  121. * @param t - the tree to swap with.
  122. */
  123. private void swap(AVLTree<T> t) {
  124. AVLTreeNode<T> tmp = t.root;
  125. t.root = root;
  126. root = tmp;
  127. }
  128.  
  129. /**
  130. * Getter for the root of the tree.
  131. *
  132. * @return the root of the tree.
  133. */
  134. public AVLTreeNode getRoot() {
  135. return root;
  136. }
  137.  
  138. /**
  139. * Find the height of the node with a given key.
  140. *
  141. * @param key - Generic parameter containing the key.
  142. * @return int representing the height of the node containing the key.
  143. */
  144. public int getNodeHeight(T key) {
  145. return Objects.requireNonNull(root.find(key)).height;
  146. }
  147.  
  148.  
  149. ////////////////////////////////////////////////////////////////////////////
  150. // //
  151. // AVL TREE NODE //
  152. // //
  153. ////////////////////////////////////////////////////////////////////////////
  154. /**
  155. * Contains the AVL Tree Node, with rotations and corresponding help functions.
  156. * @author Magnus Nielsen (magnus.nielsen@liu.se)
  157. * Partially based on C++-laborations by Tommy Olsson and Filip Strömbäck.
  158. */
  159. public class AVLTreeNode<T extends Comparable<T>> {
  160.  
  161. private int height;
  162. private T element;
  163. private AVLTreeNode<T> left, right;
  164.  
  165. /**
  166. * Constructor.
  167. *
  168. * @param data - Generic parameter containing the data element for the node.
  169. */
  170. public AVLTreeNode(T data) {
  171. element = data;
  172. }
  173.  
  174. /**
  175. * Constructor.
  176. *
  177. * @param data - Generic parameter containing the data element for the node.
  178. * @param l - AVLTreeNode<T> containing the intended left child for the node being created.
  179. * @param r - AVLTreeNode<T> containing the intended right child for the node being created.
  180. */
  181. public AVLTreeNode(T data, AVLTreeNode<T> l, AVLTreeNode<T> r) {
  182. element = data;
  183. left = l;
  184. right = r;
  185. }
  186.  
  187. ////////////////////////////////////////////////////////////////////////////
  188. // //
  189. // ROTATIONS //
  190. // //
  191. ////////////////////////////////////////////////////////////////////////////
  192.  
  193.  
  194. /**
  195. * Single rotation, left to right, using pivot as pivot.
  196. *
  197. * @param pivot - AVLTreeNode used as pivot for the rotation.
  198. * @return AVLTreeNode with the new node for the pivot location in the tree.
  199. */
  200. private AVLTreeNode<T> singleRotationWithLeftChild(AVLTreeNode<T> pivot) {
  201. AVLTreeNode<T> temp = pivot.left;
  202.  
  203. pivot.left = temp.right;
  204. temp.right = pivot;
  205.  
  206. calculateHeight(pivot);
  207. calculateHeight(temp);
  208. return temp;
  209. }
  210.  
  211. /**
  212. * Single rotation, right to left, using pivot as pivot.
  213. *
  214. * @param pivot - AVLTreeNode used as pivot for the rotation.
  215. * @return AVLTreeNode with the new node for the pivot location in the tree.
  216. */
  217. private AVLTreeNode<T> singleRotationWithRightChild(AVLTreeNode<T> pivot) {
  218. AVLTreeNode<T> temp = pivot.right;
  219.  
  220. pivot.right = temp.left;
  221. temp.left = pivot;
  222.  
  223. calculateHeight(pivot);
  224. calculateHeight(temp);
  225. return temp;
  226. }
  227.  
  228. /**
  229. * Double rotation, left to right, using pivot as pivot.
  230. *
  231. * @param pivot - AVLTreeNode used as pivot for the rotation.
  232. * @return AVLTreeNode with the new node for the pivot location in the tree.
  233. */
  234. private AVLTreeNode<T> doubleRotationWithLeftChild(AVLTreeNode<T> pivot) {
  235. pivot.left = singleRotationWithRightChild(pivot.left);
  236. return singleRotationWithLeftChild(pivot);
  237. }
  238.  
  239. /**
  240. * Double rotation, right to left, using pivot as pivot.
  241. *
  242. * @param pivot - AVLTreeNode used as pivot for the rotation.
  243. * @return AVLTreeNode with the new node for the pivot location in the tre.
  244. */
  245. private AVLTreeNode<T> doubleRotationWithRightChild(AVLTreeNode<T> pivot) {
  246. pivot.right = singleRotationWithLeftChild(pivot.right);
  247. return singleRotationWithRightChild(pivot);
  248. }
  249.  
  250.  
  251. ////////////////////////////////////////////////////////////////////////////
  252. // //
  253. // NODE FUNCTIONALITY //
  254. // //
  255. ////////////////////////////////////////////////////////////////////////////
  256.  
  257. /**
  258. * Adjust the height for a given node n.
  259. *
  260. * @param n - AVLTreeNode for which to calculate the height.
  261. */
  262. private void calculateHeight(AVLTreeNode<T> n) {
  263. n.height = 1 + Math.max(nodeHeight(n.left), nodeHeight(n.right));
  264. }
  265.  
  266. /**
  267. * Insert element into the tree originating from t. Check balance and adjust as needed.
  268. *
  269. * @param data - Generic element parameter to be inserted.
  270. * @return AVLTreeNode containing the appropriate node for the call position, after insertion.
  271. */
  272. private AVLTreeNode<T> insert(T data) {
  273. if (data.compareTo(element) < 0) {
  274. if (left == null) {
  275. left = new AVLTreeNode<>(data);
  276. } else {
  277. left = left.insert(data);
  278. }
  279.  
  280. if (nodeHeight(left) - nodeHeight(right) == 2) {
  281. if (data.compareTo(left.element) < 0) {
  282. return singleRotationWithLeftChild(this);
  283. } else {
  284. return doubleRotationWithLeftChild(this);
  285. }
  286. } else {
  287. calculateHeight(this);
  288. }
  289. } else if (element.compareTo(data) < 0) {
  290. if (right == null) {
  291. right = new AVLTreeNode<>(data);
  292. } else {
  293. right = right.insert(data);
  294. }
  295.  
  296. if (nodeHeight(right) - nodeHeight(left) == 2) {
  297. if (data.compareTo(right.element) > 0) {
  298. return singleRotationWithRightChild(this);
  299. } else {
  300. return doubleRotationWithRightChild(this);
  301. }
  302. } else {
  303. calculateHeight(this);
  304. }
  305. } else {
  306. throw new AVLTreeException("Element already exists.");
  307. }
  308. return this;
  309. }
  310.  
  311. /**
  312. * Returns the height of (sub) tree node.
  313. *
  314. * @param n - AVLTreeNode for which to get the height.
  315. */
  316. private int nodeHeight(AVLTreeNode<T> n) {
  317. if (n != null) {
  318. return n.height;
  319. }
  320. return -1;
  321. }
  322.  
  323. /**
  324. * Search for a node containing the key. If found: return the node, otherwise return null.
  325. *
  326. * @param key - Generic key type for which to search.
  327. * @return AVLTreeNode containing the key, if not found null be returned.
  328. */
  329. private AVLTreeNode<T> find(T key) {
  330. if (key.compareTo(element) < 0) {
  331. if (left == null) {
  332. return null;
  333. }
  334. return left.find(key);
  335. } else if (element.compareTo(key) < 0) {
  336. if (right == null) {
  337. return null;
  338. }
  339. return right.find(key);
  340. } else {
  341. return this;
  342. }
  343. }
  344.  
  345. /**
  346. * Looks for the node with the smallest value in the tree (the leftmost node), and returns that node.
  347. * If the tree is empty, null will be returned.
  348. *
  349. * @return AVLTreeNode with the smallest value in the tree, null if the tree is empty.
  350. */
  351. private AVLTreeNode<T> findMin() {
  352. if (left == null) {
  353. return this;
  354. } else {
  355. return left.findMin();
  356. }
  357. }
  358.  
  359. /**
  360. * Looks for the node with the largest value in the tree (the rightmost node), and returns that node.
  361. * If the tree is empty, null will be returned.
  362. *
  363. * @return AVLTreeNode with the largest value in the tree, null if the tree is empty.
  364. */
  365.  
  366. private AVLTreeNode<T> findMax() {
  367. if (right == null) {
  368. return this;
  369. } else {
  370. return right.findMax();
  371. }
  372. }
  373.  
  374. /**
  375. * Clear the given tree completely.
  376. *
  377. * @return null (to be used for clearing the root node.
  378. */
  379. private AVLTreeNode<T> clear() {
  380. if (left != null) {
  381. left = left.clear();
  382. }
  383. if (right != null) {
  384. right = right.clear();
  385. }
  386. return null;
  387. }
  388.  
  389. /**
  390. * Simple remove will remove in a lazy fashion, as with non balancing trees. Can be used as a guide when
  391. * implementing the real remove function.
  392. *
  393. * @param x - Generic parameter with the key to be deleted.
  394. * @param t - The (sub) tree from which to remove.
  395. * @return - AVLTreeNode<T>, the correct node for the source position in the tree.
  396. */
  397. private AVLTreeNode<T> simpleRemove(T x, AVLTreeNode<T> t) {
  398. if (t == null) {
  399. return null;
  400. }
  401.  
  402. if (x.compareTo(t.element) < 0) {
  403. t.left = simpleRemove(x, t.left);
  404. } else if (t.element.compareTo(x) < 0) {
  405. t.right = simpleRemove(x, t.right);
  406. } else {
  407. if (t.left != null && t.right != null) {
  408. // The node has two children, so we replace it with the next node inorder.
  409. AVLTreeNode<T> tmp = t.right.findMin();
  410. t.element = tmp.element;
  411. t.right = simpleRemove(tmp.element, t.right);
  412. } else {
  413. // The node has, at most, one child.
  414. if (t.left == null) {
  415. return t.right;
  416. } else {
  417. return t.left;
  418. }
  419. }
  420. }
  421. return t;
  422. }
  423.  
  424. /**
  425. * Getter for element.
  426. *
  427. * @return the element in said node.
  428. */
  429. public T getElement() {
  430. return element;
  431. }
  432.  
  433. /**
  434. * Getter for the left hand tree node.
  435. *
  436. * @return the left hand tree node.
  437. */
  438. public AVLTreeNode<T> getLeft() {
  439. return left;
  440. }
  441.  
  442. /**
  443. * Getter for the right hand tree node.
  444. *
  445. * @return the right hand tree node.
  446. */
  447. public AVLTreeNode<T> getRight() {
  448. return right;
  449. }
  450. }
  451. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement