From 2abe59726f060093ee015e7862357e62feee2b91 Mon Sep 17 00:00:00 2001 From: Jozef Jankaj Date: Sat, 29 May 2021 20:43:22 +0200 Subject: [PATCH] binary tree implemented --- TreeLib.iml | 11 ++ out/production/TreeLib/Main.class | Bin 0 -> 515 bytes .../TreeLib/binarytree/BinaryTree.class | Bin 0 -> 3670 bytes .../TreeLib/binarytree/BinaryTreeNode.class | Bin 0 -> 3769 bytes out/production/TreeLib/graph/Node.class | Bin 0 -> 1754 bytes out/production/TreeLib/graph/Tree.class | Bin 0 -> 1429 bytes out/test/TreeLib/BinaryTreeTests.class | Bin 0 -> 2278 bytes src/binarytree/BinaryTree.java | 168 ++++++++++++++++++ src/binarytree/BinaryTreeNode.java | 78 ++++++++ src/graph/Graph.java | 11 -- src/graph/Node.java | 42 ++++- src/graph/Tree.java | 35 ++++ tests/BinaryTreeTests.java | 55 ++++++ 13 files changed, 381 insertions(+), 19 deletions(-) create mode 100644 out/production/TreeLib/Main.class create mode 100644 out/production/TreeLib/binarytree/BinaryTree.class create mode 100644 out/production/TreeLib/binarytree/BinaryTreeNode.class create mode 100644 out/production/TreeLib/graph/Node.class create mode 100644 out/production/TreeLib/graph/Tree.class create mode 100644 out/test/TreeLib/BinaryTreeTests.class create mode 100644 src/binarytree/BinaryTree.java create mode 100644 src/binarytree/BinaryTreeNode.java delete mode 100644 src/graph/Graph.java create mode 100644 src/graph/Tree.java create mode 100644 tests/BinaryTreeTests.java diff --git a/TreeLib.iml b/TreeLib.iml index c90834f..e4b5f69 100644 --- a/TreeLib.iml +++ b/TreeLib.iml @@ -4,8 +4,19 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/out/production/TreeLib/Main.class b/out/production/TreeLib/Main.class new file mode 100644 index 0000000000000000000000000000000000000000..9b14f1b3a71488a990a81554626f9e8ae7533027 GIT binary patch literal 515 zcmZuu%TB^T6g|VMv{pe7d@Hy@7k0@4`qVcnIp@|DWz>hMX zDJDol7x&IR_slu>PQQOXzW}sxV4;9D6E)O}Shui&O#@p7wgn0&Dpbj-K(=+*6Ud!K z_ntt>RiSq^3Hn}qEBii?iW?22-;=S@^&gl^9@Ll`?xj>=hqnV}fqLuC9myx@_%a+i z-6U4wu#>9Gcu0PAL0iD;Mw58pohxl;YQbYw>}ud}IA(Kst(yCM$aZ5q-IxiV=H5rjmU} ZZYE%{1!U=y`zKTq4f-`u0qZjCjzUd%ycF z_ndE0fBL__{{z6i_)`*{cruADoYC=A5>c32D4CHZ--uaQNn~(Vj&qH8NFC=zX3On@ zn4i;85XoW^DHKKQh^iy9lI)(=;mU7WmIYb7Moge0%aV>~lGuqejd&F2Wm%Tx*(AP) z?>FEFI)0c$2hNDI=VbT1EYIoqk&Yj0NDSLW+skT*c6OcA5F2r3Ee)xhU9=`Di!+ux zWzG~RX~{WxvvAUMZ8-ltNeY*c8jJ61t7O?qbj+_+f^*vk0f zH&INw)}pgyDaT(4{WPDEpSKIM8Z?`KW6W032hre*U8|^Jn_{El*@ga`UH0VdWzTdy z4IQ^!4S(q+*&!V-RB2+kRA-&aP}gZ47c^|I7b>V-)NMFx7Xwc9e8uHs7&88J#gZH~ z*M)vWM10o1TV?coX;vs^0OJv=oy zSa%Q<$7|DsJ8ywWS48VQC+b>NL=edt~Wh;7vO~GAar`G4NB|Z{TNm zNyp0uUcsvdeva1+ypCfAej#q|!=QnSa`7+*HQeUczn{kkUDsTeWE%J--VlFp8u*oH z{u;kA@LOEckPOS!z+3p8f#2h81MlDu2L6c4WbPJ!M=a*Xz`Nq+J<)m}mvww#;0j)4 z;*Ktsyk&NF*oBJhfKCG^amv67KGcxj6ngDRLZ^nUVR%8pc@hf7Jj*pb$0fs|&@U4W zch*lavF^h@%AuxHFU% z`f-q_yEjO_&Xf4Ohc@DKfmUMO(!GjE_jN?4wVqYP{)Twye=Fkv+Yv*WQ8IpvjIs)1 z&>n~I4SJSn;hjWNcLTh;m-`65$sI>P5dUBN74M_ne?_8a4SEEpxQ$;!!zb9q-4;2m zAsNVfuAxyRS7qVB7#E#hrOHd(puC9yIb3AdP)o_mjs?GSbWF2XKTt;cAbH zUc)hpAs@$mXu>e==j#MfsHG5zmLO7ES!#WYT2W{R1CS5!@?6KZ zk$9YG1)&NRDMCyWQ#+~a#Zlt?HnKQ|9L8{(>pZ4#j-O*L2WAD+xIpPeJjTI1&58S@ zPxdjgaFO0dNNfVjOvn*>iVHKf1Y8Lckf!FSpMZ9}$XLh7;W^%o(IVz2s(k_dD>wgB$Nhe6 zVN9EBEy%Yr?tsJcEfJT8Niuu}OPIm=S`kmO?S)rqrr8>svp$EaEv1N+R<@?4_!6xw zF$*^aqN#Np)G={`tSLTD@Q(khgK9p(U*X#eid9v!cJ(@TPOsvQ@m?vaHSChYUBhmT zwSJtNJqod)CF=G|i1%IPL2)w}Yl{W!+%7vs&tSZ_E$~EgR&M@93mbfZ%m6QNy+D3m zMk~KH_VQDs2d}Y#U&jOd*f@+gkjI-S@FT+EH-yVi2x)q$oILpzzT(s##3KQ7UX3{~ zsKZt~f$xwvH3&k>Y|T=!DVB;&v6SjlmQ%D8UfWo6>uAyO=sI?@^45_g$DgA;Qa3XA ztwBSX%b(FqiteZso!`1|A%VD>wg3uI~z2+vU%p zx0&U4$l7JT@m;d<9?`!~#;(+==@8lZZotXWfRk3e3jj^K&^1CQVdh5!Hn literal 0 HcmV?d00001 diff --git a/out/production/TreeLib/binarytree/BinaryTreeNode.class b/out/production/TreeLib/binarytree/BinaryTreeNode.class new file mode 100644 index 0000000000000000000000000000000000000000..a48050d57e6cf34d5305e4d75c193929820a658d GIT binary patch literal 3769 zcma)9`*R!R6+J82UPs#4j!En!PMic{kSzxVLJL^N6x#`y$~MGq(u6)(OKWQrX;-XP zfzStiLEq)k2Tcnt1Zet5+t5-aPNto9`dg=eK>I`gkawx9#cNqh_^bev3ZvLug>>o}Ewj??mZOtwFveW&X4n z`%Dsx_^doW*NxAMk7s1>84X>NwqyHK8b(sNHP5URGYf9P%I40P=gdsWbk;I6Zni^ zhAm6>nq&GkkDLahNl`FjBn`S*C`kAk4yM}2HyZIkv)zvM- zDl^cTSM+1m6%D&KA*O3gj^$-_d_ltOHL^vO*D6?Wb8FN>SR#v7YkDhRdlr(Pn(j;$#OWk?J=^ z7H8MdAu%UZ3+>z>wU$cgxQiLLOv-wwfeFG=s~Kj7o7n^|}I7>I|C3yw?Mng85xrW&Yy0O$gOC#;Gqk4C-q7){z z^sGWHPu0vt-Gz}TZyVF|E(=lbO)+)bPD4hj$%7oImZ8g4*DK3ycW>0C+RZ)|Vb~@` zA&N$*0?VOf54AB84N9G8T!EB0UwvVF4Q$9!qwS=+yw?}lK0zXuAO0RC7ur)d-9x-FOIG!uIv5pJn4(A?Hym8%%RCDI;G4?j`=5j&C8vkmAfmoIgMxOOIcL_BMxc zjPjWv0N6r!0%IKQS1_b8&KVEj5N@X_8D(&o=sP%Wq3#q=fI8Ad-9^-gxEjNUxyBb2 zM-s$88Jq+$JN6D@>xeT07qR^YI!=wHucC8)Y`l)H@hh@>1Ny0}=xze**s_j941Y#) zemq@=afNm|0tUMoJ9tNI#Q+BR+k;&g=6C88_63Z_h#O>t_mYQjoo#ZPl@}T#oT7zn zuq)hJ_#;icVk!8$nt0irBt8ypIHY?Ym-sH{Q|SJcTSE6}lSSu6Y?DcP9b02Kc?shm zgliA!o|K9yz60pw_!ja#h#@-4GU8cQt5LlytEt$~b(8B++#l4jQ9XrH3SB{E3~-5+=#P-jE$w1S5)N6Rgr zJGm!5LkSFUlV2{O^M6oL9o#&A1G}l?p?Q39hWG%3e3-v^~q)3IB};=eIMR;sff!K1Vnqs8CzZ-SQI ZMjgLn@2zky7W1@KfQ8jybQUF){|{8Zgx&xE literal 0 HcmV?d00001 diff --git a/out/production/TreeLib/graph/Node.class b/out/production/TreeLib/graph/Node.class new file mode 100644 index 0000000000000000000000000000000000000000..608ce7dd800435828649abb8586fd76937eaec31 GIT binary patch literal 1754 zcmb7D+fEZv6kVq+y)hKZovH`|+7_gW7ZfT=FeWAqn$R?nw}DRDA*ID(O2SY0B|c~( zl4#-w_)*5SXQu76ln457diLe4wfEY4{{H**2f#YEGeu(r*V9uTlzuG*i?w^nU%V3H!UUwi$!|E3>tM? zK`T@&{iK@PZImT5=`-`p+@ddfST$>9rYnrN3{BgtdXB^q0r|s;SbpK=l4W~WyL89-p)f;UQ`1M=5;_R_?~u_*)3?x z7i+`D_Zm&>(0FIcmc*p*RUy|ffj1fkp=lV#h{Bjtk~4yB%hJzfk2Q>9Ov4HuYFI^1 zA>NUfTi@FR+e>Fkp?Q9raelBtew)OH!Vs+h60}Lxwv!ka{I)&LcT^6O%$?$kFGL9P zKb5_N%C1}>kX^n&F#8*!PnQ_DK=`}EGR<=m13U-Gpb=$=TnWsOZHC@C7X>MD%P-|s zAvdWnfLmQz$#zzf^|)CHX1QJ5rtc1By&AV^NzOp_2Lj)C2|~&VJI+yuUIbu*M=w+z zk5IX=cbPSZc@K7<{{g{~jsu-Gh6!{|r|iHcosnqJ$r6pV+qiq&digZr^2^I8hV z%7^BOnQwb`BVV>#9=8?-LdBuu0*IfOjkXX{q4bI+fXV(yw`9C%H*JrOqnYe3eQ(i$ z9Jia+PWx!ja;xTEgOQ1{Q!^X8rfZAt1Xb_AX0dLURo9X(r}|S*kGtvJmL;!SKUufD zQllX+h@^>3He|EY`qEJF^5!+7D)uLuWiM|Oh<@jfVU&cvL8SWvT`!uszb{4-Kl{$gq~> zIvSY5w1V`-)hxNLc`8FPFotnn>5Hw`X6u0W&OjQI8a55Q!h!(c|A=oo zsIOr3f+B3*$rgvI&hzt1@@tGj6%Lq46+w!c)q8q^nnip1DiU1NI-l2gqDF$k|GC^b zl-y55-k&3S29?Vgm+>=bU;Q#Od`O;?irhvDf|V zq4Cnl6b-wOS++g1V7jw&3~jz|*_Jn_pedE!WU3`6PmoJl%QjalrCrnAFm{WybY-1A zqqu3fmgrSu+&i$!3NB~EYBtQWS0-*;U=<9kS8UHJnVVMGV%&mlJD%ZLj?FMax`oVP zg^rm;bKh~L72PAiLOySalY*E%PFuF%8b=42Rn|tAm_4DOufCq+qgqYZBhGJYx-*hl z3MOcKG%xY%^hpJ6a=&htoR>yXftGVB?wlniO3VIukOvk%;Psawn z)Uk;z9Z#{X;+c-;*wOKoSf1l+9pB(v9R_xF>>*E{|2IM%Cbo6#qoCqIhlNAd7LrB& z8|D`xrNHl06m^tft8jE2NwyboIsOYBDd-GSuk9Y1dmODwCMxFIK4+0yPB&ODx)}Mq z1zRf_~^0oH1z$eH#w2ooo%Y29&{x+8U=+!kJK3JVI7ybC#s zbjZ>yyXMu#fTaVgn0HMscULW@;#tK^*76sz!$&!{kO{^}b#)w9n^15g6=kq-3DQMm zfVtzcXO;-;R0KGPv7F2kmxbo|bumgDMYmr^y_sYjiBplqYp%QuW-#7?D0h+O)6a07 zAI+=$N-F&4*7JEyzL~T)Q|3#;bC{M4pW>4kIfe4dce%k+oPZYGD~B z6EtThWx=B}nc z(H+AZ^whaXOHB}3ZlaZE7b)pR61~*>FvXvc2h`RvfC2{bGp_jUUJKf&wyWbue1I`F zoJ5(dkCB`^#OmWSxEnve8>g*C&jfuGOxEbZ52Qy%GavTdycISb$U)12tOm4g^`JLs z-={5{(jcb*E{M(rNpd}gxg2+R&avTe`tuj27L;}OysW1zOQzlN8vWafjO`T3Y)D+N z3u$h{h>t35)4Ph=&Xxjlgc8}ez#^2?6ESt3@z*L5J8vW6Hw**~4~8CBwnA%l8+-gtPD8dnBti_+{{dH7> extends Tree { + + public BinaryTree() { + this(null); + } + + public BinaryTree(T initialValue) { + this.root = new BinaryTreeNode<>(null, initialValue); // initialize the root + } + + /** + * Adds a new node to the tree + * + * @param value value of the node to be added + * @return true if the addition was successful, false otherwise + */ + @Override + public Node addNode(T value) { + this.values.add(value); + + // if root has not been initialized yet + if (this.root.getValue() == null) { + this.nodes.add(root); + + this.root.setValue(value); + + return root; + } + + // root has been initialized, so call on the root to add the value + Node newNode = root.addNode(value); + + this.nodes.add(newNode); + + return newNode; + } + + /** + * removes a node from the tree, based on value + * + * @param value the value of the node to be removed + * @return true if the node was successfully removed, false otherwise + */ + @Override + public boolean removeNode(T value) { + if (!this.values.contains(value)) { + return false; + } + + Node node = findNode(value); + + List> children = new ArrayList<>(node.getChildren()); + + // remove the node + this.values.remove(value); + this.nodes.remove(node); + + if(node.getParent() != null) { + node.getParent().getChildren().remove(node); + this.nodes.remove(node); + } else { // if the value had no parent, it was the root node + // set the root node to be the first node of the children list + this.root = children.get(0); + } + + // binary tree does not put any restrictions on what order the children are in the tree + // re-introduce all children into the root + + // it could happen that we have removed the root node and set the first child to be the new root + // if so, only reintroduce the other children, omitting the first one + int start = 0; + if(node.getParent() == null) { + start = 1; + } + + for (int i = start; i < children.size(); i++) { + Node child = children.get(i); + this.root.addNode(child.getValue()); + } + + return true; + } + + /** + * Removes the passed node + * + * @param node node to be removed + * @return true if the removal was successful, false otherwise + */ + @Override + public boolean removeNode(Node node) { + if (!this.nodes.contains(node)) { + return false; + } + + // remove the node + this.values.remove(node.getValue()); + this.nodes.remove(node); + node.getParent().getChildren().remove(node); + + // binary tree does not put any restrictions on what order the children are in the tree + // re-introduce all children into the parent + for (Node child : node.getChildren()) { + node.getParent().addNode(child.getValue()); + } + + return true; + } + + /** + * Finds the node with passed value + * + * @param value the value the required node should have + * @return the required node if one is present, null otherwise + */ + @Override + public Node findNode(T value) { + if (!this.values.contains(value)) { + return null; + } + + // because Binary Tree does not put ANY restrictions on what order the children are in, + // we need search through the entire tree + // we shall perform a BFS to do this + Queue> queue = new ArrayDeque<>(); + queue.offer(root); + + while (!queue.isEmpty()) { + Node current = queue.poll(); + if (current.getValue().equals(value)) { + return current; + } + + for (Node child : current.getChildren()) { + queue.offer(child); + } + } + + return null; + } + + @Override + public String toString() { + if(nodes.size() == 0) { + return "Empty"; + } + + StringBuilder sb = new StringBuilder(); + for(Node n : nodes) { + sb.append(n.toString()); + } + + return sb.toString(); + } +} diff --git a/src/binarytree/BinaryTreeNode.java b/src/binarytree/BinaryTreeNode.java new file mode 100644 index 0000000..a1eb26e --- /dev/null +++ b/src/binarytree/BinaryTreeNode.java @@ -0,0 +1,78 @@ +package binarytree; + +import graph.Node; + +import java.util.Random; + +public class BinaryTreeNode> extends Node { + public BinaryTreeNode(Node parent, T item) { + super(parent, item); + } + + /** + * Adds a new node to the current node + * if the numbers of nodes is larger than 2, proceed to the next node + * + * @param value value to be added + * @return the new node if adding was successful, null otherwise + */ + @Override + public Node addNode(T value) { + if (children.size() < 2) { + Node newChild = new BinaryTreeNode(this, value); + this.addNode(newChild); + + return newChild; + } + + // pick a random child out of the current children + Node randomChild = this.children.get(new Random().nextInt(this.children.size())); + + return randomChild.addNode(value); + } + + private void addNode(Node node) { + if (children.size() < 2) { // we can still add a node + this.children.add(node); + } else { + + // pick a random child out of the current children + Node randomChild = this.children.get(new Random().nextInt(this.children.size())); + + randomChild.addNode(node.getValue()); + } + } + + @Override + public int hashCode() { + int randomPrime = 13; // chosen randomly + + int sum = this.children.stream() + .map(Node::hashCode) + .reduce(0, Integer::sum); + + return (this.value.hashCode() + sum) * randomPrime; + } + + @Override + public boolean equals(Object that) { + if (that instanceof Node) { + return ((Node) that).getValue().equals(value); + } + + return false; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(String.format("BT(%s)", value)); + + for(Node child : children) { + sb.append(":"); + sb.append(child.toString()); + } + + return sb.toString(); + } +} diff --git a/src/graph/Graph.java b/src/graph/Graph.java deleted file mode 100644 index 3948543..0000000 --- a/src/graph/Graph.java +++ /dev/null @@ -1,11 +0,0 @@ -package graph; - -import java.util.List; - -public abstract class Graph { - protected List nodes; - - public List getAllNodes() { - return nodes; - } -} diff --git a/src/graph/Node.java b/src/graph/Node.java index 5f4d687..c6bb444 100644 --- a/src/graph/Node.java +++ b/src/graph/Node.java @@ -1,20 +1,46 @@ package graph; +import java.util.ArrayList; import java.util.List; -public abstract class Node { - private final String item; - private List children; +public abstract class Node> { + protected T value; + protected Node parent; + protected final List> children; - public Node(String item) { - this.item = item; + public Node(Node parent, T value) { + this.value = value; + this.parent = parent; + this.children = new ArrayList<>(); } - public String getItem() { - return item; + public T getValue() { + return value; } - public List getChildren() { + public void setValue(T value) { + this.value = value; + } + + public List> getChildren() { return children; } + + public Node getParent() { + return parent; + } + + public abstract Node addNode(T value); + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } + + public abstract String toString(); } diff --git a/src/graph/Tree.java b/src/graph/Tree.java new file mode 100644 index 0000000..9630a08 --- /dev/null +++ b/src/graph/Tree.java @@ -0,0 +1,35 @@ +package graph; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public abstract class Tree> { + protected Node root; + protected List> nodes; + protected Set values; + + public Tree() { + this.nodes = new ArrayList<>(); + this.values = new HashSet<>(); + } + + public List> getAllNodes() { + return nodes; + } + + public int getSize() { + return nodes.size(); + } + + public Node getRoot() { + return root; + } + + public abstract Node addNode(T value); + public abstract boolean removeNode(T value); + public abstract boolean removeNode (Node n); + public abstract Node findNode(T value); + public abstract String toString(); +} diff --git a/tests/BinaryTreeTests.java b/tests/BinaryTreeTests.java new file mode 100644 index 0000000..b36be50 --- /dev/null +++ b/tests/BinaryTreeTests.java @@ -0,0 +1,55 @@ +import binarytree.BinaryTree; +import binarytree.BinaryTreeNode; +import graph.Node; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class BinaryTreeTests { + BinaryTree tree; + + @Before + public void init() { + this.tree = new BinaryTree<>(); + } + + @Test + public void testAddition() { + Node n1 = tree.addNode(1); + Node n2 = tree.addNode(2); + + Assert.assertEquals(2, tree.getSize()); + Assert.assertEquals(n1, tree.findNode(1)); + Assert.assertEquals(n2, tree.findNode(2)); + Assert.assertNull(tree.findNode(3)); + Assert.assertEquals(1, tree.getRoot().getValue().intValue()); + Assert.assertEquals(2, tree.getRoot().getChildren().get(0).getValue().intValue()); + } + + @Test + public void testAddition2() { + tree.addNode(1); + tree.addNode(2); + tree.addNode(3); + tree.addNode(4); + + Assert.assertEquals(4, tree.getSize()); + } + + @Test + public void testAddition3() { + Node n1 = new BinaryTreeNode<>(null, 1); + } + + @Test + public void testRemoval() { + tree.addNode(1); + tree.addNode(2); + System.out.println(tree); + + tree.removeNode(1); + System.out.println(tree); + Assert.assertEquals(1, tree.getSize()); + Assert.assertEquals(2, tree.getRoot().getValue().intValue()); + } +}