Advertisement
the_alator

Untitled

May 30th, 2018
154
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.43 KB | None | 0 0
  1. package ua.nure.rozdaybeda.Practice6.part5;
  2.  
  3. import java.util.Arrays;
  4.  
  5. /**
  6. * Implements binary tree
  7. * @author Oleg
  8. *
  9. * @param <E> specifies type of stored data in the tree has to support comperison.
  10. */
  11. public class Tree<E extends Comparable<E>> {
  12.  
  13. /**
  14. * Indent between levels of tree in string representation
  15. */
  16. private static final String INDENT = " ";
  17.  
  18. /**
  19. * Root node of tree
  20. */
  21. private Node<E> root = null;
  22.  
  23. /**
  24. * Max size of string representation of element in tree
  25. */
  26. private int elSize = 0;
  27.  
  28. /**
  29. * Adds element to the tree
  30. * @param e element
  31. * @return true if element successfully added, false if the element is already exists in the tree
  32. */
  33. public boolean add(E e) {
  34. int l = e.toString().length();
  35. if(l > elSize) {
  36. elSize = l;
  37. }
  38. if(root == null) {
  39. root = new Node<E>(e);
  40. return true;
  41. }
  42. return addRec(e, root);
  43. }
  44. /**
  45. * Recursively bypasses the tree and finds the place to add new element
  46. * @param e element
  47. * @param node current node
  48. * @return true if element successfully added, false if the element is already exists in the tree
  49. */
  50. private boolean addRec(E e, Node<E> node) {
  51. int compResult = e.compareTo(node.data);
  52. if(compResult == 0) {
  53. return false;
  54. }
  55. if(compResult < 0) {
  56. if(node.left == null) {
  57. createAndAppendNode(e, node, LEFT);
  58. return true;
  59. } else {
  60. return addRec(e, node.left);
  61. }
  62. } else {
  63. if(node.right == null) {
  64. createAndAppendNode(e, node, RIGHT);
  65. return true;
  66. } else {
  67. return addRec(e, node.right);
  68. }
  69. }
  70. }
  71.  
  72. /**
  73. * Left branch of node
  74. */
  75. private static final int LEFT = -1;
  76. /**
  77. * Right branch of node
  78. */
  79. private static final int RIGHT = 1;
  80.  
  81. /**
  82. * Creates new node and appends it to another specifien node
  83. * @param e element
  84. * @param parent parent node
  85. * @param side side of parrent node to attach new node
  86. */
  87. private void createAndAppendNode(E e, Node<E> parent, int side) {
  88. if(side == LEFT) {
  89. parent.left = new Node<E>(e);
  90. } else {
  91. parent.right = new Node<E>(e);
  92. }
  93. }
  94.  
  95. /**
  96. * Adds elements of array to tree one by one
  97. * @param elements the array
  98. */
  99. public void add(E[] elements) {
  100. for(E e : elements) {
  101. add(e);
  102. }
  103. }
  104.  
  105. /**
  106. * Removes element from tree keeping the binary property of tree
  107. * @param e element to remove
  108. * @return true if element found, false if element is not in the tree
  109. */
  110. public boolean remove(E e) {
  111. if(root == null) {
  112. return false;
  113. }
  114. if(root.data.compareTo(e) == 0) {
  115. root = null;
  116. return true;
  117. }
  118.  
  119. return removeRec(e, root);
  120. }
  121.  
  122. /**
  123. * Recursively bypasses the tree and finds a node with equal data to remove the node
  124. * @param e element
  125. * @param node current node
  126. * @return true if element found, false if element is not in the tree
  127. */
  128. private boolean removeRec(E e, Node<E> node) {
  129. int compResult = e.compareTo(node.data);
  130.  
  131. if(compResult < 0) {
  132. if(node.left == null) {
  133. return false;
  134. } else {
  135. if(e.compareTo(node.left.data) == 0) {
  136. removeChildNode(node, LEFT);
  137. return true;
  138. } else {
  139. return removeRec(e, node.left);
  140. }
  141. }
  142. } else {
  143. if(node.right == null) {
  144. return false;
  145. } else {
  146. if(e.compareTo(node.right.data) == 0) {
  147. removeChildNode(node, RIGHT);
  148. return true;
  149. } else {
  150. return removeRec(e, node.right);
  151. }
  152. }
  153. }
  154. }
  155.  
  156. /**
  157. * Removes child node in specified side of parent node
  158. * @param parent parent node
  159. * @param side side of parent node with node will be deleted
  160. */
  161. private void removeChildNode(Node<E> parent, int side) {
  162. Node<E> child;
  163. if(side == LEFT) {
  164. child = parent.left;
  165. } else {
  166. child = parent.right;
  167. }
  168. if(child.left == null && child.right == null) {
  169. setSide(parent, side, null);
  170. return;
  171. }
  172. if(child.left == null ^ child.right == null) {
  173. if(child.left != null) {
  174. setSide(parent, side, child.left);
  175. } else {
  176. setSide(parent, side, child.right);
  177. }
  178. return;
  179. }
  180. if(child.left != null && child.right != null) {
  181. if(child.left.right == null) {
  182. replaceSide(parent, side, child.left);
  183. removeChildNode(child, LEFT);
  184. return;
  185. }
  186. Node<E> rightestParent = getParentOfRightest(child.left);
  187. replaceSide(parent, side, rightestParent.right);
  188. removeChildNode(rightestParent, RIGHT);
  189. }
  190. }
  191. /**
  192. * Returns parent node of node which doesn`t have right node
  193. * @param parent initial node
  194. * @return parent node of node which doesn`t have right node
  195. */
  196. private Node<E> getParentOfRightest(Node<E> parent){
  197. while(parent.right.right != null) {
  198. parent = parent.right;
  199. }
  200. return parent;
  201. }
  202.  
  203. /**
  204. * Sets specifeid node to specifien side of node
  205. * @param parent parent node
  206. * @param side side of parent node
  207. * @param newChild node will be appended to parent node
  208. */
  209. private void setSide(Node<E> parent, int side, Node<E> newChild) {
  210. if(side == LEFT) {
  211. parent.left = newChild;
  212. } else {
  213. parent.right = newChild;
  214. }
  215. }
  216. /**
  217. * Replaces data of one node with data of other node
  218. * @param parent node which child`s data will be repleced
  219. * @param side side with child node
  220. * @param newNode node with new data
  221. */
  222. private void replaceSide(Node<E> parent, int side, Node<E> newNode) {
  223. if(side == LEFT) {
  224. parent.left.data = newNode.data;
  225. } else {
  226. parent.right.data = newNode.data;
  227. }
  228. }
  229. /**
  230. * Calculates heigth of the tree
  231. * @return height of the tree
  232. */
  233. public int getHeight() {
  234. if(root == null)
  235. return 0;
  236. return calcHeight(root);
  237. }
  238.  
  239. /**
  240. * Recursively calculates height of tree. Counts height of each node from leaves to root
  241. * @param node current node
  242. * @return height of current node
  243. */
  244. private int calcHeight(Node<E> node) {
  245. if(node == null)
  246. return 0;
  247. int result = 1;
  248.  
  249. if(node.left != null) {
  250. result = calcHeight(node.left) + 1;
  251. }
  252.  
  253. if(node.right != null) {
  254. int temp = calcHeight(node.right) + 1;
  255. if(temp > result)
  256. result = temp;
  257. }
  258.  
  259. return result;
  260. }
  261. /**
  262. * Prints string representation of tree to standart output stream
  263. */
  264. public void print() {
  265. System.out.println(toString());
  266. }
  267.  
  268. @Override
  269. public String toString() {
  270. int height = calcHeight(root);
  271. if(height == 0) {
  272. return "";
  273. }
  274. if(height == 1) {
  275. return root.toString();
  276. }
  277.  
  278. return new TreeToString<E>(height, root, elSize).represent();
  279. }
  280.  
  281. /**
  282. * Implements node of tree
  283. * @author Oleg
  284. *
  285. * @param <E> type of stored data in node. Equal to tree`s type
  286. */
  287. private static class Node<E> {
  288. /**
  289. * Reference to left node
  290. */
  291. Node<E> left;
  292. /**
  293. * Reference to right node
  294. */
  295. Node<E> right;
  296. /**
  297. * Data of this node
  298. */
  299. E data;
  300.  
  301. /**
  302. * Constructor
  303. * @param data data of current node
  304. */
  305. Node(E data){
  306. this.data = data;
  307. }
  308.  
  309. @Override
  310. public String toString() {
  311. return data.toString();
  312. }
  313. }
  314. /**
  315. * Makes string representation of the tree
  316. * @author Oleg
  317. *
  318. * @param <E> type of stored data in the tree.
  319. */
  320. private static class TreeToString<E> {
  321. /**
  322. * Height of tree
  323. */
  324. private int height;
  325. /**
  326. * Reference to root node of tree
  327. */
  328. private Node<E> root;
  329. /**
  330. * Buffer storage of string representation
  331. */
  332. private StringBuilder result;
  333. /**
  334. * Max size of string representation of element in tree
  335. */
  336. int elSize;
  337. /**
  338. * Length of line in buffer
  339. */
  340. int resultLineLength;
  341. /**
  342. * Count of lines in buffer
  343. */
  344. int resultLinesCount;
  345. /**
  346. * Registers amount of visited nodes in each level of tree
  347. */
  348. int nodeVisited[];
  349. /**
  350. * Vertical indent bettween two elements for each level
  351. */
  352. int verticalOffsets[];
  353.  
  354. /**
  355. * Constructor
  356. * @param height height
  357. * @param root root
  358. * @param elSize elSize
  359. */
  360. private TreeToString(int height, Node<E> root, int elSize) {
  361. this.height = height;
  362. this.root = root;
  363. this.elSize = elSize;
  364.  
  365. resultLineLength = elSize + (height - 1) * (elSize + INDENT.length()) + System.lineSeparator().length();
  366. resultLinesCount = ((int) Math.pow(2, height)) - 1;
  367.  
  368. result = new StringBuilder(resultLineLength * resultLinesCount);
  369.  
  370. // String spacesStr = createEmptyLine(resultLineLength - System.lineSeparator().length());
  371. for(int i = 0; i < resultLinesCount; i++) {
  372. result.append(createEmptyLine(resultLineLength - System.lineSeparator().length()));
  373. }
  374.  
  375. nodeVisited = new int[height];
  376.  
  377. verticalOffsets = new int[height + 1];
  378. verticalOffsets[height - 1] = 1;
  379. for(int i = height - 2; i >= 0; i--) {
  380. verticalOffsets[i] = (verticalOffsets[i + 1] * 2) + 1;
  381. }
  382. }
  383.  
  384. /**
  385. * Creates string representation of tree
  386. * @return string representation of tree
  387. */
  388. private String represent() {
  389. out.println("height = " + height + " resultLineLength " + resultLineLength + " resultLinesCount " + resultLinesCount);
  390. out.println(Arrays.toString(verticalOffsets));
  391. traversal(root, 0);
  392.  
  393. return result.toString();
  394. }
  395. /**
  396. * Recursively bypasses the tree node by node and makes appropriate changes to the buffer
  397. * @param node current node
  398. * @param currentLevel current level
  399. */
  400. private void traversal(Node<E> node, int currentLevel) {
  401. int horOffset = 1 + currentLevel * (INDENT.length() + elSize);
  402. int vertOffset = verticalOffsets[currentLevel + 1] /*+ 1*/ + nodeVisited[currentLevel] * (verticalOffsets[currentLevel] + 1);
  403.  
  404. int pos = vertOffset * resultLineLength + horOffset;
  405. String str = node.toString();
  406. out.println("node.toString " + str + " currentLevel " + currentLevel);
  407. out.println("replacePos " + pos + " horOffset " + horOffset + " vertOffset " + vertOffset);
  408. result.replace(pos, pos + str.length(), str);
  409.  
  410. if(node.right == null) {
  411. changeNodeVisited(currentLevel + 1);
  412. } else {
  413. traversal(node.right, currentLevel + 1);
  414. }
  415. if(node.left == null) {
  416. changeNodeVisited(currentLevel + 1);
  417. } else {
  418. traversal(node.left, currentLevel + 1);
  419. }
  420.  
  421. nodeVisited[currentLevel]++;
  422. }
  423.  
  424. /**
  425. * Is called to change {@link #nodeVisited nodeVisited} due to null nodes
  426. * @param currentLevel start level for changers
  427. */
  428. private void changeNodeVisited(int currentLevel) {
  429. out.println("START changeNodeVisited");
  430. if(currentLevel == height) {
  431. out.println("END changeNodeVisited");
  432. return;
  433. }
  434. for(int summand = 1; currentLevel < height; currentLevel++, summand *= 2) {
  435. out.println("[changeNodeVisited] currentLevel " + currentLevel + " summand " + summand);
  436. nodeVisited[currentLevel] += summand;
  437. }
  438. out.println("END changeNodeVisited");
  439. }
  440. /**
  441. * Creates line with spaces and system-independent line separator int the end of line
  442. * @param spaces count of spaces
  443. * @return created line
  444. */
  445. private String createEmptyLine(int spaces) {
  446. StringBuilder result = new StringBuilder(spaces + System.lineSeparator().length());
  447. for(int i = 0; i < spaces; i++) {
  448. result.append(" ");
  449. }
  450. result.append(System.lineSeparator());
  451. return result.toString();
  452. }
  453.  
  454. }
  455.  
  456. final static DebugOut out = new DebugOut();
  457. static boolean debug = false;
  458. static class DebugOut{
  459. public void println(String data) {
  460. if(debug == true) {
  461. System.out.println(data);
  462. }
  463. }
  464. }
  465.  
  466. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement