From fa8fbf1b22277ff020582d432bb3876f6346cbcc Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 19:08:24 +0000 Subject: [PATCH 001/186] Setting up GitHub Classroom Feedback From 4e4040425b592dc2169e3e36d93a513cfad27562 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sat, 23 Mar 2024 11:45:11 +0300 Subject: [PATCH 002/186] build: project init --- .gitignore | 8 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 60756 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 234 ++++++++++++++++++++++ gradlew.bat | 89 ++++++++ settings.gradle.kts | 5 + src/main/kotlin/xddcc/bintrees/AVLTree.kt | 4 + src/main/kotlin/xddcc/bintrees/BSTree.kt | 4 + src/main/kotlin/xddcc/bintrees/RBTree.kt | 4 + src/main/kotlin/xddcc/nodes/AVLNode.kt | 4 + src/main/kotlin/xddcc/nodes/BSTNode.kt | 4 + src/main/kotlin/xddcc/nodes/RBNode.kt | 4 + 12 files changed, 366 insertions(+) create mode 100644 .gitignore create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle.kts create mode 100644 src/main/kotlin/xddcc/bintrees/AVLTree.kt create mode 100644 src/main/kotlin/xddcc/bintrees/BSTree.kt create mode 100644 src/main/kotlin/xddcc/bintrees/RBTree.kt create mode 100644 src/main/kotlin/xddcc/nodes/AVLNode.kt create mode 100644 src/main/kotlin/xddcc/nodes/BSTNode.kt create mode 100644 src/main/kotlin/xddcc/nodes/RBNode.kt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3353073 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +### Gradle ### +.gradle +build +build.gradle.kts +gradle.properties + +### IntelliJ IDEA ### +.idea diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..249e5832f090a2944b7473328c07c9755baa3196 GIT binary patch literal 60756 zcmb5WV{~QRw(p$^Dz@00IL3?^hro$gg*4VI_WAaTyVM5Foj~O|-84 z$;06hMwt*rV;^8iB z1~&0XWpYJmG?Ts^K9PC62H*`G}xom%S%yq|xvG~FIfP=9*f zZoDRJBm*Y0aId=qJ?7dyb)6)JGWGwe)MHeNSzhi)Ko6J<-m@v=a%NsP537lHe0R* z`If4$aaBA#S=w!2z&m>{lpTy^Lm^mg*3?M&7HFv}7K6x*cukLIGX;bQG|QWdn{%_6 zHnwBKr84#B7Z+AnBXa16a?or^R?+>$4`}{*a_>IhbjvyTtWkHw)|ay)ahWUd-qq$~ zMbh6roVsj;_qnC-R{G+Cy6bApVOinSU-;(DxUEl!i2)1EeQ9`hrfqj(nKI7?Z>Xur zoJz-a`PxkYit1HEbv|jy%~DO^13J-ut986EEG=66S}D3!L}Efp;Bez~7tNq{QsUMm zh9~(HYg1pA*=37C0}n4g&bFbQ+?-h-W}onYeE{q;cIy%eZK9wZjSwGvT+&Cgv z?~{9p(;bY_1+k|wkt_|N!@J~aoY@|U_RGoWX<;p{Nu*D*&_phw`8jYkMNpRTWx1H* z>J-Mi_!`M468#5Aix$$u1M@rJEIOc?k^QBc?T(#=n&*5eS#u*Y)?L8Ha$9wRWdH^3D4|Ps)Y?m0q~SiKiSfEkJ!=^`lJ(%W3o|CZ zSrZL-Xxc{OrmsQD&s~zPfNJOpSZUl%V8tdG%ei}lQkM+z@-4etFPR>GOH9+Y_F<3=~SXln9Kb-o~f>2a6Xz@AS3cn^;c_>lUwlK(n>z?A>NbC z`Ud8^aQy>wy=$)w;JZzA)_*Y$Z5hU=KAG&htLw1Uh00yE!|Nu{EZkch zY9O6x7Y??>!7pUNME*d!=R#s)ghr|R#41l!c?~=3CS8&zr6*aA7n9*)*PWBV2w+&I zpW1-9fr3j{VTcls1>ua}F*bbju_Xq%^v;-W~paSqlf zolj*dt`BBjHI)H9{zrkBo=B%>8}4jeBO~kWqO!~Thi!I1H(in=n^fS%nuL=X2+s!p}HfTU#NBGiwEBF^^tKU zbhhv+0dE-sbK$>J#t-J!B$TMgN@Wh5wTtK2BG}4BGfsZOoRUS#G8Cxv|6EI*n&Xxq zt{&OxCC+BNqz$9b0WM7_PyBJEVObHFh%%`~!@MNZlo*oXDCwDcFwT~Rls!aApL<)^ zbBftGKKBRhB!{?fX@l2_y~%ygNFfF(XJzHh#?`WlSL{1lKT*gJM zs>bd^H9NCxqxn(IOky5k-wALFowQr(gw%|`0991u#9jXQh?4l|l>pd6a&rx|v=fPJ z1mutj{YzpJ_gsClbWFk(G}bSlFi-6@mwoQh-XeD*j@~huW4(8ub%^I|azA)h2t#yG z7e_V_<4jlM3D(I+qX}yEtqj)cpzN*oCdYHa!nm%0t^wHm)EmFP*|FMw!tb@&`G-u~ zK)=Sf6z+BiTAI}}i{*_Ac$ffr*Wrv$F7_0gJkjx;@)XjYSh`RjAgrCck`x!zP>Ifu z&%he4P|S)H*(9oB4uvH67^0}I-_ye_!w)u3v2+EY>eD3#8QR24<;7?*hj8k~rS)~7 zSXs5ww)T(0eHSp$hEIBnW|Iun<_i`}VE0Nc$|-R}wlSIs5pV{g_Dar(Zz<4X3`W?K z6&CAIl4U(Qk-tTcK{|zYF6QG5ArrEB!;5s?tW7 zrE3hcFY&k)+)e{+YOJ0X2uDE_hd2{|m_dC}kgEKqiE9Q^A-+>2UonB+L@v3$9?AYw zVQv?X*pK;X4Ovc6Ev5Gbg{{Eu*7{N3#0@9oMI~}KnObQE#Y{&3mM4`w%wN+xrKYgD zB-ay0Q}m{QI;iY`s1Z^NqIkjrTlf`B)B#MajZ#9u41oRBC1oM1vq0i|F59> z#StM@bHt|#`2)cpl_rWB($DNJ3Lap}QM-+A$3pe}NyP(@+i1>o^fe-oxX#Bt`mcQc zb?pD4W%#ep|3%CHAYnr*^M6Czg>~L4?l16H1OozM{P*en298b+`i4$|w$|4AHbzqB zHpYUsHZET$Z0ztC;U+0*+amF!@PI%^oUIZy{`L{%O^i{Xk}X0&nl)n~tVEpcAJSJ} zverw15zP1P-O8h9nd!&hj$zuwjg?DoxYIw{jWM zW5_pj+wFy8Tsa9g<7Qa21WaV&;ejoYflRKcz?#fSH_)@*QVlN2l4(QNk| z4aPnv&mrS&0|6NHq05XQw$J^RR9T{3SOcMKCXIR1iSf+xJ0E_Wv?jEc*I#ZPzyJN2 zUG0UOXHl+PikM*&g$U@g+KbG-RY>uaIl&DEtw_Q=FYq?etc!;hEC_}UX{eyh%dw2V zTTSlap&5>PY{6I#(6`j-9`D&I#|YPP8a;(sOzgeKDWsLa!i-$frD>zr-oid!Hf&yS z!i^cr&7tN}OOGmX2)`8k?Tn!!4=tz~3hCTq_9CdiV!NIblUDxHh(FJ$zs)B2(t5@u z-`^RA1ShrLCkg0)OhfoM;4Z{&oZmAec$qV@ zGQ(7(!CBk<5;Ar%DLJ0p0!ResC#U<+3i<|vib1?{5gCebG7$F7URKZXuX-2WgF>YJ^i zMhHDBsh9PDU8dlZ$yJKtc6JA#y!y$57%sE>4Nt+wF1lfNIWyA`=hF=9Gj%sRwi@vd z%2eVV3y&dvAgyuJ=eNJR+*080dbO_t@BFJO<@&#yqTK&+xc|FRR;p;KVk@J3$S{p` zGaMj6isho#%m)?pOG^G0mzOAw0z?!AEMsv=0T>WWcE>??WS=fII$t$(^PDPMU(P>o z_*0s^W#|x)%tx8jIgZY~A2yG;US0m2ZOQt6yJqW@XNY_>_R7(Nxb8Ged6BdYW6{prd!|zuX$@Q2o6Ona8zzYC1u!+2!Y$Jc9a;wy+pXt}o6~Bu1oF1c zp7Y|SBTNi@=I(K%A60PMjM#sfH$y*c{xUgeSpi#HB`?|`!Tb&-qJ3;vxS!TIzuTZs-&%#bAkAyw9m4PJgvey zM5?up*b}eDEY+#@tKec)-c(#QF0P?MRlD1+7%Yk*jW;)`f;0a-ZJ6CQA?E%>i2Dt7T9?s|9ZF|KP4;CNWvaVKZ+Qeut;Jith_y{v*Ny6Co6!8MZx;Wgo z=qAi%&S;8J{iyD&>3CLCQdTX*$+Rx1AwA*D_J^0>suTgBMBb=*hefV+Ars#mmr+YsI3#!F@Xc1t4F-gB@6aoyT+5O(qMz*zG<9Qq*f0w^V!03rpr*-WLH}; zfM{xSPJeu6D(%8HU%0GEa%waFHE$G?FH^kMS-&I3)ycx|iv{T6Wx}9$$D&6{%1N_8 z_CLw)_9+O4&u94##vI9b-HHm_95m)fa??q07`DniVjAy`t7;)4NpeyAY(aAk(+T_O z1om+b5K2g_B&b2DCTK<>SE$Ode1DopAi)xaJjU>**AJK3hZrnhEQ9E`2=|HHe<^tv z63e(bn#fMWuz>4erc47}!J>U58%<&N<6AOAewyzNTqi7hJc|X{782&cM zHZYclNbBwU6673=!ClmxMfkC$(CykGR@10F!zN1Se83LR&a~$Ht&>~43OX22mt7tcZUpa;9@q}KDX3O&Ugp6< zLZLfIMO5;pTee1vNyVC$FGxzK2f>0Z-6hM82zKg44nWo|n}$Zk6&;5ry3`(JFEX$q zK&KivAe${e^5ZGc3a9hOt|!UOE&OocpVryE$Y4sPcs4rJ>>Kbi2_subQ9($2VN(3o zb~tEzMsHaBmBtaHAyES+d3A(qURgiskSSwUc9CfJ@99&MKp2sooSYZu+-0t0+L*!I zYagjOlPgx|lep9tiU%ts&McF6b0VE57%E0Ho%2oi?=Ks+5%aj#au^OBwNwhec zta6QAeQI^V!dF1C)>RHAmB`HnxyqWx?td@4sd15zPd*Fc9hpDXP23kbBenBxGeD$k z;%0VBQEJ-C)&dTAw_yW@k0u?IUk*NrkJ)(XEeI z9Y>6Vel>#s_v@=@0<{4A{pl=9cQ&Iah0iD0H`q)7NeCIRz8zx;! z^OO;1+IqoQNak&pV`qKW+K0^Hqp!~gSohcyS)?^P`JNZXw@gc6{A3OLZ?@1Uc^I2v z+X!^R*HCm3{7JPq{8*Tn>5;B|X7n4QQ0Bs79uTU%nbqOJh`nX(BVj!#f;#J+WZxx4 z_yM&1Y`2XzhfqkIMO7tB3raJKQS+H5F%o83bM+hxbQ zeeJm=Dvix$2j|b4?mDacb67v-1^lTp${z=jc1=j~QD>7c*@+1?py>%Kj%Ejp7Y-!? z8iYRUlGVrQPandAaxFfks53@2EC#0)%mrnmGRn&>=$H$S8q|kE_iWko4`^vCS2aWg z#!`RHUGyOt*k?bBYu3*j3u0gB#v(3tsije zgIuNNWNtrOkx@Pzs;A9un+2LX!zw+p3_NX^Sh09HZAf>m8l@O*rXy_82aWT$Q>iyy zqO7Of)D=wcSn!0+467&!Hl))eff=$aneB?R!YykdKW@k^_uR!+Q1tR)+IJb`-6=jj zymzA>Sv4>Z&g&WWu#|~GcP7qP&m*w-S$)7Xr;(duqCTe7p8H3k5>Y-n8438+%^9~K z3r^LIT_K{i7DgEJjIocw_6d0!<;wKT`X;&vv+&msmhAAnIe!OTdybPctzcEzBy88_ zWO{6i4YT%e4^WQZB)KHCvA(0tS zHu_Bg+6Ko%a9~$EjRB90`P(2~6uI@SFibxct{H#o&y40MdiXblu@VFXbhz>Nko;7R z70Ntmm-FePqhb%9gL+7U8@(ch|JfH5Fm)5${8|`Lef>LttM_iww6LW2X61ldBmG0z zax3y)njFe>j*T{i0s8D4=L>X^j0)({R5lMGVS#7(2C9@AxL&C-lZQx~czI7Iv+{%1 z2hEG>RzX4S8x3v#9sgGAnPzptM)g&LB}@%E>fy0vGSa(&q0ch|=ncKjNrK z`jA~jObJhrJ^ri|-)J^HUyeZXz~XkBp$VhcTEcTdc#a2EUOGVX?@mYx#Vy*!qO$Jv zQ4rgOJ~M*o-_Wptam=~krnmG*p^j!JAqoQ%+YsDFW7Cc9M%YPiBOrVcD^RY>m9Pd< zu}#9M?K{+;UIO!D9qOpq9yxUquQRmQNMo0pT`@$pVt=rMvyX)ph(-CCJLvUJy71DI zBk7oc7)-%ngdj~s@76Yse3L^gV0 z2==qfp&Q~L(+%RHP0n}+xH#k(hPRx(!AdBM$JCfJ5*C=K3ts>P?@@SZ_+{U2qFZb>4kZ{Go37{# zSQc+-dq*a-Vy4?taS&{Ht|MLRiS)Sn14JOONyXqPNnpq&2y~)6wEG0oNy>qvod$FF z`9o&?&6uZjhZ4_*5qWVrEfu(>_n2Xi2{@Gz9MZ8!YmjYvIMasE9yVQL10NBrTCczq zcTY1q^PF2l!Eraguf{+PtHV3=2A?Cu&NN&a8V(y;q(^_mFc6)%Yfn&X&~Pq zU1?qCj^LF(EQB1F`8NxNjyV%fde}dEa(Hx=r7$~ts2dzDwyi6ByBAIx$NllB4%K=O z$AHz1<2bTUb>(MCVPpK(E9wlLElo(aSd(Os)^Raum`d(g9Vd_+Bf&V;l=@mM=cC>) z)9b0enb)u_7V!!E_bl>u5nf&Rl|2r=2F3rHMdb7y9E}}F82^$Rf+P8%dKnOeKh1vs zhH^P*4Ydr^$)$h@4KVzxrHyy#cKmWEa9P5DJ|- zG;!Qi35Tp7XNj60=$!S6U#!(${6hyh7d4q=pF{`0t|N^|L^d8pD{O9@tF~W;#Je*P z&ah%W!KOIN;SyAEhAeTafJ4uEL`(RtnovM+cb(O#>xQnk?dzAjG^~4$dFn^<@-Na3 z395;wBnS{t*H;Jef2eE!2}u5Ns{AHj>WYZDgQJt8v%x?9{MXqJsGP|l%OiZqQ1aB! z%E=*Ig`(!tHh>}4_z5IMpg{49UvD*Pp9!pxt_gdAW%sIf3k6CTycOT1McPl=_#0?8 zVjz8Hj*Vy9c5-krd-{BQ{6Xy|P$6LJvMuX$* zA+@I_66_ET5l2&gk9n4$1M3LN8(yEViRx&mtd#LD}AqEs?RW=xKC(OCWH;~>(X6h!uDxXIPH06xh z*`F4cVlbDP`A)-fzf>MuScYsmq&1LUMGaQ3bRm6i7OsJ|%uhTDT zlvZA1M}nz*SalJWNT|`dBm1$xlaA>CCiQ zK`xD-RuEn>-`Z?M{1%@wewf#8?F|(@1e0+T4>nmlSRrNK5f)BJ2H*$q(H>zGD0>eL zQ!tl_Wk)k*e6v^m*{~A;@6+JGeWU-q9>?+L_#UNT%G?4&BnOgvm9@o7l?ov~XL+et zbGT)|G7)KAeqb=wHSPk+J1bdg7N3$vp(ekjI1D9V$G5Cj!=R2w=3*4!z*J-r-cyeb zd(i2KmX!|Lhey!snRw z?#$Gu%S^SQEKt&kep)up#j&9}e+3=JJBS(s>MH+|=R(`8xK{mmndWo_r`-w1#SeRD&YtAJ#GiVI*TkQZ}&aq<+bU2+coU3!jCI6E+Ad_xFW*ghnZ$q zAoF*i&3n1j#?B8x;kjSJD${1jdRB;)R*)Ao!9bd|C7{;iqDo|T&>KSh6*hCD!rwv= zyK#F@2+cv3=|S1Kef(E6Niv8kyLVLX&e=U;{0x{$tDfShqkjUME>f8d(5nzSkY6@! z^-0>DM)wa&%m#UF1F?zR`8Y3X#tA!*7Q$P3lZJ%*KNlrk_uaPkxw~ zxZ1qlE;Zo;nb@!SMazSjM>;34ROOoygo%SF);LL>rRonWwR>bmSd1XD^~sGSu$Gg# zFZ`|yKU0%!v07dz^v(tY%;So(e`o{ZYTX`hm;@b0%8|H>VW`*cr8R%3n|ehw2`(9B+V72`>SY}9^8oh$En80mZK9T4abVG*to;E z1_S6bgDOW?!Oy1LwYy=w3q~KKdbNtyH#d24PFjX)KYMY93{3-mPP-H>@M-_>N~DDu zENh~reh?JBAK=TFN-SfDfT^=+{w4ea2KNWXq2Y<;?(gf(FgVp8Zp-oEjKzB%2Iqj;48GmY3h=bcdYJ}~&4tS`Q1sb=^emaW$IC$|R+r-8V- zf0$gGE(CS_n4s>oicVk)MfvVg#I>iDvf~Ov8bk}sSxluG!6#^Z_zhB&U^`eIi1@j( z^CK$z^stBHtaDDHxn+R;3u+>Lil^}fj?7eaGB z&5nl^STqcaBxI@v>%zG|j))G(rVa4aY=B@^2{TFkW~YP!8!9TG#(-nOf^^X-%m9{Z zCC?iC`G-^RcBSCuk=Z`(FaUUe?hf3{0C>>$?Vs z`2Uud9M+T&KB6o4o9kvdi^Q=Bw!asPdxbe#W-Oaa#_NP(qpyF@bVxv5D5))srkU#m zj_KA+#7sqDn*Ipf!F5Byco4HOSd!Ui$l94|IbW%Ny(s1>f4|Mv^#NfB31N~kya9!k zWCGL-$0ZQztBate^fd>R!hXY_N9ZjYp3V~4_V z#eB)Kjr8yW=+oG)BuNdZG?jaZlw+l_ma8aET(s+-x+=F-t#Qoiuu1i`^x8Sj>b^U} zs^z<()YMFP7CmjUC@M=&lA5W7t&cxTlzJAts*%PBDAPuqcV5o7HEnqjif_7xGt)F% zGx2b4w{@!tE)$p=l3&?Bf#`+!-RLOleeRk3 z7#pF|w@6_sBmn1nECqdunmG^}pr5(ZJQVvAt$6p3H(16~;vO>?sTE`Y+mq5YP&PBo zvq!7#W$Gewy`;%6o^!Dtjz~x)T}Bdk*BS#=EY=ODD&B=V6TD2z^hj1m5^d6s)D*wk zu$z~D7QuZ2b?5`p)E8e2_L38v3WE{V`bVk;6fl#o2`) z99JsWhh?$oVRn@$S#)uK&8DL8>An0&S<%V8hnGD7Z^;Y(%6;^9!7kDQ5bjR_V+~wp zfx4m3z6CWmmZ<8gDGUyg3>t8wgJ5NkkiEm^(sedCicP^&3D%}6LtIUq>mXCAt{9eF zNXL$kGcoUTf_Lhm`t;hD-SE)m=iBnxRU(NyL}f6~1uH)`K!hmYZjLI%H}AmEF5RZt z06$wn63GHnApHXZZJ}s^s)j9(BM6e*7IBK6Bq(!)d~zR#rbxK9NVIlgquoMq z=eGZ9NR!SEqP6=9UQg#@!rtbbSBUM#ynF);zKX+|!Zm}*{H z+j=d?aZ2!?@EL7C~%B?6ouCKLnO$uWn;Y6Xz zX8dSwj732u(o*U3F$F=7xwxm>E-B+SVZH;O-4XPuPkLSt_?S0)lb7EEg)Mglk0#eS z9@jl(OnH4juMxY+*r03VDfPx_IM!Lmc(5hOI;`?d37f>jPP$?9jQQIQU@i4vuG6MagEoJrQ=RD7xt@8E;c zeGV*+Pt+t$@pt!|McETOE$9k=_C!70uhwRS9X#b%ZK z%q(TIUXSS^F0`4Cx?Rk07C6wI4!UVPeI~-fxY6`YH$kABdOuiRtl73MqG|~AzZ@iL&^s?24iS;RK_pdlWkhcF z@Wv-Om(Aealfg)D^adlXh9Nvf~Uf@y;g3Y)i(YP zEXDnb1V}1pJT5ZWyw=1i+0fni9yINurD=EqH^ciOwLUGi)C%Da)tyt=zq2P7pV5-G zR7!oq28-Fgn5pW|nlu^b!S1Z#r7!Wtr{5J5PQ>pd+2P7RSD?>(U7-|Y z7ZQ5lhYIl_IF<9?T9^IPK<(Hp;l5bl5tF9>X-zG14_7PfsA>6<$~A338iYRT{a@r_ zuXBaT=`T5x3=s&3=RYx6NgG>No4?5KFBVjE(swfcivcIpPQFx5l+O;fiGsOrl5teR z_Cm+;PW}O0Dwe_(4Z@XZ)O0W-v2X><&L*<~*q3dg;bQW3g7)a#3KiQP>+qj|qo*Hk z?57>f2?f@`=Fj^nkDKeRkN2d$Z@2eNKpHo}ksj-$`QKb6n?*$^*%Fb3_Kbf1(*W9K>{L$mud2WHJ=j0^=g30Xhg8$#g^?36`p1fm;;1@0Lrx+8t`?vN0ZorM zSW?rhjCE8$C|@p^sXdx z|NOHHg+fL;HIlqyLp~SSdIF`TnSHehNCU9t89yr@)FY<~hu+X`tjg(aSVae$wDG*C zq$nY(Y494R)hD!i1|IIyP*&PD_c2FPgeY)&mX1qujB1VHPG9`yFQpLFVQ0>EKS@Bp zAfP5`C(sWGLI?AC{XEjLKR4FVNw(4+9b?kba95ukgR1H?w<8F7)G+6&(zUhIE5Ef% z=fFkL3QKA~M@h{nzjRq!Y_t!%U66#L8!(2-GgFxkD1=JRRqk=n%G(yHKn%^&$dW>; zSjAcjETMz1%205se$iH_)ZCpfg_LwvnsZQAUCS#^FExp8O4CrJb6>JquNV@qPq~3A zZ<6dOU#6|8+fcgiA#~MDmcpIEaUO02L5#T$HV0$EMD94HT_eXLZ2Zi&(! z&5E>%&|FZ`)CN10tM%tLSPD*~r#--K(H-CZqIOb99_;m|D5wdgJ<1iOJz@h2Zkq?} z%8_KXb&hf=2Wza(Wgc;3v3TN*;HTU*q2?#z&tLn_U0Nt!y>Oo>+2T)He6%XuP;fgn z-G!#h$Y2`9>Jtf}hbVrm6D70|ERzLAU>3zoWhJmjWfgM^))T+2u$~5>HF9jQDkrXR z=IzX36)V75PrFjkQ%TO+iqKGCQ-DDXbaE;C#}!-CoWQx&v*vHfyI>$HNRbpvm<`O( zlx9NBWD6_e&J%Ous4yp~s6)Ghni!I6)0W;9(9$y1wWu`$gs<$9Mcf$L*piP zPR0Av*2%ul`W;?-1_-5Zy0~}?`e@Y5A&0H!^ApyVTT}BiOm4GeFo$_oPlDEyeGBbh z1h3q&Dx~GmUS|3@4V36&$2uO8!Yp&^pD7J5&TN{?xphf*-js1fP?B|`>p_K>lh{ij zP(?H%e}AIP?_i^f&Li=FDSQ`2_NWxL+BB=nQr=$ zHojMlXNGauvvwPU>ZLq!`bX-5F4jBJ&So{kE5+ms9UEYD{66!|k~3vsP+mE}x!>%P za98bAU0!h0&ka4EoiDvBM#CP#dRNdXJcb*(%=<(g+M@<)DZ!@v1V>;54En?igcHR2 zhubQMq}VSOK)onqHfczM7YA@s=9*ow;k;8)&?J3@0JiGcP! zP#00KZ1t)GyZeRJ=f0^gc+58lc4Qh*S7RqPIC6GugG1gXe$LIQMRCo8cHf^qXgAa2 z`}t>u2Cq1CbSEpLr~E=c7~=Qkc9-vLE%(v9N*&HF`(d~(0`iukl5aQ9u4rUvc8%m) zr2GwZN4!s;{SB87lJB;veebPmqE}tSpT>+`t?<457Q9iV$th%i__Z1kOMAswFldD6 ztbOvO337S5o#ZZgN2G99_AVqPv!?Gmt3pzgD+Hp3QPQ`9qJ(g=kjvD+fUSS3upJn! zqoG7acIKEFRX~S}3|{EWT$kdz#zrDlJU(rPkxjws_iyLKU8+v|*oS_W*-guAb&Pj1 z35Z`3z<&Jb@2Mwz=KXucNYdY#SNO$tcVFr9KdKm|%^e-TXzs6M`PBper%ajkrIyUe zp$vVxVs9*>Vp4_1NC~Zg)WOCPmOxI1V34QlG4!aSFOH{QqSVq1^1)- z0P!Z?tT&E-ll(pwf0?=F=yOzik=@nh1Clxr9}Vij89z)ePDSCYAqw?lVI?v?+&*zH z)p$CScFI8rrwId~`}9YWPFu0cW1Sf@vRELs&cbntRU6QfPK-SO*mqu|u~}8AJ!Q$z znzu}50O=YbjwKCuSVBs6&CZR#0FTu)3{}qJJYX(>QPr4$RqWiwX3NT~;>cLn*_&1H zaKpIW)JVJ>b{uo2oq>oQt3y=zJjb%fU@wLqM{SyaC6x2snMx-}ivfU<1- znu1Lh;i$3Tf$Kh5Uk))G!D1UhE8pvx&nO~w^fG)BC&L!_hQk%^p`Kp@F{cz>80W&T ziOK=Sq3fdRu*V0=S53rcIfWFazI}Twj63CG(jOB;$*b`*#B9uEnBM`hDk*EwSRdwP8?5T?xGUKs=5N83XsR*)a4|ijz|c{4tIU+4j^A5C<#5 z*$c_d=5ml~%pGxw#?*q9N7aRwPux5EyqHVkdJO=5J>84!X6P>DS8PTTz>7C#FO?k#edkntG+fJk8ZMn?pmJSO@`x-QHq;7^h6GEXLXo1TCNhH z8ZDH{*NLAjo3WM`xeb=X{((uv3H(8&r8fJJg_uSs_%hOH%JDD?hu*2NvWGYD+j)&` zz#_1%O1wF^o5ryt?O0n;`lHbzp0wQ?rcbW(F1+h7_EZZ9{>rePvLAPVZ_R|n@;b$;UchU=0j<6k8G9QuQf@76oiE*4 zXOLQ&n3$NR#p4<5NJMVC*S);5x2)eRbaAM%VxWu9ohlT;pGEk7;002enCbQ>2r-us z3#bpXP9g|mE`65VrN`+3mC)M(eMj~~eOf)do<@l+fMiTR)XO}422*1SL{wyY(%oMpBgJagtiDf zz>O6(m;};>Hi=t8o{DVC@YigqS(Qh+ix3Rwa9aliH}a}IlOCW1@?%h_bRbq-W{KHF z%Vo?-j@{Xi@=~Lz5uZP27==UGE15|g^0gzD|3x)SCEXrx`*MP^FDLl%pOi~~Il;dc z^hrwp9sYeT7iZ)-ajKy@{a`kr0-5*_!XfBpXwEcFGJ;%kV$0Nx;apKrur zJN2J~CAv{Zjj%FolyurtW8RaFmpn&zKJWL>(0;;+q(%(Hx!GMW4AcfP0YJ*Vz!F4g z!ZhMyj$BdXL@MlF%KeInmPCt~9&A!;cRw)W!Hi@0DY(GD_f?jeV{=s=cJ6e}JktJw zQORnxxj3mBxfrH=x{`_^Z1ddDh}L#V7i}$njUFRVwOX?qOTKjfPMBO4y(WiU<)epb zvB9L=%jW#*SL|Nd_G?E*_h1^M-$PG6Pc_&QqF0O-FIOpa4)PAEPsyvB)GKasmBoEt z?_Q2~QCYGH+hW31x-B=@5_AN870vY#KB~3a*&{I=f);3Kv7q4Q7s)0)gVYx2#Iz9g(F2;=+Iy4 z6KI^8GJ6D@%tpS^8boU}zpi=+(5GfIR)35PzrbuXeL1Y1N%JK7PG|^2k3qIqHfX;G zQ}~JZ-UWx|60P5?d1e;AHx!_;#PG%d=^X(AR%i`l0jSpYOpXoKFW~7ip7|xvN;2^? zsYC9fanpO7rO=V7+KXqVc;Q5z%Bj})xHVrgoR04sA2 zl~DAwv=!(()DvH*=lyhIlU^hBkA0$e*7&fJpB0|oB7)rqGK#5##2T`@_I^|O2x4GO z;xh6ROcV<9>?e0)MI(y++$-ksV;G;Xe`lh76T#Htuia+(UrIXrf9?

L(tZ$0BqX1>24?V$S+&kLZ`AodQ4_)P#Q3*4xg8}lMV-FLwC*cN$< zt65Rf%7z41u^i=P*qO8>JqXPrinQFapR7qHAtp~&RZ85$>ob|Js;GS^y;S{XnGiBc zGa4IGvDl?x%gY`vNhv8wgZnP#UYI-w*^4YCZnxkF85@ldepk$&$#3EAhrJY0U)lR{F6sM3SONV^+$;Zx8BD&Eku3K zKNLZyBni3)pGzU0;n(X@1fX8wYGKYMpLmCu{N5-}epPDxClPFK#A@02WM3!myN%bkF z|GJ4GZ}3sL{3{qXemy+#Uk{4>Kf8v11;f8I&c76+B&AQ8udd<8gU7+BeWC`akUU~U zgXoxie>MS@rBoyY8O8Tc&8id!w+_ooxcr!1?#rc$-|SBBtH6S?)1e#P#S?jFZ8u-Bs&k`yLqW|{j+%c#A4AQ>+tj$Y z^CZajspu$F%73E68Lw5q7IVREED9r1Ijsg#@DzH>wKseye>hjsk^{n0g?3+gs@7`i zHx+-!sjLx^fS;fY!ERBU+Q zVJ!e0hJH%P)z!y%1^ZyG0>PN@5W~SV%f>}c?$H8r;Sy-ui>aruVTY=bHe}$e zi&Q4&XK!qT7-XjCrDaufT@>ieQ&4G(SShUob0Q>Gznep9fR783jGuUynAqc6$pYX; z7*O@@JW>O6lKIk0G00xsm|=*UVTQBB`u1f=6wGAj%nHK_;Aqmfa!eAykDmi-@u%6~ z;*c!pS1@V8r@IX9j&rW&d*}wpNs96O2Ute>%yt{yv>k!6zfT6pru{F1M3P z2WN1JDYqoTB#(`kE{H676QOoX`cnqHl1Yaru)>8Ky~VU{)r#{&s86Vz5X)v15ULHA zAZDb{99+s~qI6;-dQ5DBjHJP@GYTwn;Dv&9kE<0R!d z8tf1oq$kO`_sV(NHOSbMwr=To4r^X$`sBW4$gWUov|WY?xccQJN}1DOL|GEaD_!@& z15p?Pj+>7d`@LvNIu9*^hPN)pwcv|akvYYq)ks%`G>!+!pW{-iXPZsRp8 z35LR;DhseQKWYSD`%gO&k$Dj6_6q#vjWA}rZcWtQr=Xn*)kJ9kacA=esi*I<)1>w^ zO_+E>QvjP)qiSZg9M|GNeLtO2D7xT6vsj`88sd!94j^AqxFLi}@w9!Y*?nwWARE0P znuI_7A-saQ+%?MFA$gttMV-NAR^#tjl_e{R$N8t2NbOlX373>e7Ox=l=;y#;M7asp zRCz*CLnrm$esvSb5{T<$6CjY zmZ(i{Rs_<#pWW>(HPaaYj`%YqBra=Ey3R21O7vUbzOkJJO?V`4-D*u4$Me0Bx$K(lYo`JO}gnC zx`V}a7m-hLU9Xvb@K2ymioF)vj12<*^oAqRuG_4u%(ah?+go%$kOpfb`T96P+L$4> zQ#S+sA%VbH&mD1k5Ak7^^dZoC>`1L%i>ZXmooA!%GI)b+$D&ziKrb)a=-ds9xk#~& z7)3iem6I|r5+ZrTRe_W861x8JpD`DDIYZNm{$baw+$)X^Jtjnl0xlBgdnNY}x%5za zkQ8E6T<^$sKBPtL4(1zi_Rd(tVth*3Xs!ulflX+70?gb&jRTnI8l+*Aj9{|d%qLZ+ z>~V9Z;)`8-lds*Zgs~z1?Fg?Po7|FDl(Ce<*c^2=lFQ~ahwh6rqSjtM5+$GT>3WZW zj;u~w9xwAhOc<kF}~`CJ68 z?(S5vNJa;kriPlim33{N5`C{9?NWhzsna_~^|K2k4xz1`xcui*LXL-1#Y}Hi9`Oo!zQ>x-kgAX4LrPz63uZ+?uG*84@PKq-KgQlMNRwz=6Yes) zY}>YN+qP}nwr$(CZQFjUOI=-6J$2^XGvC~EZ+vrqWaOXB$k?%Suf5k=4>AveC1aJ! ziaW4IS%F$_Babi)kA8Y&u4F7E%99OPtm=vzw$$ zEz#9rvn`Iot_z-r3MtV>k)YvErZ<^Oa${`2>MYYODSr6?QZu+be-~MBjwPGdMvGd!b!elsdi4% z`37W*8+OGulab8YM?`KjJ8e+jM(tqLKSS@=jimq3)Ea2EB%88L8CaM+aG7;27b?5` z4zuUWBr)f)k2o&xg{iZ$IQkJ+SK>lpq4GEacu~eOW4yNFLU!Kgc{w4&D$4ecm0f}~ zTTzquRW@`f0}|IILl`!1P+;69g^upiPA6F{)U8)muWHzexRenBU$E^9X-uIY2%&1w z_=#5*(nmxJ9zF%styBwivi)?#KMG96-H@hD-H_&EZiRNsfk7mjBq{L%!E;Sqn!mVX*}kXhwH6eh;b42eD!*~upVG@ z#smUqz$ICm!Y8wY53gJeS|Iuard0=;k5i5Z_hSIs6tr)R4n*r*rE`>38Pw&lkv{_r!jNN=;#?WbMj|l>cU(9trCq; z%nN~r^y7!kH^GPOf3R}?dDhO=v^3BeP5hF|%4GNQYBSwz;x({21i4OQY->1G=KFyu z&6d`f2tT9Yl_Z8YACZaJ#v#-(gcyeqXMhYGXb=t>)M@fFa8tHp2x;ODX=Ap@a5I=U z0G80^$N0G4=U(>W%mrrThl0DjyQ-_I>+1Tdd_AuB3qpYAqY54upwa3}owa|x5iQ^1 zEf|iTZxKNGRpI>34EwkIQ2zHDEZ=(J@lRaOH>F|2Z%V_t56Km$PUYu^xA5#5Uj4I4RGqHD56xT%H{+P8Ag>e_3pN$4m8n>i%OyJFPNWaEnJ4McUZPa1QmOh?t8~n& z&RulPCors8wUaqMHECG=IhB(-tU2XvHP6#NrLVyKG%Ee*mQ5Ps%wW?mcnriTVRc4J`2YVM>$ixSF2Xi+Wn(RUZnV?mJ?GRdw%lhZ+t&3s7g!~g{%m&i<6 z5{ib-<==DYG93I(yhyv4jp*y3#*WNuDUf6`vTM%c&hiayf(%=x@4$kJ!W4MtYcE#1 zHM?3xw63;L%x3drtd?jot!8u3qeqctceX3m;tWetK+>~q7Be$h>n6riK(5@ujLgRS zvOym)k+VAtyV^mF)$29Y`nw&ijdg~jYpkx%*^ z8dz`C*g=I?;clyi5|!27e2AuSa$&%UyR(J3W!A=ZgHF9OuKA34I-1U~pyD!KuRkjA zbkN!?MfQOeN>DUPBxoy5IX}@vw`EEB->q!)8fRl_mqUVuRu|C@KD-;yl=yKc=ZT0% zB$fMwcC|HE*0f8+PVlWHi>M`zfsA(NQFET?LrM^pPcw`cK+Mo0%8*x8@65=CS_^$cG{GZQ#xv($7J z??R$P)nPLodI;P!IC3eEYEHh7TV@opr#*)6A-;EU2XuogHvC;;k1aI8asq7ovoP!* z?x%UoPrZjj<&&aWpsbr>J$Er-7!E(BmOyEv!-mbGQGeJm-U2J>74>o5x`1l;)+P&~ z>}f^=Rx(ZQ2bm+YE0u=ZYrAV@apyt=v1wb?R@`i_g64YyAwcOUl=C!i>=Lzb$`tjv zOO-P#A+)t-JbbotGMT}arNhJmmGl-lyUpMn=2UacVZxmiG!s!6H39@~&uVokS zG=5qWhfW-WOI9g4!R$n7!|ViL!|v3G?GN6HR0Pt_L5*>D#FEj5wM1DScz4Jv@Sxnl zB@MPPmdI{(2D?;*wd>3#tjAirmUnQoZrVv`xM3hARuJksF(Q)wd4P$88fGYOT1p6U z`AHSN!`St}}UMBT9o7i|G`r$ zrB=s$qV3d6$W9@?L!pl0lf%)xs%1ko^=QY$ty-57=55PvP(^6E7cc zGJ*>m2=;fOj?F~yBf@K@9qwX0hA803Xw+b0m}+#a(>RyR8}*Y<4b+kpp|OS+!whP( zH`v{%s>jsQI9rd$*vm)EkwOm#W_-rLTHcZRek)>AtF+~<(did)*oR1|&~1|e36d-d zgtm5cv1O0oqgWC%Et@P4Vhm}Ndl(Y#C^MD03g#PH-TFy+7!Osv1z^UWS9@%JhswEq~6kSr2DITo59+; ze=ZC}i2Q?CJ~Iyu?vn|=9iKV>4j8KbxhE4&!@SQ^dVa-gK@YfS9xT(0kpW*EDjYUkoj! zE49{7H&E}k%5(>sM4uGY)Q*&3>{aitqdNnRJkbOmD5Mp5rv-hxzOn80QsG=HJ_atI-EaP69cacR)Uvh{G5dTpYG7d zbtmRMq@Sexey)||UpnZ?;g_KMZq4IDCy5}@u!5&B^-=6yyY{}e4Hh3ee!ZWtL*s?G zxG(A!<9o!CL+q?u_utltPMk+hn?N2@?}xU0KlYg?Jco{Yf@|mSGC<(Zj^yHCvhmyx z?OxOYoxbptDK()tsJ42VzXdINAMWL$0Gcw?G(g8TMB)Khw_|v9`_ql#pRd2i*?CZl z7k1b!jQB=9-V@h%;Cnl7EKi;Y^&NhU0mWEcj8B|3L30Ku#-9389Q+(Yet0r$F=+3p z6AKOMAIi|OHyzlHZtOm73}|ntKtFaXF2Fy|M!gOh^L4^62kGUoWS1i{9gsds_GWBc zLw|TaLP64z3z9?=R2|T6Xh2W4_F*$cq>MtXMOy&=IPIJ`;!Tw?PqvI2b*U1)25^<2 zU_ZPoxg_V0tngA0J+mm?3;OYw{i2Zb4x}NedZug!>EoN3DC{1i)Z{Z4m*(y{ov2%- zk(w>+scOO}MN!exSc`TN)!B=NUX`zThWO~M*ohqq;J2hx9h9}|s#?@eR!=F{QTrq~ zTcY|>azkCe$|Q0XFUdpFT=lTcyW##i;-e{}ORB4D?t@SfqGo_cS z->?^rh$<&n9DL!CF+h?LMZRi)qju!meugvxX*&jfD!^1XB3?E?HnwHP8$;uX{Rvp# zh|)hM>XDv$ZGg=$1{+_bA~u-vXqlw6NH=nkpyWE0u}LQjF-3NhATL@9rRxMnpO%f7 z)EhZf{PF|mKIMFxnC?*78(}{Y)}iztV12}_OXffJ;ta!fcFIVjdchyHxH=t%ci`Xd zX2AUB?%?poD6Zv*&BA!6c5S#|xn~DK01#XvjT!w!;&`lDXSJT4_j$}!qSPrb37vc{ z9^NfC%QvPu@vlxaZ;mIbn-VHA6miwi8qJ~V;pTZkKqqOii<1Cs}0i?uUIss;hM4dKq^1O35y?Yp=l4i zf{M!@QHH~rJ&X~8uATV><23zZUbs-J^3}$IvV_ANLS08>k`Td7aU_S1sLsfi*C-m1 z-e#S%UGs4E!;CeBT@9}aaI)qR-6NU@kvS#0r`g&UWg?fC7|b^_HyCE!8}nyh^~o@< zpm7PDFs9yxp+byMS(JWm$NeL?DNrMCNE!I^ko-*csB+dsf4GAq{=6sfyf4wb>?v1v zmb`F*bN1KUx-`ra1+TJ37bXNP%`-Fd`vVQFTwWpX@;s(%nDQa#oWhgk#mYlY*!d>( zE&!|ySF!mIyfING+#%RDY3IBH_fW$}6~1%!G`suHub1kP@&DoAd5~7J55;5_noPI6eLf{t;@9Kf<{aO0`1WNKd?<)C-|?C?)3s z>wEq@8=I$Wc~Mt$o;g++5qR+(6wt9GI~pyrDJ%c?gPZe)owvy^J2S=+M^ z&WhIE`g;;J^xQLVeCtf7b%Dg#Z2gq9hp_%g)-%_`y*zb; zn9`f`mUPN-Ts&fFo(aNTsXPA|J!TJ{0hZp0^;MYHLOcD=r_~~^ymS8KLCSeU3;^QzJNqS z5{5rEAv#l(X?bvwxpU;2%pQftF`YFgrD1jt2^~Mt^~G>T*}A$yZc@(k9orlCGv&|1 zWWvVgiJsCAtamuAYT~nzs?TQFt<1LSEx!@e0~@yd6$b5!Zm(FpBl;(Cn>2vF?k zOm#TTjFwd2D-CyA!mqR^?#Uwm{NBemP>(pHmM}9;;8`c&+_o3#E5m)JzfwN?(f-a4 zyd%xZc^oQx3XT?vcCqCX&Qrk~nu;fxs@JUoyVoi5fqpi&bUhQ2y!Ok2pzsFR(M(|U zw3E+kH_zmTRQ9dUMZWRE%Zakiwc+lgv7Z%|YO9YxAy`y28`Aw;WU6HXBgU7fl@dnt z-fFBV)}H-gqP!1;V@Je$WcbYre|dRdp{xt!7sL3Eoa%IA`5CAA%;Wq8PktwPdULo! z8!sB}Qt8#jH9Sh}QiUtEPZ6H0b*7qEKGJ%ITZ|vH)5Q^2m<7o3#Z>AKc%z7_u`rXA zqrCy{-{8;9>dfllLu$^M5L z-hXs))h*qz%~ActwkIA(qOVBZl2v4lwbM>9l70Y`+T*elINFqt#>OaVWoja8RMsep z6Or3f=oBnA3vDbn*+HNZP?8LsH2MY)x%c13@(XfuGR}R?Nu<|07{$+Lc3$Uv^I!MQ z>6qWgd-=aG2Y^24g4{Bw9ueOR)(9h`scImD=86dD+MnSN4$6 z^U*o_mE-6Rk~Dp!ANp#5RE9n*LG(Vg`1)g6!(XtDzsov$Dvz|Gv1WU68J$CkshQhS zCrc|cdkW~UK}5NeaWj^F4MSgFM+@fJd{|LLM)}_O<{rj z+?*Lm?owq?IzC%U%9EBga~h-cJbIu=#C}XuWN>OLrc%M@Gu~kFEYUi4EC6l#PR2JS zQUkGKrrS#6H7}2l0F@S11DP`@pih0WRkRJl#F;u{c&ZC{^$Z+_*lB)r)-bPgRFE;* zl)@hK4`tEP=P=il02x7-C7p%l=B`vkYjw?YhdJU9!P!jcmY$OtC^12w?vy3<<=tlY zUwHJ_0lgWN9vf>1%WACBD{UT)1qHQSE2%z|JHvP{#INr13jM}oYv_5#xsnv9`)UAO zuwgyV4YZ;O)eSc3(mka6=aRohi!HH@I#xq7kng?Acdg7S4vDJb6cI5fw?2z%3yR+| zU5v@Hm}vy;${cBp&@D=HQ9j7NcFaOYL zj-wV=eYF{|XTkFNM2uz&T8uH~;)^Zo!=KP)EVyH6s9l1~4m}N%XzPpduPg|h-&lL` zAXspR0YMOKd2yO)eMFFJ4?sQ&!`dF&!|niH*!^*Ml##o0M(0*uK9&yzekFi$+mP9s z>W9d%Jb)PtVi&-Ha!o~Iyh@KRuKpQ@)I~L*d`{O8!kRObjO7=n+Gp36fe!66neh+7 zW*l^0tTKjLLzr`x4`_8&on?mjW-PzheTNox8Hg7Nt@*SbE-%kP2hWYmHu#Fn@Q^J(SsPUz*|EgOoZ6byg3ew88UGdZ>9B2Tq=jF72ZaR=4u%1A6Vm{O#?@dD!(#tmR;eP(Fu z{$0O%=Vmua7=Gjr8nY%>ul?w=FJ76O2js&17W_iq2*tb!i{pt#`qZB#im9Rl>?t?0c zicIC}et_4d+CpVPx)i4~$u6N-QX3H77ez z?ZdvXifFk|*F8~L(W$OWM~r`pSk5}#F?j_5u$Obu9lDWIknO^AGu+Blk7!9Sb;NjS zncZA?qtASdNtzQ>z7N871IsPAk^CC?iIL}+{K|F@BuG2>qQ;_RUYV#>hHO(HUPpk@ z(bn~4|F_jiZi}Sad;_7`#4}EmD<1EiIxa48QjUuR?rC}^HRocq`OQPM@aHVKP9E#q zy%6bmHygCpIddPjE}q_DPC`VH_2m;Eey&ZH)E6xGeStOK7H)#+9y!%-Hm|QF6w#A( zIC0Yw%9j$s-#odxG~C*^MZ?M<+&WJ+@?B_QPUyTg9DJGtQN#NIC&-XddRsf3n^AL6 zT@P|H;PvN;ZpL0iv$bRb7|J{0o!Hq+S>_NrH4@coZtBJu#g8#CbR7|#?6uxi8d+$g z87apN>EciJZ`%Zv2**_uiET9Vk{pny&My;+WfGDw4EVL#B!Wiw&M|A8f1A@ z(yFQS6jfbH{b8Z-S7D2?Ixl`j0{+ZnpT=;KzVMLW{B$`N?Gw^Fl0H6lT61%T2AU**!sX0u?|I(yoy&Xveg7XBL&+>n6jd1##6d>TxE*Vj=8lWiG$4=u{1UbAa5QD>5_ z;Te^42v7K6Mmu4IWT6Rnm>oxrl~b<~^e3vbj-GCdHLIB_>59}Ya+~OF68NiH=?}2o zP(X7EN=quQn&)fK>M&kqF|<_*H`}c zk=+x)GU>{Af#vx&s?`UKUsz})g^Pc&?Ka@t5$n$bqf6{r1>#mWx6Ep>9|A}VmWRnowVo`OyCr^fHsf# zQjQ3Ttp7y#iQY8l`zEUW)(@gGQdt(~rkxlkefskT(t%@i8=|p1Y9Dc5bc+z#n$s13 zGJk|V0+&Ekh(F};PJzQKKo+FG@KV8a<$gmNSD;7rd_nRdc%?9)p!|B-@P~kxQG}~B zi|{0}@}zKC(rlFUYp*dO1RuvPC^DQOkX4<+EwvBAC{IZQdYxoq1Za!MW7%p7gGr=j zzWnAq%)^O2$eItftC#TTSArUyL$U54-O7e|)4_7%Q^2tZ^0-d&3J1}qCzR4dWX!)4 zzIEKjgnYgMus^>6uw4Jm8ga6>GBtMjpNRJ6CP~W=37~||gMo_p@GA@#-3)+cVYnU> zE5=Y4kzl+EbEh%dhQokB{gqNDqx%5*qBusWV%!iprn$S!;oN_6E3?0+umADVs4ako z?P+t?m?};gev9JXQ#Q&KBpzkHPde_CGu-y z<{}RRAx=xlv#mVi+Ibrgx~ujW$h{?zPfhz)Kp7kmYS&_|97b&H&1;J-mzrBWAvY} zh8-I8hl_RK2+nnf&}!W0P+>5?#?7>npshe<1~&l_xqKd0_>dl_^RMRq@-Myz&|TKZBj1=Q()) zF{dBjv5)h=&Z)Aevx}+i|7=R9rG^Di!sa)sZCl&ctX4&LScQ-kMncgO(9o6W6)yd< z@Rk!vkja*X_N3H=BavGoR0@u0<}m-7|2v!0+2h~S2Q&a=lTH91OJsvms2MT~ zY=c@LO5i`mLpBd(vh|)I&^A3TQLtr>w=zoyzTd=^f@TPu&+*2MtqE$Avf>l>}V|3-8Fp2hzo3y<)hr_|NO(&oSD z!vEjTWBxbKTiShVl-U{n*B3#)3a8$`{~Pk}J@elZ=>Pqp|MQ}jrGv7KrNcjW%TN_< zZz8kG{#}XoeWf7qY?D)L)8?Q-b@Na&>i=)(@uNo zr;cH98T3$Iau8Hn*@vXi{A@YehxDE2zX~o+RY`)6-X{8~hMpc#C`|8y> zU8Mnv5A0dNCf{Ims*|l-^ z(MRp{qoGohB34|ggDI*p!Aw|MFyJ|v+<+E3brfrI)|+l3W~CQLPbnF@G0)P~Ly!1TJLp}xh8uW`Q+RB-v`MRYZ9Gam3cM%{ zb4Cb*f)0deR~wtNb*8w-LlIF>kc7DAv>T0D(a3@l`k4TFnrO+g9XH7;nYOHxjc4lq zMmaW6qpgAgy)MckYMhl?>sq;-1E)-1llUneeA!ya9KM$)DaNGu57Z5aE>=VST$#vb zFo=uRHr$0M{-ha>h(D_boS4zId;3B|Tpqo|?B?Z@I?G(?&Iei+-{9L_A9=h=Qfn-U z1wIUnQe9!z%_j$F_{rf&`ZFSott09gY~qrf@g3O=Y>vzAnXCyL!@(BqWa)Zqt!#_k zfZHuwS52|&&)aK;CHq9V-t9qt0au{$#6c*R#e5n3rje0hic7c7m{kW$p(_`wB=Gw7 z4k`1Hi;Mc@yA7dp@r~?@rfw)TkjAW++|pkfOG}0N|2guek}j8Zen(!+@7?qt_7ndX zB=BG6WJ31#F3#Vk3=aQr8T)3`{=p9nBHlKzE0I@v`{vJ}h8pd6vby&VgFhzH|q;=aonunAXL6G2y(X^CtAhWr*jI zGjpY@raZDQkg*aMq}Ni6cRF z{oWv}5`nhSAv>usX}m^GHt`f(t8@zHc?K|y5Zi=4G*UG1Sza{$Dpj%X8 zzEXaKT5N6F5j4J|w#qlZP!zS7BT)9b+!ZSJdToqJts1c!)fwih4d31vfb{}W)EgcA zH2pZ^8_k$9+WD2n`6q5XbOy8>3pcYH9 z07eUB+p}YD@AH!}p!iKv><2QF-Y^&xx^PAc1F13A{nUeCDg&{hnix#FiO!fe(^&%Qcux!h znu*S!s$&nnkeotYsDthh1dq(iQrE|#f_=xVgfiiL&-5eAcC-> z5L0l|DVEM$#ulf{bj+Y~7iD)j<~O8CYM8GW)dQGq)!mck)FqoL^X zwNdZb3->hFrbHFm?hLvut-*uK?zXn3q1z|UX{RZ;-WiLoOjnle!xs+W0-8D)kjU#R z+S|A^HkRg$Ij%N4v~k`jyHffKaC~=wg=9)V5h=|kLQ@;^W!o2^K+xG&2n`XCd>OY5Ydi= zgHH=lgy++erK8&+YeTl7VNyVm9-GfONlSlVb3)V9NW5tT!cJ8d7X)!b-$fb!s76{t z@d=Vg-5K_sqHA@Zx-L_}wVnc@L@GL9_K~Zl(h5@AR#FAiKad8~KeWCo@mgXIQ#~u{ zgYFwNz}2b6Vu@CP0XoqJ+dm8px(5W5-Jpis97F`+KM)TuP*X8H@zwiVKDKGVp59pI zifNHZr|B+PG|7|Y<*tqap0CvG7tbR1R>jn70t1X`XJixiMVcHf%Ez*=xm1(CrTSDt z0cle!+{8*Ja&EOZ4@$qhBuKQ$U95Q%rc7tg$VRhk?3=pE&n+T3upZg^ZJc9~c2es% zh7>+|mrmA-p&v}|OtxqmHIBgUxL~^0+cpfkSK2mhh+4b=^F1Xgd2)}U*Yp+H?ls#z zrLxWg_hm}AfK2XYWr!rzW4g;+^^&bW%LmbtRai9f3PjU${r@n`JThy-cphbcwn)rq9{A$Ht`lmYKxOacy z6v2R(?gHhD5@&kB-Eg?4!hAoD7~(h>(R!s1c1Hx#s9vGPePUR|of32bS`J5U5w{F) z>0<^ktO2UHg<0{oxkdOQ;}coZDQph8p6ruj*_?uqURCMTac;>T#v+l1Tc~%^k-Vd@ zkc5y35jVNc49vZpZx;gG$h{%yslDI%Lqga1&&;mN{Ush1c7p>7e-(zp}6E7f-XmJb4nhk zb8zS+{IVbL$QVF8pf8}~kQ|dHJAEATmmnrb_wLG}-yHe>W|A&Y|;muy-d^t^<&)g5SJfaTH@P1%euONny=mxo+C z4N&w#biWY41r8k~468tvuYVh&XN&d#%QtIf9;iVXfWY)#j=l`&B~lqDT@28+Y!0E+MkfC}}H*#(WKKdJJq=O$vNYCb(ZG@p{fJgu;h z21oHQ(14?LeT>n5)s;uD@5&ohU!@wX8w*lB6i@GEH0pM>YTG+RAIWZD;4#F1&F%Jp zXZUml2sH0!lYJT?&sA!qwez6cXzJEd(1ZC~kT5kZSp7(@=H2$Azb_*W&6aA|9iwCL zdX7Q=42;@dspHDwYE?miGX#L^3xD&%BI&fN9^;`v4OjQXPBaBmOF1;#C)8XA(WFlH zycro;DS2?(G&6wkr6rqC>rqDv3nfGw3hmN_9Al>TgvmGsL8_hXx09};l9Ow@)F5@y z#VH5WigLDwZE4nh^7&@g{1FV^UZ%_LJ-s<{HN*2R$OPg@R~Z`c-ET*2}XB@9xvAjrK&hS=f|R8Gr9 zr|0TGOsI7RD+4+2{ZiwdVD@2zmg~g@^D--YL;6UYGSM8i$NbQr4!c7T9rg!8;TM0E zT#@?&S=t>GQm)*ua|?TLT2ktj#`|R<_*FAkOu2Pz$wEc%-=Y9V*$&dg+wIei3b*O8 z2|m$!jJG!J!ZGbbIa!(Af~oSyZV+~M1qGvelMzPNE_%5?c2>;MeeG2^N?JDKjFYCy z7SbPWH-$cWF9~fX%9~v99L!G(wi!PFp>rB!9xj7=Cv|F+7CsGNwY0Q_J%FID%C^CBZQfJ9K(HK%k31j~e#&?hQ zNuD6gRkVckU)v+53-fc} z7ZCzYN-5RG4H7;>>Hg?LU9&5_aua?A0)0dpew1#MMlu)LHe(M;OHjHIUl7|%%)YPo z0cBk;AOY00%Fe6heoN*$(b<)Cd#^8Iu;-2v@>cE-OB$icUF9EEoaC&q8z9}jMTT2I z8`9;jT%z0;dy4!8U;GW{i`)3!c6&oWY`J3669C!tM<5nQFFrFRglU8f)5Op$GtR-3 zn!+SPCw|04sv?%YZ(a7#L?vsdr7ss@WKAw&A*}-1S|9~cL%uA+E~>N6QklFE>8W|% zyX-qAUGTY1hQ-+um`2|&ji0cY*(qN!zp{YpDO-r>jPk*yuVSay<)cUt`t@&FPF_&$ zcHwu1(SQ`I-l8~vYyUxm@D1UEdFJ$f5Sw^HPH7b!9 zzYT3gKMF((N(v0#4f_jPfVZ=ApN^jQJe-X$`A?X+vWjLn_%31KXE*}5_}d8 zw_B1+a#6T1?>M{ronLbHIlEsMf93muJ7AH5h%;i99<~JX^;EAgEB1uHralD*!aJ@F zV2ruuFe9i2Q1C?^^kmVy921eb=tLDD43@-AgL^rQ3IO9%+vi_&R2^dpr}x{bCVPej z7G0-0o64uyWNtr*loIvslyo0%)KSDDKjfThe0hcqs)(C-MH1>bNGBDRTW~scy_{w} zp^aq8Qb!h9Lwielq%C1b8=?Z=&U)ST&PHbS)8Xzjh2DF?d{iAv)Eh)wsUnf>UtXN( zL7=$%YrZ#|^c{MYmhn!zV#t*(jdmYdCpwqpZ{v&L8KIuKn`@IIZfp!uo}c;7J57N` zAxyZ-uA4=Gzl~Ovycz%MW9ZL7N+nRo&1cfNn9(1H5eM;V_4Z_qVann7F>5f>%{rf= zPBZFaV@_Sobl?Fy&KXyzFDV*FIdhS5`Uc~S^Gjo)aiTHgn#<0C=9o-a-}@}xDor;D zZyZ|fvf;+=3MZd>SR1F^F`RJEZo+|MdyJYQAEauKu%WDol~ayrGU3zzbHKsnHKZ*z zFiwUkL@DZ>!*x05ql&EBq@_Vqv83&?@~q5?lVmffQZ+V-=qL+!u4Xs2Z2zdCQ3U7B&QR9_Iggy} z(om{Y9eU;IPe`+p1ifLx-XWh?wI)xU9ik+m#g&pGdB5Bi<`PR*?92lE0+TkRuXI)z z5LP!N2+tTc%cB6B1F-!fj#}>S!vnpgVU~3!*U1ej^)vjUH4s-bd^%B=ItQqDCGbrEzNQi(dJ`J}-U=2{7-d zK8k^Rlq2N#0G?9&1?HSle2vlkj^KWSBYTwx`2?9TU_DX#J+f+qLiZCqY1TXHFxXZqYMuD@RU$TgcnCC{_(vwZ-*uX)~go#%PK z@}2Km_5aQ~(<3cXeJN6|F8X_1@L%@xTzs}$_*E|a^_URF_qcF;Pfhoe?FTFwvjm1o z8onf@OY@jC2tVcMaZS;|T!Ks(wOgPpRzRnFS-^RZ4E!9dsnj9sFt609a|jJbb1Dt@ z<=Gal2jDEupxUSwWu6zp<<&RnAA;d&4gKVG0iu6g(DsST(4)z6R)zDpfaQ}v{5ARt zyhwvMtF%b-YazR5XLz+oh=mn;y-Mf2a8>7?2v8qX;19y?b>Z5laGHvzH;Nu9S`B8} zI)qN$GbXIQ1VL3lnof^6TS~rvPVg4V?Dl2Bb*K2z4E{5vy<(@@K_cN@U>R!>aUIRnb zL*)=787*cs#zb31zBC49x$`=fkQbMAef)L2$dR{)6BAz!t5U_B#1zZG`^neKSS22oJ#5B=gl%U=WeqL9REF2g zZnfCb0?quf?Ztj$VXvDSWoK`0L=Zxem2q}!XWLoT-kYMOx)!7fcgT35uC~0pySEme z`{wGWTkGr7>+Kb^n;W?BZH6ZP(9tQX%-7zF>vc2}LuWDI(9kh1G#7B99r4x6;_-V+k&c{nPUrR zAXJGRiMe~aup{0qzmLNjS_BC4cB#sXjckx{%_c&^xy{M61xEb>KW_AG5VFXUOjAG4 z^>Qlm9A#1N{4snY=(AmWzatb!ngqiqPbBZ7>Uhb3)dTkSGcL#&SH>iMO-IJBPua`u zo)LWZ>=NZLr758j{%(|uQuZ)pXq_4c!!>s|aDM9#`~1bzK3J1^^D#<2bNCccH7~-X}Ggi!pIIF>uFx%aPARGQsnC8ZQc8lrQ5o~smqOg>Ti^GNme94*w z)JZy{_{#$jxGQ&`M z!OMvZMHR>8*^>eS%o*6hJwn!l8VOOjZQJvh)@tnHVW&*GYPuxqXw}%M!(f-SQf`=L z5;=5w2;%82VMH6Xi&-K3W)o&K^+vJCepWZ-rW%+Dc6X3(){z$@4zjYxQ|}8UIojeC zYZpQ1dU{fy=oTr<4VX?$q)LP}IUmpiez^O&N3E_qPpchGTi5ZM6-2ScWlQq%V&R2Euz zO|Q0Hx>lY1Q1cW5xHv5!0OGU~PVEqSuy#fD72d#O`N!C;o=m+YioGu-wH2k6!t<~K zSr`E=W9)!g==~x9VV~-8{4ZN9{~-A9zJpRe%NGg$+MDuI-dH|b@BD)~>pPCGUNNzY zMDg||0@XGQgw`YCt5C&A{_+J}mvV9Wg{6V%2n#YSRN{AP#PY?1FF1#|vO_%e+#`|2*~wGAJaeRX6=IzFNeWhz6gJc8+(03Ph4y6ELAm=AkN7TOgMUEw*N{= z_)EIDQx5q22oUR+_b*tazu9+pX|n1c*IB-}{DqIj z-?E|ks{o3AGRNb;+iKcHkZvYJvFsW&83RAPs1Oh@IWy%l#5x2oUP6ZCtv+b|q>jsf zZ_9XO;V!>n`UxH1LvH8)L4?8raIvasEhkpQoJ`%!5rBs!0Tu(s_D{`4opB;57)pkX z4$A^8CsD3U5*!|bHIEqsn~{q+Ddj$ME@Gq4JXtgVz&7l{Ok!@?EA{B3P~NAqb9)4? zkQo30A^EbHfQ@87G5&EQTd`frrwL)&Yw?%-W@uy^Gn23%j?Y!Iea2xw<-f;esq zf%w5WN@E1}zyXtYv}}`U^B>W`>XPmdLj%4{P298|SisrE;7HvXX;A}Ffi8B#3Lr;1 zHt6zVb`8{#+e$*k?w8|O{Uh|&AG}|DG1PFo1i?Y*cQm$ZwtGcVgMwtBUDa{~L1KT-{jET4w60>{KZ27vXrHJ;fW{6| z=|Y4!&UX020wU1>1iRgB@Q#m~1^Z^9CG1LqDhYBrnx%IEdIty z!46iOoKlKs)c}newDG)rWUikD%j`)p z_w9Ph&e40=(2eBy;T!}*1p1f1SAUDP9iWy^u^Ubdj21Kn{46;GR+hwLO=4D11@c~V zI8x&(D({K~Df2E)Nx_yQvYfh4;MbMJ@Z}=Dt3_>iim~QZ*hZIlEs0mEb z_54+&*?wMD`2#vsQRN3KvoT>hWofI_Vf(^C1ff-Ike@h@saEf7g}<9T`W;HAne-Nd z>RR+&SP35w)xKn8^U$7))PsM!jKwYZ*RzEcG-OlTrX3}9a{q%#Un5E5W{{hp>w~;` zGky+3(vJvQyGwBo`tCpmo0mo((?nM8vf9aXrrY1Ve}~TuVkB(zeds^jEfI}xGBCM2 zL1|#tycSaWCurP+0MiActG3LCas@_@tao@(R1ANlwB$4K53egNE_;!&(%@Qo$>h`^1S_!hN6 z)vZtG$8fN!|BXBJ=SI>e(LAU(y(i*PHvgQ2llulxS8>qsimv7yL}0q_E5WiAz7)(f zC(ahFvG8&HN9+6^jGyLHM~$)7auppeWh_^zKk&C_MQ~8;N??OlyH~azgz5fe^>~7F zl3HnPN3z-kN)I$4@`CLCMQx3sG~V8hPS^}XDXZrQA>}mQPw%7&!sd(Pp^P=tgp-s^ zjl}1-KRPNWXgV_K^HkP__SR`S-|OF0bR-N5>I%ODj&1JUeAQ3$9i;B~$S6}*^tK?= z**%aCiH7y?xdY?{LgVP}S0HOh%0%LI$wRx;$T|~Y8R)Vdwa}kGWv8?SJVm^>r6+%I z#lj1aR94{@MP;t-scEYQWc#xFA30^}?|BeX*W#9OL;Q9#WqaaM546j5j29((^_8Nu z4uq}ESLr~r*O7E7$D{!k9W>`!SLoyA53i9QwRB{!pHe8um|aDE`Cg0O*{jmor)^t)3`>V>SWN-2VJcFmj^1?~tT=JrP`fVh*t zXHarp=8HEcR#vFe+1a%XXuK+)oFs`GDD}#Z+TJ}Ri`FvKO@ek2ayn}yaOi%(8p%2$ zpEu)v0Jym@f}U|-;}CbR=9{#<^z28PzkkTNvyKvJDZe+^VS2bES3N@Jq!-*}{oQlz z@8bgC_KnDnT4}d#&Cpr!%Yb?E!brx0!eVOw~;lLwUoz#Np%d$o%9scc3&zPm`%G((Le|6o1 zM(VhOw)!f84zG^)tZ1?Egv)d8cdNi+T${=5kV+j;Wf%2{3g@FHp^Gf*qO0q!u$=m9 zCaY`4mRqJ;FTH5`a$affE5dJrk~k`HTP_7nGTY@B9o9vvnbytaID;^b=Tzp7Q#DmD zC(XEN)Ktn39z5|G!wsVNnHi) z%^q94!lL|hF`IijA^9NR0F$@h7k5R^ljOW(;Td9grRN0Mb)l_l7##{2nPQ@?;VjXv zaLZG}yuf$r$<79rVPpXg?6iiieX|r#&`p#Con2i%S8*8F}(E) zI5E6c3tG*<;m~6>!&H!GJ6zEuhH7mkAzovdhLy;)q z{H2*8I^Pb}xC4s^6Y}6bJvMu=8>g&I)7!N!5QG$xseeU#CC?ZM-TbjsHwHgDGrsD= z{%f;@Sod+Ch66Ko2WF~;Ty)v>&x^aovCbCbD7>qF*!?BXmOV3(s|nxsb*Lx_2lpB7 zokUnzrk;P=T-&kUHO}td+Zdj!3n&NR?K~cRU zAXU!DCp?51{J4w^`cV#ye}(`SQhGQkkMu}O3M*BWt4UsC^jCFUy;wTINYmhD$AT;4 z?Xd{HaJjP`raZ39qAm;%beDbrLpbRf(mkKbANan7XsL>_pE2oo^$TgdidjRP!5-`% zv0d!|iKN$c0(T|L0C~XD0aS8t{*&#LnhE;1Kb<9&=c2B+9JeLvJr*AyyRh%@jHej=AetOMSlz^=!kxX>>B{2B1uIrQyfd8KjJ+DBy!h)~*(!|&L4^Q_07SQ~E zcemVP`{9CwFvPFu7pyVGCLhH?LhEVb2{7U+Z_>o25#+3<|8%1T^5dh}*4(kfJGry} zm%r#hU+__Z;;*4fMrX=Bkc@7|v^*B;HAl0((IBPPii%X9+u3DDF6%bI&6?Eu$8&aWVqHIM7mK6?Uvq$1|(-T|)IV<>e?!(rY zqkmO1MRaLeTR=)io(0GVtQT@s6rN%C6;nS3@eu;P#ry4q;^O@1ZKCJyp_Jo)Ty^QW z+vweTx_DLm{P-XSBj~Sl<%_b^$=}odJ!S2wAcxenmzFGX1t&Qp8Vxz2VT`uQsQYtdn&_0xVivIcxZ_hnrRtwq4cZSj1c-SG9 z7vHBCA=fd0O1<4*=lu$6pn~_pVKyL@ztw1swbZi0B?spLo56ZKu5;7ZeUml1Ws1?u zqMf1p{5myAzeX$lAi{jIUqo1g4!zWLMm9cfWcnw`k6*BR^?$2(&yW?>w;G$EmTA@a z6?y#K$C~ZT8+v{87n5Dm&H6Pb_EQ@V0IWmG9cG=O;(;5aMWWrIPzz4Q`mhK;qQp~a z+BbQrEQ+w{SeiuG-~Po5f=^EvlouB@_|4xQXH@A~KgpFHrwu%dwuCR)=B&C(y6J4J zvoGk9;lLs9%iA-IJGU#RgnZZR+@{5lYl8(e1h6&>Vc_mvg0d@);X zji4T|n#lB!>pfL|8tQYkw?U2bD`W{na&;*|znjmalA&f;*U++_aBYerq;&C8Kw7mI z7tsG*?7*5j&dU)Lje;^{D_h`%(dK|pB*A*1(Jj)w^mZ9HB|vGLkF1GEFhu&rH=r=8 zMxO42e{Si6$m+Zj`_mXb&w5Q(i|Yxyg?juUrY}78uo@~3v84|8dfgbPd0iQJRdMj< zncCNGdMEcsxu#o#B5+XD{tsg*;j-eF8`mp~K8O1J!Z0+>0=7O=4M}E?)H)ENE;P*F z$Ox?ril_^p0g7xhDUf(q652l|562VFlC8^r8?lQv;TMvn+*8I}&+hIQYh2 z1}uQQaag&!-+DZ@|C+C$bN6W;S-Z@)d1|en+XGvjbOxCa-qAF*LA=6s(Jg+g;82f$ z(Vb)8I)AH@cdjGFAR5Rqd0wiNCu!xtqWbcTx&5kslzTb^7A78~Xzw1($UV6S^VWiP zFd{Rimd-0CZC_Bu(WxBFW7+k{cOW7DxBBkJdJ;VsJ4Z@lERQr%3eVv&$%)b%<~ zCl^Y4NgO}js@u{|o~KTgH}>!* z_iDNqX2(As7T0xivMH|3SC1ivm8Q}6Ffcd7owUKN5lHAtzMM4<0v+ykUT!QiowO;`@%JGv+K$bBx@*S7C8GJVqQ_K>12}M`f_Ys=S zKFh}HM9#6Izb$Y{wYzItTy+l5U2oL%boCJn?R3?jP@n$zSIwlmyGq30Cw4QBO|14` zW5c);AN*J3&eMFAk$SR~2k|&+&Bc$e>s%c{`?d~85S-UWjA>DS5+;UKZ}5oVa5O(N zqqc@>)nee)+4MUjH?FGv%hm2{IlIF-QX}ym-7ok4Z9{V+ZHVZQl$A*x!(q%<2~iVv znUa+BX35&lCb#9VE-~Y^W_f;Xhl%vgjwdjzMy$FsSIj&ok}L+X`4>J=9BkN&nu^E*gbhj3(+D>C4E z@Fwq_=N)^bKFSHTzZk?-gNU$@l}r}dwGyh_fNi=9b|n}J>&;G!lzilbWF4B}BBq4f zYIOl?b)PSh#XTPp4IS5ZR_2C!E)Z`zH0OW%4;&~z7UAyA-X|sh9@~>cQW^COA9hV4 zXcA6qUo9P{bW1_2`eo6%hgbN%(G-F1xTvq!sc?4wN6Q4`e9Hku zFwvlAcRY?6h^Fj$R8zCNEDq8`=uZB8D-xn)tA<^bFFy}4$vA}Xq0jAsv1&5!h!yRA zU()KLJya5MQ`q&LKdH#fwq&(bNFS{sKlEh_{N%{XCGO+po#(+WCLmKW6&5iOHny>g z3*VFN?mx!16V5{zyuMWDVP8U*|BGT$(%IO|)?EF|OI*sq&RovH!N%=>i_c?K*A>>k zyg1+~++zY4Q)J;VWN0axhoIKx;l&G$gvj(#go^pZskEVj8^}is3Jw26LzYYVos0HX zRPvmK$dVxM8(Tc?pHFe0Z3uq){{#OK3i-ra#@+;*=ui8)y6hsRv z4Fxx1c1+fr!VI{L3DFMwXKrfl#Q8hfP@ajgEau&QMCxd{g#!T^;ATXW)nUg&$-n25 zruy3V!!;{?OTobo|0GAxe`Acn3GV@W=&n;~&9 zQM>NWW~R@OYORkJAo+eq1!4vzmf9K%plR4(tB@TR&FSbDoRgJ8qVcH#;7lQub*nq&?Z>7WM=oeEVjkaG zT#f)=o!M2DO5hLR+op>t0CixJCIeXH*+z{-XS|%jx)y(j&}Wo|3!l7{o)HU3m7LYyhv*xF&tq z%IN7N;D4raue&&hm0xM=`qv`+TK@;_xAcGKuK(2|75~ar2Yw)geNLSmVxV@x89bQu zpViVKKnlkwjS&&c|-X6`~xdnh}Ps)Hs z4VbUL^{XNLf7_|Oi>tA%?SG5zax}esF*FH3d(JH^Gvr7Rp*n=t7frH!U;!y1gJB^i zY_M$KL_}mW&XKaDEi9K-wZR|q*L32&m+2n_8lq$xRznJ7p8}V>w+d@?uB!eS3#u<} zIaqi!b!w}a2;_BfUUhGMy#4dPx>)_>yZ`ai?Rk`}d0>~ce-PfY-b?Csd(28yX22L% zI7XI>OjIHYTk_@Xk;Gu^F52^Gn6E1&+?4MxDS2G_#PQ&yXPXP^<-p|2nLTb@AAQEY zI*UQ9Pmm{Kat}wuazpjSyXCdnrD&|C1c5DIb1TnzF}f4KIV6D)CJ!?&l&{T)e4U%3HTSYqsQ zo@zWB1o}ceQSV)<4G<)jM|@@YpL+XHuWsr5AYh^Q{K=wSV99D~4RRU52FufmMBMmd z_H}L#qe(}|I9ZyPRD6kT>Ivj&2Y?qVZq<4bG_co_DP`sE*_Xw8D;+7QR$Uq(rr+u> z8bHUWbV19i#)@@G4bCco@Xb<8u~wVDz9S`#k@ciJtlu@uP1U0X?yov8v9U3VOig2t zL9?n$P3=1U_Emi$#slR>N5wH-=J&T=EdUHA}_Z zZIl3nvMP*AZS9{cDqFanrA~S5BqxtNm9tlu;^`)3X&V4tMAkJ4gEIPl= zoV!Gyx0N{3DpD@)pv^iS*dl2FwANu;1;%EDl}JQ7MbxLMAp>)UwNwe{=V}O-5C*>F zu?Ny+F64jZn<+fKjF01}8h5H_3pey|;%bI;SFg$w8;IC<8l|3#Lz2;mNNik6sVTG3 z+Su^rIE#40C4a-587$U~%KedEEw1%r6wdvoMwpmlXH$xPnNQN#f%Z7|p)nC>WsuO= z4zyqapLS<8(UJ~Qi9d|dQijb_xhA2)v>la)<1md5s^R1N&PiuA$^k|A<+2C?OiHbj z>Bn$~t)>Y(Zb`8hW7q9xQ=s>Rv81V+UiuZJc<23HplI88isqRCId89fb`Kt|CxVIg znWcwprwXnotO>3s&Oypkte^9yJjlUVVxSe%_xlzmje|mYOVPH^vjA=?6xd0vaj0Oz zwJ4OJNiFdnHJX3rw&inskjryukl`*fRQ#SMod5J|KroJRsVXa5_$q7whSQ{gOi*s0 z1LeCy|JBWRsDPn7jCb4s(p|JZiZ8+*ExC@Vj)MF|*Vp{B(ziccSn`G1Br9bV(v!C2 z6#?eqpJBc9o@lJ#^p-`-=`4i&wFe>2)nlPK1p9yPFzJCzBQbpkcR>={YtamIw)3nt z(QEF;+)4`>8^_LU)_Q3 zC5_7lgi_6y>U%m)m@}Ku4C}=l^J=<<7c;99ec3p{aR+v=diuJR7uZi%aQv$oP?dn?@6Yu_+*^>T0ptf(oobdL;6)N-I!TO`zg^Xbv3#L0I~sn@WGk-^SmPh5>W+LB<+1PU}AKa?FCWF|qMNELOgdxR{ zbqE7@jVe+FklzdcD$!(A$&}}H*HQFTJ+AOrJYnhh}Yvta(B zQ_bW4Rr;R~&6PAKwgLWXS{Bnln(vUI+~g#kl{r+_zbngT`Y3`^Qf=!PxN4IYX#iW4 zucW7@LLJA9Zh3(rj~&SyN_pjO8H&)|(v%!BnMWySBJV=eSkB3YSTCyIeJ{i;(oc%_hk{$_l;v>nWSB)oVeg+blh=HB5JSlG_r7@P z3q;aFoZjD_qS@zygYqCn=;Zxjo!?NK!%J$ z52lOP`8G3feEj+HTp@Tnn9X~nG=;tS+z}u{mQX_J0kxtr)O30YD%oo)L@wy`jpQYM z@M>Me=95k1p*FW~rHiV1CIfVc{K8r|#Kt(ApkXKsDG$_>76UGNhHExFCw#Ky9*B-z zNq2ga*xax!HMf_|Vp-86r{;~YgQKqu7%szk8$hpvi_2I`OVbG1doP(`gn}=W<8%Gn z%81#&WjkH4GV;4u43EtSW>K_Ta3Zj!XF?;SO3V#q=<=>Tc^@?A`i;&`-cYj|;^ zEo#Jl5zSr~_V-4}y8pnufXLa80vZY4z2ko7fj>DR)#z=wWuS1$$W!L?(y}YC+yQ|G z@L&`2upy3f>~*IquAjkVNU>}c10(fq#HdbK$~Q3l6|=@-eBbo>B9(6xV`*)sae58*f zym~RRVx;xoCG3`JV`xo z!lFw)=t2Hy)e!IFs?0~7osWk(d%^wxq&>_XD4+U#y&-VF%4z?XH^i4w`TxpF{`XhZ z%G}iEzf!T(l>g;W9<~K+)$g!{UvhW{E0Lis(S^%I8OF&%kr!gJ&fMOpM=&=Aj@wuL zBX?*6i51Qb$uhkwkFYkaD_UDE+)rh1c;(&Y=B$3)J&iJfQSx!1NGgPtK!$c9OtJuu zX(pV$bfuJpRR|K(dp@^j}i&HeJOh@|7lWo8^$*o~Xqo z5Sb+!EtJ&e@6F+h&+_1ETbg7LfP5GZjvIUIN3ibCOldAv z)>YdO|NH$x7AC8dr=<2ekiY1%fN*r~e5h6Yaw<{XIErujKV~tiyrvV_DV0AzEknC- zR^xKM3i<1UkvqBj3C{wDvytOd+YtDSGu!gEMg+!&|8BQrT*|p)(dwQLEy+ zMtMzij3zo40)CA!BKZF~yWg?#lWhqD3@qR)gh~D{uZaJO;{OWV8XZ_)J@r3=)T|kt zUS1pXr6-`!Z}w2QR7nP%d?ecf90;K_7C3d!UZ`N(TZoWNN^Q~RjVhQG{Y<%E1PpV^4 z-m-K+$A~-+VDABs^Q@U*)YvhY4Znn2^w>732H?NRK(5QSS$V@D7yz2BVX4)f5A04~$WbxGOam22>t&uD)JB8-~yiQW6ik;FGblY_I>SvB_z2?PS z*Qm&qbKI{H1V@YGWzpx`!v)WeLT02};JJo*#f$a*FH?IIad-^(;9XC#YTWN6;Z6+S zm4O1KH=#V@FJw7Pha0!9Vb%ZIM$)a`VRMoiN&C|$YA3~ZC*8ayZRY^fyuP6$n%2IU z$#XceYZeqLTXw(m$_z|33I$B4k~NZO>pP6)H_}R{E$i%USGy{l{-jOE;%CloYPEU+ zRFxOn4;7lIOh!7abb23YKD+_-?O z0FP9otcAh+oSj;=f#$&*ExUHpd&e#bSF%#8*&ItcL2H$Sa)?pt0Xtf+t)z$_u^wZi z44oE}r4kIZGy3!Mc8q$B&6JqtnHZ>Znn!Zh@6rgIu|yU+zG8q`q9%B18|T|oN3zMq z`l&D;U!OL~%>vo&q0>Y==~zLiCZk4v%s_7!9DxQ~id1LLE93gf*gg&2$|hB#j8;?3 z5v4S;oM6rT{Y;I+#FdmNw z){d%tNM<<#GN%n9ox7B=3#;u7unZ~tLB_vRZ52a&2=IM)2VkXm=L+Iqq~uk#Dug|x z>S84e+A7EiOY5lj*!q?6HDkNh~0g;0Jy(al!ZHHDtur9T$y-~)94HelX1NHjXWIM7UAe}$?jiz z9?P4`I0JM=G5K{3_%2jPLC^_Mlw?-kYYgb7`qGa3@dn|^1fRMwiyM@Ch z;CB&o7&&?c5e>h`IM;Wnha0QKnEp=$hA8TJgR-07N~U5(>9vJzeoFsSRBkDq=x(YgEMpb=l4TDD`2 zwVJpWGTA_u7}?ecW7s6%rUs&NXD3+n;jB86`X?8(l3MBo6)PdakI6V6a}22{)8ilT zM~T*mU}__xSy|6XSrJ^%lDAR3Lft%+yxC|ZUvSO_nqMX!_ul3;R#*{~4DA=h$bP)%8Yv9X zyp><|e8=_ttI}ZAwOd#dlnSjck#6%273{E$kJuCGu=I@O)&6ID{nWF5@gLb16sj|&Sb~+du4e4O_%_o`Ix4NRrAsyr1_}MuP94s>de8cH-OUkVPk3+K z&jW)It9QiU-ti~AuJkL`XMca8Oh4$SyJ=`-5WU<{cIh+XVH#e4d&zive_UHC!pN>W z3TB;Mn5i)9Qn)#6@lo4QpI3jFYc0~+jS)4AFz8fVC;lD^+idw^S~Qhq>Tg(!3$yLD zzktzoFrU@6s4wwCMz}edpF5i5Q1IMmEJQHzp(LAt)pgN3&O!&d?3W@6U4)I^2V{;- z6A(?zd93hS*uQmnh4T)nHnE{wVhh(=MMD(h(P4+^p83Om6t<*cUW>l(qJzr%5vp@K zN27ka(L{JX=1~e2^)F^i=TYj&;<7jyUUR2Bek^A8+3Up*&Xwc{)1nRR5CT8vG>ExV zHnF3UqXJOAno_?bnhCX-&kwI~Ti8t4`n0%Up>!U`ZvK^w2+0Cs-b9%w%4`$+To|k= zKtgc&l}P`*8IS>8DOe?EB84^kx4BQp3<7P{Pq}&p%xF_81pg!l2|u=&I{AuUgmF5n zJQCTLv}%}xbFGYtKfbba{CBo)lWW%Z>i(_NvLhoQZ*5-@2l&x>e+I~0Nld3UI9tdL zRzu8}i;X!h8LHVvN?C+|M81e>Jr38%&*9LYQec9Ax>?NN+9(_>XSRv&6hlCYB`>Qm z1&ygi{Y()OU4@D_jd_-7vDILR{>o|7-k)Sjdxkjgvi{@S>6GqiF|o`*Otr;P)kLHN zZkpts;0zw_6;?f(@4S1FN=m!4^mv~W+lJA`&7RH%2$)49z0A+8@0BCHtj|yH--AEL z0tW6G%X-+J+5a{5*WKaM0QDznf;V?L5&uQw+yegDNDP`hA;0XPYc6e0;Xv6|i|^F2WB)Z$LR|HR4 zTQsRAby9(^Z@yATyOgcfQw7cKyr^3Tz7lc7+JEwwzA7)|2x+PtEb>nD(tpxJQm)Kn zW9K_*r!L%~N*vS8<5T=iv|o!zTe9k_2jC_j*7ik^M_ zaf%k{WX{-;0*`t`G!&`eW;gChVXnJ-Rn)To8vW-?>>a%QU1v`ZC=U)f8iA@%JG0mZ zDqH;~mgBnrCP~1II<=V9;EBL)J+xzCoiRBaeH&J6rL!{4zIY8tZka?_FBeQeNO3q6 zyG_alW54Ba&wQf{&F1v-r1R6ID)PTsqjIBc+5MHkcW5Fnvi~{-FjKe)t1bl}Y;z@< z=!%zvpRua>>t_x}^}z0<7MI!H2v6|XAyR9!t50q-A)xk0nflgF4*OQlCGK==4S|wc zRMsSscNhRzHMBU8TdcHN!q^I}x0iXJ%uehac|Zs_B$p@CnF)HeXPpB_Za}F{<@6-4 zl%kml@}kHQ(ypD8FsPJ2=14xXJE|b20RUIgs!2|R3>LUMGF6X*B_I|$`Qg=;zm7C z{mEDy9dTmPbued7mlO@phdmAmJ7p@GR1bjCkMw6*G7#4+`k>fk1czdJUB!e@Q(~6# zwo%@p@V5RL0ABU2LH7Asq^quDUho@H>eTZH9f*no9fY0T zD_-9px3e}A!>>kv5wk91%C9R1J_Nh!*&Kk$J3KNxC}c_@zlgpJZ+5L)Nw|^p=2ue}CJtm;uj*Iqr)K})kA$xtNUEvX;4!Px*^&9T_`IN{D z{6~QY=Nau6EzpvufB^hflc#XIsSq0Y9(nf$d~6ZwK}fal92)fr%T3=q{0mP-EyP_G z)UR5h@IX}3Qll2b0oCAcBF>b*@Etu*aTLPU<%C>KoOrk=x?pN!#f_Og-w+;xbFgjQ zXp`et%lDBBh~OcFnMKMUoox0YwBNy`N0q~bSPh@+enQ=4RUw1) zpovN`QoV>vZ#5LvC;cl|6jPr}O5tu!Ipoyib8iXqy}TeJ;4+_7r<1kV0v5?Kv>fYp zg>9L`;XwXa&W7-jf|9~uP2iyF5`5AJ`Q~p4eBU$MCC00`rcSF>`&0fbd^_eqR+}mK z4n*PMMa&FOcc)vTUR zlDUAn-mh`ahi_`f`=39JYTNVjsTa_Y3b1GOIi)6dY)D}xeshB0T8Eov5%UhWd1)u}kjEQ|LDo{tqKKrYIfVz~@dp!! zMOnah@vp)%_-jDTUG09l+;{CkDCH|Q{NqX*uHa1YxFShy*1+;J`gywKaz|2Q{lG8x zP?KBur`}r`!WLKXY_K;C8$EWG>jY3UIh{+BLv0=2)KH%P}6xE2kg)%(-uA6lC?u8}{K(#P*c zE9C8t*u%j2r_{;Rpe1A{9nNXU;b_N0vNgyK!EZVut~}+R2rcbsHilqsOviYh-pYX= zHw@53nlmwYI5W5KP>&`dBZe0Jn?nAdC^HY1wlR6$u^PbpB#AS&5L6zqrXN&7*N2Q` z+Rae1EwS)H=aVSIkr8Ek^1jy2iS2o7mqm~Mr&g5=jjt7VxwglQ^`h#Mx+x2v|9ZAwE$i_9918MjJxTMr?n!bZ6n$}y11u8I9COTU`Z$Fi z!AeAQLMw^gp_{+0QTEJrhL424pVDp%wpku~XRlD3iv{vQ!lAf!_jyqd_h}+Tr1XG| z`*FT*NbPqvHCUsYAkFnM`@l4u_QH&bszpUK#M~XLJt{%?00GXY?u_{gj3Hvs!=N(I z(=AuWPijyoU!r?aFTsa8pLB&cx}$*%;K$e*XqF{~*rA-qn)h^!(-;e}O#B$|S~c+U zN4vyOK0vmtx$5K!?g*+J@G1NmlEI=pyZXZ69tAv=@`t%ag_Hk{LP~OH9iE)I= zaJ69b4kuCkV0V zo(M0#>phpQ_)@j;h%m{-a*LGi(72TP)ws2w*@4|C-3+;=5DmC4s7Lp95%n%@Ko zfdr3-a7m*dys9iIci$A=4NPJ`HfJ;hujLgU)ZRuJI`n;Pw|yksu!#LQnJ#dJysgNb z@@qwR^wrk(jbq4H?d!lNyy72~Dnn87KxsgQ!)|*m(DRM+eC$wh7KnS-mho3|KE)7h zK3k;qZ;K1Lj6uEXLYUYi)1FN}F@-xJ z@@3Hb84sl|j{4$3J}aTY@cbX@pzB_qM~APljrjju6P0tY{C@ zpUCOz_NFmALMv1*blCcwUD3?U6tYs+N%cmJ98D%3)%)Xu^uvzF zS5O!sc#X6?EwsYkvPo6A%O8&y8sCCQH<%f2togVwW&{M;PR!a(ZT_A+jVAbf{@5kL zB@Z(hb$3U{T_}SKA_CoQVU-;j>2J=L#lZ~aQCFg-d<9rzs$_gO&d5N6eFSc z1ml8)P*FSi+k@!^M9nDWR5e@ATD8oxtDu=36Iv2!;dZzidIS(PCtEuXAtlBb1;H%Z zwnC^Ek*D)EX4#Q>R$$WA2sxC_t(!!6Tr?C#@{3}n{<^o;9id1RA&-Pig1e-2B1XpG zliNjgmd3c&%A}s>qf{_j#!Z`fu0xIwm4L0)OF=u(OEmp;bLCIaZX$&J_^Z%4Sq4GZ zPn6sV_#+6pJmDN_lx@1;Zw6Md_p0w9h6mHtzpuIEwNn>OnuRSC2=>fP^Hqgc)xu^4 z<3!s`cORHJh#?!nKI`Et7{3C27+EuH)Gw1f)aoP|B3y?fuVfvpYYmmukx0ya-)TQX zR{ggy5cNf4X|g)nl#jC9p>7|09_S7>1D2GTRBUTW zAkQ=JMRogZqG#v;^=11O6@rPPwvJkr{bW-Qg8`q8GoD#K`&Y+S#%&B>SGRL>;ZunM@49!}Uy zN|bBCJ%sO;@3wl0>0gbl3L@1^O60ONObz8ZI7nder>(udj-jt`;yj^nTQ$L9`OU9W zX4alF#$|GiR47%x@s&LV>2Sz2R6?;2R~5k6V>)nz!o_*1Y!$p>BC5&?hJg_MiE6UBy>RkVZj`9UWbRkN-Hk!S`=BS3t3uyX6)7SF#)71*}`~Ogz z1rap5H6~dhBJ83;q-Y<5V35C2&F^JI-it(=5D#v!fAi9p#UwV~2tZQI+W(Dv?1t9? zfh*xpxxO{-(VGB>!Q&0%^YW_F!@aZS#ucP|YaD#>wd1Fv&Z*SR&mc;asi}1G) z_H>`!akh-Zxq9#io(7%;a$)w+{QH)Y$?UK1Dt^4)up!Szcxnu}kn$0afcfJL#IL+S z5gF_Y30j;{lNrG6m~$Ay?)*V9fZuU@3=kd40=LhazjFrau>(Y>SJNtOz>8x_X-BlA zIpl{i>OarVGj1v(4?^1`R}aQB&WCRQzS~;7R{tDZG=HhgrW@B`W|#cdyj%YBky)P= zpxuOZkW>S6%q7U{VsB#G(^FMsH5QuGXhb(sY+!-R8Bmv6Sx3WzSW<1MPPN1!&PurYky(@`bP9tz z52}LH9Q?+FF5jR6-;|+GVdRA!qtd;}*-h&iIw3Tq3qF9sDIb1FFxGbo&fbG5n8$3F zyY&PWL{ys^dTO}oZ#@sIX^BKW*bon=;te9j5k+T%wJ zNJtoN1~YVj4~YRrlZl)b&kJqp+Z`DqT!la$x&&IxgOQw#yZd-nBP3!7FijBXD|IsU8Zl^ zc6?MKpJQ+7ka|tZQLfchD$PD|;K(9FiLE|eUZX#EZxhG!S-63C$jWX1Yd!6-Yxi-u zjULIr|0-Q%D9jz}IF~S%>0(jOqZ(Ln<$9PxiySr&2Oic7vb<8q=46)Ln%Z|<*z5&> z3f~Zw@m;vR(bESB<=Jqkxn(=#hQw42l(7)h`vMQQTttz9XW6^|^8EK7qhju4r_c*b zJIi`)MB$w@9epwdIfnEBR+?~);yd6C(LeMC& zn&&N*?-g&BBJcV;8&UoZi4Lmxcj16ojlxR~zMrf=O_^i1wGb9X-0@6_rpjPYemIin zmJb+;lHe;Yp=8G)Q(L1bzH*}I>}uAqhj4;g)PlvD9_e_ScR{Ipq|$8NvAvLD8MYr}xl=bU~)f%B3E>r3Bu9_t|ThF3C5~BdOve zEbk^r&r#PT&?^V1cb{72yEWH}TXEE}w>t!cY~rA+hNOTK8FAtIEoszp!qqptS&;r$ zaYV-NX96-h$6aR@1xz6_E0^N49mU)-v#bwtGJm)ibygzJ8!7|WIrcb`$XH~^!a#s& z{Db-0IOTFq#9!^j!n_F}#Z_nX{YzBK8XLPVmc&X`fT7!@$U-@2KM9soGbmOSAmqV z{nr$L^MBo_u^Joyf0E^=eo{Rt0{{e$IFA(#*kP@SQd6lWT2-#>` zP1)7_@IO!9lk>Zt?#CU?cuhiLF&)+XEM9B)cS(gvQT!X3`wL*{fArTS;Ak`J<84du zALKPz4}3nlG8Fo^MH0L|oK2-4xIY!~Oux~1sw!+It)&D3p;+N8AgqKI`ld6v71wy8I!eP0o~=RVcFQR2Gr(eP_JbSytoQ$Yt}l*4r@A8Me94y z8cTDWhqlq^qoAhbOzGBXv^Wa4vUz$(7B!mX`T=x_ueKRRDfg&Uc-e1+z4x$jyW_Pm zp?U;-R#xt^Z8Ev~`m`iL4*c#65Nn)q#=Y0l1AuD&+{|8-Gsij3LUZXpM0Bx0u7WWm zH|%yE@-#XEph2}-$-thl+S;__ciBxSSzHveP%~v}5I%u!z_l_KoW{KRx2=eB33umE zIYFtu^5=wGU`Jab8#}cnYry@9p5UE#U|VVvx_4l49JQ;jQdp(uw=$^A$EA$LM%vmE zvdEOaIcp5qX8wX{mYf0;#51~imYYPn4=k&#DsKTxo{_Mg*;S495?OBY?#gv=edYC* z^O@-sd-qa+U24xvcbL0@C7_6o!$`)sVr-jSJE4XQUQ$?L7}2(}Eixqv;L8AdJAVqc zq}RPgpnDb@E_;?6K58r3h4-!4rT4Ab#rLHLX?eMOfluJk=3i1@Gt1i#iA=O`M0@x! z(HtJP9BMHXEzuD93m|B&woj0g6T?f#^)>J>|I4C5?Gam>n9!8CT%~aT;=oco5d6U8 zMXl(=W;$ND_8+DD*?|5bJ!;8ebESXMUKBAf7YBwNVJibGaJ*(2G`F%wx)grqVPjudiaq^Kl&g$8A2 zWMxMr@_$c}d+;_B`#kUX-t|4VKH&_f^^EP0&=DPLW)H)UzBG%%Tra*5 z%$kyZe3I&S#gfie^z5)!twG={3Cuh)FdeA!Kj<-9** zvT*5%Tb`|QbE!iW-XcOuy39>D3oe6x{>&<#E$o8Ac|j)wq#kQzz|ATd=Z0K!p2$QE zPu?jL8Lb^y3_CQE{*}sTDe!2!dtlFjq&YLY@2#4>XS`}v#PLrpvc4*@q^O{mmnr5D zmyJq~t?8>FWU5vZdE(%4cuZuao0GNjp3~Dt*SLaxI#g_u>hu@k&9Ho*#CZP~lFJHj z(e!SYlLigyc?&5-YxlE{uuk$9b&l6d`uIlpg_z15dPo*iU&|Khx2*A5Fp;8iK_bdP z?T6|^7@lcx2j0T@x>X7|kuuBSB7<^zeY~R~4McconTxA2flHC0_jFxmSTv-~?zVT| zG_|yDqa9lkF*B6_{j=T>=M8r<0s;@z#h)3BQ4NLl@`Xr__o7;~M&dL3J8fP&zLfDfy z);ckcTev{@OUlZ`bCo(-3? z1u1xD`PKgSg?RqeVVsF<1SLF;XYA@Bsa&cY!I48ZJn1V<3d!?s=St?TLo zC0cNr`qD*M#s6f~X>SCNVkva^9A2ZP>CoJ9bvgXe_c}WdX-)pHM5m7O zrHt#g$F0AO+nGA;7dSJ?)|Mo~cf{z2L)Rz!`fpi73Zv)H=a5K)*$5sf_IZypi($P5 zsPwUc4~P-J1@^3C6-r9{V-u0Z&Sl7vNfmuMY4yy*cL>_)BmQF!8Om9Dej%cHxbIzA zhtV0d{=%cr?;bpBPjt@4w=#<>k5ee=TiWAXM2~tUGfm z$s&!Dm0R^V$}fOR*B^kGaipi~rx~A2cS0;t&khV1a4u38*XRUP~f za!rZMtay8bsLt6yFYl@>-y^31(*P!L^^s@mslZy(SMsv9bVoX`O#yBgEcjCmGpyc* zeH$Dw6vB5P*;jor+JOX@;6K#+xc)Z9B8M=x2a@Wx-{snPGpRmOC$zpsqW*JCh@M2Y z#K+M(>=#d^>Of9C`))h<=Bsy)6zaMJ&x-t%&+UcpLjV`jo4R2025 zXaG8EA!0lQa)|dx-@{O)qP6`$rhCkoQqZ`^SW8g-kOwrwsK8 z3ms*AIcyj}-1x&A&vSq{r=QMyp3CHdWH35!sad#!Sm>^|-|afB+Q;|Iq@LFgqIp#Z zD1%H+3I?6RGnk&IFo|u+E0dCxXz4yI^1i!QTu7uvIEH>i3rR{srcST`LIRwdV1P;W z+%AN1NIf@xxvVLiSX`8ILA8MzNqE&7>%jMzGt9wm78bo9<;h*W84i29^w!>V>{N+S zd`5Zmz^G;f=icvoOZfK5#1ctx*~UwD=ab4DGQXehQ!XYnak*dee%YN$_ZPL%KZuz$ zD;$PpT;HM^$KwtQm@7uvT`i6>Hae1CoRVM2)NL<2-k2PiX=eAx+-6j#JI?M}(tuBW zkF%jjLR)O`gI2fcPBxF^HeI|DWwQWHVR!;;{BXXHskxh8F@BMDn`oEi-NHt;CLymW z=KSv5)3dyzec0T5B*`g-MQ<;gz=nIWKUi9ko<|4I(-E0k$QncH>E4l z**1w&#={&zv4Tvhgz#c29`m|;lU-jmaXFMC11 z*dlXDMEOG>VoLMc>!rApwOu2prKSi*!w%`yzGmS+k(zm*CsLK*wv{S_0WX^8A-rKy zbk^Gf_92^7iB_uUF)EE+ET4d|X|>d&mdN?x@vxKAQk`O+r4Qdu>XGy(a(19g;=jU} zFX{O*_NG>!$@jh!U369Lnc+D~qch3uT+_Amyi}*k#LAAwh}k8IPK5a-WZ81ufD>l> z$4cF}GSz>ce`3FAic}6W4Z7m9KGO?(eWqi@L|5Hq0@L|&2flN1PVl}XgQ2q*_n2s3 zt5KtowNkTYB5b;SVuoXA@i5irXO)A&%7?V`1@HGCB&)Wgk+l|^XXChq;u(nyPB}b3 zY>m5jkxpZgi)zfbgv&ec4Zqdvm+D<?Im*mXweS9H+V>)zF#Zp3)bhl$PbISY{5=_z!8&*Jv~NYtI-g!>fDs zmvL5O^U%!^VaKA9gvKw|5?-jk>~%CVGvctKmP$kpnpfN{D8@X*Aazi$txfa%vd-|E z>kYmV66W!lNekJPom29LdZ%(I+ZLZYTXzTg*to~m?7vp%{V<~>H+2}PQ?PPAq`36R z<%wR8v6UkS>Wt#hzGk#44W<%9S=nBfB);6clKwnxY}T*w21Qc3_?IJ@4gYzC7s;WP zVQNI(M=S=JT#xsZy7G`cR(BP9*je0bfeN8JN5~zY(DDs0t{LpHOIbN);?T-69Pf3R zSNe*&p2%AwXHL>__g+xd4Hlc_vu<25H?(`nafS%)3UPP7_4;gk-9ckt8SJRTv5v0M z_Hww`qPudL?ajIR&X*;$y-`<)6dxx1U~5eGS13CB!lX;3w7n&lDDiArbAhSycd}+b zya_3p@A`$kQy;|NJZ~s44Hqo7Hwt}X86NK=(ey>lgWTtGL6k@Gy;PbO!M%1~Wcn2k zUFP|*5d>t-X*RU8g%>|(wwj*~#l4z^Aatf^DWd1Wj#Q*AY0D^V@sC`M zjJc6qXu0I7Y*2;;gGu!plAFzG=J;1%eIOdn zQA>J&e05UN*7I5@yRhK|lbBSfJ+5Uq;!&HV@xfPZrgD}kE*1DSq^=%{o%|LChhl#0 zlMb<^a6ixzpd{kNZr|3jTGeEzuo}-eLT-)Q$#b{!vKx8Tg}swCni>{#%vDY$Ww$84 zew3c9BBovqb}_&BRo#^!G(1Eg((BScRZ}C)Oz?y`T5wOrv);)b^4XR8 zhJo7+<^7)qB>I;46!GySzdneZ>n_E1oWZY;kf94#)s)kWjuJN1c+wbVoNQcmnv}{> zN0pF+Sl3E}UQ$}slSZeLJrwT>Sr}#V(dVaezCQl2|4LN`7L7v&siYR|r7M(*JYfR$ zst3=YaDw$FSc{g}KHO&QiKxuhEzF{f%RJLKe3p*7=oo`WNP)M(9X1zIQPP0XHhY3c znrP{$4#Ol$A0s|4S7Gx2L23dv*Gv2o;h((XVn+9+$qvm}s%zi6nI-_s6?mG! zj{DV;qesJb&owKeEK?=J>UcAlYckA7Sl+I&IN=yasrZOkejir*kE@SN`fk<8Fgx*$ zy&fE6?}G)d_N`){P~U@1jRVA|2*69)KSe_}!~?+`Yb{Y=O~_+@!j<&oVQQMnhoIRU zA0CyF1OFfkK44n*JD~!2!SCPM;PRSk%1XL=0&rz00wxPs&-_eapJy#$h!eqY%nS0{ z!aGg58JIJPF3_ci%n)QSVpa2H`vIe$RD43;#IRfDV&Ibit z+?>HW4{2wOfC6Fw)}4x}i1maDxcE1qi@BS*qcxD2gE@h3#4cgU*D-&3z7D|tVZWt= z-Cy2+*Cm@P4GN_TPUtaVyVesbVDazF@)j8VJ4>XZv!f%}&eO1SvIgr}4`A*3#vat< z_MoByL(qW6L7SFZ#|Gc1fFN)L2PxY+{B8tJp+pxRyz*87)vXR}*=&ahXjBlQKguuf zX6x<<6fQulE^C*KH8~W%ptpaC0l?b=_{~*U4?5Vt;dgM4t_{&UZ1C2j?b>b+5}{IF_CUyvz-@QZPMlJ)r_tS$9kH%RPv#2_nMb zRLj5;chJ72*U`Z@Dqt4$@_+k$%|8m(HqLG!qT4P^DdfvGf&){gKnGCX#H0!;W=AGP zbA&Z`-__a)VTS}kKFjWGk z%|>yE?t*EJ!qeQ%dPk$;xIQ+P0;()PCBDgjJm6Buj{f^awNoVx+9<|lg3%-$G(*f) zll6oOkN|yamn1uyl2*N-lnqRI1cvs_JxLTeahEK=THV$Sz*gQhKNb*p0fNoda#-&F zB-qJgW^g}!TtM|0bS2QZekW7_tKu%GcJ!4?lObt0z_$mZ4rbQ0o=^curCs3bJK6sq z9fu-aW-l#>z~ca(B;4yv;2RZ?tGYAU)^)Kz{L|4oPj zdOf_?de|#yS)p2v8-N||+XL=O*%3+y)oI(HbM)Ds?q8~HPzIP(vs*G`iddbWq}! z(2!VjP&{Z1w+%eUq^ '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..ac1b06f --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..a9dd0c9 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,5 @@ +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.5.0" +} +rootProject.name = "trees-4" + diff --git a/src/main/kotlin/xddcc/bintrees/AVLTree.kt b/src/main/kotlin/xddcc/bintrees/AVLTree.kt new file mode 100644 index 0000000..66153f3 --- /dev/null +++ b/src/main/kotlin/xddcc/bintrees/AVLTree.kt @@ -0,0 +1,4 @@ +package xddcc.bintrees + +class AVLTree { +} \ No newline at end of file diff --git a/src/main/kotlin/xddcc/bintrees/BSTree.kt b/src/main/kotlin/xddcc/bintrees/BSTree.kt new file mode 100644 index 0000000..8d744a6 --- /dev/null +++ b/src/main/kotlin/xddcc/bintrees/BSTree.kt @@ -0,0 +1,4 @@ +package xddcc.bintrees + +class BSTree { +} \ No newline at end of file diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt new file mode 100644 index 0000000..d385c04 --- /dev/null +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -0,0 +1,4 @@ +package xddcc.bintrees + +class RBTree { +} \ No newline at end of file diff --git a/src/main/kotlin/xddcc/nodes/AVLNode.kt b/src/main/kotlin/xddcc/nodes/AVLNode.kt new file mode 100644 index 0000000..9694fca --- /dev/null +++ b/src/main/kotlin/xddcc/nodes/AVLNode.kt @@ -0,0 +1,4 @@ +package xddcc.nodes + +class AVLNode { +} \ No newline at end of file diff --git a/src/main/kotlin/xddcc/nodes/BSTNode.kt b/src/main/kotlin/xddcc/nodes/BSTNode.kt new file mode 100644 index 0000000..d9f1b55 --- /dev/null +++ b/src/main/kotlin/xddcc/nodes/BSTNode.kt @@ -0,0 +1,4 @@ +package xddcc.nodes + +class BSTNode { +} \ No newline at end of file diff --git a/src/main/kotlin/xddcc/nodes/RBNode.kt b/src/main/kotlin/xddcc/nodes/RBNode.kt new file mode 100644 index 0000000..7eb8b39 --- /dev/null +++ b/src/main/kotlin/xddcc/nodes/RBNode.kt @@ -0,0 +1,4 @@ +package xddcc.nodes + +class RBNode { +} \ No newline at end of file From cf5368680325f393a467dee0bf8b703777258084 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sat, 23 Mar 2024 15:52:18 +0300 Subject: [PATCH 003/186] feat: add RBNode --- src/main/kotlin/xddcc/nodes/RBNode.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/xddcc/nodes/RBNode.kt b/src/main/kotlin/xddcc/nodes/RBNode.kt index 7eb8b39..4c0ecb0 100644 --- a/src/main/kotlin/xddcc/nodes/RBNode.kt +++ b/src/main/kotlin/xddcc/nodes/RBNode.kt @@ -1,4 +1,11 @@ package xddcc.nodes -class RBNode { +class RBNode> ( + var value: Any, + val key: K, + var right: RBNode? = null, + var left: RBNode? = null, +) { + enum class Color {RED, BLACK} + var color = Color.RED } \ No newline at end of file From 0de843e3ee341a8f988910e2fb1963c9e2945b70 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 24 Mar 2024 17:17:56 +0300 Subject: [PATCH 004/186] feat: add fun compareTo(), add generic type V for value --- src/main/kotlin/xddcc/nodes/RBNode.kt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/xddcc/nodes/RBNode.kt b/src/main/kotlin/xddcc/nodes/RBNode.kt index 4c0ecb0..ce257ba 100644 --- a/src/main/kotlin/xddcc/nodes/RBNode.kt +++ b/src/main/kotlin/xddcc/nodes/RBNode.kt @@ -1,11 +1,19 @@ package xddcc.nodes -class RBNode> ( - var value: Any, +class RBNode, V> ( + var value: V, val key: K, - var right: RBNode? = null, - var left: RBNode? = null, -) { + var right: RBNode? = null, + var left: RBNode? = null, +): Comparable> { enum class Color {RED, BLACK} var color = Color.RED + + override fun compareTo(other: RBNode): Int { + return when { + key > other.key -> 1 + key < other.key -> -1 + else -> 0 + } + } } \ No newline at end of file From 86b461dfd730ce9d4e36371503d7cff634c17c85 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 24 Mar 2024 22:43:23 +0300 Subject: [PATCH 005/186] fix!: simplified version of Node (without value) --- src/main/kotlin/xddcc/nodes/RBNode.kt | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/xddcc/nodes/RBNode.kt b/src/main/kotlin/xddcc/nodes/RBNode.kt index ce257ba..2939ad2 100644 --- a/src/main/kotlin/xddcc/nodes/RBNode.kt +++ b/src/main/kotlin/xddcc/nodes/RBNode.kt @@ -1,19 +1,14 @@ package xddcc.nodes -class RBNode, V> ( - var value: V, +class RBNode>( val key: K, - var right: RBNode? = null, - var left: RBNode? = null, -): Comparable> { + var right: RBNode? = null, + var left: RBNode? = null, +): Comparable> { enum class Color {RED, BLACK} var color = Color.RED - override fun compareTo(other: RBNode): Int { - return when { - key > other.key -> 1 - key < other.key -> -1 - else -> 0 - } + override fun compareTo(other: RBNode): Int { + return key.compareTo(other.key) } } \ No newline at end of file From 8f7bb9f60254ff1cfa04b249dda6221bc4c7c4e5 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 24 Mar 2024 22:45:47 +0300 Subject: [PATCH 006/186] feat: add simple version of fun add() --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 40 +++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index d385c04..1ffc2fc 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -1,4 +1,42 @@ package xddcc.bintrees -class RBTree { +import xddcc.nodes.RBNode + +class RBTree> { + private var root: RBNode? = null + + fun add(key: K): Boolean { + val addNode = RBNode(key) + if (root == null) { + root = addNode + return true + } + + var curNode = root + while (curNode != null) { + when { + addNode > curNode -> { + if (curNode.right == null) { + curNode.right = addNode + return true + } else { + curNode = curNode.right + } + } + addNode < curNode -> { + if (curNode.left == null) { + curNode.left = addNode + return true + } else { + curNode = curNode.left + } + } + addNode == curNode -> return false + } + } + + return false + } + + } \ No newline at end of file From fd9a2e3a807e63f085357ce5131ce1cfa08cf7d7 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 24 Mar 2024 23:32:37 +0300 Subject: [PATCH 007/186] feat: add simple version of fun max() and min() --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index 1ffc2fc..a78da70 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -38,5 +38,16 @@ class RBTree> { return false } + fun max(): K? { + var maxNode = root + while (maxNode?.right != null) maxNode = maxNode.right + return maxNode?.key + } + + fun min(): K? { + var minNode = root + while (minNode?.left != null) minNode = minNode.left + return minNode?.key + } } \ No newline at end of file From d02f04158a56640db5c91d1ba4b6e354acddfec5 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 24 Mar 2024 23:41:29 +0300 Subject: [PATCH 008/186] feat: add simple version of fun root() and clear() --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index a78da70..351373d 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -50,4 +50,8 @@ class RBTree> { return minNode?.key } + fun root(): K? = root?.key + + fun clear(): Unit { root = null } + } \ No newline at end of file From d0726f828b6f95d8eb8e1c60b2ae300fc1464b2c Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 24 Mar 2024 23:50:54 +0300 Subject: [PATCH 009/186] feat: add simple version of fun find() --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index 351373d..6b7cdd9 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -38,6 +38,18 @@ class RBTree> { return false } + fun find(key: K): Boolean { + var curNode = root + while (curNode != null) { + when (key.compareTo(curNode.key)){ + +1 -> curNode = curNode.right + +0 -> return true + -1 -> curNode = curNode.left + } + } + return false + } + fun max(): K? { var maxNode = root while (maxNode?.right != null) maxNode = maxNode.right From 3a2e5df6d3a871d3414e432c175fe8a68f13ee7a Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Mon, 25 Mar 2024 00:36:43 +0300 Subject: [PATCH 010/186] fix: add() correctly compares keys --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index 6b7cdd9..c454a86 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -14,8 +14,8 @@ class RBTree> { var curNode = root while (curNode != null) { - when { - addNode > curNode -> { + when (addNode.compareTo(curNode)) { + +1 -> { if (curNode.right == null) { curNode.right = addNode return true @@ -23,7 +23,8 @@ class RBTree> { curNode = curNode.right } } - addNode < curNode -> { + +0 -> return false + -1 -> { if (curNode.left == null) { curNode.left = addNode return true @@ -31,7 +32,6 @@ class RBTree> { curNode = curNode.left } } - addNode == curNode -> return false } } From 5c20be8d79dc29f5c46257a591f95fa6829b9578 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Mon, 25 Mar 2024 00:48:35 +0300 Subject: [PATCH 011/186] feat: add simple fun remove() (it can't remove yet) --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index c454a86..674a6ff 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -38,6 +38,33 @@ class RBTree> { return false } + fun remove(key: K): Boolean { + var prevNode: RBNode? = null + var removeNode = root + while (removeNode != null) { + when (key.compareTo(removeNode.key)){ + +1 -> { + prevNode = removeNode + removeNode = removeNode.right + } + +0 -> { + if (prevNode == null) { + root = null + } else { + TODO("correct remove") + } + return true + } + -1 -> { + prevNode = removeNode + removeNode = removeNode.left + } + } + } + + return false + } + fun find(key: K): Boolean { var curNode = root while (curNode != null) { From 1004576b347eebe3812cf399499243e7ebd233b8 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 25 Mar 2024 05:15:18 +0300 Subject: [PATCH 012/186] refactor: package name xddcc -> treeLib --- src/main/kotlin/{xddcc => treeLib}/bintrees/AVLTree.kt | 0 src/main/kotlin/{xddcc => treeLib}/bintrees/BSTree.kt | 0 src/main/kotlin/{xddcc => treeLib}/bintrees/RBTree.kt | 0 src/main/kotlin/{xddcc => treeLib}/nodes/AVLNode.kt | 0 src/main/kotlin/{xddcc => treeLib}/nodes/BSTNode.kt | 0 src/main/kotlin/{xddcc => treeLib}/nodes/RBNode.kt | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/main/kotlin/{xddcc => treeLib}/bintrees/AVLTree.kt (100%) rename src/main/kotlin/{xddcc => treeLib}/bintrees/BSTree.kt (100%) rename src/main/kotlin/{xddcc => treeLib}/bintrees/RBTree.kt (100%) rename src/main/kotlin/{xddcc => treeLib}/nodes/AVLNode.kt (100%) rename src/main/kotlin/{xddcc => treeLib}/nodes/BSTNode.kt (100%) rename src/main/kotlin/{xddcc => treeLib}/nodes/RBNode.kt (100%) diff --git a/src/main/kotlin/xddcc/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt similarity index 100% rename from src/main/kotlin/xddcc/bintrees/AVLTree.kt rename to src/main/kotlin/treeLib/bintrees/AVLTree.kt diff --git a/src/main/kotlin/xddcc/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt similarity index 100% rename from src/main/kotlin/xddcc/bintrees/BSTree.kt rename to src/main/kotlin/treeLib/bintrees/BSTree.kt diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt similarity index 100% rename from src/main/kotlin/xddcc/bintrees/RBTree.kt rename to src/main/kotlin/treeLib/bintrees/RBTree.kt diff --git a/src/main/kotlin/xddcc/nodes/AVLNode.kt b/src/main/kotlin/treeLib/nodes/AVLNode.kt similarity index 100% rename from src/main/kotlin/xddcc/nodes/AVLNode.kt rename to src/main/kotlin/treeLib/nodes/AVLNode.kt diff --git a/src/main/kotlin/xddcc/nodes/BSTNode.kt b/src/main/kotlin/treeLib/nodes/BSTNode.kt similarity index 100% rename from src/main/kotlin/xddcc/nodes/BSTNode.kt rename to src/main/kotlin/treeLib/nodes/BSTNode.kt diff --git a/src/main/kotlin/xddcc/nodes/RBNode.kt b/src/main/kotlin/treeLib/nodes/RBNode.kt similarity index 100% rename from src/main/kotlin/xddcc/nodes/RBNode.kt rename to src/main/kotlin/treeLib/nodes/RBNode.kt From 2d395c82dbcb93abee3c599a113415455a38e2cf Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 25 Mar 2024 05:18:23 +0300 Subject: [PATCH 013/186] refactor: interface Tree created --- src/main/kotlin/treeLib/bintrees/Tree.kt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/main/kotlin/treeLib/bintrees/Tree.kt diff --git a/src/main/kotlin/treeLib/bintrees/Tree.kt b/src/main/kotlin/treeLib/bintrees/Tree.kt new file mode 100644 index 0000000..e2a12f6 --- /dev/null +++ b/src/main/kotlin/treeLib/bintrees/Tree.kt @@ -0,0 +1,4 @@ +package treeLib.bintrees + +interface Tree { +} \ No newline at end of file From 34d0e5b97690527b7a98918ed971840d6f931ff7 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 25 Mar 2024 05:24:44 +0300 Subject: [PATCH 014/186] refactor!: setting up hierarchy --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 4 ++-- src/main/kotlin/treeLib/bintrees/BSTree.kt | 4 ++-- src/main/kotlin/treeLib/bintrees/RBTree.kt | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 66153f3..bd20c0a 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -1,4 +1,4 @@ -package xddcc.bintrees +package treeLib.bintrees -class AVLTree { +class AVLTree : BSTree() { } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 8d744a6..2e6bd06 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -1,4 +1,4 @@ -package xddcc.bintrees +package treeLib.bintrees -class BSTree { +open class BSTree : Tree { } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index d385c04..b0379ac 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -1,4 +1,4 @@ -package xddcc.bintrees +package treeLib.bintrees -class RBTree { +class RBTree : BSTree() { } \ No newline at end of file From f5cb76c085f34b7ae99994f99fd7240cf4ec3308 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Mon, 25 Mar 2024 13:34:07 +0300 Subject: [PATCH 015/186] feat: add simple TreeIterator class TreeIterator implements hasNext(), next() and treeToStack() funs --- .../kotlin/xddcc/bintrees/TreeIterator.kt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/kotlin/xddcc/bintrees/TreeIterator.kt diff --git a/src/main/kotlin/xddcc/bintrees/TreeIterator.kt b/src/main/kotlin/xddcc/bintrees/TreeIterator.kt new file mode 100644 index 0000000..2db1ab5 --- /dev/null +++ b/src/main/kotlin/xddcc/bintrees/TreeIterator.kt @@ -0,0 +1,23 @@ +package xddcc.bintrees + +import xddcc.nodes.RBNode +import kotlin.collections.ArrayDeque + +class TreeIterator>(val root: RBNode?): Iterator{ + val stack: ArrayDeque> = ArrayDeque() + init { + root?.let { treeToStack(root) } + } + + private fun treeToStack(curNode: RBNode) { + val leftNode = curNode.left + val rightNode = curNode.right + leftNode?.let { treeToStack(leftNode) } + stack.add(curNode) + rightNode?.let { treeToStack(rightNode) } + } + + override fun hasNext() = stack.isNotEmpty() + + override fun next() = stack.removeFirst().key +} \ No newline at end of file From 0c067eb4593f9cd83d15685dcc1f92b386d6b5d1 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Mon, 25 Mar 2024 13:35:31 +0300 Subject: [PATCH 016/186] feat: add simple version of fun iterator() --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index 674a6ff..daf479d 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -2,7 +2,7 @@ package xddcc.bintrees import xddcc.nodes.RBNode -class RBTree> { +class RBTree>: Iterable { private var root: RBNode? = null fun add(key: K): Boolean { @@ -93,4 +93,6 @@ class RBTree> { fun clear(): Unit { root = null } + override fun iterator(): Iterator = TreeIterator(root) + } \ No newline at end of file From 78eabed5d2b7533b943cbcf171541236759b33c2 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Mon, 25 Mar 2024 15:06:22 +0300 Subject: [PATCH 017/186] feat: add fun addHelper() for fun add() :) --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 49 ++++++++++++------------ 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index daf479d..f352461 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -5,37 +5,36 @@ import xddcc.nodes.RBNode class RBTree>: Iterable { private var root: RBNode? = null - fun add(key: K): Boolean { - val addNode = RBNode(key) - if (root == null) { - root = addNode - return true + fun add(key: K) { + val (uncle, dad, son) = addHelper(key) + + when { + dad == null -> root = RBNode(key) + son != null -> return //Node already exist + son == null -> if (dad.right == null) dad.right = RBNode(key) else dad.left = RBNode(key) } + } - var curNode = root - while (curNode != null) { - when (addNode.compareTo(curNode)) { - +1 -> { - if (curNode.right == null) { - curNode.right = addNode - return true - } else { - curNode = curNode.right - } + private fun addHelper(key: K): Triple?, RBNode?, RBNode?> { + var (uncle, dad, son) = + Triple?, RBNode?, RBNode?>(null, null, root) + while (son != null) { + val keyCompare = key.compareTo(son.key) + when { + keyCompare > 0 -> { + uncle = dad + dad = son + son = son.left } - +0 -> return false - -1 -> { - if (curNode.left == null) { - curNode.left = addNode - return true - } else { - curNode = curNode.left - } + keyCompare < 0 -> { + uncle = dad + dad = son + son = son.right } + else -> return Triple(uncle, dad, son) } } - - return false + return Triple(uncle, dad, son) } fun remove(key: K): Boolean { From 847533457bc731292e151ac88ca83cf9a8e5f208 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Mon, 25 Mar 2024 15:35:47 +0300 Subject: [PATCH 018/186] fix: change field color: Color to red: Boolean --- src/main/kotlin/xddcc/nodes/RBNode.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/xddcc/nodes/RBNode.kt b/src/main/kotlin/xddcc/nodes/RBNode.kt index 2939ad2..7061fae 100644 --- a/src/main/kotlin/xddcc/nodes/RBNode.kt +++ b/src/main/kotlin/xddcc/nodes/RBNode.kt @@ -2,13 +2,9 @@ package xddcc.nodes class RBNode>( val key: K, + var red: Boolean = true, var right: RBNode? = null, var left: RBNode? = null, ): Comparable> { - enum class Color {RED, BLACK} - var color = Color.RED - - override fun compareTo(other: RBNode): Int { - return key.compareTo(other.key) - } + override fun compareTo(other: RBNode) = this.key.compareTo(other.key) } \ No newline at end of file From 5b6f4441046a94f66ea44c05aa39941bfd060c24 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Mon, 25 Mar 2024 16:46:27 +0300 Subject: [PATCH 019/186] fix: change fun addHelper() to balanceAdd() --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 91 ++++++++++++++++++------ 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index f352461..39298ff 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -6,35 +6,82 @@ class RBTree>: Iterable { private var root: RBNode? = null fun add(key: K) { - val (uncle, dad, son) = addHelper(key) - - when { - dad == null -> root = RBNode(key) - son != null -> return //Node already exist - son == null -> if (dad.right == null) dad.right = RBNode(key) else dad.left = RBNode(key) + val treeBranch = ArrayDeque>() + val newNode = RBNode(key) + if (root == null) { + root = newNode + } else { + var curNode = root + while (curNode != null) { + treeBranch.addFirst(curNode) + when { + newNode > curNode -> curNode = curNode.right + newNode < curNode -> curNode = curNode.left + else -> TODO("private fun replace(father, new)") + } + } + val father = treeBranch.first() + if (newNode > father) { + father.right = newNode + } else { + father.left = newNode + } } + + balanceAdd(treeBranch) } - private fun addHelper(key: K): Triple?, RBNode?, RBNode?> { - var (uncle, dad, son) = - Triple?, RBNode?, RBNode?>(null, null, root) - while (son != null) { - val keyCompare = key.compareTo(son.key) - when { - keyCompare > 0 -> { - uncle = dad - dad = son - son = son.left + private fun balanceAdd(treeBranch: ArrayDeque>) { + var (son, parent, grandparent) = + Triple(treeBranch.removeFirst(), treeBranch.removeFirst(), treeBranch.removeFirst()) + + while (parent.red) { + if (parent === grandparent.left) { + val uncle = grandparent.right + if (uncle?.red == true) { + parent.red = false + uncle.red = false + grandparent.red = true + + son = grandparent + parent = treeBranch.removeFirst() + grandparent = treeBranch.removeFirst() + } else { + if (son === parent.right) { + son = parent + parent = grandparent + grandparent = treeBranch.removeFirst() + TODO("leftRotate(son)") + } + parent.red = false + grandparent.red = true + TODO("rightRotate(grandfather)") } - keyCompare < 0 -> { - uncle = dad - dad = son - son = son.right + } else if (parent == grandparent.right){ + val uncle = grandparent.left + if (uncle?.red == true) { + parent.red = false + uncle.red = false + grandparent.red = true + + son = grandparent + parent = treeBranch.removeFirst() + grandparent = treeBranch.removeFirst() + } else { + if (son === parent.left) { + son = parent + parent = grandparent + grandparent = treeBranch.removeFirst() + TODO("rightRotate(son)") + } + parent.red = false + grandparent.red = true + TODO("leftRotate(grandfather)") } - else -> return Triple(uncle, dad, son) } } - return Triple(uncle, dad, son) + + root?.red = false } fun remove(key: K): Boolean { From adf8de2b1f0559f9f89acce7cc3d5eb9c8ccb034 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Mon, 25 Mar 2024 17:21:07 +0300 Subject: [PATCH 020/186] fix: remove replaced with removeOrNull in balanceAdd --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index 39298ff..2aa99be 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -33,10 +33,10 @@ class RBTree>: Iterable { private fun balanceAdd(treeBranch: ArrayDeque>) { var (son, parent, grandparent) = - Triple(treeBranch.removeFirst(), treeBranch.removeFirst(), treeBranch.removeFirst()) + Triple(treeBranch.removeFirstOrNull(), treeBranch.removeFirstOrNull(), treeBranch.removeFirstOrNull()) - while (parent.red) { - if (parent === grandparent.left) { + while (parent?.red == true) { + if (parent === grandparent?.left) { val uncle = grandparent.right if (uncle?.red == true) { parent.red = false @@ -44,9 +44,9 @@ class RBTree>: Iterable { grandparent.red = true son = grandparent - parent = treeBranch.removeFirst() - grandparent = treeBranch.removeFirst() - } else { + parent = treeBranch.removeFirstOrNull() + grandparent = treeBranch.removeFirstOrNull() + } else /*uncle == null*/ { if (son === parent.right) { son = parent parent = grandparent @@ -57,7 +57,7 @@ class RBTree>: Iterable { grandparent.red = true TODO("rightRotate(grandfather)") } - } else if (parent == grandparent.right){ + } else if (parent === grandparent?.right){ val uncle = grandparent.left if (uncle?.red == true) { parent.red = false @@ -65,19 +65,21 @@ class RBTree>: Iterable { grandparent.red = true son = grandparent - parent = treeBranch.removeFirst() - grandparent = treeBranch.removeFirst() + parent = treeBranch.removeFirstOrNull() + grandparent = treeBranch.removeFirstOrNull() } else { if (son === parent.left) { son = parent parent = grandparent - grandparent = treeBranch.removeFirst() + grandparent = treeBranch.removeFirstOrNull() TODO("rightRotate(son)") } parent.red = false grandparent.red = true TODO("leftRotate(grandfather)") } + } else /*grandparent == null*/{ + parent.red = false } } From c5ad5a9c5fcb8e9d3080fcf1a2b0cedb23cf3d8c Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Mon, 25 Mar 2024 19:03:52 +0300 Subject: [PATCH 021/186] feat: add fun rotateRight() and rotateLeft() implement rotates to fun balanceAdd() --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 42 +++++++++++++++++++----- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index 2aa99be..40195f7 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -35,7 +35,7 @@ class RBTree>: Iterable { var (son, parent, grandparent) = Triple(treeBranch.removeFirstOrNull(), treeBranch.removeFirstOrNull(), treeBranch.removeFirstOrNull()) - while (parent?.red == true) { + while (parent != null && parent.red) { if (parent === grandparent?.left) { val uncle = grandparent.right if (uncle?.red == true) { @@ -46,16 +46,16 @@ class RBTree>: Iterable { son = grandparent parent = treeBranch.removeFirstOrNull() grandparent = treeBranch.removeFirstOrNull() - } else /*uncle == null*/ { + } else /*uncle == black or null*/ { if (son === parent.right) { son = parent parent = grandparent grandparent = treeBranch.removeFirst() - TODO("leftRotate(son)") + rotateLeft(son, parent) } parent.red = false grandparent.red = true - TODO("rightRotate(grandfather)") + rotateRight(grandparent, treeBranch.firstOrNull()) } } else if (parent === grandparent?.right){ val uncle = grandparent.left @@ -67,16 +67,18 @@ class RBTree>: Iterable { son = grandparent parent = treeBranch.removeFirstOrNull() grandparent = treeBranch.removeFirstOrNull() - } else { + } else /*uncle == black or null*/ { if (son === parent.left) { son = parent parent = grandparent grandparent = treeBranch.removeFirstOrNull() - TODO("rightRotate(son)") + rotateRight(son, parent) } parent.red = false - grandparent.red = true - TODO("leftRotate(grandfather)") + if (grandparent != null) {//why safe call + grandparent.red = true + rotateLeft(grandparent, treeBranch.firstOrNull()) + } } } else /*grandparent == null*/{ parent.red = false @@ -86,6 +88,30 @@ class RBTree>: Iterable { root?.red = false } + private fun rotateRight(node: RBNode, parent: RBNode?) { + val nodeLeft = node.left + node.left = nodeLeft?.right + nodeLeft?.right = node + + if (parent != null) + if (node > parent) + parent.right = nodeLeft + else + parent.left = nodeLeft + } + + private fun rotateLeft(node: RBNode, parent: RBNode?) { + val nodeRight = node.right + node.right = nodeRight?.left + nodeRight?.left = node + + if (parent != null) + if (node > parent) + parent.right = nodeRight + else + parent.left = nodeRight + } + fun remove(key: K): Boolean { var prevNode: RBNode? = null var removeNode = root From a1eef016fb1f19b65fca859ee77d56371d14526e Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Mon, 25 Mar 2024 20:13:25 +0300 Subject: [PATCH 022/186] fix: rotation works properly if node is root --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 28 ++++++++++++++---------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index 40195f7..d0545e5 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -14,20 +14,20 @@ class RBTree>: Iterable { var curNode = root while (curNode != null) { treeBranch.addFirst(curNode) - when { - newNode > curNode -> curNode = curNode.right - newNode < curNode -> curNode = curNode.left - else -> TODO("private fun replace(father, new)") + curNode = when { + newNode > curNode -> curNode.right + newNode < curNode -> curNode.left + else -> curNode //endless loop for equal keys } } - val father = treeBranch.first() - if (newNode > father) { - father.right = newNode + val parent = treeBranch.first() + if (newNode > parent) { + parent.right = newNode } else { - father.left = newNode + parent.left = newNode } + treeBranch.addFirst(newNode) } - balanceAdd(treeBranch) } @@ -93,11 +93,14 @@ class RBTree>: Iterable { node.left = nodeLeft?.right nodeLeft?.right = node - if (parent != null) + if (parent != null) { if (node > parent) parent.right = nodeLeft else parent.left = nodeLeft + } else /* node == root */ { + root = nodeLeft + } } private fun rotateLeft(node: RBNode, parent: RBNode?) { @@ -105,11 +108,14 @@ class RBTree>: Iterable { node.right = nodeRight?.left nodeRight?.left = node - if (parent != null) + if (parent != null) { if (node > parent) parent.right = nodeRight else parent.left = nodeRight + } else /* node == root */ { + root = nodeRight + } } fun remove(key: K): Boolean { From cf9db46f795911491678095b8f54feea1f8889f4 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 10:42:27 +0300 Subject: [PATCH 023/186] feat: inorder traverse (avl) --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 14 +++++++++++++- src/main/kotlin/treeLib/bintrees/BSTree.kt | 5 ++++- src/main/kotlin/treeLib/bintrees/RBTree.kt | 3 ++- src/main/kotlin/treeLib/bintrees/Tree.kt | 3 ++- src/main/kotlin/treeLib/nodes/AVLNode.kt | 7 +++++-- src/main/kotlin/treeLib/nodes/BSTNode.kt | 2 +- src/main/kotlin/treeLib/nodes/RBNode.kt | 2 +- 7 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index bd20c0a..b55a771 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -1,4 +1,16 @@ package treeLib.bintrees -class AVLTree : BSTree() { +import treeLib.nodes.AVLNode + +class AVLTree, V> : BSTree() { + private val root : AVLNode? = null + + ///пока больше для отладки + fun inorder(root: AVLNode?) { + if (root != null) { + inorder(root.left) + println(root.key) + inorder(root.right) + } + } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 2e6bd06..2c9f1f1 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -1,4 +1,7 @@ package treeLib.bintrees -open class BSTree : Tree { +open class BSTree, V> : Tree { + override fun add(key: K, value: V) { + + } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index b0379ac..d8ee5b1 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -1,4 +1,5 @@ package treeLib.bintrees -class RBTree : BSTree() { +class RBTree, V> : BSTree(){ + } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/Tree.kt b/src/main/kotlin/treeLib/bintrees/Tree.kt index e2a12f6..a181d4a 100644 --- a/src/main/kotlin/treeLib/bintrees/Tree.kt +++ b/src/main/kotlin/treeLib/bintrees/Tree.kt @@ -1,4 +1,5 @@ package treeLib.bintrees -interface Tree { +interface Tree, V> { + fun add(key: K, value: V) } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/nodes/AVLNode.kt b/src/main/kotlin/treeLib/nodes/AVLNode.kt index 9694fca..db46d50 100644 --- a/src/main/kotlin/treeLib/nodes/AVLNode.kt +++ b/src/main/kotlin/treeLib/nodes/AVLNode.kt @@ -1,4 +1,7 @@ -package xddcc.nodes +package treeLib.nodes -class AVLNode { +class AVLNode , V> (internal val key: K, internal var value: V){ + internal var right: AVLNode? = null + internal var left: AVLNode? = null + internal var height: Int = 1 } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/nodes/BSTNode.kt b/src/main/kotlin/treeLib/nodes/BSTNode.kt index d9f1b55..c9f597f 100644 --- a/src/main/kotlin/treeLib/nodes/BSTNode.kt +++ b/src/main/kotlin/treeLib/nodes/BSTNode.kt @@ -1,4 +1,4 @@ -package xddcc.nodes +package treeLib.nodes class BSTNode { } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/nodes/RBNode.kt b/src/main/kotlin/treeLib/nodes/RBNode.kt index 7eb8b39..ef84aa3 100644 --- a/src/main/kotlin/treeLib/nodes/RBNode.kt +++ b/src/main/kotlin/treeLib/nodes/RBNode.kt @@ -1,4 +1,4 @@ -package xddcc.nodes +package treeLib.nodes class RBNode { } \ No newline at end of file From 7293b3da6c2c68496802a6763df72f26af91fe6c Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 13:08:34 +0300 Subject: [PATCH 024/186] feat: insert node (avl) --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 23 +++++++++++++++++++-- src/main/kotlin/treeLib/bintrees/BSTree.kt | 1 - 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index b55a771..9077698 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -2,8 +2,27 @@ package treeLib.bintrees import treeLib.nodes.AVLNode -class AVLTree, V> : BSTree() { - private val root : AVLNode? = null +class AVLTree, V> : BSTree() { + private var root: AVLNode? = null + + override fun add(key: K, value: V) { + var node: AVLNode? = null + var curr = root + while (curr != null) { + node = curr + if (key < curr.key) { curr = curr.left } + else { curr = curr.right } + } + if (node == null) { + root = AVLNode(key, value) + } else { + if (key < node.key) { + node.left = AVLNode(key, value) + } else { + node.right = AVLNode(key, value) + } + } + } ///пока больше для отладки fun inorder(root: AVLNode?) { diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 2c9f1f1..0b2a8ac 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -2,6 +2,5 @@ package treeLib.bintrees open class BSTree, V> : Tree { override fun add(key: K, value: V) { - } } \ No newline at end of file From 605014a5d104af23f7ef4a3c3c33a8831e6e61aa Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 15:06:20 +0300 Subject: [PATCH 025/186] fix: add() can replace equal keys --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index d0545e5..4aaf77f 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -14,10 +14,23 @@ class RBTree>: Iterable { var curNode = root while (curNode != null) { treeBranch.addFirst(curNode) - curNode = when { + val nextNode = when { newNode > curNode -> curNode.right newNode < curNode -> curNode.left - else -> curNode //endless loop for equal keys + else -> curNode + } + if (nextNode === curNode) { //replace + val parent = treeBranch.first() + newNode.left = curNode.left + newNode.right = curNode.right + newNode.red = curNode.red + if (newNode > parent) { + parent.right = newNode + } else { + parent.left = newNode + } + } else { + curNode = nextNode } } val parent = treeBranch.first() From 1f7bd207c0ec4e84ad298750614bda16044ca86f Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 16:11:54 +0300 Subject: [PATCH 026/186] feat: init tree (avl) --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 29 ++++++++++++++++----- src/main/kotlin/treeLib/bintrees/BSTree.kt | 7 ++++- src/main/kotlin/treeLib/bintrees/Tree.kt | 3 ++- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 9077698..fa77011 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -24,12 +24,29 @@ class AVLTree, V> : BSTree() { } } - ///пока больше для отладки - fun inorder(root: AVLNode?) { - if (root != null) { - inorder(root.left) - println(root.key) - inorder(root.right) + // add для коллекций? + + override fun initTree(data: List>): AVLTree { + val tree = AVLTree() + for (element in data) { + if (tree.root == null) { + tree.root = AVLNode(element.first, element.second) + } else { + tree.add(element.first, element.second) + } + } + return tree + } + + // пока больше для отладки -> замена на iterable + fun inorder() { + fun inorderRec(root: AVLNode?) { + if (root != null) { + inorderRec(root.left) + println(root.key) + inorderRec(root.right) + } } + inorderRec(root) } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 0b2a8ac..ad72fef 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -1,6 +1,11 @@ package treeLib.bintrees -open class BSTree, V> : Tree { +open class BSTree, V> : Tree> { override fun add(key: K, value: V) { + TODO("not implemented") + } + + override fun initTree(data: List>): BSTree { + TODO("Not yet implemented") } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/Tree.kt b/src/main/kotlin/treeLib/bintrees/Tree.kt index a181d4a..39f388e 100644 --- a/src/main/kotlin/treeLib/bintrees/Tree.kt +++ b/src/main/kotlin/treeLib/bintrees/Tree.kt @@ -1,5 +1,6 @@ package treeLib.bintrees -interface Tree, V> { +interface Tree, V, TREE_TYPE> { fun add(key: K, value: V) + fun initTree(data: List>): TREE_TYPE } \ No newline at end of file From 12b31fb3f287b6dc895a687ce2323e185a174e07 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 16:17:13 +0300 Subject: [PATCH 027/186] refactor: cleanup --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 23 ++++++--------------- src/main/kotlin/treeLib/bintrees/BSTree.kt | 6 +++--- src/main/kotlin/treeLib/bintrees/RBTree.kt | 4 +--- src/main/kotlin/treeLib/bintrees/Tree.kt | 2 +- 4 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index fa77011..89af095 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -10,8 +10,11 @@ class AVLTree, V> : BSTree() { var curr = root while (curr != null) { node = curr - if (key < curr.key) { curr = curr.left } - else { curr = curr.right } + if (key < curr.key) { + curr = curr.left + } else { + curr = curr.right + } } if (node == null) { root = AVLNode(key, value) @@ -24,9 +27,7 @@ class AVLTree, V> : BSTree() { } } - // add для коллекций? - - override fun initTree(data: List>): AVLTree { + override fun initTree(data: List>): AVLTree { val tree = AVLTree() for (element in data) { if (tree.root == null) { @@ -37,16 +38,4 @@ class AVLTree, V> : BSTree() { } return tree } - - // пока больше для отладки -> замена на iterable - fun inorder() { - fun inorderRec(root: AVLNode?) { - if (root != null) { - inorderRec(root.left) - println(root.key) - inorderRec(root.right) - } - } - inorderRec(root) - } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index ad72fef..573e6eb 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -1,11 +1,11 @@ package treeLib.bintrees -open class BSTree, V> : Tree> { +open class BSTree, V> : Tree> { override fun add(key: K, value: V) { - TODO("not implemented") + TODO("Not yet implemented") } - override fun initTree(data: List>): BSTree { + override fun initTree(data: List>): BSTree { TODO("Not yet implemented") } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index d8ee5b1..2904160 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -1,5 +1,3 @@ package treeLib.bintrees -class RBTree, V> : BSTree(){ - -} \ No newline at end of file +class RBTree, V> : BSTree() \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/Tree.kt b/src/main/kotlin/treeLib/bintrees/Tree.kt index 39f388e..83934f6 100644 --- a/src/main/kotlin/treeLib/bintrees/Tree.kt +++ b/src/main/kotlin/treeLib/bintrees/Tree.kt @@ -2,5 +2,5 @@ package treeLib.bintrees interface Tree, V, TREE_TYPE> { fun add(key: K, value: V) - fun initTree(data: List>): TREE_TYPE + fun initTree(data: List>): TREE_TYPE } \ No newline at end of file From 6dbec76d08cfbfd22225b4e40cdd08a168e9476e Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 16:35:47 +0300 Subject: [PATCH 028/186] feat: implement value in RBTree --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index 4aaf77f..b5afe46 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -2,12 +2,12 @@ package xddcc.bintrees import xddcc.nodes.RBNode -class RBTree>: Iterable { - private var root: RBNode? = null +class RBTree, V>: Iterable { + private var root: RBNode? = null - fun add(key: K) { - val treeBranch = ArrayDeque>() - val newNode = RBNode(key) + fun add(key: K, value: V) { + val treeBranch = ArrayDeque>() + val newNode = RBNode(key, value) if (root == null) { root = newNode } else { @@ -44,7 +44,7 @@ class RBTree>: Iterable { balanceAdd(treeBranch) } - private fun balanceAdd(treeBranch: ArrayDeque>) { + private fun balanceAdd(treeBranch: ArrayDeque>) { var (son, parent, grandparent) = Triple(treeBranch.removeFirstOrNull(), treeBranch.removeFirstOrNull(), treeBranch.removeFirstOrNull()) @@ -101,7 +101,7 @@ class RBTree>: Iterable { root?.red = false } - private fun rotateRight(node: RBNode, parent: RBNode?) { + private fun rotateRight(node: RBNode, parent: RBNode?) { val nodeLeft = node.left node.left = nodeLeft?.right nodeLeft?.right = node @@ -116,7 +116,7 @@ class RBTree>: Iterable { } } - private fun rotateLeft(node: RBNode, parent: RBNode?) { + private fun rotateLeft(node: RBNode, parent: RBNode?) { val nodeRight = node.right node.right = nodeRight?.left nodeRight?.left = node @@ -132,7 +132,7 @@ class RBTree>: Iterable { } fun remove(key: K): Boolean { - var prevNode: RBNode? = null + var prevNode: RBNode? = null var removeNode = root while (removeNode != null) { when (key.compareTo(removeNode.key)){ From bbb37ecc8036496e0071ab9eb1372bb19fd91f0a Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 16:36:03 +0300 Subject: [PATCH 029/186] feat: implement value field in RBNode --- src/main/kotlin/xddcc/nodes/RBNode.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/xddcc/nodes/RBNode.kt b/src/main/kotlin/xddcc/nodes/RBNode.kt index 7061fae..ed72510 100644 --- a/src/main/kotlin/xddcc/nodes/RBNode.kt +++ b/src/main/kotlin/xddcc/nodes/RBNode.kt @@ -1,10 +1,11 @@ package xddcc.nodes -class RBNode>( +class RBNode, V>( val key: K, + val value: V, var red: Boolean = true, - var right: RBNode? = null, - var left: RBNode? = null, -): Comparable> { - override fun compareTo(other: RBNode) = this.key.compareTo(other.key) + var right: RBNode? = null, + var left: RBNode? = null, +): Comparable> { + override fun compareTo(other: RBNode) = this.key.compareTo(other.key) } \ No newline at end of file From b36fee4650043ac50e3d004bbdc85d5d5d04313e Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 16:37:05 +0300 Subject: [PATCH 030/186] feat: implement value --- src/main/kotlin/xddcc/bintrees/TreeIterator.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/TreeIterator.kt b/src/main/kotlin/xddcc/bintrees/TreeIterator.kt index 2db1ab5..0ae9ccf 100644 --- a/src/main/kotlin/xddcc/bintrees/TreeIterator.kt +++ b/src/main/kotlin/xddcc/bintrees/TreeIterator.kt @@ -3,13 +3,13 @@ package xddcc.bintrees import xddcc.nodes.RBNode import kotlin.collections.ArrayDeque -class TreeIterator>(val root: RBNode?): Iterator{ - val stack: ArrayDeque> = ArrayDeque() +class TreeIterator, V>(private val root: RBNode?): Iterator{ + private val stack: ArrayDeque> = ArrayDeque() init { root?.let { treeToStack(root) } } - private fun treeToStack(curNode: RBNode) { + private fun treeToStack(curNode: RBNode) { val leftNode = curNode.left val rightNode = curNode.right leftNode?.let { treeToStack(leftNode) } From 19a5bd73944b9ee942ce7e18f4943c012b74f585 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 16:58:46 +0300 Subject: [PATCH 031/186] refactor: change name from red to isRed in RBNode --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 32 ++++++++++++------------ src/main/kotlin/xddcc/nodes/RBNode.kt | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index b5afe46..a7c4b37 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -23,7 +23,7 @@ class RBTree, V>: Iterable { val parent = treeBranch.first() newNode.left = curNode.left newNode.right = curNode.right - newNode.red = curNode.red + newNode.isRed = curNode.isRed if (newNode > parent) { parent.right = newNode } else { @@ -48,13 +48,13 @@ class RBTree, V>: Iterable { var (son, parent, grandparent) = Triple(treeBranch.removeFirstOrNull(), treeBranch.removeFirstOrNull(), treeBranch.removeFirstOrNull()) - while (parent != null && parent.red) { + while (parent != null && parent.isRed) { if (parent === grandparent?.left) { val uncle = grandparent.right - if (uncle?.red == true) { - parent.red = false - uncle.red = false - grandparent.red = true + if (uncle?.isRed == true) { + parent.isRed = false + uncle.isRed = false + grandparent.isRed = true son = grandparent parent = treeBranch.removeFirstOrNull() @@ -66,16 +66,16 @@ class RBTree, V>: Iterable { grandparent = treeBranch.removeFirst() rotateLeft(son, parent) } - parent.red = false - grandparent.red = true + parent.isRed = false + grandparent.isRed = true rotateRight(grandparent, treeBranch.firstOrNull()) } } else if (parent === grandparent?.right){ val uncle = grandparent.left - if (uncle?.red == true) { - parent.red = false - uncle.red = false - grandparent.red = true + if (uncle?.isRed == true) { + parent.isRed = false + uncle.isRed = false + grandparent.isRed = true son = grandparent parent = treeBranch.removeFirstOrNull() @@ -87,18 +87,18 @@ class RBTree, V>: Iterable { grandparent = treeBranch.removeFirstOrNull() rotateRight(son, parent) } - parent.red = false + parent.isRed = false if (grandparent != null) {//why safe call - grandparent.red = true + grandparent.isRed = true rotateLeft(grandparent, treeBranch.firstOrNull()) } } } else /*grandparent == null*/{ - parent.red = false + parent.isRed = false } } - root?.red = false + root?.isRed = false } private fun rotateRight(node: RBNode, parent: RBNode?) { diff --git a/src/main/kotlin/xddcc/nodes/RBNode.kt b/src/main/kotlin/xddcc/nodes/RBNode.kt index ed72510..2256688 100644 --- a/src/main/kotlin/xddcc/nodes/RBNode.kt +++ b/src/main/kotlin/xddcc/nodes/RBNode.kt @@ -3,7 +3,7 @@ package xddcc.nodes class RBNode, V>( val key: K, val value: V, - var red: Boolean = true, + var isRed: Boolean = true, var right: RBNode? = null, var left: RBNode? = null, ): Comparable> { From 5c8a0f47eb08ff192c4a60b3e97963ed8c2c2952 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 17:19:08 +0300 Subject: [PATCH 032/186] feat: add fun attach() --- src/main/kotlin/xddcc/nodes/RBNode.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/kotlin/xddcc/nodes/RBNode.kt b/src/main/kotlin/xddcc/nodes/RBNode.kt index 2256688..a9cc2b7 100644 --- a/src/main/kotlin/xddcc/nodes/RBNode.kt +++ b/src/main/kotlin/xddcc/nodes/RBNode.kt @@ -8,4 +8,13 @@ class RBNode, V>( var left: RBNode? = null, ): Comparable> { override fun compareTo(other: RBNode) = this.key.compareTo(other.key) + + fun attach(node: RBNode): Boolean { + when { + this > node -> this.left = node + this < node -> this.right = node + else -> return false + } + return true + } } \ No newline at end of file From fc6fb2831d0f6b614eda1fd8a9a1f209252e579c Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 17:35:24 +0300 Subject: [PATCH 033/186] fix!: initTree fun (avl) now is unable to accept random things as an argument --- src/main/kotlin/treeLib/bintrees/BSTree.kt | 4 ++-- src/main/kotlin/treeLib/bintrees/Tree.kt | 3 +-- src/main/kotlin/treeLib/nodes/AVLNode.kt | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 573e6eb..81d073c 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -1,11 +1,11 @@ package treeLib.bintrees -open class BSTree, V> : Tree> { +open class BSTree, V> : Tree { override fun add(key: K, value: V) { TODO("Not yet implemented") } - override fun initTree(data: List>): BSTree { + open fun initTree(data: List>): BSTree { TODO("Not yet implemented") } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/Tree.kt b/src/main/kotlin/treeLib/bintrees/Tree.kt index 83934f6..a181d4a 100644 --- a/src/main/kotlin/treeLib/bintrees/Tree.kt +++ b/src/main/kotlin/treeLib/bintrees/Tree.kt @@ -1,6 +1,5 @@ package treeLib.bintrees -interface Tree, V, TREE_TYPE> { +interface Tree, V> { fun add(key: K, value: V) - fun initTree(data: List>): TREE_TYPE } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/nodes/AVLNode.kt b/src/main/kotlin/treeLib/nodes/AVLNode.kt index db46d50..92ed991 100644 --- a/src/main/kotlin/treeLib/nodes/AVLNode.kt +++ b/src/main/kotlin/treeLib/nodes/AVLNode.kt @@ -1,6 +1,6 @@ package treeLib.nodes -class AVLNode , V> (internal val key: K, internal var value: V){ +class AVLNode , V> (internal val key: K, internal var value: V) { internal var right: AVLNode? = null internal var left: AVLNode? = null internal var height: Int = 1 From ae998a60c9bacd139cbbd92f891550c87c9ae327 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 18:35:15 +0300 Subject: [PATCH 034/186] feat: TreeIterator is compatible with binary trees Now TreeIterator take also generic type V, Node_T and returns Iterator> --- src/main/kotlin/xddcc/bintrees/TreeIterator.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/TreeIterator.kt b/src/main/kotlin/xddcc/bintrees/TreeIterator.kt index 0ae9ccf..d1a429a 100644 --- a/src/main/kotlin/xddcc/bintrees/TreeIterator.kt +++ b/src/main/kotlin/xddcc/bintrees/TreeIterator.kt @@ -1,15 +1,15 @@ package xddcc.bintrees -import xddcc.nodes.RBNode +import xddcc.nodes.TreeNode import kotlin.collections.ArrayDeque -class TreeIterator, V>(private val root: RBNode?): Iterator{ - private val stack: ArrayDeque> = ArrayDeque() +class TreeIterator, V, Node_T: TreeNode>(private val root: Node_T?): Iterator>{ + private val stack: ArrayDeque = ArrayDeque() init { root?.let { treeToStack(root) } } - private fun treeToStack(curNode: RBNode) { + private fun treeToStack(curNode: Node_T) { val leftNode = curNode.left val rightNode = curNode.right leftNode?.let { treeToStack(leftNode) } @@ -19,5 +19,8 @@ class TreeIterator, V>(private val root: RBNode?): Iterat override fun hasNext() = stack.isNotEmpty() - override fun next() = stack.removeFirst().key + override fun next(): Pair { + val node = stack.removeFirst() + return Pair(node.key, node.value) + } } \ No newline at end of file From d6cdc12320b14a3aad147a16563b2266626b0c24 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 18:36:15 +0300 Subject: [PATCH 035/186] feat: now avl node can store parent --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 6 +++++- src/main/kotlin/treeLib/nodes/AVLNode.kt | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 89af095..5a7dc36 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -21,8 +21,12 @@ class AVLTree, V> : BSTree() { } else { if (key < node.key) { node.left = AVLNode(key, value) - } else { + (node.left)?.parent = node + } else if (key > node.key) { node.right = AVLNode(key, value) + (node.right)?.parent = node + } else { + println("Error: this key is already in the tree\n.") } } } diff --git a/src/main/kotlin/treeLib/nodes/AVLNode.kt b/src/main/kotlin/treeLib/nodes/AVLNode.kt index 92ed991..21df738 100644 --- a/src/main/kotlin/treeLib/nodes/AVLNode.kt +++ b/src/main/kotlin/treeLib/nodes/AVLNode.kt @@ -3,5 +3,6 @@ package treeLib.nodes class AVLNode , V> (internal val key: K, internal var value: V) { internal var right: AVLNode? = null internal var left: AVLNode? = null + internal var parent: AVLNode? = null internal var height: Int = 1 } \ No newline at end of file From bcebba2c2742e579804eafc04c218c8845ce93a0 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 18:39:23 +0300 Subject: [PATCH 036/186] feat: add abstract class TreeNode TreeNode implements compareTo(), hashCode(), equals() and attach() methods --- src/main/kotlin/xddcc/nodes/TreeNode.kt | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/kotlin/xddcc/nodes/TreeNode.kt diff --git a/src/main/kotlin/xddcc/nodes/TreeNode.kt b/src/main/kotlin/xddcc/nodes/TreeNode.kt new file mode 100644 index 0000000..2460ce0 --- /dev/null +++ b/src/main/kotlin/xddcc/nodes/TreeNode.kt @@ -0,0 +1,26 @@ +package xddcc.nodes + +abstract class TreeNode, V, Node_T: TreeNode>( + val key: K, + val value: V, + var right: Node_T? = null, + var left: Node_T? = null, +): Comparable { + override fun compareTo(other: Node_T) = key.compareTo(other.key) + + override fun hashCode() = Pair(key, value).hashCode() + + override fun equals(other: Any?): Boolean { + val node = other as? Node_T + return (node != null) && (Pair(key, value) == Pair(node.key, node.value)) + } + + fun attach(node: Node_T): Boolean { + when { + this > node -> left = node + this < node -> right = node + else -> return false + } + return true + } +} \ No newline at end of file From 335d55c6610eb5761272126fe0b8fc78db1df407 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 19:37:15 +0300 Subject: [PATCH 037/186] feat: left rotation for avl tree --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 28 ++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 5a7dc36..08b77b7 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -42,4 +42,30 @@ class AVLTree, V> : BSTree() { } return tree } -} \ No newline at end of file + + fun rotateLeft(node: AVLNode) { + if ((node.right) != null) { + val oldRight = node.right + node.right = oldRight?.left + + if (oldRight?.left != null){ + (oldRight.left)?.parent = node + } + + oldRight?.parent = node.parent + if ((node.parent) == null) { + root = oldRight + } else if (node == (node.parent)?.left) { + (node.parent)?.left = oldRight + } else { + (node.parent)?.right = oldRight + } + + oldRight?.left = node + node.parent = oldRight + + } else { + println("Node.right is null.\n") + } + } +} From 037f1e38fffb92c9c9145f23cf59344ce9d40db5 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 19:40:17 +0300 Subject: [PATCH 038/186] feat: right rotation for avl tree --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 08b77b7..27a916b 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -68,4 +68,30 @@ class AVLTree, V> : BSTree() { println("Node.right is null.\n") } } + + fun rotateRight(node: AVLNode) { + if ((node.left) != null) { + val oldLeft = node.left + node.left = oldLeft?.right + + if (oldLeft?.right != null){ + (oldLeft.right)?.parent = node + } + + oldLeft?.parent = node.parent + if ((node.parent) == null) { + root = oldLeft + } else if (node == (node.parent)?.right) { + (node.parent)?.right = oldLeft + } else { + (node.parent)?.left = oldLeft + } + + oldLeft?.right = node + node.parent = oldLeft + + } else { + println("Node.left is null.\n") + } + } } From 1aaa729e56a40f0160479794f454b0d4e8a71036 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 20:10:14 +0300 Subject: [PATCH 039/186] fix: change Node_T to Node_T? in attach method --- src/main/kotlin/xddcc/nodes/TreeNode.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/xddcc/nodes/TreeNode.kt b/src/main/kotlin/xddcc/nodes/TreeNode.kt index 2460ce0..80a0741 100644 --- a/src/main/kotlin/xddcc/nodes/TreeNode.kt +++ b/src/main/kotlin/xddcc/nodes/TreeNode.kt @@ -15,7 +15,8 @@ abstract class TreeNode, V, Node_T: TreeNode>( return (node != null) && (Pair(key, value) == Pair(node.key, node.value)) } - fun attach(node: Node_T): Boolean { + fun attach(node: Node_T?): Boolean { + if (node == null) return false when { this > node -> left = node this < node -> right = node From 89a6c64c897ff2ca677f846c50e1197bbbc087f8 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 20:18:04 +0300 Subject: [PATCH 040/186] fix: RBNode implements TreeNode now --- src/main/kotlin/xddcc/nodes/RBNode.kt | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/main/kotlin/xddcc/nodes/RBNode.kt b/src/main/kotlin/xddcc/nodes/RBNode.kt index a9cc2b7..90e0bf0 100644 --- a/src/main/kotlin/xddcc/nodes/RBNode.kt +++ b/src/main/kotlin/xddcc/nodes/RBNode.kt @@ -1,20 +1,9 @@ package xddcc.nodes class RBNode, V>( - val key: K, - val value: V, + key: K, + value: V, + right: RBNode? = null, + left: RBNode? = null, var isRed: Boolean = true, - var right: RBNode? = null, - var left: RBNode? = null, -): Comparable> { - override fun compareTo(other: RBNode) = this.key.compareTo(other.key) - - fun attach(node: RBNode): Boolean { - when { - this > node -> this.left = node - this < node -> this.right = node - else -> return false - } - return true - } -} \ No newline at end of file +): TreeNode>(key, value, right, left) \ No newline at end of file From 8a7e6338f34cfb397674c3fc6d1e65cb27c8a0da Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 20:19:27 +0300 Subject: [PATCH 041/186] feat: TreeBalancer interface --- .../xddcc/bintrees/interfaces/TreeBalancer.kt | 35 +++++++++++++++++++ .../bintrees/{ => interfaces}/TreeIterator.kt | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/xddcc/bintrees/interfaces/TreeBalancer.kt rename src/main/kotlin/xddcc/bintrees/{ => interfaces}/TreeIterator.kt (95%) diff --git a/src/main/kotlin/xddcc/bintrees/interfaces/TreeBalancer.kt b/src/main/kotlin/xddcc/bintrees/interfaces/TreeBalancer.kt new file mode 100644 index 0000000..ecdd258 --- /dev/null +++ b/src/main/kotlin/xddcc/bintrees/interfaces/TreeBalancer.kt @@ -0,0 +1,35 @@ +package xddcc.bintrees.interfaces + +import xddcc.nodes.RBNode +import xddcc.nodes.TreeNode + +interface TreeBalancer, V, Node_T: TreeNode> { + var root: RBNode? + + fun balancerAdd(treeBranch: ArrayDeque>) + + fun balancerRemove(treeBranch: ArrayDeque>) + + fun rotateRight(node: RBNode, parent: RBNode?) { + val nodeLeft = node.left + node.left = nodeLeft?.right + nodeLeft?.right = node + + if (parent != null) + parent.attach(nodeLeft) + else /*only root doesn't have parent*/ + root = nodeLeft + } + + fun rotateLeft(node: RBNode, parent: RBNode?) { + val nodeRight = node.right + node.right = nodeRight?.left + nodeRight?.left = node + + if (parent != null) + parent.attach(nodeRight) + else /*only root doesn't have parent*/ + root = nodeRight + + } +} \ No newline at end of file diff --git a/src/main/kotlin/xddcc/bintrees/TreeIterator.kt b/src/main/kotlin/xddcc/bintrees/interfaces/TreeIterator.kt similarity index 95% rename from src/main/kotlin/xddcc/bintrees/TreeIterator.kt rename to src/main/kotlin/xddcc/bintrees/interfaces/TreeIterator.kt index d1a429a..754b033 100644 --- a/src/main/kotlin/xddcc/bintrees/TreeIterator.kt +++ b/src/main/kotlin/xddcc/bintrees/interfaces/TreeIterator.kt @@ -1,4 +1,4 @@ -package xddcc.bintrees +package xddcc.bintrees.interfaces import xddcc.nodes.TreeNode import kotlin.collections.ArrayDeque From 4bbc6677eae4912f4b0046066cc8451f7ffb3e75 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 20:22:39 +0300 Subject: [PATCH 042/186] feat: BinTree interface BinTree implements fun iterator(), add(), remove(), find(), max(), min(), root(), clear(), size() --- .../xddcc/bintrees/interfaces/BinTree.kt | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/main/kotlin/xddcc/bintrees/interfaces/BinTree.kt diff --git a/src/main/kotlin/xddcc/bintrees/interfaces/BinTree.kt b/src/main/kotlin/xddcc/bintrees/interfaces/BinTree.kt new file mode 100644 index 0000000..80bcc90 --- /dev/null +++ b/src/main/kotlin/xddcc/bintrees/interfaces/BinTree.kt @@ -0,0 +1,46 @@ +package xddcc.bintrees.interfaces + +import xddcc.nodes.TreeNode + +interface BinTree, V, Node_T: TreeNode>: Iterable> { + var root: Node_T? + var size: Int + + override fun iterator(): Iterator> = TreeIterator(root) + + fun add(key: K, value: V): Pair? + + fun remove(key: K): Pair? + + fun find(key: K): Pair? { + var curNode = root + while (curNode != null) + curNode = when { + key > curNode.key -> curNode.right + key < curNode.key -> curNode.left + else -> return Pair(key, curNode.value) + } + return null + } + + fun max(): Pair? { + var curNode = root + while (curNode?.right != null) + curNode = curNode.right + return if (curNode != null) Pair(curNode.key, curNode.value) else null + } + + + fun min(): Pair? { + var curNode = root + while (curNode?.left != null) + curNode = curNode.left + return if (curNode != null) Pair(curNode.key, curNode.value) else null + } + + fun root(): Pair? = root?.let { Pair(it.key, it.value) } + + fun clear() { root?.let { root = null } } + + fun size(): Int = size +} \ No newline at end of file From 6da1a32fd9473bfd1f2b625ef576146e9a02bbc4 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 20:24:03 +0300 Subject: [PATCH 043/186] fix!: RBTree inherit from BinTree and TreeBalancer interfaces --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 81 ++++-------------------- 1 file changed, 14 insertions(+), 67 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index a7c4b37..af5a9cc 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -1,11 +1,14 @@ package xddcc.bintrees +import xddcc.bintrees.interfaces.BinTree +import xddcc.bintrees.interfaces.TreeBalancer import xddcc.nodes.RBNode -class RBTree, V>: Iterable { - private var root: RBNode? = null +class RBTree, V> : BinTree>, TreeBalancer> { + override var root: RBNode? = null + override var size: Int = 0 - fun add(key: K, value: V) { + override fun add(key: K, value: V): Pair? { val treeBranch = ArrayDeque>() val newNode = RBNode(key, value) if (root == null) { @@ -41,10 +44,11 @@ class RBTree, V>: Iterable { } treeBranch.addFirst(newNode) } - balanceAdd(treeBranch) + balancerAdd(treeBranch) + return Pair(key, value) } - private fun balanceAdd(treeBranch: ArrayDeque>) { + override fun balancerAdd(treeBranch: ArrayDeque>) { var (son, parent, grandparent) = Triple(treeBranch.removeFirstOrNull(), treeBranch.removeFirstOrNull(), treeBranch.removeFirstOrNull()) @@ -101,37 +105,7 @@ class RBTree, V>: Iterable { root?.isRed = false } - private fun rotateRight(node: RBNode, parent: RBNode?) { - val nodeLeft = node.left - node.left = nodeLeft?.right - nodeLeft?.right = node - - if (parent != null) { - if (node > parent) - parent.right = nodeLeft - else - parent.left = nodeLeft - } else /* node == root */ { - root = nodeLeft - } - } - - private fun rotateLeft(node: RBNode, parent: RBNode?) { - val nodeRight = node.right - node.right = nodeRight?.left - nodeRight?.left = node - - if (parent != null) { - if (node > parent) - parent.right = nodeRight - else - parent.left = nodeRight - } else /* node == root */ { - root = nodeRight - } - } - - fun remove(key: K): Boolean { + override fun remove(key: K): Pair? { var prevNode: RBNode? = null var removeNode = root while (removeNode != null) { @@ -146,7 +120,7 @@ class RBTree, V>: Iterable { } else { TODO("correct remove") } - return true + TODO() } -1 -> { prevNode = removeNode @@ -155,37 +129,10 @@ class RBTree, V>: Iterable { } } - return false - } - - fun find(key: K): Boolean { - var curNode = root - while (curNode != null) { - when (key.compareTo(curNode.key)){ - +1 -> curNode = curNode.right - +0 -> return true - -1 -> curNode = curNode.left - } - } - return false - } - - fun max(): K? { - var maxNode = root - while (maxNode?.right != null) maxNode = maxNode.right - return maxNode?.key + TODO() } - fun min(): K? { - var minNode = root - while (minNode?.left != null) minNode = minNode.left - return minNode?.key + override fun balancerRemove(treeBranch: ArrayDeque>) { + TODO("Not yet implemented") } - - fun root(): K? = root?.key - - fun clear(): Unit { root = null } - - override fun iterator(): Iterator = TreeIterator(root) - } \ No newline at end of file From 490a9d4f786e3f205f126eca10464e4ace04fbd9 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 20:57:44 +0300 Subject: [PATCH 044/186] feat!: support for TreeNode interface (avl) --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 13 +++++++++++++ src/main/kotlin/treeLib/nodes/AVLNode.kt | 9 ++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 27a916b..9a3a531 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -94,4 +94,17 @@ class AVLTree, V> : BSTree() { println("Node.left is null.\n") } } + + //дебаг + fun inorder() { + fun inorderRec(root: AVLNode?) { + if (root != null) { + inorderRec(root.left) + println(root.key) + inorderRec(root.right) + println("-") + } + } + inorderRec(root) + } } diff --git a/src/main/kotlin/treeLib/nodes/AVLNode.kt b/src/main/kotlin/treeLib/nodes/AVLNode.kt index 21df738..72bcd01 100644 --- a/src/main/kotlin/treeLib/nodes/AVLNode.kt +++ b/src/main/kotlin/treeLib/nodes/AVLNode.kt @@ -1,8 +1,11 @@ package treeLib.nodes -class AVLNode , V> (internal val key: K, internal var value: V) { - internal var right: AVLNode? = null - internal var left: AVLNode? = null +class AVLNode, V>( + key: K, + value: V, + right: AVLNode? = null, + left: AVLNode? = null +) : TreeNode>(key, value, right, left) { internal var parent: AVLNode? = null internal var height: Int = 1 } \ No newline at end of file From 0cfa29e0a0b795e4791de87a1e0b7e666e557d7b Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 21:06:28 +0300 Subject: [PATCH 045/186] feat: support for TreeIterator (avl) --- .../bintrees/interfaces/TreeIterator.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt new file mode 100644 index 0000000..83a791f --- /dev/null +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt @@ -0,0 +1,25 @@ +package treeLib.bintrees.interfaces + +import treeLib.nodes.TreeNode + +class TreeIterator, V, Node_T: TreeNode>(private val root: Node_T?): Iterator>{ + private val stack: ArrayDeque = ArrayDeque() + init { + root?.let { treeToStack(root) } + } + + private fun treeToStack(curNode: Node_T) { + val leftNode = curNode.left + val rightNode = curNode.right + leftNode?.let { treeToStack(leftNode) } + stack.add(curNode) + rightNode?.let { treeToStack(rightNode) } + } + + override fun hasNext() = stack.isNotEmpty() + + override fun next(): Pair { + val node = stack.removeFirst() + return Pair(node.key, node.value) + } +} \ No newline at end of file From 61a730ebd86450a173fa7bb3dd230559fec1de64 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 21:07:33 +0300 Subject: [PATCH 046/186] refactor: move Tree to interfaces package --- src/main/kotlin/treeLib/bintrees/BSTree.kt | 2 ++ src/main/kotlin/treeLib/bintrees/{ => interfaces}/Tree.kt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) rename src/main/kotlin/treeLib/bintrees/{ => interfaces}/Tree.kt (65%) diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 81d073c..0832d4c 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -1,5 +1,7 @@ package treeLib.bintrees +import treeLib.bintrees.interfaces.Tree + open class BSTree, V> : Tree { override fun add(key: K, value: V) { TODO("Not yet implemented") diff --git a/src/main/kotlin/treeLib/bintrees/Tree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/Tree.kt similarity index 65% rename from src/main/kotlin/treeLib/bintrees/Tree.kt rename to src/main/kotlin/treeLib/bintrees/interfaces/Tree.kt index a181d4a..e892f4e 100644 --- a/src/main/kotlin/treeLib/bintrees/Tree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/Tree.kt @@ -1,4 +1,4 @@ -package treeLib.bintrees +package treeLib.bintrees.interfaces interface Tree, V> { fun add(key: K, value: V) From cc7d1fee92ffa89859d744b7a91db7a46f269f6a Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 21:08:22 +0300 Subject: [PATCH 047/186] feat!: add abstract TreeNode --- src/main/kotlin/treeLib/nodes/TreeNode.kt | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/kotlin/treeLib/nodes/TreeNode.kt diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt new file mode 100644 index 0000000..d4d9eb6 --- /dev/null +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -0,0 +1,28 @@ +package treeLib.nodes + +abstract class TreeNode, V, Node_T: TreeNode>( + internal val key: K, + internal val value: V, + internal var right: Node_T? = null, + internal var left: Node_T? = null, +): Comparable { + + override fun compareTo(other: Node_T) = key.compareTo(other.key) + + override fun hashCode() = Pair(key, value).hashCode() + + override fun equals(other: Any?): Boolean { + val node = other as? Node_T + return (node != null) && (Pair(key, value) == Pair(node.key, node.value)) + } + + fun attach(node: Node_T?): Boolean { + if (node == null) return false + when { + this > node -> left = node + this < node -> right = node + else -> return false + } + return true + } +} \ No newline at end of file From 0268148cd72f2a13166ccb12c65337f3996c9e9a Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 21:13:36 +0300 Subject: [PATCH 048/186] fix!: avl inherits interface Tree now --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 9a3a531..6a90964 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -1,8 +1,9 @@ package treeLib.bintrees +import treeLib.bintrees.interfaces.Tree import treeLib.nodes.AVLNode -class AVLTree, V> : BSTree() { +class AVLTree, V> : Tree { private var root: AVLNode? = null override fun add(key: K, value: V) { @@ -31,7 +32,7 @@ class AVLTree, V> : BSTree() { } } - override fun initTree(data: List>): AVLTree { + fun initTree(data: List>): AVLTree { val tree = AVLTree() for (element in data) { if (tree.root == null) { From 3cfcc2b3cbeda746a2739566f4667af682594e4a Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 21:16:08 +0300 Subject: [PATCH 049/186] docs: add description for class and it's methods --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index af5a9cc..a95093c 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -4,10 +4,20 @@ import xddcc.bintrees.interfaces.BinTree import xddcc.bintrees.interfaces.TreeBalancer import xddcc.nodes.RBNode +/** + * Class which implements... Red-Black Tree :O + * Takes two types: for key(K) and for value(V) + */ class RBTree, V> : BinTree>, TreeBalancer> { override var root: RBNode? = null override var size: Int = 0 + /** + * Adds or replaces node to the tree depending on given key: + * 1. Adds node to the tree and returns null, + * 2. If node with given key already exist, it will replace it with new node(also with new value). + * In this case, method will return Pair(key, old value) + */ override fun add(key: K, value: V): Pair? { val treeBranch = ArrayDeque>() val newNode = RBNode(key, value) @@ -48,6 +58,9 @@ class RBTree, V> : BinTree>, TreeBalancer>) { var (son, parent, grandparent) = Triple(treeBranch.removeFirstOrNull(), treeBranch.removeFirstOrNull(), treeBranch.removeFirstOrNull()) @@ -105,6 +118,10 @@ class RBTree, V> : BinTree>, TreeBalancer? { var prevNode: RBNode? = null var removeNode = root @@ -132,6 +149,9 @@ class RBTree, V> : BinTree>, TreeBalancer>) { TODO("Not yet implemented") } From 2b9b796a15a0363dfab4d23a7627f9e8ff38a4d0 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 21:19:00 +0300 Subject: [PATCH 050/186] fix: add missing methods and variables to Tree and AVLTree --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 8 ++++++-- src/main/kotlin/treeLib/bintrees/interfaces/Tree.kt | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 6a90964..69b232c 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -3,8 +3,8 @@ package treeLib.bintrees import treeLib.bintrees.interfaces.Tree import treeLib.nodes.AVLNode -class AVLTree, V> : Tree { - private var root: AVLNode? = null +class AVLTree, V> : Tree> { + override var root: AVLNode? = null override fun add(key: K, value: V) { var node: AVLNode? = null @@ -108,4 +108,8 @@ class AVLTree, V> : Tree { } inorderRec(root) } + + override fun iterator(): Iterator> { + TODO("Not yet implemented") + } } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/Tree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/Tree.kt index e892f4e..b78a9d2 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/Tree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/Tree.kt @@ -1,5 +1,9 @@ package treeLib.bintrees.interfaces -interface Tree, V> { +import treeLib.nodes.TreeNode + +interface Tree, V, Node_T: TreeNode>: Iterable> { + var root: Node_T? fun add(key: K, value: V) -} \ No newline at end of file + override fun iterator(): Iterator> = TreeIterator(root) +} From fd4b45c86ffb6d2a1df8ea16792bc3762bfea16f Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 21:38:01 +0300 Subject: [PATCH 051/186] refactor: cleanup --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 69b232c..d26edfe 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -95,21 +95,4 @@ class AVLTree, V> : Tree> { println("Node.left is null.\n") } } - - //дебаг - fun inorder() { - fun inorderRec(root: AVLNode?) { - if (root != null) { - inorderRec(root.left) - println(root.key) - inorderRec(root.right) - println("-") - } - } - inorderRec(root) - } - - override fun iterator(): Iterator> { - TODO("Not yet implemented") - } } From 92ec5f7e302f55cbaaca5fe2f072346e24cce25c Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 21:50:00 +0300 Subject: [PATCH 052/186] refactor: rename Tree -> BinTree --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index d26edfe..7dd62e9 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -1,9 +1,9 @@ package treeLib.bintrees -import treeLib.bintrees.interfaces.Tree +import treeLib.bintrees.interfaces.BinTree import treeLib.nodes.AVLNode -class AVLTree, V> : Tree> { +class AVLTree, V> : BinTree> { override var root: AVLNode? = null override fun add(key: K, value: V) { From fda03b35cbeb414221cc91064a5a39b39a3bb799 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 21:58:03 +0300 Subject: [PATCH 053/186] refactor: attach() and moveOn() become abstract fun --- src/main/kotlin/xddcc/nodes/TreeNode.kt | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/xddcc/nodes/TreeNode.kt b/src/main/kotlin/xddcc/nodes/TreeNode.kt index 80a0741..2a42b0e 100644 --- a/src/main/kotlin/xddcc/nodes/TreeNode.kt +++ b/src/main/kotlin/xddcc/nodes/TreeNode.kt @@ -15,13 +15,7 @@ abstract class TreeNode, V, Node_T: TreeNode>( return (node != null) && (Pair(key, value) == Pair(node.key, node.value)) } - fun attach(node: Node_T?): Boolean { - if (node == null) return false - when { - this > node -> left = node - this < node -> right = node - else -> return false - } - return true - } + abstract fun attach(node: Node_T?): Boolean + + abstract fun moveOn(otherKey: K): Node_T? } \ No newline at end of file From a563e67c353673acb20ad3f5c31bb53e6b63327e Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 21:58:55 +0300 Subject: [PATCH 054/186] feat: add fun attach() and moveOn() --- src/main/kotlin/xddcc/nodes/RBNode.kt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/xddcc/nodes/RBNode.kt b/src/main/kotlin/xddcc/nodes/RBNode.kt index 90e0bf0..13b271c 100644 --- a/src/main/kotlin/xddcc/nodes/RBNode.kt +++ b/src/main/kotlin/xddcc/nodes/RBNode.kt @@ -6,4 +6,20 @@ class RBNode, V>( right: RBNode? = null, left: RBNode? = null, var isRed: Boolean = true, -): TreeNode>(key, value, right, left) \ No newline at end of file +): TreeNode>(key, value, right, left) { + override fun attach(node: RBNode?): Boolean { + if (node == null) return false + when { + this > node -> left = node + this < node -> right = node + else -> return false + } + return true + } + + override fun moveOn(otherKey: K) = when { + key > otherKey -> left + key < otherKey -> right + else -> this + } +} \ No newline at end of file From e2c88d7fd7000bcbd531af5243ec6129b9b74b5a Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 22:10:46 +0300 Subject: [PATCH 055/186] refactor: insert attach() method in add(), change returns --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 26 +++++++----------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index a95093c..4bd4e22 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -27,35 +27,23 @@ class RBTree, V> : BinTree>, TreeBalancer curNode -> curNode.right - newNode < curNode -> curNode.left - else -> curNode - } + val nextNode = curNode.moveOn(key) if (nextNode === curNode) { //replace val parent = treeBranch.first() + parent.attach(newNode) newNode.left = curNode.left newNode.right = curNode.right newNode.isRed = curNode.isRed - if (newNode > parent) { - parent.right = newNode - } else { - parent.left = newNode - } - } else { - curNode = nextNode + return Pair(curNode.key, curNode.value) } + curNode = nextNode } val parent = treeBranch.first() - if (newNode > parent) { - parent.right = newNode - } else { - parent.left = newNode - } - treeBranch.addFirst(newNode) + parent.attach(newNode) } + treeBranch.addFirst(newNode) balancerAdd(treeBranch) - return Pair(key, value) + return null } /** From 694d76882a6abc96915a005e99f9f5a53deddf5a Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 22:15:18 +0300 Subject: [PATCH 056/186] refactor!!!: remove space --- src/main/kotlin/xddcc/bintrees/interfaces/TreeBalancer.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/kotlin/xddcc/bintrees/interfaces/TreeBalancer.kt b/src/main/kotlin/xddcc/bintrees/interfaces/TreeBalancer.kt index ecdd258..6718521 100644 --- a/src/main/kotlin/xddcc/bintrees/interfaces/TreeBalancer.kt +++ b/src/main/kotlin/xddcc/bintrees/interfaces/TreeBalancer.kt @@ -30,6 +30,5 @@ interface TreeBalancer, V, Node_T: TreeNode> { parent.attach(nodeRight) else /*only root doesn't have parent*/ root = nodeRight - } } \ No newline at end of file From 8d115e1fb691aea086b21a0818ede2d86eaa1d3d Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 22:17:50 +0300 Subject: [PATCH 057/186] feat!: fun search(key) (avl) now you can find node with key --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 31 +++++++++++++++++++ .../interfaces/{Tree.kt => BinTree.kt} | 3 +- 2 files changed, 33 insertions(+), 1 deletion(-) rename src/main/kotlin/treeLib/bintrees/interfaces/{Tree.kt => BinTree.kt} (59%) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 7dd62e9..832b800 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -32,6 +32,24 @@ class AVLTree, V> : BinTree> { } } + override fun search(key: K): AVLNode? { + fun searchRec(node: AVLNode?): AVLNode? { + if ((node == null) or (node?.key == key) ){ + return node + } + if (node != null) { + if (key < node.key) { + return searchRec(node.left) + } else { + return searchRec(node.right) + } + } + return node + } + + return searchRec(root) + } + fun initTree(data: List>): AVLTree { val tree = AVLTree() for (element in data) { @@ -95,4 +113,17 @@ class AVLTree, V> : BinTree> { println("Node.left is null.\n") } } + + //дебаг + fun inorder() { + fun inorderRec(root: AVLNode?) { + if (root != null) { + inorderRec(root.left) + println(root.key) + inorderRec(root.right) + println("-") + } + } + inorderRec(root) + } } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/Tree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt similarity index 59% rename from src/main/kotlin/treeLib/bintrees/interfaces/Tree.kt rename to src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index b78a9d2..080c479 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/Tree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -2,8 +2,9 @@ package treeLib.bintrees.interfaces import treeLib.nodes.TreeNode -interface Tree, V, Node_T: TreeNode>: Iterable> { +interface BinTree, V, Node_T: TreeNode>: Iterable> { var root: Node_T? fun add(key: K, value: V) + fun search(key: K): Node_T? override fun iterator(): Iterator> = TreeIterator(root) } From cb39220950263bd7bdabb5ec23f13030a2958f40 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 22:50:50 +0300 Subject: [PATCH 058/186] refactor: rewrite fun remove() --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 37 ++++++++++-------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index 4bd4e22..2ca7a17 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -41,6 +41,7 @@ class RBTree, V> : BinTree>, TreeBalancer, V> : BinTree>, TreeBalancer? { - var prevNode: RBNode? = null - var removeNode = root - while (removeNode != null) { - when (key.compareTo(removeNode.key)){ - +1 -> { - prevNode = removeNode - removeNode = removeNode.right - } - +0 -> { - if (prevNode == null) { - root = null - } else { - TODO("correct remove") - } - TODO() - } - -1 -> { - prevNode = removeNode - removeNode = removeNode.left + val treeBranch = ArrayDeque>() + var curNode = root + while (curNode != null) { + treeBranch.addFirst(curNode) + val nextNode = curNode.moveOn(key) + if (nextNode === curNode) { //remove + val parent = treeBranch.first() + when { + curNode.left != null && curNode.right != null -> TODO() + curNode.left != null -> TODO("replace nodes") + curNode.right != null -> TODO("replace nodes") + else -> TODO("удалить у родителя указатель") } + balancerRemove(treeBranch) + return Pair(curNode.key, curNode.value) } } - - TODO() + return null } /** From a2f57d9fba0f46a78cfa556667b48fffcaab795f Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 26 Mar 2024 22:53:22 +0300 Subject: [PATCH 059/186] fix: return types --- src/main/kotlin/xddcc/bintrees/RBTree.kt | 8 ++++---- src/main/kotlin/xddcc/bintrees/interfaces/BinTree.kt | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/xddcc/bintrees/RBTree.kt index 2ca7a17..36981dc 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/xddcc/bintrees/RBTree.kt @@ -18,7 +18,7 @@ class RBTree, V> : BinTree>, TreeBalancer? { + override fun add(key: K, value: V): V? { val treeBranch = ArrayDeque>() val newNode = RBNode(key, value) if (root == null) { @@ -34,7 +34,7 @@ class RBTree, V> : BinTree>, TreeBalancer, V> : BinTree>, TreeBalancer? { + override fun remove(key: K): V? { val treeBranch = ArrayDeque>() var curNode = root while (curNode != null) { @@ -126,7 +126,7 @@ class RBTree, V> : BinTree>, TreeBalancer TODO("удалить у родителя указатель") } balancerRemove(treeBranch) - return Pair(curNode.key, curNode.value) + return curNode.value } } return null diff --git a/src/main/kotlin/xddcc/bintrees/interfaces/BinTree.kt b/src/main/kotlin/xddcc/bintrees/interfaces/BinTree.kt index 80bcc90..4ada7a3 100644 --- a/src/main/kotlin/xddcc/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/xddcc/bintrees/interfaces/BinTree.kt @@ -8,17 +8,17 @@ interface BinTree, V, Node_T: TreeNode>: Iterable override fun iterator(): Iterator> = TreeIterator(root) - fun add(key: K, value: V): Pair? + fun add(key: K, value: V): V? - fun remove(key: K): Pair? + fun remove(key: K): V? - fun find(key: K): Pair? { + fun find(key: K): V? { var curNode = root while (curNode != null) curNode = when { key > curNode.key -> curNode.right key < curNode.key -> curNode.left - else -> return Pair(key, curNode.value) + else -> return curNode.value } return null } From f9a5091c9ab7232612cb11380d09c3735bbebd1d Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 23:11:16 +0300 Subject: [PATCH 060/186] refactor!: implement search for interface --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 18 ------------------ .../treeLib/bintrees/interfaces/BinTree.kt | 11 ++++++++++- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 832b800..7a21ea8 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -32,24 +32,6 @@ class AVLTree, V> : BinTree> { } } - override fun search(key: K): AVLNode? { - fun searchRec(node: AVLNode?): AVLNode? { - if ((node == null) or (node?.key == key) ){ - return node - } - if (node != null) { - if (key < node.key) { - return searchRec(node.left) - } else { - return searchRec(node.right) - } - } - return node - } - - return searchRec(root) - } - fun initTree(data: List>): AVLTree { val tree = AVLTree() for (element in data) { diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 080c479..81f81db 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -5,6 +5,15 @@ import treeLib.nodes.TreeNode interface BinTree, V, Node_T: TreeNode>: Iterable> { var root: Node_T? fun add(key: K, value: V) - fun search(key: K): Node_T? + fun search(key: K): Node_T? { + var curNode = root + while (curNode != null) + curNode = when { + key > curNode.key -> curNode.right + key < curNode.key -> curNode.left + else -> return curNode + } + return null + } override fun iterator(): Iterator> = TreeIterator(root) } From 073c75d9e52a1c43437de9f96e907f40605fa6d5 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 23:14:22 +0300 Subject: [PATCH 061/186] fix(avl): rotation func is not public anymore --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 7a21ea8..aa4513d 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -44,7 +44,7 @@ class AVLTree, V> : BinTree> { return tree } - fun rotateLeft(node: AVLNode) { + private fun rotateLeft(node: AVLNode) { if ((node.right) != null) { val oldRight = node.right node.right = oldRight?.left @@ -70,7 +70,7 @@ class AVLTree, V> : BinTree> { } } - fun rotateRight(node: AVLNode) { + private fun rotateRight(node: AVLNode) { if ((node.left) != null) { val oldLeft = node.left node.left = oldLeft?.right From 9b0164b31a458f938e74334ebb69e3dab1772541 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 23:16:17 +0300 Subject: [PATCH 062/186] refactor: cleanup --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index aa4513d..b5e772c 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -95,17 +95,4 @@ class AVLTree, V> : BinTree> { println("Node.left is null.\n") } } - - //дебаг - fun inorder() { - fun inorderRec(root: AVLNode?) { - if (root != null) { - inorderRec(root.left) - println(root.key) - inorderRec(root.right) - println("-") - } - } - inorderRec(root) - } } From 9978ed7ee645ba2c98492bb36095a86be55eee9e Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 26 Mar 2024 23:17:35 +0300 Subject: [PATCH 063/186] refactor: auto code reformat --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 4 ++-- src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt | 3 ++- src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt | 4 +++- src/main/kotlin/treeLib/nodes/TreeNode.kt | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index b5e772c..232644e 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -49,7 +49,7 @@ class AVLTree, V> : BinTree> { val oldRight = node.right node.right = oldRight?.left - if (oldRight?.left != null){ + if (oldRight?.left != null) { (oldRight.left)?.parent = node } @@ -75,7 +75,7 @@ class AVLTree, V> : BinTree> { val oldLeft = node.left node.left = oldLeft?.right - if (oldLeft?.right != null){ + if (oldLeft?.right != null) { (oldLeft.right)?.parent = node } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 81f81db..a3c67dc 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -2,7 +2,7 @@ package treeLib.bintrees.interfaces import treeLib.nodes.TreeNode -interface BinTree, V, Node_T: TreeNode>: Iterable> { +interface BinTree, V, Node_T : TreeNode> : Iterable> { var root: Node_T? fun add(key: K, value: V) fun search(key: K): Node_T? { @@ -15,5 +15,6 @@ interface BinTree, V, Node_T: TreeNode>: Iterabl } return null } + override fun iterator(): Iterator> = TreeIterator(root) } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt index 83a791f..33fb893 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt @@ -2,8 +2,10 @@ package treeLib.bintrees.interfaces import treeLib.nodes.TreeNode -class TreeIterator, V, Node_T: TreeNode>(private val root: Node_T?): Iterator>{ +class TreeIterator, V, Node_T : TreeNode>(private val root: Node_T?) : + Iterator> { private val stack: ArrayDeque = ArrayDeque() + init { root?.let { treeToStack(root) } } diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index d4d9eb6..a8a3f7b 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -1,11 +1,11 @@ package treeLib.nodes -abstract class TreeNode, V, Node_T: TreeNode>( +abstract class TreeNode, V, Node_T : TreeNode>( internal val key: K, internal val value: V, internal var right: Node_T? = null, internal var left: Node_T? = null, -): Comparable { +) : Comparable { override fun compareTo(other: Node_T) = key.compareTo(other.key) From 912557c5368d747b79a4c9ab9fbe6469f1ed32a8 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 27 Mar 2024 10:24:33 +0300 Subject: [PATCH 064/186] refactor: rename package name xddcc -> treeLib --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 4 ++++ src/main/kotlin/treeLib/bintrees/BSTree.kt | 4 ++++ src/main/kotlin/{xddcc => treeLib}/bintrees/RBTree.kt | 8 ++++---- .../{xddcc => treeLib}/bintrees/interfaces/BinTree.kt | 4 ++-- .../bintrees/interfaces/TreeBalancer.kt | 6 +++--- .../bintrees/interfaces/TreeIterator.kt | 4 ++-- src/main/kotlin/treeLib/nodes/AVLNode.kt | 4 ++++ src/main/kotlin/treeLib/nodes/BSTNode.kt | 4 ++++ src/main/kotlin/{xddcc => treeLib}/nodes/RBNode.kt | 2 +- src/main/kotlin/{xddcc => treeLib}/nodes/TreeNode.kt | 2 +- src/main/kotlin/xddcc/bintrees/AVLTree.kt | 4 ---- src/main/kotlin/xddcc/bintrees/BSTree.kt | 4 ---- src/main/kotlin/xddcc/nodes/AVLNode.kt | 4 ---- src/main/kotlin/xddcc/nodes/BSTNode.kt | 4 ---- 14 files changed, 29 insertions(+), 29 deletions(-) create mode 100644 src/main/kotlin/treeLib/bintrees/AVLTree.kt create mode 100644 src/main/kotlin/treeLib/bintrees/BSTree.kt rename src/main/kotlin/{xddcc => treeLib}/bintrees/RBTree.kt (97%) rename src/main/kotlin/{xddcc => treeLib}/bintrees/interfaces/BinTree.kt (94%) rename src/main/kotlin/{xddcc => treeLib}/bintrees/interfaces/TreeBalancer.kt (90%) rename src/main/kotlin/{xddcc => treeLib}/bintrees/interfaces/TreeIterator.kt (91%) create mode 100644 src/main/kotlin/treeLib/nodes/AVLNode.kt create mode 100644 src/main/kotlin/treeLib/nodes/BSTNode.kt rename src/main/kotlin/{xddcc => treeLib}/nodes/RBNode.kt (96%) rename src/main/kotlin/{xddcc => treeLib}/nodes/TreeNode.kt (96%) delete mode 100644 src/main/kotlin/xddcc/bintrees/AVLTree.kt delete mode 100644 src/main/kotlin/xddcc/bintrees/BSTree.kt delete mode 100644 src/main/kotlin/xddcc/nodes/AVLNode.kt delete mode 100644 src/main/kotlin/xddcc/nodes/BSTNode.kt diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt new file mode 100644 index 0000000..add4e03 --- /dev/null +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -0,0 +1,4 @@ +package treeLib.bintrees + +class AVLTree { +} \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt new file mode 100644 index 0000000..c6ff110 --- /dev/null +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -0,0 +1,4 @@ +package treeLib.bintrees + +class BSTree { +} \ No newline at end of file diff --git a/src/main/kotlin/xddcc/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt similarity index 97% rename from src/main/kotlin/xddcc/bintrees/RBTree.kt rename to src/main/kotlin/treeLib/bintrees/RBTree.kt index 36981dc..fcfcd3c 100644 --- a/src/main/kotlin/xddcc/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -1,8 +1,8 @@ -package xddcc.bintrees +package treeLib.bintrees -import xddcc.bintrees.interfaces.BinTree -import xddcc.bintrees.interfaces.TreeBalancer -import xddcc.nodes.RBNode +import treeLib.bintrees.interfaces.BinTree +import treeLib.bintrees.interfaces.TreeBalancer +import treeLib.nodes.RBNode /** * Class which implements... Red-Black Tree :O diff --git a/src/main/kotlin/xddcc/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt similarity index 94% rename from src/main/kotlin/xddcc/bintrees/interfaces/BinTree.kt rename to src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 4ada7a3..9469cfc 100644 --- a/src/main/kotlin/xddcc/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -1,6 +1,6 @@ -package xddcc.bintrees.interfaces +package treeLib.bintrees.interfaces -import xddcc.nodes.TreeNode +import treeLib.nodes.TreeNode interface BinTree, V, Node_T: TreeNode>: Iterable> { var root: Node_T? diff --git a/src/main/kotlin/xddcc/bintrees/interfaces/TreeBalancer.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt similarity index 90% rename from src/main/kotlin/xddcc/bintrees/interfaces/TreeBalancer.kt rename to src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt index 6718521..0ff40c4 100644 --- a/src/main/kotlin/xddcc/bintrees/interfaces/TreeBalancer.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt @@ -1,7 +1,7 @@ -package xddcc.bintrees.interfaces +package treeLib.bintrees.interfaces -import xddcc.nodes.RBNode -import xddcc.nodes.TreeNode +import treeLib.nodes.RBNode +import treeLib.nodes.TreeNode interface TreeBalancer, V, Node_T: TreeNode> { var root: RBNode? diff --git a/src/main/kotlin/xddcc/bintrees/interfaces/TreeIterator.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt similarity index 91% rename from src/main/kotlin/xddcc/bintrees/interfaces/TreeIterator.kt rename to src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt index 754b033..52e1861 100644 --- a/src/main/kotlin/xddcc/bintrees/interfaces/TreeIterator.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt @@ -1,6 +1,6 @@ -package xddcc.bintrees.interfaces +package treeLib.bintrees.interfaces -import xddcc.nodes.TreeNode +import treeLib.nodes.TreeNode import kotlin.collections.ArrayDeque class TreeIterator, V, Node_T: TreeNode>(private val root: Node_T?): Iterator>{ diff --git a/src/main/kotlin/treeLib/nodes/AVLNode.kt b/src/main/kotlin/treeLib/nodes/AVLNode.kt new file mode 100644 index 0000000..a9ded86 --- /dev/null +++ b/src/main/kotlin/treeLib/nodes/AVLNode.kt @@ -0,0 +1,4 @@ +package treeLib.nodes + +class AVLNode { +} \ No newline at end of file diff --git a/src/main/kotlin/treeLib/nodes/BSTNode.kt b/src/main/kotlin/treeLib/nodes/BSTNode.kt new file mode 100644 index 0000000..c9f597f --- /dev/null +++ b/src/main/kotlin/treeLib/nodes/BSTNode.kt @@ -0,0 +1,4 @@ +package treeLib.nodes + +class BSTNode { +} \ No newline at end of file diff --git a/src/main/kotlin/xddcc/nodes/RBNode.kt b/src/main/kotlin/treeLib/nodes/RBNode.kt similarity index 96% rename from src/main/kotlin/xddcc/nodes/RBNode.kt rename to src/main/kotlin/treeLib/nodes/RBNode.kt index 13b271c..ea4781b 100644 --- a/src/main/kotlin/xddcc/nodes/RBNode.kt +++ b/src/main/kotlin/treeLib/nodes/RBNode.kt @@ -1,4 +1,4 @@ -package xddcc.nodes +package treeLib.nodes class RBNode, V>( key: K, diff --git a/src/main/kotlin/xddcc/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt similarity index 96% rename from src/main/kotlin/xddcc/nodes/TreeNode.kt rename to src/main/kotlin/treeLib/nodes/TreeNode.kt index 2a42b0e..0654115 100644 --- a/src/main/kotlin/xddcc/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -1,4 +1,4 @@ -package xddcc.nodes +package treeLib.nodes abstract class TreeNode, V, Node_T: TreeNode>( val key: K, diff --git a/src/main/kotlin/xddcc/bintrees/AVLTree.kt b/src/main/kotlin/xddcc/bintrees/AVLTree.kt deleted file mode 100644 index 66153f3..0000000 --- a/src/main/kotlin/xddcc/bintrees/AVLTree.kt +++ /dev/null @@ -1,4 +0,0 @@ -package xddcc.bintrees - -class AVLTree { -} \ No newline at end of file diff --git a/src/main/kotlin/xddcc/bintrees/BSTree.kt b/src/main/kotlin/xddcc/bintrees/BSTree.kt deleted file mode 100644 index 8d744a6..0000000 --- a/src/main/kotlin/xddcc/bintrees/BSTree.kt +++ /dev/null @@ -1,4 +0,0 @@ -package xddcc.bintrees - -class BSTree { -} \ No newline at end of file diff --git a/src/main/kotlin/xddcc/nodes/AVLNode.kt b/src/main/kotlin/xddcc/nodes/AVLNode.kt deleted file mode 100644 index 9694fca..0000000 --- a/src/main/kotlin/xddcc/nodes/AVLNode.kt +++ /dev/null @@ -1,4 +0,0 @@ -package xddcc.nodes - -class AVLNode { -} \ No newline at end of file diff --git a/src/main/kotlin/xddcc/nodes/BSTNode.kt b/src/main/kotlin/xddcc/nodes/BSTNode.kt deleted file mode 100644 index d9f1b55..0000000 --- a/src/main/kotlin/xddcc/nodes/BSTNode.kt +++ /dev/null @@ -1,4 +0,0 @@ -package xddcc.nodes - -class BSTNode { -} \ No newline at end of file From dd7b0aa2e80b233a9b1e4d7588c135dce8deaa2a Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 27 Mar 2024 11:51:00 +0300 Subject: [PATCH 065/186] fix!: compatibility (rbt) fun add returns V? remove overrides nothing --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 2 +- src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index c5ed962..23121bd 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -111,7 +111,7 @@ class RBTree, V> : BinTree>, TreeBalancer>() var curNode = root while (curNode != null) { diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 2330189..108fd7b 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -6,7 +6,8 @@ interface BinTree, V, Node_T : TreeNode> : Itera var root: Node_T? var size: Int - fun add(key: K, value: V) + fun add(key: K, value: V) : V? + fun search(key: K): Node_T? { var curNode = root while (curNode != null) From a3b3a30c7b03cfc1d07afb45a7c1142fe9c27706 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 27 Mar 2024 12:24:24 +0300 Subject: [PATCH 066/186] fix: compatibility (avl) - fun attach, moveOn in AVLNode - value in AVLNode now mutable - add in AVLTree now returns V? --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 8 ++++++-- src/main/kotlin/treeLib/nodes/AVLNode.kt | 7 +++++++ src/main/kotlin/treeLib/nodes/TreeNode.kt | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index bca03b5..442ff7d 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -6,9 +6,10 @@ import treeLib.nodes.AVLNode class AVLTree, V> : BinTree> { override var root: AVLNode? = null - override fun add(key: K, value: V) { + override fun add(key: K, value: V): V? { var node: AVLNode? = null var curr = root + var toReturn: V? = null while (curr != null) { node = curr if (key < curr.key) { @@ -27,9 +28,12 @@ class AVLTree, V> : BinTree> { node.right = AVLNode(key, value) (node.right)?.parent = node } else { - println("Error: this key is already in the tree\n.") + toReturn = node.value + node.value = value } } + + return toReturn } fun initTree(data: List>): AVLTree { diff --git a/src/main/kotlin/treeLib/nodes/AVLNode.kt b/src/main/kotlin/treeLib/nodes/AVLNode.kt index 72bcd01..0acacff 100644 --- a/src/main/kotlin/treeLib/nodes/AVLNode.kt +++ b/src/main/kotlin/treeLib/nodes/AVLNode.kt @@ -8,4 +8,11 @@ class AVLNode, V>( ) : TreeNode>(key, value, right, left) { internal var parent: AVLNode? = null internal var height: Int = 1 + override fun attach(node: AVLNode?): Boolean { + TODO("Not yet implemented") + } + + override fun moveOn(otherKey: K): AVLNode? { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index af263cc..986cc39 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -2,7 +2,7 @@ package treeLib.nodes abstract class TreeNode, V, Node_T : TreeNode>( internal val key: K, - internal val value: V, + internal var value: V, internal var right: Node_T? = null, internal var left: Node_T? = null, ) : Comparable { From 99b57beb7e06e68bf0d07238a22070c276486d31 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 27 Mar 2024 12:38:54 +0300 Subject: [PATCH 067/186] refactor: rename size func variable size -> amountOfNodes func size -> countNodes --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 3 +++ src/main/kotlin/treeLib/bintrees/BSTree.kt | 15 ++++++++++++--- src/main/kotlin/treeLib/bintrees/RBTree.kt | 4 ++-- .../treeLib/bintrees/interfaces/BinTree.kt | 4 ++-- src/main/kotlin/treeLib/nodes/BSTNode.kt | 16 +++++++++++++++- 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 442ff7d..fa1e212 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -5,6 +5,9 @@ import treeLib.nodes.AVLNode class AVLTree, V> : BinTree> { override var root: AVLNode? = null + override var amountOfNodes: Int + get() = TODO("Not yet implemented") + set(value) {} override fun add(key: K, value: V): V? { var node: AVLNode? = null diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 0832d4c..191bab1 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -1,13 +1,22 @@ package treeLib.bintrees -import treeLib.bintrees.interfaces.Tree +import treeLib.bintrees.interfaces.BinTree +import treeLib.nodes.AVLNode +import treeLib.nodes.BSTNode -open class BSTree, V> : Tree { - override fun add(key: K, value: V) { +class BSTree, V> : BinTree> { + override fun add(key: K, value: V): V? { TODO("Not yet implemented") } open fun initTree(data: List>): BSTree { TODO("Not yet implemented") } + + override var root: BSTNode? + get() = TODO("Not yet implemented") + set(value) {} + override var amountOfNodes: Int + get() = TODO("Not yet implemented") + set(value) {} } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index 23121bd..cf9e03b 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -10,7 +10,7 @@ import treeLib.nodes.RBNode */ class RBTree, V> : BinTree>, TreeBalancer> { override var root: RBNode? = null - override var size: Int = 0 + override var amountOfNodes: Int = 0 /** * Adds or replaces node to the tree depending on given key: @@ -41,7 +41,7 @@ class RBTree, V> : BinTree>, TreeBalancer, V, Node_T : TreeNode> : Iterable> { var root: Node_T? - var size: Int + var amountOfNodes: Int fun add(key: K, value: V) : V? @@ -37,7 +37,7 @@ interface BinTree, V, Node_T : TreeNode> : Itera fun clear() { root?.let { root = null } } - fun size(): Int = size + fun countNodes(): Int = amountOfNodes override fun iterator(): Iterator> = TreeIterator(root) } diff --git a/src/main/kotlin/treeLib/nodes/BSTNode.kt b/src/main/kotlin/treeLib/nodes/BSTNode.kt index c9f597f..773c5ce 100644 --- a/src/main/kotlin/treeLib/nodes/BSTNode.kt +++ b/src/main/kotlin/treeLib/nodes/BSTNode.kt @@ -1,4 +1,18 @@ package treeLib.nodes -class BSTNode { +class BSTNode, V>( + key: K, + value: V, + right: BSTNode? = null, + left: BSTNode? = null +) : TreeNode>(key, value, right, left) { + internal var parent: AVLNode? = null + internal var height: Int = 1 + override fun attach(node: BSTNode?): Boolean { + TODO("Not yet implemented") + } + + override fun moveOn(otherKey: K): BSTNode? { + TODO("Not yet implemented") + } } \ No newline at end of file From cba8ce420190a22927568699213c55b6442284b6 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 27 Mar 2024 13:05:00 +0300 Subject: [PATCH 068/186] refactor: auto code reformat + cleanup --- src/main/kotlin/treeLib/bintrees/BSTree.kt | 5 -- src/main/kotlin/treeLib/bintrees/RBTree.kt | 12 ++-- .../treeLib/bintrees/interfaces/BinTree.kt | 6 +- .../bintrees/interfaces/TreeBalancer.kt | 56 +++++++++---------- .../bintrees/interfaces/TreeIterator.kt | 1 - src/main/kotlin/treeLib/nodes/RBNode.kt | 4 +- 6 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 191bab1..b4c8719 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -1,7 +1,6 @@ package treeLib.bintrees import treeLib.bintrees.interfaces.BinTree -import treeLib.nodes.AVLNode import treeLib.nodes.BSTNode class BSTree, V> : BinTree> { @@ -9,10 +8,6 @@ class BSTree, V> : BinTree> { TODO("Not yet implemented") } - open fun initTree(data: List>): BSTree { - TODO("Not yet implemented") - } - override var root: BSTNode? get() = TODO("Not yet implemented") set(value) {} diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index cf9e03b..83e9a93 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -8,7 +8,7 @@ import treeLib.nodes.RBNode * Class which implements... Red-Black Tree :O * Takes two types: for key(K) and for value(V) */ -class RBTree, V> : BinTree>, TreeBalancer> { +class RBTree, V> : BinTree>, TreeBalancer> { override var root: RBNode? = null override var amountOfNodes: Int = 0 @@ -52,7 +52,11 @@ class RBTree, V> : BinTree>, TreeBalancer>) { var (son, parent, grandparent) = - Triple(treeBranch.removeFirstOrNull(), treeBranch.removeFirstOrNull(), treeBranch.removeFirstOrNull()) + Triple( + treeBranch.removeFirstOrNull(), + treeBranch.removeFirstOrNull(), + treeBranch.removeFirstOrNull() + ) while (parent != null && parent.isRed) { if (parent === grandparent?.left) { @@ -76,7 +80,7 @@ class RBTree, V> : BinTree>, TreeBalancer, V> : BinTree>, TreeBalancer, V, Node_T : TreeNode> : Itera var root: Node_T? var amountOfNodes: Int - fun add(key: K, value: V) : V? + fun add(key: K, value: V): V? fun search(key: K): Node_T? { var curNode = root @@ -35,7 +35,9 @@ interface BinTree, V, Node_T : TreeNode> : Itera fun root(): Pair? = root?.let { Pair(it.key, it.value) } - fun clear() { root?.let { root = null } } + fun clear() { + root?.let { root = null } + } fun countNodes(): Int = amountOfNodes diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt index 0ff40c4..0e53a58 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt @@ -3,32 +3,32 @@ package treeLib.bintrees.interfaces import treeLib.nodes.RBNode import treeLib.nodes.TreeNode -interface TreeBalancer, V, Node_T: TreeNode> { - var root: RBNode? - - fun balancerAdd(treeBranch: ArrayDeque>) - - fun balancerRemove(treeBranch: ArrayDeque>) - - fun rotateRight(node: RBNode, parent: RBNode?) { - val nodeLeft = node.left - node.left = nodeLeft?.right - nodeLeft?.right = node - - if (parent != null) - parent.attach(nodeLeft) - else /*only root doesn't have parent*/ - root = nodeLeft - } - - fun rotateLeft(node: RBNode, parent: RBNode?) { - val nodeRight = node.right - node.right = nodeRight?.left - nodeRight?.left = node - - if (parent != null) - parent.attach(nodeRight) - else /*only root doesn't have parent*/ - root = nodeRight - } +interface TreeBalancer, V, Node_T : TreeNode> { + var root: RBNode? + + fun balancerAdd(treeBranch: ArrayDeque>) + + fun balancerRemove(treeBranch: ArrayDeque>) + + fun rotateRight(node: RBNode, parent: RBNode?) { + val nodeLeft = node.left + node.left = nodeLeft?.right + nodeLeft?.right = node + + if (parent != null) + parent.attach(nodeLeft) + else /*only root doesn't have parent*/ + root = nodeLeft + } + + fun rotateLeft(node: RBNode, parent: RBNode?) { + val nodeRight = node.right + node.right = nodeRight?.left + nodeRight?.left = node + + if (parent != null) + parent.attach(nodeRight) + else /*only root doesn't have parent*/ + root = nodeRight + } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt index ecc847a..33fb893 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt @@ -1,7 +1,6 @@ package treeLib.bintrees.interfaces import treeLib.nodes.TreeNode -import kotlin.collections.ArrayDeque class TreeIterator, V, Node_T : TreeNode>(private val root: Node_T?) : Iterator> { diff --git a/src/main/kotlin/treeLib/nodes/RBNode.kt b/src/main/kotlin/treeLib/nodes/RBNode.kt index a682163..ca135af 100644 --- a/src/main/kotlin/treeLib/nodes/RBNode.kt +++ b/src/main/kotlin/treeLib/nodes/RBNode.kt @@ -1,12 +1,12 @@ package treeLib.nodes -class RBNode, V>( +class RBNode, V>( key: K, value: V, right: RBNode? = null, left: RBNode? = null, var isRed: Boolean = true, -): TreeNode>(key, value, right, left) { +) : TreeNode>(key, value, right, left) { override fun attach(node: RBNode?): Boolean { if (node == null) return false when { From 93d7d6eea4f247b7008f9dc769c46168e04c80ba Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 27 Mar 2024 13:14:12 +0300 Subject: [PATCH 069/186] chore: add wrapper for height in AVLNODe --- src/main/kotlin/treeLib/nodes/AVLNode.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/treeLib/nodes/AVLNode.kt b/src/main/kotlin/treeLib/nodes/AVLNode.kt index 0acacff..b2d0c85 100644 --- a/src/main/kotlin/treeLib/nodes/AVLNode.kt +++ b/src/main/kotlin/treeLib/nodes/AVLNode.kt @@ -7,7 +7,15 @@ class AVLNode, V>( left: AVLNode? = null ) : TreeNode>(key, value, right, left) { internal var parent: AVLNode? = null - internal var height: Int = 1 + private var height: Int = 1 + + fun height(node: AVLNode?) : Int { + if (node == null) { + return 0 + } + return node.height + } + override fun attach(node: AVLNode?): Boolean { TODO("Not yet implemented") } From 2f2e03ba712bc6d4696326c7e4d27a8cf1a963b7 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 27 Mar 2024 21:03:26 +0300 Subject: [PATCH 070/186] refactor: fun height(avl) now in the tree, notin the node --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 7 +++++++ src/main/kotlin/treeLib/nodes/AVLNode.kt | 11 ++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index fa1e212..5f5114e 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -102,4 +102,11 @@ class AVLTree, V> : BinTree> { println("Node.left is null.\n") } } + + fun height(node: AVLNode?) : Int { + if (node == null) { + return 0 + } + return node.height + } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/nodes/AVLNode.kt b/src/main/kotlin/treeLib/nodes/AVLNode.kt index b2d0c85..41ba84d 100644 --- a/src/main/kotlin/treeLib/nodes/AVLNode.kt +++ b/src/main/kotlin/treeLib/nodes/AVLNode.kt @@ -7,14 +7,7 @@ class AVLNode, V>( left: AVLNode? = null ) : TreeNode>(key, value, right, left) { internal var parent: AVLNode? = null - private var height: Int = 1 - - fun height(node: AVLNode?) : Int { - if (node == null) { - return 0 - } - return node.height - } + internal var height: Int = 1 override fun attach(node: AVLNode?): Boolean { TODO("Not yet implemented") @@ -23,4 +16,4 @@ class AVLNode, V>( override fun moveOn(otherKey: K): AVLNode? { TODO("Not yet implemented") } -} \ No newline at end of file +} From 6cf946b933dfa08d30dc820f37f877fe89d49429 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 27 Mar 2024 21:08:44 +0300 Subject: [PATCH 071/186] chore: add helper fun bFactor (avl) --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 5f5114e..52b379b 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -103,10 +103,17 @@ class AVLTree, V> : BinTree> { } } - fun height(node: AVLNode?) : Int { + private fun height(node: AVLNode?) : Int { if (node == null) { return 0 } return node.height } + + private fun bFactor(node: AVLNode?) : Int? { + if (node != null) { + return height(node.right) - height(node.left) + } + return null + } } \ No newline at end of file From 0d7ec55a560e5f595e20b73b6f303858eff0913a Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 27 Mar 2024 21:17:31 +0300 Subject: [PATCH 072/186] chore: add helper fun fixHeight (avl) --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 52b379b..bbec91d 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -116,4 +116,16 @@ class AVLTree, V> : BinTree> { } return null } + + private fun fixHeight(node: AVLNode?) { + if (node != null) { + var heightLeft = height(node.left) + var heightRight = height(node.right) + if (heightLeft > heightRight) { + node.height = heightLeft + 1 + } else { + node.height = heightRight + 1 + } + } + } } \ No newline at end of file From fe3c8e228b6f2770fcb035be0286acb005ab7720 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 27 Mar 2024 21:31:23 +0300 Subject: [PATCH 073/186] feat: now AVL nodes can balance themselves --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 25 +++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index bbec91d..15fb075 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -110,11 +110,11 @@ class AVLTree, V> : BinTree> { return node.height } - private fun bFactor(node: AVLNode?) : Int? { + private fun bFactor(node: AVLNode?) : Int { if (node != null) { return height(node.right) - height(node.left) } - return null + return 0 } private fun fixHeight(node: AVLNode?) { @@ -128,4 +128,25 @@ class AVLTree, V> : BinTree> { } } } + + private fun balanceNode(node: AVLNode?) { + fixHeight(node) + if (bFactor(node) == 2) { + if (node != null) { + if (bFactor(node.right) < 0) { + node.right?.let { rotateRight(it) } + rotateLeft(node) + } + } + } + if (bFactor(node) == -2) { + if (node != null) { + if (bFactor(node.left) > 0) { + node.left?.let { rotateLeft(it) } + rotateRight(node) + } + } + } + } + } \ No newline at end of file From b2ef74657f92bb4b9e228483c8bd8b8e24f9cc77 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 27 Mar 2024 21:37:22 +0300 Subject: [PATCH 074/186] fix: now add in AVL tree is balanced --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 15fb075..c994220 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -36,6 +36,8 @@ class AVLTree, V> : BinTree> { } } + balanceNode(node) + return toReturn } From 70912ddd7ccb984c643d496ee56aa0203425c46d Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Thu, 28 Mar 2024 14:13:36 +0300 Subject: [PATCH 075/186] refactor(avl): small changes in private methods regarding null check --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 96 +++++++++++---------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index c994220..f1e0ae0 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -53,55 +53,63 @@ class AVLTree, V> : BinTree> { return tree } - private fun rotateLeft(node: AVLNode) { - if ((node.right) != null) { - val oldRight = node.right - node.right = oldRight?.left + private fun rotateLeft(node: AVLNode?) { + if (node != null) { + if ((node.right) != null) { + val oldRight = node.right + node.right = oldRight?.left - if (oldRight?.left != null) { - (oldRight.left)?.parent = node - } + if (oldRight?.left != null) { + (oldRight.left)?.parent = node + } - oldRight?.parent = node.parent - if ((node.parent) == null) { - root = oldRight - } else if (node == (node.parent)?.left) { - (node.parent)?.left = oldRight - } else { - (node.parent)?.right = oldRight - } + oldRight?.parent = node.parent + if ((node.parent) == null) { + root = oldRight + } else if (node == (node.parent)?.left) { + (node.parent)?.left = oldRight + } else { + (node.parent)?.right = oldRight + } - oldRight?.left = node - node.parent = oldRight + oldRight?.left = node + node.parent = oldRight + } else { + throw NullPointerException("Right child node cannot be null.") + } } else { - println("Node.right is null.\n") + throw NullPointerException("Node cannot be null.") } } - private fun rotateRight(node: AVLNode) { - if ((node.left) != null) { - val oldLeft = node.left - node.left = oldLeft?.right + private fun rotateRight(node: AVLNode?) { + if (node != null) { + if ((node.left) != null) { + val oldLeft = node.left + node.left = oldLeft?.right + + if (oldLeft?.right != null) { + (oldLeft.right)?.parent = node + } - if (oldLeft?.right != null) { - (oldLeft.right)?.parent = node - } + oldLeft?.parent = node.parent + if ((node.parent) == null) { + root = oldLeft + } else if (node == (node.parent)?.right) { + (node.parent)?.right = oldLeft + } else { + (node.parent)?.left = oldLeft + } + + oldLeft?.right = node + node.parent = oldLeft - oldLeft?.parent = node.parent - if ((node.parent) == null) { - root = oldLeft - } else if (node == (node.parent)?.right) { - (node.parent)?.right = oldLeft } else { - (node.parent)?.left = oldLeft + throw NullPointerException("Left child node cannot be null.") } - - oldLeft?.right = node - node.parent = oldLeft - } else { - println("Node.left is null.\n") + throw NullPointerException("Node cannot be null.") } } @@ -112,11 +120,11 @@ class AVLTree, V> : BinTree> { return node.height } - private fun bFactor(node: AVLNode?) : Int { - if (node != null) { - return height(node.right) - height(node.left) + private fun balanceFactor(node: AVLNode?) : Int { + if (node == null) { + throw NullPointerException("Node cannot be null.") } - return 0 + return height(node.right) - height(node.left) } private fun fixHeight(node: AVLNode?) { @@ -133,17 +141,17 @@ class AVLTree, V> : BinTree> { private fun balanceNode(node: AVLNode?) { fixHeight(node) - if (bFactor(node) == 2) { + if (balanceFactor(node) == 2) { if (node != null) { - if (bFactor(node.right) < 0) { + if (balanceFactor(node.right) < 0) { node.right?.let { rotateRight(it) } rotateLeft(node) } } } - if (bFactor(node) == -2) { + if (balanceFactor(node) == -2) { if (node != null) { - if (bFactor(node.left) > 0) { + if (balanceFactor(node.left) > 0) { node.left?.let { rotateLeft(it) } rotateRight(node) } From fff057f5245f2159b2756604cc26f9ec7efb9103 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Thu, 28 Mar 2024 14:23:15 +0300 Subject: [PATCH 076/186] fix (avl): avl node no longer stores the parent node --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 46 +++------------------ src/main/kotlin/treeLib/nodes/AVLNode.kt | 1 - 2 files changed, 6 insertions(+), 41 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index f1e0ae0..7ab47f4 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -26,10 +26,8 @@ class AVLTree, V> : BinTree> { } else { if (key < node.key) { node.left = AVLNode(key, value) - (node.left)?.parent = node } else if (key > node.key) { node.right = AVLNode(key, value) - (node.right)?.parent = node } else { toReturn = node.value node.value = value @@ -53,28 +51,12 @@ class AVLTree, V> : BinTree> { return tree } - private fun rotateLeft(node: AVLNode?) { - if (node != null) { - if ((node.right) != null) { - val oldRight = node.right - node.right = oldRight?.left - - if (oldRight?.left != null) { - (oldRight.left)?.parent = node - } - - oldRight?.parent = node.parent - if ((node.parent) == null) { - root = oldRight - } else if (node == (node.parent)?.left) { - (node.parent)?.left = oldRight - } else { - (node.parent)?.right = oldRight - } - - oldRight?.left = node - node.parent = oldRight - + private fun rotateLeft(nodeA: AVLNode?) { + if (nodeA != null) { + if ((nodeA.right) != null) { + val nodeB = nodeA.right + nodeA.right = nodeB?.left + nodeB?.left = nodeA } else { throw NullPointerException("Right child node cannot be null.") } @@ -88,23 +70,7 @@ class AVLTree, V> : BinTree> { if ((node.left) != null) { val oldLeft = node.left node.left = oldLeft?.right - - if (oldLeft?.right != null) { - (oldLeft.right)?.parent = node - } - - oldLeft?.parent = node.parent - if ((node.parent) == null) { - root = oldLeft - } else if (node == (node.parent)?.right) { - (node.parent)?.right = oldLeft - } else { - (node.parent)?.left = oldLeft - } - oldLeft?.right = node - node.parent = oldLeft - } else { throw NullPointerException("Left child node cannot be null.") } diff --git a/src/main/kotlin/treeLib/nodes/AVLNode.kt b/src/main/kotlin/treeLib/nodes/AVLNode.kt index 41ba84d..8de63cd 100644 --- a/src/main/kotlin/treeLib/nodes/AVLNode.kt +++ b/src/main/kotlin/treeLib/nodes/AVLNode.kt @@ -6,7 +6,6 @@ class AVLNode, V>( right: AVLNode? = null, left: AVLNode? = null ) : TreeNode>(key, value, right, left) { - internal var parent: AVLNode? = null internal var height: Int = 1 override fun attach(node: AVLNode?): Boolean { From 13be6bbf6f08974e50de317e44808d0a25b14f99 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Thu, 28 Mar 2024 14:26:36 +0300 Subject: [PATCH 077/186] refactor(avl): rename variables in rotation functions --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 7ab47f4..79cfadc 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -65,12 +65,12 @@ class AVLTree, V> : BinTree> { } } - private fun rotateRight(node: AVLNode?) { - if (node != null) { - if ((node.left) != null) { - val oldLeft = node.left - node.left = oldLeft?.right - oldLeft?.right = node + private fun rotateRight(nodeA: AVLNode?) { + if (nodeA != null) { + if ((nodeA.left) != null) { + val nodeB = nodeA.left + nodeA.left = nodeB?.right + nodeB?.right = nodeA } else { throw NullPointerException("Left child node cannot be null.") } From 6a718d987504dab46433941b27b4d50a73d9f86d Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Thu, 28 Mar 2024 14:29:35 +0300 Subject: [PATCH 078/186] fix(avl): now rotation methods fix height of nodes after rotation --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 79cfadc..91a145d 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -57,6 +57,8 @@ class AVLTree, V> : BinTree> { val nodeB = nodeA.right nodeA.right = nodeB?.left nodeB?.left = nodeA + fixHeight(nodeA) + fixHeight(nodeB) } else { throw NullPointerException("Right child node cannot be null.") } @@ -71,6 +73,8 @@ class AVLTree, V> : BinTree> { val nodeB = nodeA.left nodeA.left = nodeB?.right nodeB?.right = nodeA + fixHeight(nodeA) + fixHeight(nodeB) } else { throw NullPointerException("Left child node cannot be null.") } From 34f4a4c412b2a7b61e6caec6aab23d98f43f6187 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Thu, 28 Mar 2024 15:20:24 +0300 Subject: [PATCH 079/186] refactor: rename method search --- src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 8e41709..c510d8e 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -8,7 +8,7 @@ interface BinTree, V, Node_T : TreeNode> : Itera fun add(key: K, value: V): V? - fun search(key: K): Node_T? { + fun findByKey(key: K): Node_T? { var curNode = root while (curNode != null) curNode = when { From 3565aedd883672528f1e3d7d868748af6fc394d2 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Thu, 28 Mar 2024 15:57:26 +0300 Subject: [PATCH 080/186] refactor(avl): add methods for big rotations, modifying balance method --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 24 +++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 91a145d..1f6805f 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -83,6 +83,24 @@ class AVLTree, V> : BinTree> { } } + private fun bigRotateLeft(nodeA: AVLNode?) { + if (nodeA != null) { + rotateRight(nodeA.right) + rotateLeft(nodeA) + } else { + throw NullPointerException("Node cannot be null.") + } + } + + private fun bigRotateRight(nodeA: AVLNode?) { + if (nodeA != null) { + rotateLeft(nodeA.left) + rotateRight(nodeA) + } else { + throw NullPointerException("Node cannot be null.") + } + } + private fun height(node: AVLNode?) : Int { if (node == null) { return 0 @@ -114,7 +132,8 @@ class AVLTree, V> : BinTree> { if (balanceFactor(node) == 2) { if (node != null) { if (balanceFactor(node.right) < 0) { - node.right?.let { rotateRight(it) } + bigRotateLeft(node) + } else { rotateLeft(node) } } @@ -122,7 +141,8 @@ class AVLTree, V> : BinTree> { if (balanceFactor(node) == -2) { if (node != null) { if (balanceFactor(node.left) > 0) { - node.left?.let { rotateLeft(it) } + bigRotateRight(node) + } else { rotateRight(node) } } From 02bbd99cd64518dbc864762f7f96089a110023c9 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Thu, 28 Mar 2024 16:40:08 +0300 Subject: [PATCH 081/186] refactor: methods attach and moveOn no longer in the TreeNode --- src/main/kotlin/treeLib/nodes/AVLNode.kt | 8 -------- src/main/kotlin/treeLib/nodes/RBNode.kt | 4 ++-- src/main/kotlin/treeLib/nodes/TreeNode.kt | 4 ---- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/treeLib/nodes/AVLNode.kt b/src/main/kotlin/treeLib/nodes/AVLNode.kt index 8de63cd..2226ea8 100644 --- a/src/main/kotlin/treeLib/nodes/AVLNode.kt +++ b/src/main/kotlin/treeLib/nodes/AVLNode.kt @@ -7,12 +7,4 @@ class AVLNode, V>( left: AVLNode? = null ) : TreeNode>(key, value, right, left) { internal var height: Int = 1 - - override fun attach(node: AVLNode?): Boolean { - TODO("Not yet implemented") - } - - override fun moveOn(otherKey: K): AVLNode? { - TODO("Not yet implemented") - } } diff --git a/src/main/kotlin/treeLib/nodes/RBNode.kt b/src/main/kotlin/treeLib/nodes/RBNode.kt index ca135af..6483b2f 100644 --- a/src/main/kotlin/treeLib/nodes/RBNode.kt +++ b/src/main/kotlin/treeLib/nodes/RBNode.kt @@ -7,7 +7,7 @@ class RBNode, V>( left: RBNode? = null, var isRed: Boolean = true, ) : TreeNode>(key, value, right, left) { - override fun attach(node: RBNode?): Boolean { + fun attach(node: RBNode?): Boolean { if (node == null) return false when { this > node -> left = node @@ -17,7 +17,7 @@ class RBNode, V>( return true } - override fun moveOn(otherKey: K) = when { + fun moveOn(otherKey: K) = when { key > otherKey -> left key < otherKey -> right else -> this diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index 986cc39..06d0592 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -15,8 +15,4 @@ abstract class TreeNode, V, Node_T : TreeNode>( val node = other as? Node_T return (node != null) && (Pair(key, value) == Pair(node.key, node.value)) } - - abstract fun attach(node: Node_T?): Boolean - - abstract fun moveOn(otherKey: K): Node_T? } From 1a179d0c99f58566b645d0fa8d9349c6c5b826a8 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Thu, 28 Mar 2024 16:42:03 +0300 Subject: [PATCH 082/186] refactor(bst node): cleanup --- src/main/kotlin/treeLib/nodes/BSTNode.kt | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/main/kotlin/treeLib/nodes/BSTNode.kt b/src/main/kotlin/treeLib/nodes/BSTNode.kt index 773c5ce..6ae4353 100644 --- a/src/main/kotlin/treeLib/nodes/BSTNode.kt +++ b/src/main/kotlin/treeLib/nodes/BSTNode.kt @@ -5,14 +5,4 @@ class BSTNode, V>( value: V, right: BSTNode? = null, left: BSTNode? = null -) : TreeNode>(key, value, right, left) { - internal var parent: AVLNode? = null - internal var height: Int = 1 - override fun attach(node: BSTNode?): Boolean { - TODO("Not yet implemented") - } - - override fun moveOn(otherKey: K): BSTNode? { - TODO("Not yet implemented") - } -} \ No newline at end of file +) : TreeNode>(key, value, right, left) \ No newline at end of file From f25fde9edc9aab502e6f892fc596aff8186fe9e6 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Thu, 28 Mar 2024 17:06:33 +0300 Subject: [PATCH 083/186] fix: change visibility modifier --- src/main/kotlin/treeLib/nodes/RBNode.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/treeLib/nodes/RBNode.kt b/src/main/kotlin/treeLib/nodes/RBNode.kt index 6483b2f..79c0840 100644 --- a/src/main/kotlin/treeLib/nodes/RBNode.kt +++ b/src/main/kotlin/treeLib/nodes/RBNode.kt @@ -7,7 +7,7 @@ class RBNode, V>( left: RBNode? = null, var isRed: Boolean = true, ) : TreeNode>(key, value, right, left) { - fun attach(node: RBNode?): Boolean { + internal fun attach(node: RBNode?): Boolean { if (node == null) return false when { this > node -> left = node @@ -17,7 +17,7 @@ class RBNode, V>( return true } - fun moveOn(otherKey: K) = when { + internal fun moveOn(otherKey: K) = when { key > otherKey -> left key < otherKey -> right else -> this From 03e82d63a69cb7c71c19837dd4bd36b84b486528 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Thu, 28 Mar 2024 17:35:01 +0300 Subject: [PATCH 084/186] feat: add fun changeVal() --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 16 ++++------------ .../treeLib/bintrees/interfaces/BinTree.kt | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index 83e9a93..b50a503 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -14,9 +14,8 @@ class RBTree, V> : BinTree>, TreeBalancer>() @@ -28,14 +27,7 @@ class RBTree, V> : BinTree>, TreeBalancer, V> : BinTree>, TreeBalancer, V, Node_T : TreeNode> : Itera return null } + fun changeVal(key: K, newValue: V): V? { + var curNode = root + while (curNode != null) + curNode = when { + key > curNode.key -> curNode.right + key < curNode.key -> curNode.left + else -> { + curNode.value = newValue + return newValue + } + } + return null + } + fun max(): Pair? { var curNode = root while (curNode?.right != null) From 458336cc411d69ddc091b07e6dd5048801b92872 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Thu, 28 Mar 2024 18:01:47 +0300 Subject: [PATCH 085/186] feat: add fun preOrderIterator() and postOrderIterator() --- .../treeLib/bintrees/interfaces/BinTree.kt | 9 ++++- .../bintrees/interfaces/IterationOrder.kt | 5 +++ .../bintrees/interfaces/TreeIterator.kt | 36 ++++++++++++++++--- 3 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 src/main/kotlin/treeLib/bintrees/interfaces/IterationOrder.kt diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 1fb59f9..35293a9 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -55,5 +55,12 @@ interface BinTree, V, Node_T : TreeNode> : Itera fun countNodes(): Int = amountOfNodes - override fun iterator(): Iterator> = TreeIterator(root) + /** + * basic In-order iterator + */ + override fun iterator(): Iterator> = TreeIterator(root, IterationOrder.IN_ORDER) + + fun preOrderIterator(): Iterator> = TreeIterator(root, IterationOrder.PRE_ORDER) + + fun postOrderIterator(): Iterator> = TreeIterator(root, IterationOrder.POST_ORDER) } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/IterationOrder.kt b/src/main/kotlin/treeLib/bintrees/interfaces/IterationOrder.kt new file mode 100644 index 0000000..9d8b151 --- /dev/null +++ b/src/main/kotlin/treeLib/bintrees/interfaces/IterationOrder.kt @@ -0,0 +1,5 @@ +package treeLib.bintrees.interfaces + +enum class IterationOrder { + IN_ORDER, PRE_ORDER, POST_ORDER, +} \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt index 33fb893..c6d061e 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt @@ -2,20 +2,46 @@ package treeLib.bintrees.interfaces import treeLib.nodes.TreeNode -class TreeIterator, V, Node_T : TreeNode>(private val root: Node_T?) : - Iterator> { +class TreeIterator, V, Node_T : TreeNode>( + private val root: Node_T?, + private val order: IterationOrder, + ): Iterator> { private val stack: ArrayDeque = ArrayDeque() init { root?.let { treeToStack(root) } } - private fun treeToStack(curNode: Node_T) { + private fun treeToStack(start: Node_T) { + when (order) { + IterationOrder.IN_ORDER -> inOrder(start) + IterationOrder.PRE_ORDER -> preOrder(start) + IterationOrder.POST_ORDER -> postOrder(start) + } + } + + private fun inOrder(curNode: Node_T) { + val leftNode = curNode.left + val rightNode = curNode.right + leftNode?.let { inOrder(leftNode) } + stack.add(curNode) + rightNode?.let { inOrder(rightNode) } + } + + private fun preOrder(curNode: Node_T) { + val leftNode = curNode.left + val rightNode = curNode.right + stack.add(curNode) + leftNode?.let { preOrder(leftNode) } + rightNode?.let { preOrder(rightNode) } + } + + private fun postOrder(curNode: Node_T) { val leftNode = curNode.left val rightNode = curNode.right - leftNode?.let { treeToStack(leftNode) } + leftNode?.let { postOrder(leftNode) } + rightNode?.let { postOrder(rightNode) } stack.add(curNode) - rightNode?.let { treeToStack(rightNode) } } override fun hasNext() = stack.isNotEmpty() From 49f5ee3630c6ad3cbc980f276771edb0ae638e00 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Thu, 28 Mar 2024 19:18:08 +0300 Subject: [PATCH 086/186] fix(avl): from now on tree balances properly --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 70 ++++++--------------- 1 file changed, 19 insertions(+), 51 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 1f6805f..68db47d 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -10,33 +10,18 @@ class AVLTree, V> : BinTree> { set(value) {} override fun add(key: K, value: V): V? { - var node: AVLNode? = null - var curr = root - var toReturn: V? = null - while (curr != null) { - node = curr - if (key < curr.key) { - curr = curr.left - } else { - curr = curr.right + fun addRec(node: AVLNode?, key: K, value: V): AVLNode? { + if (node == null) { + return AVLNode(key, value) } - } - if (node == null) { - root = AVLNode(key, value) - } else { if (key < node.key) { - node.left = AVLNode(key, value) + node.left = addRec(node.left, key, value) } else if (key > node.key) { - node.right = AVLNode(key, value) - } else { - toReturn = node.value - node.value = value + node.right = addRec(node.right, key, value) } + return balanceNode(node) } - - balanceNode(node) - - return toReturn + return addRec(root, key, value)?.value } fun initTree(data: List>): AVLTree { @@ -51,7 +36,7 @@ class AVLTree, V> : BinTree> { return tree } - private fun rotateLeft(nodeA: AVLNode?) { + private fun rotateLeft(nodeA: AVLNode?) : AVLNode? { if (nodeA != null) { if ((nodeA.right) != null) { val nodeB = nodeA.right @@ -59,6 +44,7 @@ class AVLTree, V> : BinTree> { nodeB?.left = nodeA fixHeight(nodeA) fixHeight(nodeB) + return nodeB } else { throw NullPointerException("Right child node cannot be null.") } @@ -67,7 +53,7 @@ class AVLTree, V> : BinTree> { } } - private fun rotateRight(nodeA: AVLNode?) { + private fun rotateRight(nodeA: AVLNode?) : AVLNode? { if (nodeA != null) { if ((nodeA.left) != null) { val nodeB = nodeA.left @@ -75,6 +61,7 @@ class AVLTree, V> : BinTree> { nodeB?.right = nodeA fixHeight(nodeA) fixHeight(nodeB) + return nodeB } else { throw NullPointerException("Left child node cannot be null.") } @@ -83,24 +70,6 @@ class AVLTree, V> : BinTree> { } } - private fun bigRotateLeft(nodeA: AVLNode?) { - if (nodeA != null) { - rotateRight(nodeA.right) - rotateLeft(nodeA) - } else { - throw NullPointerException("Node cannot be null.") - } - } - - private fun bigRotateRight(nodeA: AVLNode?) { - if (nodeA != null) { - rotateLeft(nodeA.left) - rotateRight(nodeA) - } else { - throw NullPointerException("Node cannot be null.") - } - } - private fun height(node: AVLNode?) : Int { if (node == null) { return 0 @@ -117,8 +86,8 @@ class AVLTree, V> : BinTree> { private fun fixHeight(node: AVLNode?) { if (node != null) { - var heightLeft = height(node.left) - var heightRight = height(node.right) + val heightLeft = height(node.left) + val heightRight = height(node.right) if (heightLeft > heightRight) { node.height = heightLeft + 1 } else { @@ -127,26 +96,25 @@ class AVLTree, V> : BinTree> { } } - private fun balanceNode(node: AVLNode?) { + private fun balanceNode(node: AVLNode?) : AVLNode? { fixHeight(node) if (balanceFactor(node) == 2) { if (node != null) { if (balanceFactor(node.right) < 0) { - bigRotateLeft(node) - } else { - rotateLeft(node) + node.right = rotateRight(node.right) } + return rotateLeft(node) } } if (balanceFactor(node) == -2) { if (node != null) { if (balanceFactor(node.left) > 0) { - bigRotateRight(node) - } else { - rotateRight(node) + node.left = rotateLeft(node.left) } + return rotateRight(node) } } + return node } } \ No newline at end of file From 0000931b1692b1ca2703ecf622f62aacf1a2b6b4 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Thu, 28 Mar 2024 19:24:04 +0300 Subject: [PATCH 087/186] feat(avl): now tree can return amount of stored nodes --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 6 +++--- src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 68db47d..f3d39a8 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -5,9 +5,7 @@ import treeLib.nodes.AVLNode class AVLTree, V> : BinTree> { override var root: AVLNode? = null - override var amountOfNodes: Int - get() = TODO("Not yet implemented") - set(value) {} + override var amountOfNodes = 0 override fun add(key: K, value: V): V? { fun addRec(node: AVLNode?, key: K, value: V): AVLNode? { @@ -29,8 +27,10 @@ class AVLTree, V> : BinTree> { for (element in data) { if (tree.root == null) { tree.root = AVLNode(element.first, element.second) + amountOfNodes = 1 } else { tree.add(element.first, element.second) + amountOfNodes += 1 } } return tree diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index c510d8e..388349a 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -19,6 +19,8 @@ interface BinTree, V, Node_T : TreeNode> : Itera return null } + + fun max(): Pair? { var curNode = root while (curNode?.right != null) @@ -39,7 +41,9 @@ interface BinTree, V, Node_T : TreeNode> : Itera root?.let { root = null } } - fun countNodes(): Int = amountOfNodes + fun countNodes(): Int { + return amountOfNodes + } override fun iterator(): Iterator> = TreeIterator(root) } From f76eec7e649c39a920db483c804884933a6ea105 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Thu, 28 Mar 2024 20:07:09 +0300 Subject: [PATCH 088/186] feat(avl): remove method available * avl tree remains balanced * you cant remove root --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 41 +++++++++++++++++++ .../treeLib/bintrees/interfaces/BinTree.kt | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index f3d39a8..f883362 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -7,6 +7,47 @@ class AVLTree, V> : BinTree> { override var root: AVLNode? = null override var amountOfNodes = 0 + override fun remove(key: K): V? { + var value : V? = null + fun removeRec(node: AVLNode?, key: K) : AVLNode? { + if (node == null) return null + if (key < node.key) { + node.left = removeRec(node.left, key) + } else if (key > node.key) { + node.right = removeRec(node.right, key) + } else { + val nodeA = node.left + val nodeB = node.right + value = node.value + if (nodeB == null) { + return nodeA + } + val min = findMin(nodeB) + min?.right = removeMin(nodeB) + min?.left = nodeA + return balanceNode(min) + } + return balanceNode(node) + } + removeRec(root, key) + return value + } + + private fun findMin(node: AVLNode?): AVLNode? { + if (node?.left != null) { + return findMin(node.left) + } + return (node) + } + + private fun removeMin(node: AVLNode?) : AVLNode? { + if (node?.left == null) { + return node?.right + } + node.left = removeMin(node.left) + return balanceNode(node) + } + override fun add(key: K, value: V): V? { fun addRec(node: AVLNode?, key: K, value: V): AVLNode? { if (node == null) { diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 388349a..0d8f607 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -19,7 +19,7 @@ interface BinTree, V, Node_T : TreeNode> : Itera return null } - + fun remove(key: K): V? fun max(): Pair? { var curNode = root From e2332ee64949988f149bb3bbc25af951ba9b52ff Mon Sep 17 00:00:00 2001 From: Islam Date: Fri, 29 Mar 2024 12:03:10 +0300 Subject: [PATCH 089/186] feat and fix: add BSTree and deleted unnecessary code Added BSTree, deleted attach() and moveOn() in TreeNode.kt, also there I change val to var (key), added height and hiddenHeight methods in BinTree.kt that counts height of tree --- src/main/kotlin/treeLib/bintrees/BSTree.kt | 109 ++++++++++++++++-- .../treeLib/bintrees/interfaces/BinTree.kt | 16 +++ src/main/kotlin/treeLib/nodes/AVLNode.kt | 9 +- src/main/kotlin/treeLib/nodes/BSTNode.kt | 10 +- src/main/kotlin/treeLib/nodes/TreeNode.kt | 6 +- 5 files changed, 118 insertions(+), 32 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index b4c8719..31e106e 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -4,14 +4,101 @@ import treeLib.bintrees.interfaces.BinTree import treeLib.nodes.BSTNode class BSTree, V> : BinTree> { - override fun add(key: K, value: V): V? { - TODO("Not yet implemented") - } - - override var root: BSTNode? - get() = TODO("Not yet implemented") - set(value) {} - override var amountOfNodes: Int - get() = TODO("Not yet implemented") - set(value) {} -} \ No newline at end of file + override var root: BSTNode? = null + override var amountOfNodes = 1 + + + fun addPairs(keys: List, values: List): Boolean{ + if(keys.size != values.size) return false + for(i in keys.indices){ + this.add(keys[i], values[i]) + } + return true + } + + override fun add(key: K, value: V): V? { + if(root == null) root = BSTNode(key, value) + var x = this.root + while(x != null){ + if(key > x.key){ + if(x.right == null){ + x.right = BSTNode(key, value) + break + } + x = x.right + } + else if(key < x.key){ + if(x.left == null){ + x.left = BSTNode(key, value) + break + } + x = x.left + } + else return null + } + this.amountOfNodes += 1 + return value + } + + override fun remove(key: K): V? { + var x: BSTNode? = root + var parent_x: BSTNode? = null + var count = 0 + while(x != null){ + if(key == x.key){ + break + } + parent_x = x + x = if(key > x.key){ + x.right + } else{ + x.left + } + } + if(x == null || parent_x == null) return null + if(x.right != null) count++ + if(x.left != null) count++ + if(count == 0){ + if(parent_x.right === x) parent_x.right = null + else parent_x.left = null + } + else if(count == 1){ + if(x.left == null){ + if(parent_x.right === x) parent_x.right = x.right + else parent_x.left = x.right + } + else{ + if(parent_x.right === x) parent_x.right = x.left + else parent_x.left = x.left + } + } + else{ + var child_x = x.right + var parent_child_x = x + while(child_x!!.left != null){ + if(child_x.left!!.left == null) parent_child_x = child_x + child_x = child_x.left + } + x.key = child_x.key + x.value = child_x.value + parent_child_x!!.left = child_x.right + } + this.amountOfNodes -= 1 + return null + } + + + fun changeVal(key: K, newValue: V): Boolean { + var x = root + while(x != null){ + x = if(key > x.key) x.right + else if(key < x.key) x.left + else{ + x.value = newValue + return true + } + } + return false + } +} + diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 8e41709..632adea 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -1,6 +1,8 @@ package treeLib.bintrees.interfaces +import treeLib.nodes.BSTNode import treeLib.nodes.TreeNode +import kotlin.math.max interface BinTree, V, Node_T : TreeNode> : Iterable> { var root: Node_T? @@ -8,6 +10,8 @@ interface BinTree, V, Node_T : TreeNode> : Itera fun add(key: K, value: V): V? + fun remove(key: K): V? + fun search(key: K): Node_T? { var curNode = root while (curNode != null) @@ -42,4 +46,16 @@ interface BinTree, V, Node_T : TreeNode> : Itera fun countNodes(): Int = amountOfNodes override fun iterator(): Iterator> = TreeIterator(root) + + private fun hiddenHeight(tNode: Node_T?): Int { + if(tNode == null) return 0 + val lf = hiddenHeight(tNode.left) + val rg = hiddenHeight(tNode.right) + return max(lf, rg) + 1 + } + + fun height(): Int { + return hiddenHeight(root) + } } + diff --git a/src/main/kotlin/treeLib/nodes/AVLNode.kt b/src/main/kotlin/treeLib/nodes/AVLNode.kt index 0acacff..fd7a9d2 100644 --- a/src/main/kotlin/treeLib/nodes/AVLNode.kt +++ b/src/main/kotlin/treeLib/nodes/AVLNode.kt @@ -8,11 +8,4 @@ class AVLNode, V>( ) : TreeNode>(key, value, right, left) { internal var parent: AVLNode? = null internal var height: Int = 1 - override fun attach(node: AVLNode?): Boolean { - TODO("Not yet implemented") - } - - override fun moveOn(otherKey: K): AVLNode? { - TODO("Not yet implemented") - } -} \ No newline at end of file +} diff --git a/src/main/kotlin/treeLib/nodes/BSTNode.kt b/src/main/kotlin/treeLib/nodes/BSTNode.kt index 773c5ce..ebc9d9a 100644 --- a/src/main/kotlin/treeLib/nodes/BSTNode.kt +++ b/src/main/kotlin/treeLib/nodes/BSTNode.kt @@ -7,12 +7,4 @@ class BSTNode, V>( left: BSTNode? = null ) : TreeNode>(key, value, right, left) { internal var parent: AVLNode? = null - internal var height: Int = 1 - override fun attach(node: BSTNode?): Boolean { - TODO("Not yet implemented") - } - - override fun moveOn(otherKey: K): BSTNode? { - TODO("Not yet implemented") - } -} \ No newline at end of file +} diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index 986cc39..f3cfc86 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -1,7 +1,7 @@ package treeLib.nodes abstract class TreeNode, V, Node_T : TreeNode>( - internal val key: K, + internal var key: K, internal var value: V, internal var right: Node_T? = null, internal var left: Node_T? = null, @@ -16,7 +16,5 @@ abstract class TreeNode, V, Node_T : TreeNode>( return (node != null) && (Pair(key, value) == Pair(node.key, node.value)) } - abstract fun attach(node: Node_T?): Boolean - - abstract fun moveOn(otherKey: K): Node_T? } + From 862c3b51fa19ffc091f378f908e64b94c5b8aa42 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sat, 30 Mar 2024 14:48:59 +0300 Subject: [PATCH 090/186] feat: add fun remove() and balancerRemove() --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 97 +++++++++++++++++++--- 1 file changed, 85 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index b50a503..0cc1e86 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -110,28 +110,101 @@ class RBTree, V> : BinTree>, TreeBalancer>() var curNode = root - while (curNode != null) { + + while (curNode != null && curNode.key != key) { treeBranch.addFirst(curNode) - val nextNode = curNode.moveOn(key) - if (nextNode === curNode) { //remove - val parent = treeBranch.first() + curNode = curNode.moveOn(key) + } + + if (curNode == null) return null //node with given key isn't exist + + val parent = treeBranch.first() + when { + curNode == parent.right -> { + when { + curNode.left != null && curNode.right != null -> { + var newNode = curNode.right + while (newNode?.left?.left != null) newNode = newNode.left + parent.right = newNode?.left + newNode?.left = null + } + else -> parent.right = if (curNode.right != null) curNode.right else curNode.left + } + } + curNode == parent.left -> { when { - curNode.left != null && curNode.right != null -> TODO() - curNode.left != null -> TODO("replace nodes") - curNode.right != null -> TODO("replace nodes") - else -> TODO("удалить у родителя указатель") + curNode.right != null && curNode.left != null -> { + var newNode = curNode.right + while (newNode?.left?.left != null) newNode = newNode.left + parent.left = newNode?.left + newNode?.left = null + } + else -> parent.left = if (curNode.right != null) curNode.right else curNode.left } - balancerRemove(treeBranch) - return curNode.value } + else -> throw Exception("Node without a parent. What a tragedy.") } - return null + amountOfNodes-- + //treeBranch.addFirst(newNode) + balancerRemove(treeBranch) + return curNode?.value } /** * Used in remove() method to balance tree :( */ override fun balancerRemove(treeBranch: ArrayDeque>) { - TODO("Not yet implemented") + val son = treeBranch.removeFirstOrNull() + val parent = treeBranch.removeFirstOrNull() + + while (son?.isRed == false) { + if (son === parent?.right) { + val brother = parent.left + if (brother?.isRed == true) { + brother.isRed = false + parent.isRed = true + rotateLeft(parent, treeBranch.firstOrNull()) + } + val nephewRight = brother?.right + val nephewLeft = brother?.left + if (nephewRight?.isRed == false && nephewLeft?.isRed == false) { + brother.isRed = true + } else { + if (nephewRight?.isRed == false) { + brother.isRed = true + nephewLeft?.isRed = false + rotateRight(brother, parent) + } + brother?.isRed = parent.isRed + parent.isRed = false + nephewRight?.isRed = false + rotateLeft(parent, treeBranch.firstOrNull()) + return + } + } else if (son === parent?.left) { + val brother = parent.right + if (brother?.isRed == true) { + brother.isRed = false + parent.isRed = true + rotateRight(parent, treeBranch.firstOrNull()) + } + val nephewRight = brother?.right + val nephewLeft = brother?.left + if (nephewRight?.isRed == false && nephewLeft?.isRed == false) { + brother.isRed = true + } else { + if (nephewLeft?.isRed == false) { + brother.isRed = true + nephewRight?.isRed = false + rotateLeft(brother, parent) + } + brother?.isRed = parent.isRed + parent.isRed = false + nephewLeft?.isRed = false + rotateRight(parent, treeBranch.firstOrNull()) + return + } + } + } } } \ No newline at end of file From 86b5989664163e109e27232d3568ebdb6482fbee Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Sat, 30 Mar 2024 16:39:21 +0300 Subject: [PATCH 091/186] refactor: rename helper method for height method --- src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 78322de..0e3fa1b 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -47,14 +47,14 @@ interface BinTree, V, Node_T : TreeNode> : Itera override fun iterator(): Iterator> = TreeIterator(root) - private fun hiddenHeight(tNode: Node_T?): Int { + private fun countHeight(tNode: Node_T?): Int { if(tNode == null) return 0 - val lf = hiddenHeight(tNode.left) - val rg = hiddenHeight(tNode.right) + val lf = countHeight(tNode.left) + val rg = countHeight(tNode.right) return kotlin.math.max(lf, rg) + 1 } - fun height(): Int { - return hiddenHeight(root) + fun height(): Int? { + return countHeight(root) } } From 20ea3c493b18f6fe113a48c33f313cf3d381f5d0 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Sat, 30 Mar 2024 16:40:19 +0300 Subject: [PATCH 092/186] refactor (avl): implement more efficient height method for abl tree --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index f883362..d507547 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -158,4 +158,11 @@ class AVLTree, V> : BinTree> { return node } + override fun height(): Int? { + if (root == null) { + return 0 + } else { + return root?.height + } + } } \ No newline at end of file From 19f5d379f10ba75209bcba2316e531f6ef408bde Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Sat, 30 Mar 2024 16:40:44 +0300 Subject: [PATCH 093/186] fix: small compatibility changes --- src/main/kotlin/treeLib/bintrees/BSTree.kt | 181 ++++++++++----------- src/main/kotlin/treeLib/bintrees/RBTree.kt | 2 +- src/main/kotlin/treeLib/nodes/TreeNode.kt | 2 +- 3 files changed, 92 insertions(+), 93 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 31e106e..14eac98 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -5,100 +5,99 @@ import treeLib.nodes.BSTNode class BSTree, V> : BinTree> { override var root: BSTNode? = null - override var amountOfNodes = 1 + override var amountOfNodes = 1 - fun addPairs(keys: List, values: List): Boolean{ - if(keys.size != values.size) return false - for(i in keys.indices){ - this.add(keys[i], values[i]) - } - return true - } + fun addPairs(keys: List, values: List): Boolean{ + if(keys.size != values.size) return false + for(i in keys.indices){ + this.add(keys[i], values[i]) + } + return true + } - override fun add(key: K, value: V): V? { - if(root == null) root = BSTNode(key, value) - var x = this.root - while(x != null){ - if(key > x.key){ - if(x.right == null){ - x.right = BSTNode(key, value) - break - } - x = x.right - } - else if(key < x.key){ - if(x.left == null){ - x.left = BSTNode(key, value) - break - } - x = x.left - } - else return null - } - this.amountOfNodes += 1 - return value - } + override fun add(key: K, value: V): V? { + if(root == null) root = BSTNode(key, value) + var x = this.root + while(x != null){ + if(key > x.key){ + if(x.right == null){ + x.right = BSTNode(key, value) + break + } + x = x.right + } + else if(key < x.key){ + if(x.left == null){ + x.left = BSTNode(key, value) + break + } + x = x.left + } + else return null + } + this.amountOfNodes += 1 + return value + } - override fun remove(key: K): V? { - var x: BSTNode? = root - var parent_x: BSTNode? = null - var count = 0 - while(x != null){ - if(key == x.key){ - break - } - parent_x = x - x = if(key > x.key){ - x.right - } else{ - x.left - } - } - if(x == null || parent_x == null) return null - if(x.right != null) count++ - if(x.left != null) count++ - if(count == 0){ - if(parent_x.right === x) parent_x.right = null - else parent_x.left = null - } - else if(count == 1){ - if(x.left == null){ - if(parent_x.right === x) parent_x.right = x.right - else parent_x.left = x.right - } - else{ - if(parent_x.right === x) parent_x.right = x.left - else parent_x.left = x.left - } - } - else{ - var child_x = x.right - var parent_child_x = x - while(child_x!!.left != null){ - if(child_x.left!!.left == null) parent_child_x = child_x - child_x = child_x.left - } - x.key = child_x.key - x.value = child_x.value - parent_child_x!!.left = child_x.right - } - this.amountOfNodes -= 1 - return null - } + override fun remove(key: K): V? { + var x: BSTNode? = root + var parent_x: BSTNode? = null + var count = 0 + while(x != null){ + if(key == x.key){ + break + } + parent_x = x + x = if(key > x.key){ + x.right + } else{ + x.left + } + } + if(x == null || parent_x == null) return null + if(x.right != null) count++ + if(x.left != null) count++ + if(count == 0){ + if(parent_x.right === x) parent_x.right = null + else parent_x.left = null + } + else if(count == 1){ + if(x.left == null){ + if(parent_x.right === x) parent_x.right = x.right + else parent_x.left = x.right + } + else{ + if(parent_x.right === x) parent_x.right = x.left + else parent_x.left = x.left + } + } + else{ + var child_x = x.right + var parent_child_x = x + while(child_x!!.left != null){ + if(child_x.left!!.left == null) parent_child_x = child_x + child_x = child_x.left + } + x.key = child_x.key + x.value = child_x.value + parent_child_x!!.left = child_x.right + } + this.amountOfNodes -= 1 + return null + } - fun changeVal(key: K, newValue: V): Boolean { - var x = root - while(x != null){ - x = if(key > x.key) x.right - else if(key < x.key) x.left - else{ - x.value = newValue - return true - } - } - return false - } -} - + fun changeVal(key: K, newValue: V): Boolean { + var x = root + while(x != null){ + x = if(key > x.key) x.right + else if(key < x.key) x.left + else{ + x.value = newValue + return true + } + } + return false + } +} \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index 83e9a93..9d74a55 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -115,7 +115,7 @@ class RBTree, V> : BinTree>, TreeBalancer>() var curNode = root while (curNode != null) { diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index 06d0592..b21a357 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -1,7 +1,7 @@ package treeLib.nodes abstract class TreeNode, V, Node_T : TreeNode>( - internal val key: K, + internal var key: K, internal var value: V, internal var right: Node_T? = null, internal var left: Node_T? = null, From 3f5d8b258b95a36c51b8ea392d69c0cd254f8d41 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Sat, 30 Mar 2024 16:50:39 +0300 Subject: [PATCH 094/186] reformat: auto code reformat --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 16 ++--- src/main/kotlin/treeLib/bintrees/BSTree.kt | 69 +++++++++---------- src/main/kotlin/treeLib/bintrees/RBTree.kt | 2 +- .../treeLib/bintrees/interfaces/BinTree.kt | 2 +- 4 files changed, 42 insertions(+), 47 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index d507547..26e558b 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -8,8 +8,8 @@ class AVLTree, V> : BinTree> { override var amountOfNodes = 0 override fun remove(key: K): V? { - var value : V? = null - fun removeRec(node: AVLNode?, key: K) : AVLNode? { + var value: V? = null + fun removeRec(node: AVLNode?, key: K): AVLNode? { if (node == null) return null if (key < node.key) { node.left = removeRec(node.left, key) @@ -40,7 +40,7 @@ class AVLTree, V> : BinTree> { return (node) } - private fun removeMin(node: AVLNode?) : AVLNode? { + private fun removeMin(node: AVLNode?): AVLNode? { if (node?.left == null) { return node?.right } @@ -77,7 +77,7 @@ class AVLTree, V> : BinTree> { return tree } - private fun rotateLeft(nodeA: AVLNode?) : AVLNode? { + private fun rotateLeft(nodeA: AVLNode?): AVLNode? { if (nodeA != null) { if ((nodeA.right) != null) { val nodeB = nodeA.right @@ -94,7 +94,7 @@ class AVLTree, V> : BinTree> { } } - private fun rotateRight(nodeA: AVLNode?) : AVLNode? { + private fun rotateRight(nodeA: AVLNode?): AVLNode? { if (nodeA != null) { if ((nodeA.left) != null) { val nodeB = nodeA.left @@ -111,14 +111,14 @@ class AVLTree, V> : BinTree> { } } - private fun height(node: AVLNode?) : Int { + private fun height(node: AVLNode?): Int { if (node == null) { return 0 } return node.height } - private fun balanceFactor(node: AVLNode?) : Int { + private fun balanceFactor(node: AVLNode?): Int { if (node == null) { throw NullPointerException("Node cannot be null.") } @@ -137,7 +137,7 @@ class AVLTree, V> : BinTree> { } } - private fun balanceNode(node: AVLNode?) : AVLNode? { + private fun balanceNode(node: AVLNode?): AVLNode? { fixHeight(node) if (balanceFactor(node) == 2) { if (node != null) { diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 14eac98..2351fe0 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -5,36 +5,34 @@ import treeLib.nodes.BSTNode class BSTree, V> : BinTree> { override var root: BSTNode? = null - override var amountOfNodes = 1 + override var amountOfNodes = 1 - fun addPairs(keys: List, values: List): Boolean{ - if(keys.size != values.size) return false - for(i in keys.indices){ + fun addPairs(keys: List, values: List): Boolean { + if (keys.size != values.size) return false + for (i in keys.indices) { this.add(keys[i], values[i]) } return true } override fun add(key: K, value: V): V? { - if(root == null) root = BSTNode(key, value) + if (root == null) root = BSTNode(key, value) var x = this.root - while(x != null){ - if(key > x.key){ - if(x.right == null){ + while (x != null) { + if (key > x.key) { + if (x.right == null) { x.right = BSTNode(key, value) break } x = x.right - } - else if(key < x.key){ - if(x.left == null){ + } else if (key < x.key) { + if (x.left == null) { x.left = BSTNode(key, value) break } x = x.left - } - else return null + } else return null } this.amountOfNodes += 1 return value @@ -44,39 +42,36 @@ class BSTree, V> : BinTree> { var x: BSTNode? = root var parent_x: BSTNode? = null var count = 0 - while(x != null){ - if(key == x.key){ + while (x != null) { + if (key == x.key) { break } parent_x = x - x = if(key > x.key){ + x = if (key > x.key) { x.right - } else{ + } else { x.left } } - if(x == null || parent_x == null) return null - if(x.right != null) count++ - if(x.left != null) count++ - if(count == 0){ - if(parent_x.right === x) parent_x.right = null + if (x == null || parent_x == null) return null + if (x.right != null) count++ + if (x.left != null) count++ + if (count == 0) { + if (parent_x.right === x) parent_x.right = null else parent_x.left = null - } - else if(count == 1){ - if(x.left == null){ - if(parent_x.right === x) parent_x.right = x.right + } else if (count == 1) { + if (x.left == null) { + if (parent_x.right === x) parent_x.right = x.right else parent_x.left = x.right - } - else{ - if(parent_x.right === x) parent_x.right = x.left + } else { + if (parent_x.right === x) parent_x.right = x.left else parent_x.left = x.left } - } - else{ + } else { var child_x = x.right var parent_child_x = x - while(child_x!!.left != null){ - if(child_x.left!!.left == null) parent_child_x = child_x + while (child_x!!.left != null) { + if (child_x.left!!.left == null) parent_child_x = child_x child_x = child_x.left } x.key = child_x.key @@ -90,10 +85,10 @@ class BSTree, V> : BinTree> { fun changeVal(key: K, newValue: V): Boolean { var x = root - while(x != null){ - x = if(key > x.key) x.right - else if(key < x.key) x.left - else{ + while (x != null) { + x = if (key > x.key) x.right + else if (key < x.key) x.left + else { x.value = newValue return true } diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index 9d74a55..c6ef3ea 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -117,7 +117,7 @@ class RBTree, V> : BinTree>, TreeBalancer>() - var curNode = root + val curNode = root while (curNode != null) { treeBranch.addFirst(curNode) val nextNode = curNode.moveOn(key) diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 0e3fa1b..0f79253 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -48,7 +48,7 @@ interface BinTree, V, Node_T : TreeNode> : Itera override fun iterator(): Iterator> = TreeIterator(root) private fun countHeight(tNode: Node_T?): Int { - if(tNode == null) return 0 + if (tNode == null) return 0 val lf = countHeight(tNode.left) val rg = countHeight(tNode.right) return kotlin.math.max(lf, rg) + 1 From ed77c40e0661bef3868fd0944da6db526ab0dbd2 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sat, 30 Mar 2024 19:40:25 +0300 Subject: [PATCH 095/186] fix: expanded types for node in rotation funs --- .../kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt index 0e53a58..43ac713 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt @@ -10,7 +10,9 @@ interface TreeBalancer, V, Node_T : TreeNode> { fun balancerRemove(treeBranch: ArrayDeque>) - fun rotateRight(node: RBNode, parent: RBNode?) { + fun rotateRight(node: RBNode?, parent: RBNode?) { + if (node == null) return + val nodeLeft = node.left node.left = nodeLeft?.right nodeLeft?.right = node @@ -21,7 +23,9 @@ interface TreeBalancer, V, Node_T : TreeNode> { root = nodeLeft } - fun rotateLeft(node: RBNode, parent: RBNode?) { + fun rotateLeft(node: RBNode?, parent: RBNode?) { + if (node == null) return + val nodeRight = node.right node.right = nodeRight?.left nodeRight?.left = node From bd1a0be7817e1d8f93b2d326737b72b5028212b8 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sat, 30 Mar 2024 19:49:19 +0300 Subject: [PATCH 096/186] refactor: prettier balancerAdd() --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 78 ++++++++-------------- 1 file changed, 28 insertions(+), 50 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index 0cc1e86..e21428f 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -43,60 +43,38 @@ class RBTree, V> : BinTree>, TreeBalancer>) { - var (son, parent, grandparent) = - Triple( - treeBranch.removeFirstOrNull(), - treeBranch.removeFirstOrNull(), - treeBranch.removeFirstOrNull() - ) + var son = treeBranch.removeFirstOrNull() + var parent = treeBranch.removeFirstOrNull() + var grandparent = treeBranch.removeFirstOrNull() while (parent != null && parent.isRed) { - if (parent === grandparent?.left) { - val uncle = grandparent.right - if (uncle?.isRed == true) { - parent.isRed = false - uncle.isRed = false - grandparent.isRed = true - - son = grandparent - parent = treeBranch.removeFirstOrNull() - grandparent = treeBranch.removeFirstOrNull() - } else /*uncle == black or null*/ { - if (son === parent.right) { - son = parent - parent = grandparent - grandparent = treeBranch.removeFirst() - rotateLeft(son, parent) - } - parent.isRed = false - grandparent.isRed = true - rotateRight(grandparent, treeBranch.firstOrNull()) - } - } else if (parent === grandparent?.right) { - val uncle = grandparent.left - if (uncle?.isRed == true) { - parent.isRed = false - uncle.isRed = false - grandparent.isRed = true + val uncle = when { + parent === grandparent?.right -> grandparent.left + parent === grandparent?.left -> grandparent.right + else -> null + } - son = grandparent - parent = treeBranch.removeFirstOrNull() - grandparent = treeBranch.removeFirstOrNull() - } else /*uncle == black or null*/ { - if (son === parent.left) { - son = parent - parent = grandparent - grandparent = treeBranch.removeFirstOrNull() - rotateRight(son, parent) - } - parent.isRed = false - if (grandparent != null) {//why safe call - grandparent.isRed = true - rotateLeft(grandparent, treeBranch.firstOrNull()) - } + if (uncle?.isRed == false) { + if (parent === grandparent?.right && son === parent.left) { + rotateRight(parent, grandparent) + parent = son + son = parent?.right + } else if (parent === grandparent?.left && son === parent.right) { + rotateLeft(parent, grandparent) + parent = son + son = parent?.left } - } else /*grandparent == null*/ { + parent?.isRed = false + grandparent?.isRed = true + if (parent === grandparent?.right) rotateLeft(grandparent, treeBranch.firstOrNull()) + else if (parent === grandparent?.left) rotateRight(grandparent, treeBranch.firstOrNull()) + } else { parent.isRed = false + uncle?.isRed = false + grandparent?.isRed = true + son = grandparent + parent = treeBranch.removeFirstOrNull() + grandparent = treeBranch.removeFirstOrNull() } } @@ -147,7 +125,7 @@ class RBTree, V> : BinTree>, TreeBalancer Date: Sat, 30 Mar 2024 22:57:28 +0300 Subject: [PATCH 097/186] fix: take fun attach() and moveOn() from RBNode to TreeNode --- src/main/kotlin/treeLib/nodes/RBNode.kt | 18 +----------------- src/main/kotlin/treeLib/nodes/TreeNode.kt | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/kotlin/treeLib/nodes/RBNode.kt b/src/main/kotlin/treeLib/nodes/RBNode.kt index 79c0840..a730563 100644 --- a/src/main/kotlin/treeLib/nodes/RBNode.kt +++ b/src/main/kotlin/treeLib/nodes/RBNode.kt @@ -6,20 +6,4 @@ class RBNode, V>( right: RBNode? = null, left: RBNode? = null, var isRed: Boolean = true, -) : TreeNode>(key, value, right, left) { - internal fun attach(node: RBNode?): Boolean { - if (node == null) return false - when { - this > node -> left = node - this < node -> right = node - else -> return false - } - return true - } - - internal fun moveOn(otherKey: K) = when { - key > otherKey -> left - key < otherKey -> right - else -> this - } -} \ No newline at end of file +) : TreeNode>(key, value, right, left) \ No newline at end of file diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index 06d0592..ab99720 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -15,4 +15,20 @@ abstract class TreeNode, V, Node_T : TreeNode>( val node = other as? Node_T return (node != null) && (Pair(key, value) == Pair(node.key, node.value)) } + + internal fun attach(node: Node_T?): Boolean { + if (node == null) return false + when { + this > node -> left = node + this < node -> right = node + else -> return false + } + return true + } + + internal fun moveOn(otherKey: K) = when { + key > otherKey -> left + key < otherKey -> right + else -> this + } } From 46229ab912c916ff207bb5cbef7cedadfc9a59de Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sat, 30 Mar 2024 23:00:11 +0300 Subject: [PATCH 098/186] fix: key is var now --- src/main/kotlin/treeLib/nodes/TreeNode.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index ab99720..127353c 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -1,7 +1,7 @@ package treeLib.nodes abstract class TreeNode, V, Node_T : TreeNode>( - internal val key: K, + internal var key: K, internal var value: V, internal var right: Node_T? = null, internal var left: Node_T? = null, From 88f0ad64de2bc59b37c59e91f3387d2552d697ad Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sat, 30 Mar 2024 23:03:55 +0300 Subject: [PATCH 099/186] fix: change RBNode to Node_T --- .../treeLib/bintrees/interfaces/TreeBalancer.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt index 43ac713..b2eee51 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt @@ -1,16 +1,15 @@ package treeLib.bintrees.interfaces -import treeLib.nodes.RBNode import treeLib.nodes.TreeNode interface TreeBalancer, V, Node_T : TreeNode> { - var root: RBNode? + var root: Node_T? - fun balancerAdd(treeBranch: ArrayDeque>) + fun balancerAdd(treeBranch: ArrayDeque) - fun balancerRemove(treeBranch: ArrayDeque>) + fun balancerRemove(parent: Node_T?, removed: Node_T?) - fun rotateRight(node: RBNode?, parent: RBNode?) { + fun rotateRight(node: Node_T?, parent: Node_T?) { if (node == null) return val nodeLeft = node.left @@ -23,7 +22,7 @@ interface TreeBalancer, V, Node_T : TreeNode> { root = nodeLeft } - fun rotateLeft(node: RBNode?, parent: RBNode?) { + fun rotateLeft(node: Node_T?, parent: Node_T?) { if (node == null) return val nodeRight = node.right From 4e3bb4add4134badd6a917477f7f5a0c4890f8fc Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Sun, 31 Mar 2024 12:49:00 +0300 Subject: [PATCH 100/186] fix!: root no more public * change: BinTree is an abstract class from now on --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 2 +- src/main/kotlin/treeLib/bintrees/BSTree.kt | 2 +- src/main/kotlin/treeLib/bintrees/RBTree.kt | 2 +- .../kotlin/treeLib/bintrees/interfaces/BinTree.kt | 12 ++++++------ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 26e558b..b364474 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -3,7 +3,7 @@ package treeLib.bintrees import treeLib.bintrees.interfaces.BinTree import treeLib.nodes.AVLNode -class AVLTree, V> : BinTree> { +class AVLTree, V> : BinTree>() { override var root: AVLNode? = null override var amountOfNodes = 0 diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 2351fe0..51e6146 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -3,7 +3,7 @@ package treeLib.bintrees import treeLib.bintrees.interfaces.BinTree import treeLib.nodes.BSTNode -class BSTree, V> : BinTree> { +class BSTree, V> : BinTree>() { override var root: BSTNode? = null override var amountOfNodes = 1 diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index c6ef3ea..09af17d 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -8,7 +8,7 @@ import treeLib.nodes.RBNode * Class which implements... Red-Black Tree :O * Takes two types: for key(K) and for value(V) */ -class RBTree, V> : BinTree>, TreeBalancer> { +class RBTree, V> : BinTree>(), TreeBalancer> { override var root: RBNode? = null override var amountOfNodes: Int = 0 diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 0f79253..efcd4cc 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -2,11 +2,11 @@ package treeLib.bintrees.interfaces import treeLib.nodes.TreeNode -interface BinTree, V, Node_T : TreeNode> : Iterable> { - var root: Node_T? - var amountOfNodes: Int +abstract class BinTree, V, Node_T : TreeNode> : Iterable> { + protected abstract var root: Node_T? + protected abstract var amountOfNodes: Int - fun add(key: K, value: V): V? + abstract fun add(key: K, value: V): V? fun findByKey(key: K): Node_T? { var curNode = root @@ -19,7 +19,7 @@ interface BinTree, V, Node_T : TreeNode> : Itera return null } - fun remove(key: K): V? + abstract fun remove(key: K): V? fun max(): Pair? { var curNode = root @@ -54,7 +54,7 @@ interface BinTree, V, Node_T : TreeNode> : Itera return kotlin.math.max(lf, rg) + 1 } - fun height(): Int? { + open fun height(): Int? { return countHeight(root) } } From 580335e13f3cfcda9538af2dbca68f8924680481 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Sun, 31 Mar 2024 13:26:37 +0300 Subject: [PATCH 101/186] refactor!: add returns nod instead of the added nod's value --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 4 ++-- src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index b364474..c6ce63c 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -48,7 +48,7 @@ class AVLTree, V> : BinTree>() { return balanceNode(node) } - override fun add(key: K, value: V): V? { + override fun add(key: K, value: V): AVLNode? { fun addRec(node: AVLNode?, key: K, value: V): AVLNode? { if (node == null) { return AVLNode(key, value) @@ -60,7 +60,7 @@ class AVLTree, V> : BinTree>() { } return balanceNode(node) } - return addRec(root, key, value)?.value + return addRec(root, key, value) } fun initTree(data: List>): AVLTree { diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index efcd4cc..cabc7ff 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -6,7 +6,7 @@ abstract class BinTree, V, Node_T : TreeNode> : protected abstract var root: Node_T? protected abstract var amountOfNodes: Int - abstract fun add(key: K, value: V): V? + abstract fun add(key: K, value: V): Node_T? fun findByKey(key: K): Node_T? { var curNode = root From fb4a420ba5ddd9171e1d03703624c8a735165d70 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 31 Mar 2024 14:29:02 +0300 Subject: [PATCH 102/186] refactor: delete fun balancerAdd() and balancerRemove() --- src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt index b2eee51..814e207 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt @@ -5,10 +5,6 @@ import treeLib.nodes.TreeNode interface TreeBalancer, V, Node_T : TreeNode> { var root: Node_T? - fun balancerAdd(treeBranch: ArrayDeque) - - fun balancerRemove(parent: Node_T?, removed: Node_T?) - fun rotateRight(node: Node_T?, parent: Node_T?) { if (node == null) return From f22445f42859114eaba11d59ba37cc32b9a4cbd6 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 31 Mar 2024 14:29:56 +0300 Subject: [PATCH 103/186] fix: moveOn() return correct type --- src/main/kotlin/treeLib/nodes/TreeNode.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index 127353c..7f217ac 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -29,6 +29,6 @@ abstract class TreeNode, V, Node_T : TreeNode>( internal fun moveOn(otherKey: K) = when { key > otherKey -> left key < otherKey -> right - else -> this + else -> this as? Node_T } } From a86fe75c242c3ddfd0586d71198f7603195ebe09 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 31 Mar 2024 14:30:58 +0300 Subject: [PATCH 104/186] feat: rewrite fun remove() and balancerRemove() --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 129 +++++++++++---------- 1 file changed, 69 insertions(+), 60 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index e21428f..1226832 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -42,7 +42,7 @@ class RBTree, V> : BinTree>, TreeBalancer>) { + private fun balancerAdd(treeBranch: ArrayDeque>) { var son = treeBranch.removeFirstOrNull() var parent = treeBranch.removeFirstOrNull() var grandparent = treeBranch.removeFirstOrNull() @@ -87,102 +87,111 @@ class RBTree, V> : BinTree>, TreeBalancer>() - var curNode = root - - while (curNode != null && curNode.key != key) { - treeBranch.addFirst(curNode) - curNode = curNode.moveOn(key) + var removedNode = if (root != null) root else return null + while (removedNode?.key != key) { + if (removedNode == null) return null //node with given key doesn't exist + treeBranch.addFirst(removedNode) + removedNode = removedNode.moveOn(key) } - if (curNode == null) return null //node with given key isn't exist - - val parent = treeBranch.first() - when { - curNode == parent.right -> { - when { - curNode.left != null && curNode.right != null -> { - var newNode = curNode.right - while (newNode?.left?.left != null) newNode = newNode.left - parent.right = newNode?.left - newNode?.left = null - } - else -> parent.right = if (curNode.right != null) curNode.right else curNode.left - } - } - curNode == parent.left -> { - when { - curNode.right != null && curNode.left != null -> { - var newNode = curNode.right - while (newNode?.left?.left != null) newNode = newNode.left - parent.left = newNode?.left - newNode?.left = null - } - else -> parent.left = if (curNode.right != null) curNode.right else curNode.left + var parent = treeBranch.firstOrNull() + val sonRight = removedNode.right + val sonLeft = removedNode.left + val sonRemoved = when { + sonRight == null && sonLeft == null -> null + sonRight != null && sonLeft == null -> sonRight + sonRight == null && sonLeft != null -> sonLeft + else /*sonRight and sonLeft != null*/ -> { + val replace = removedNode //Will rewrite this node with other one + treeBranch.addFirst(replace) + removedNode = sonRight + while (removedNode?.left != null) { + treeBranch.addFirst(removedNode) + removedNode = removedNode.left } + parent = treeBranch.first() + replace.key = removedNode?.key ?: throw Exception("well...") + replace.value = removedNode?.value ?: throw Exception("that's bad") + removedNode.right } - else -> throw Exception("Node without a parent. What a tragedy.") } + + if (removedNode === parent?.right) parent.right + else if (removedNode === parent?.left) parent.left = sonRemoved amountOfNodes-- - //treeBranch.addFirst(newNode) - balancerRemove(treeBranch) - return curNode.value + if (sonRemoved != null && removedNode.isRed == false) { + treeBranch.addFirst(sonRemoved) + balancerRemove(treeBranch) + } + + return removedNode.value } /** * Used in remove() method to balance tree :( */ - override fun balancerRemove(treeBranch: ArrayDeque>) { - val son = treeBranch.removeFirstOrNull() - val parent = treeBranch.removeFirstOrNull() + private fun balancerRemove(treeBranch: ArrayDeque>) { + var son = treeBranch.removeFirstOrNull() + var parent = treeBranch.removeFirstOrNull() + var grandparent = treeBranch.removeFirstOrNull() + - while (son?.isRed == false) { - if (son === parent?.right) { - val brother = parent.left + while (parent != null && son?.isRed == false) { + if (son === parent.right) { + var brother = parent.left if (brother?.isRed == true) { brother.isRed = false parent.isRed = true - rotateLeft(parent, treeBranch.firstOrNull()) + rotateRight(parent, grandparent) + grandparent = brother + brother = parent.left } + val nephewRight = brother?.right val nephewLeft = brother?.left if (nephewRight?.isRed == false && nephewLeft?.isRed == false) { - brother.isRed = true + brother?.isRed = true } else { - if (nephewRight?.isRed == false) { - brother.isRed = true - nephewLeft?.isRed = false - rotateRight(brother, parent) + if (nephewLeft?.isRed == false) { + nephewRight?.isRed = false + brother?.isRed = true + rotateLeft(brother, parent) + parent = nephewLeft } brother?.isRed = parent.isRed parent.isRed = false nephewRight?.isRed = false - rotateLeft(parent, treeBranch.firstOrNull()) - return + rotateLeft(parent, grandparent) } - } else if (son === parent?.left) { - val brother = parent.right + } else if (son === parent.left) { + var brother = parent.right if (brother?.isRed == true) { brother.isRed = false parent.isRed = true - rotateRight(parent, treeBranch.firstOrNull()) + rotateLeft(parent, grandparent) + grandparent = brother + brother = parent.right } + val nephewRight = brother?.right val nephewLeft = brother?.left if (nephewRight?.isRed == false && nephewLeft?.isRed == false) { - brother.isRed = true + brother?.isRed = true } else { - if (nephewLeft?.isRed == false) { - brother.isRed = true - nephewRight?.isRed = false - rotateLeft(brother, parent) + if (nephewRight?.isRed == false) { + nephewLeft?.isRed = false + brother?.isRed = true + rotateRight(brother, parent) } - brother?.isRed = parent.isRed + brother?.isRed = parent.isRed == true parent.isRed = false - nephewLeft?.isRed = false - rotateRight(parent, treeBranch.firstOrNull()) - return + nephewRight?.isRed = false + rotateLeft(parent, grandparent) + break } } } + + root?.isRed = false } } \ No newline at end of file From d262d43c983b187fb55b7bfb9ad314d8e64cc204 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Sun, 31 Mar 2024 14:44:47 +0300 Subject: [PATCH 105/186] refactor!(all): root method returns node instead of the Pair --- src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index cabc7ff..bc3b3ca 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -35,7 +35,9 @@ abstract class BinTree, V, Node_T : TreeNode> : return if (curNode != null) Pair(curNode.key, curNode.value) else null } - fun root(): Pair? = root?.let { Pair(it.key, it.value) } + open fun root(): Node_T? { + return root + } fun clear() { root?.let { root = null } From e161a358ff8837db525f74be0c0b4482805dbe15 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Sun, 31 Mar 2024 14:45:36 +0300 Subject: [PATCH 106/186] fix(avl): add function now initializes a tree root when used on the empty tree --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index c6ce63c..38598d6 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -60,6 +60,9 @@ class AVLTree, V> : BinTree>() { } return balanceNode(node) } + if (root == null) { + root = AVLNode(key, value) + } return addRec(root, key, value) } From 65103572fc302aafbdb77e77d2d40984eb2d96c3 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 31 Mar 2024 15:07:20 +0300 Subject: [PATCH 107/186] refactor: rewrite fun equals() --- src/main/kotlin/treeLib/nodes/TreeNode.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index 7f217ac..fc66e5d 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -12,8 +12,8 @@ abstract class TreeNode, V, Node_T : TreeNode>( override fun hashCode() = Pair(key, value).hashCode() override fun equals(other: Any?): Boolean { - val node = other as? Node_T - return (node != null) && (Pair(key, value) == Pair(node.key, node.value)) + val equals = (other as? Node_T != null) && (key == other.key) && (value == other.value) + return equals } internal fun attach(node: Node_T?): Boolean { From 22aa08a0d9912a31fa81282f2462ea9af9ae16aa Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 31 Mar 2024 15:07:43 +0300 Subject: [PATCH 108/186] feat: add fun toString() --- src/main/kotlin/treeLib/nodes/TreeNode.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index fc66e5d..2ef8e1f 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -16,6 +16,8 @@ abstract class TreeNode, V, Node_T : TreeNode>( return equals } + override fun toString() = Pair(key, value).toString() + internal fun attach(node: Node_T?): Boolean { if (node == null) return false when { From 087942ddfd9a7b66f6a20b582c2634535d6d8d89 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 31 Mar 2024 15:09:25 +0300 Subject: [PATCH 109/186] fix: change return value for add() --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index 1e488b6..d0b19a2 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -17,7 +17,7 @@ class RBTree, V> : BinTree>(), TreeBalancer * 1. Adds node to the tree and returns VALUE, * 2. If node with given key already exist, it does nothing(check changeVAAAAAAAAAAAAAAAAAAAL() method) */ - override fun add(key: K, value: V): V? { + override fun add(key: K, value: V): RBNode? { val treeBranch = ArrayDeque>() val newNode = RBNode(key, value) if (root == null) { @@ -36,7 +36,7 @@ class RBTree, V> : BinTree>(), TreeBalancer amountOfNodes++ treeBranch.addFirst(newNode) balancerAdd(treeBranch) - return value + return newNode } /** From fcce19883ef3ce77ca4e226bcc689619a5742d2f Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 31 Mar 2024 15:10:39 +0300 Subject: [PATCH 110/186] refactor: rewrite fun equals() (again) --- src/main/kotlin/treeLib/nodes/TreeNode.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index 2ef8e1f..711e401 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -12,8 +12,7 @@ abstract class TreeNode, V, Node_T : TreeNode>( override fun hashCode() = Pair(key, value).hashCode() override fun equals(other: Any?): Boolean { - val equals = (other as? Node_T != null) && (key == other.key) && (value == other.value) - return equals + return (other as? Node_T != null) && (key == other.key) && (value == other.value) } override fun toString() = Pair(key, value).toString() From c67724a3bf557add534716610d1fc98c7d388ea4 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 31 Mar 2024 15:24:19 +0300 Subject: [PATCH 111/186] refactor: minor clean up --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 8 ++++---- .../kotlin/treeLib/bintrees/interfaces/BinTree.kt | 8 ++++---- .../treeLib/bintrees/interfaces/TreeBalancer.kt | 14 +++----------- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index d0b19a2..fdf8759 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -45,7 +45,7 @@ class RBTree, V> : BinTree>(), TreeBalancer private fun balancerAdd(treeBranch: ArrayDeque>) { var son = treeBranch.removeFirstOrNull() var parent = treeBranch.removeFirstOrNull() - var grandparent = treeBranch.removeFirstOrNull() + var grandparent = treeBranch.removeFirstOrNull() while (parent != null && parent.isRed) { val uncle = when { @@ -67,7 +67,7 @@ class RBTree, V> : BinTree>(), TreeBalancer parent?.isRed = false grandparent?.isRed = true if (parent === grandparent?.right) rotateLeft(grandparent, treeBranch.firstOrNull()) - else if (parent === grandparent?.left) rotateRight(grandparent, treeBranch.firstOrNull()) + else rotateRight(grandparent, treeBranch.firstOrNull()) } else { parent.isRed = false uncle?.isRed = false @@ -119,7 +119,7 @@ class RBTree, V> : BinTree>(), TreeBalancer if (removedNode === parent?.right) parent.right else if (removedNode === parent?.left) parent.left = sonRemoved amountOfNodes-- - if (sonRemoved != null && removedNode.isRed == false) { + if (sonRemoved != null && !removedNode.isRed) { treeBranch.addFirst(sonRemoved) balancerRemove(treeBranch) } @@ -131,7 +131,7 @@ class RBTree, V> : BinTree>(), TreeBalancer * Used in remove() method to balance tree :( */ private fun balancerRemove(treeBranch: ArrayDeque>) { - var son = treeBranch.removeFirstOrNull() + val son = treeBranch.removeFirstOrNull() var parent = treeBranch.removeFirstOrNull() var grandparent = treeBranch.removeFirstOrNull() diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 80997e0..77a604b 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -7,17 +7,17 @@ abstract class BinTree, V, Node_T : TreeNode> : protected abstract var amountOfNodes: Int abstract fun add(key: K, value: V): Node_T? - - abstract fun remove(key: K): V? + + abstract fun remove(key: K): V? fun findByKey(key: K): Node_T? { var curNode = root while (curNode != null) - curNode = when { + curNode = when { key > curNode.key -> curNode.right key < curNode.key -> curNode.left else -> return curNode - } + } return null } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt index 814e207..ad76200 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt @@ -2,32 +2,24 @@ package treeLib.bintrees.interfaces import treeLib.nodes.TreeNode -interface TreeBalancer, V, Node_T : TreeNode> { +internal interface TreeBalancer, V, Node_T : TreeNode> { var root: Node_T? fun rotateRight(node: Node_T?, parent: Node_T?) { if (node == null) return - val nodeLeft = node.left node.left = nodeLeft?.right nodeLeft?.right = node - if (parent != null) - parent.attach(nodeLeft) - else /*only root doesn't have parent*/ - root = nodeLeft + if (parent != null) parent.attach(nodeLeft) else root = nodeLeft //root doesn't have parent } fun rotateLeft(node: Node_T?, parent: Node_T?) { if (node == null) return - val nodeRight = node.right node.right = nodeRight?.left nodeRight?.left = node - if (parent != null) - parent.attach(nodeRight) - else /*only root doesn't have parent*/ - root = nodeRight + if (parent != null) parent.attach(nodeRight) else root = nodeRight //root doesn't have parent } } \ No newline at end of file From fbef425448191e461992c22d619afc4be50eb76d Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Sun, 31 Mar 2024 16:13:36 +0300 Subject: [PATCH 112/186] refactor(avl): helper func --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 38598d6..6ca3b18 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -2,6 +2,8 @@ package treeLib.bintrees import treeLib.bintrees.interfaces.BinTree import treeLib.nodes.AVLNode +import kotlin.math.abs + class AVLTree, V> : BinTree>() { override var root: AVLNode? = null @@ -128,6 +130,18 @@ class AVLTree, V> : BinTree>() { return height(node.right) - height(node.left) } + fun isBalanced(node: AVLNode?): Boolean { + if (node == null) return true + val lh = height(node.left) + val rh = height(node.right) + + if (abs(balanceFactor(node)) <= 1 && isBalanced(node.left) && isBalanced(node.right)) { + return true + } + + return false + } + private fun fixHeight(node: AVLNode?) { if (node != null) { val heightLeft = height(node.left) From 486c2b86dd89cbe699de8a037cb10dc32b73da73 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Sun, 31 Mar 2024 16:30:12 +0300 Subject: [PATCH 113/186] fix: small compatibility fixes --- src/main/kotlin/treeLib/bintrees/BSTree.kt | 10 +++++----- src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 51e6146..10100c3 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -16,7 +16,7 @@ class BSTree, V> : BinTree>() { return true } - override fun add(key: K, value: V): V? { + override fun add(key: K, value: V): BSTNode? { if (root == null) root = BSTNode(key, value) var x = this.root while (x != null) { @@ -35,7 +35,7 @@ class BSTree, V> : BinTree>() { } else return null } this.amountOfNodes += 1 - return value + return null } override fun remove(key: K): V? { @@ -83,16 +83,16 @@ class BSTree, V> : BinTree>() { } - fun changeVal(key: K, newValue: V): Boolean { + override fun changeVal(key: K, newValue: V): V? { var x = root while (x != null) { x = if (key > x.key) x.right else if (key < x.key) x.left else { x.value = newValue - return true + return newValue } } - return false + return null } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index c493171..405f5de 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -21,7 +21,7 @@ abstract class BinTree, V, Node_T : TreeNode> : return null } - fun changeVal(key: K, newValue: V): V? { + open fun changeVal(key: K, newValue: V): V? { var curNode = root while (curNode != null) curNode = when { From a969df5b9642beafa08e3e051e2d62549009bdf9 Mon Sep 17 00:00:00 2001 From: Islam Date: Sun, 31 Mar 2024 16:50:19 +0300 Subject: [PATCH 114/186] feat and refactor: add new methods to BS node and tree Added ability to get and delete subTree and also added findParent that makes code easier, added isThereChild in node --- src/main/kotlin/treeLib/bintrees/BSTree.kt | 136 +++++++++++------- .../treeLib/bintrees/interfaces/BinTree.kt | 10 +- src/main/kotlin/treeLib/nodes/BSTNode.kt | 7 +- 3 files changed, 93 insertions(+), 60 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 51e6146..a8ffb07 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -10,89 +10,115 @@ class BSTree, V> : BinTree>() { fun addPairs(keys: List, values: List): Boolean { if (keys.size != values.size) return false - for (i in keys.indices) { - this.add(keys[i], values[i]) + for (curKey in keys.indices) { + this.add(keys[currentKey], values[currentKey]) } return true } - override fun add(key: K, value: V): V? { - if (root == null) root = BSTNode(key, value) - var x = this.root - while (x != null) { - if (key > x.key) { - if (x.right == null) { - x.right = BSTNode(key, value) - break + override fun add(key: K, value: V): Node_T? { + if (root == null) this.root = BSTNode(key, value) + var curNode = this.root + while (curNode != null) { + if (key > curNode.key) { + if (curNode.right == null) { + curNode.right = BSTNode(key, value) + return curNode.right } - x = x.right - } else if (key < x.key) { - if (x.left == null) { - x.left = BSTNode(key, value) - break + curNode = curNode.right + } else if (key < curNode.key) { + if (curNode.left == null) { + curNode.left = BSTNode(key, value) + return curNode.left } - x = x.left + curNode = curNode.left } else return null } this.amountOfNodes += 1 - return value + return null } override fun remove(key: K): V? { - var x: BSTNode? = root - var parent_x: BSTNode? = null var count = 0 - while (x != null) { - if (key == x.key) { - break - } - parent_x = x - x = if (key > x.key) { - x.right - } else { - x.left - } - } - if (x == null || parent_x == null) return null - if (x.right != null) count++ - if (x.left != null) count++ + var curNode: BSTNode? = null + var parent = this.findParent(key) + if(parent == null) return null + if(parent.right != null && parent.right.key == key) curNode = parent.right + else curNode = parent.left + if (curNode.right != null) count++ + if (curNode.left != null) count++ if (count == 0) { - if (parent_x.right === x) parent_x.right = null - else parent_x.left = null + if (parent.right === curNode) parent.right = null + else parent.left = null } else if (count == 1) { - if (x.left == null) { - if (parent_x.right === x) parent_x.right = x.right - else parent_x.left = x.right + if (curNode.left == null) { + if (parent.right === x) parent_x.right = curNode.right + else parent.left = curNode.right } else { - if (parent_x.right === x) parent_x.right = x.left - else parent_x.left = x.left + if (parent.right === curNode) parent.right = curNode.left + else parent.left = curNode.left } } else { - var child_x = x.right - var parent_child_x = x - while (child_x!!.left != null) { - if (child_x.left!!.left == null) parent_child_x = child_x - child_x = child_x.left + var child = curNode.right + var parent_child = curNode + while (child!!.left != null) { + if (child.left!!.left == null) parent_child = child + child = child.left } - x.key = child_x.key - x.value = child_x.value - parent_child_x!!.left = child_x.right + curNode.key = child.key + curNode.value = child.value + parent_child!!.left = child.right } this.amountOfNodes -= 1 - return null + return curNode.value } fun changeVal(key: K, newValue: V): Boolean { - var x = root - while (x != null) { - x = if (key > x.key) x.right - else if (key < x.key) x.left + var curNode = this.root + while (curNode != null) { + curNode = if (key > curNode.key) curNode.right + else if (key < curNode.key) curNode.left else { - x.value = newValue + curNode.value = newValue return true } } return false } -} \ No newline at end of file + + fun findParent(key: K): Node_T?{ + var parent = this.root + if(parent == null || root.key == key) return null + while(parent.isThereChild == true){ + if( (parent.right != null && parent.right.key == key) || (parent.left != null && parent.left.key == key)) return parent + else{ + if(key > parent.key){ + if(parent.right == null) return null + parent = parent.right + } + else{ + if(parent.left == null) return null + parent = parent.left + } + } + } + } + + fun deleteSubTree(key: K): Boolean{ + var parent: BSTNode? = this.findParent(key) + if(parent == null) return false + if(parent.right != null && parent.right.key == key) parent.right = null + else parent.left = null + return true + } + + fun getSubTree(key: K): BSTree?{ + var parent: BSTNode? = this.findParent(key) + var child: BSTree = BSTree() + if(parent == null) return null + if(parent.right != null && parent.right.key == key) child.add(key, parent.right.value) + else child.add(key, parent.left.value) + return child + } +} diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 77a604b..06b1492 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -68,14 +68,16 @@ abstract class BinTree, V, Node_T : TreeNode> : fun postOrderIterator(): Iterator> = TreeIterator(root, IterationOrder.POST_ORDER) + private fun countHeight(tNode: Node_T?): Int { if (tNode == null) return 0 - val lf = countHeight(tNode.left) - val rg = countHeight(tNode.right) - return kotlin.math.max(lf, rg) + 1 + val leftChild = countHeight(tNode.left) + val rightChild = countHeight(tNode.right) + return kotlin.math.max(leftChild, rightChild) + 1 } - open fun height(): Int? { + + fun height(): Int { return countHeight(root) } } diff --git a/src/main/kotlin/treeLib/nodes/BSTNode.kt b/src/main/kotlin/treeLib/nodes/BSTNode.kt index c64e6a4..35eaec2 100644 --- a/src/main/kotlin/treeLib/nodes/BSTNode.kt +++ b/src/main/kotlin/treeLib/nodes/BSTNode.kt @@ -5,4 +5,9 @@ class BSTNode, V>( value: V, right: BSTNode? = null, left: BSTNode? = null -) : TreeNode>(key, value, right, left) +) : TreeNode>(key, value, right, left){ + internal fun isThereChild(): Boolean{ + if(this.left != null || this.right != null) return true + else false + } +} From 5c67b7fa880025c9086a8bf2ec49b611a0a61805 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 31 Mar 2024 22:40:35 +0300 Subject: [PATCH 115/186] refactor: simplified balancerAdd() (mostly for tests) --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 38 +++++++++------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index fdf8759..7727380 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -43,38 +43,32 @@ class RBTree, V> : BinTree>(), TreeBalancer * Used in add() method to balance tree :) */ private fun balancerAdd(treeBranch: ArrayDeque>) { - var son = treeBranch.removeFirstOrNull() + var son = treeBranch.removeFirst() var parent = treeBranch.removeFirstOrNull() var grandparent = treeBranch.removeFirstOrNull() - while (parent != null && parent.isRed) { - val uncle = when { - parent === grandparent?.right -> grandparent.left - parent === grandparent?.left -> grandparent.right - else -> null - } + while (parent != null && parent.isRed && grandparent != null) { + val uncle = if (parent != grandparent.right) grandparent.right else grandparent.left - if (uncle?.isRed == false) { - if (parent === grandparent?.right && son === parent.left) { + if (uncle?.isRed == true) { + parent.isRed = false + uncle.isRed = false + grandparent.isRed = true + son = grandparent + parent = treeBranch.removeFirstOrNull() + grandparent = treeBranch.removeFirstOrNull() + } else { + if (parent === grandparent.right && son === parent.left) { rotateRight(parent, grandparent) parent = son - son = parent?.right - } else if (parent === grandparent?.left && son === parent.right) { + } else if (parent === grandparent.left && son === parent.right) { rotateLeft(parent, grandparent) parent = son - son = parent?.left } - parent?.isRed = false - grandparent?.isRed = true - if (parent === grandparent?.right) rotateLeft(grandparent, treeBranch.firstOrNull()) - else rotateRight(grandparent, treeBranch.firstOrNull()) - } else { parent.isRed = false - uncle?.isRed = false - grandparent?.isRed = true - son = grandparent - parent = treeBranch.removeFirstOrNull() - grandparent = treeBranch.removeFirstOrNull() + grandparent.isRed = true + if (parent === grandparent.right) rotateLeft(grandparent, treeBranch.firstOrNull()) + else rotateRight(grandparent, treeBranch.firstOrNull()) } } From 1808a602b6472d1422a521fa225397c18973e2ad Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 31 Mar 2024 23:16:39 +0300 Subject: [PATCH 116/186] refactor: change descriptions and removedNode declaration in remove() --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index 7727380..5e72ae9 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -15,7 +15,8 @@ class RBTree, V> : BinTree>(), TreeBalancer /** * Adds or replaces node to the tree depending on given key: * 1. Adds node to the tree and returns VALUE, - * 2. If node with given key already exist, it does nothing(check changeVAAAAAAAAAAAAAAAAAAAL() method) + * 2. If node with given key already exist, it does nothing + * (to actually change value check changeVal) */ override fun add(key: K, value: V): RBNode? { val treeBranch = ArrayDeque>() @@ -76,12 +77,12 @@ class RBTree, V> : BinTree>(), TreeBalancer } /** - * Removes node with the same key and returns node's key and value. - * Or returns null if node with the same key doesn't exist. + * Removes node with the same key and returns node's value. + * Or returns null if there's no such node. */ override fun remove(key: K): V? { val treeBranch = ArrayDeque>() - var removedNode = if (root != null) root else return null + var removedNode = root while (removedNode?.key != key) { if (removedNode == null) return null //node with given key doesn't exist treeBranch.addFirst(removedNode) From dffbd8a143099af29a68bf4d4832e43df12d7aef Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 31 Mar 2024 23:26:44 +0300 Subject: [PATCH 117/186] fix: change type from pair to Node --- src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt | 8 ++++---- .../kotlin/treeLib/bintrees/interfaces/TreeIterator.kt | 7 ++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 77a604b..920b30f 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -2,7 +2,7 @@ package treeLib.bintrees.interfaces import treeLib.nodes.TreeNode -abstract class BinTree, V, Node_T : TreeNode> : Iterable> { +abstract class BinTree, V, Node_T : TreeNode> : Iterable { protected abstract var root: Node_T? protected abstract var amountOfNodes: Int @@ -62,11 +62,11 @@ abstract class BinTree, V, Node_T : TreeNode> : /** * basic In-order iterator */ - override fun iterator(): Iterator> = TreeIterator(root, IterationOrder.IN_ORDER) + override fun iterator(): Iterator = TreeIterator(root, IterationOrder.IN_ORDER) - fun preOrderIterator(): Iterator> = TreeIterator(root, IterationOrder.PRE_ORDER) + fun preOrderIterator(): Iterator = TreeIterator(root, IterationOrder.PRE_ORDER) - fun postOrderIterator(): Iterator> = TreeIterator(root, IterationOrder.POST_ORDER) + fun postOrderIterator(): Iterator = TreeIterator(root, IterationOrder.POST_ORDER) private fun countHeight(tNode: Node_T?): Int { if (tNode == null) return 0 diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt index c6d061e..78ff1a8 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt @@ -5,7 +5,7 @@ import treeLib.nodes.TreeNode class TreeIterator, V, Node_T : TreeNode>( private val root: Node_T?, private val order: IterationOrder, - ): Iterator> { + ): Iterator { private val stack: ArrayDeque = ArrayDeque() init { @@ -46,8 +46,5 @@ class TreeIterator, V, Node_T : TreeNode>( override fun hasNext() = stack.isNotEmpty() - override fun next(): Pair { - val node = stack.removeFirst() - return Pair(node.key, node.value) - } + override fun next() = stack.removeFirst() } \ No newline at end of file From 44d2bf0954d49124e8f6b7651eb2a2e8fdaabc26 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 31 Mar 2024 23:58:37 +0300 Subject: [PATCH 118/186] fix: correct root remove --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index 5e72ae9..4cf3f08 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -111,9 +111,12 @@ class RBTree, V> : BinTree>(), TreeBalancer } } - if (removedNode === parent?.right) parent.right - else if (removedNode === parent?.left) parent.left = sonRemoved amountOfNodes-- + when (removedNode) { + parent?.right -> parent.right = sonRemoved + parent?.left -> parent.left = sonRemoved + else -> root = null //only root doesn't have parent + } if (sonRemoved != null && !removedNode.isRed) { treeBranch.addFirst(sonRemoved) balancerRemove(treeBranch) From 959590b4b3248048c4ba81b14efade2f8d81ef2e Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 00:49:07 +0300 Subject: [PATCH 119/186] fix(avl): now tree can change root when balancing --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 35 ++++++--------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 6ca3b18..e920819 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -64,24 +64,11 @@ class AVLTree, V> : BinTree>() { } if (root == null) { root = AVLNode(key, value) + return root } return addRec(root, key, value) } - fun initTree(data: List>): AVLTree { - val tree = AVLTree() - for (element in data) { - if (tree.root == null) { - tree.root = AVLNode(element.first, element.second) - amountOfNodes = 1 - } else { - tree.add(element.first, element.second) - amountOfNodes += 1 - } - } - return tree - } - private fun rotateLeft(nodeA: AVLNode?): AVLNode? { if (nodeA != null) { if ((nodeA.right) != null) { @@ -130,18 +117,6 @@ class AVLTree, V> : BinTree>() { return height(node.right) - height(node.left) } - fun isBalanced(node: AVLNode?): Boolean { - if (node == null) return true - val lh = height(node.left) - val rh = height(node.right) - - if (abs(balanceFactor(node)) <= 1 && isBalanced(node.left) && isBalanced(node.right)) { - return true - } - - return false - } - private fun fixHeight(node: AVLNode?) { if (node != null) { val heightLeft = height(node.left) @@ -161,6 +136,10 @@ class AVLTree, V> : BinTree>() { if (balanceFactor(node.right) < 0) { node.right = rotateRight(node.right) } + if (node == root) { + root = rotateLeft(node) + return root + } return rotateLeft(node) } } @@ -169,6 +148,10 @@ class AVLTree, V> : BinTree>() { if (balanceFactor(node.left) > 0) { node.left = rotateLeft(node.left) } + if (node == root) { + root = rotateRight(node) + return root + } return rotateRight(node) } } From ef37bda5c18c8c1fd25f7e6d2b29c7c650933e8d Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 01:13:33 +0300 Subject: [PATCH 120/186] refactor: min / max return node instead of pair(key, value) --- src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 405f5de..5f213d0 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -35,18 +35,18 @@ abstract class BinTree, V, Node_T : TreeNode> : return null } - fun max(): Pair? { + fun max(): Node_T? { var curNode = root while (curNode?.right != null) curNode = curNode.right - return if (curNode != null) Pair(curNode.key, curNode.value) else null + return curNode } - fun min(): Pair? { + fun min(): Node_T? { var curNode = root while (curNode?.left != null) curNode = curNode.left - return if (curNode != null) Pair(curNode.key, curNode.value) else null + return curNode } open fun root(): Node_T? { From 82a0c24a62cda43bcd843febcf91c1f407714967 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 01:40:22 +0300 Subject: [PATCH 121/186] fix: countNodes returns proper value --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 4 +++- src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index e920819..ceb1a83 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -2,7 +2,6 @@ package treeLib.bintrees import treeLib.bintrees.interfaces.BinTree import treeLib.nodes.AVLNode -import kotlin.math.abs class AVLTree, V> : BinTree>() { @@ -32,6 +31,7 @@ class AVLTree, V> : BinTree>() { return balanceNode(node) } removeRec(root, key) + amountOfNodes -= 1 return value } @@ -64,8 +64,10 @@ class AVLTree, V> : BinTree>() { } if (root == null) { root = AVLNode(key, value) + amountOfNodes += 1 return root } + amountOfNodes += 1 return addRec(root, key, value) } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 5f213d0..0567fc7 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -55,6 +55,7 @@ abstract class BinTree, V, Node_T : TreeNode> : fun clear() { root?.let { root = null } + amountOfNodes = 0 } fun countNodes(): Int { From d6d09ab8dbe5474b31f628057880d2abd940a10c Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 01:40:54 +0300 Subject: [PATCH 122/186] build: add AVL tests --- src/test/kotlin/AVLTreeTest.kt | 203 +++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 src/test/kotlin/AVLTreeTest.kt diff --git a/src/test/kotlin/AVLTreeTest.kt b/src/test/kotlin/AVLTreeTest.kt new file mode 100644 index 0000000..d358686 --- /dev/null +++ b/src/test/kotlin/AVLTreeTest.kt @@ -0,0 +1,203 @@ +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Nested +import treeLib.bintrees.AVLTree +import treeLib.nodes.AVLNode +import kotlin.math.abs +import org.junit.jupiter.api.Test + + +class AVLTreeTest { + var tree = AVLTree() + + @Nested + inner class InsertionTests { + @Test + fun useAddOnEmptyTree() { + tree.clear() + tree.add(0, "a") + assertEquals(0, tree.root()?.key) + assertEquals("a", tree.root()?.value) + } + + @BeforeEach + fun setUp() { + tree.add(0, "a") + tree.add(1, "b") + tree.add(-1, "b") + } + + @Test + fun addByKey () { + assertEquals(-1, tree.root()?.left?.key) + assertEquals("b", tree.root()?.left?.value) + assertEquals(1, tree.root()?.right?.key) + assertEquals("b", tree.root()?.right?.value) + } + + @Test + fun addDoesNothingWhenKeyExists() { + tree.add(0, "a") + tree.add(1, "b") + tree.add(-1, "b") + assertEquals(null, tree.root()?.right?.right) + assertEquals(null, tree.root()?.right?.left) + } + } + + @Nested + inner class RemoveTests { + + @BeforeEach + fun setUp() { + for (i in 0..10) { + tree.add(i, "test") + } + } + + @Test + fun removeRoot() { + val key : Int? = tree.root()?.key + if (key != null) { + tree.remove(key) + assertNotNull(tree.root()) + } else { + fail() + } + } + + @Test + fun removeNodeWithNoChildren(){ + tree.remove(10) + assertNull(tree.findByKey(10)) + for (i in 0..9) { + assertNotNull(tree.findByKey(i)) + } + } + + @Test + fun removeNodeWithChildren(){ + tree.remove(7) + assertNull(tree.findByKey(7)) + for (i in 0..10) { + if (i != 7) { + assertNotNull(tree.findByKey(i)) + } + } + } + + @Test + fun removeNonExistentNode() { + assertNull(tree.remove(999)) + } + } + + @Nested + inner class BalanceTests { + private fun isBalanced(node: AVLNode?): Boolean { + fun height(node: AVLNode?): Int { + if (node == null) { + return 0 + } + return node.height + } + + fun balanceFactor(node: AVLNode?): Int { + if (node == null) { + throw NullPointerException("Node cannot be null.") + } + return height(node.right) - height(node.left) + } + + if (node == null) return true + + if (abs(balanceFactor(node)) <= 1 && isBalanced(node.left) && isBalanced(node.right)) { + return true + } + + return false + } + + @BeforeEach + fun setUpRandomTree(){ + val ranLen = (2..100).random() + for (i in 1..ranLen) { + val ranItem = (1..10000).random() + tree.add(ranItem, "test") + } + } + + @Test + fun afterInsertAVLIsBalanced() { + assertTrue(isBalanced(tree.root())) + } + + @Test + fun afterRemoveAVLIsBalanced() { + tree.root()?.left?.let { tree.remove(it.key) } + assertTrue(isBalanced(tree.root())) + } + } + + @Nested + inner class InterfaceMethods { + + @BeforeEach + fun setUp() { + for (i in 0..10) { + tree.add(i, "test") + } + } + + @Test + fun findReturnsTrueNode() { + val rightNode = tree.findByKey(7) + val leftNode = tree.findByKey(1) + assertEquals(tree.root()?.right, rightNode) + assertEquals(tree.root()?.left, leftNode) + assertNull(tree.findByKey(999)) + } + + @Test + fun changeValChangesVal() { + tree.changeVal(3, "tomato") + tree.changeVal(7, "banana") + tree.changeVal(1, "tea") + + assertEquals("tomato", tree.root()?.value) + assertEquals("banana", tree.root()?.right?.value) + assertEquals("tea", tree.root()?.left?.value) + assertNull(tree.changeVal(99999, "tea")) + } + + @Test + fun findMax(){ + assertEquals(tree.findByKey(10), tree.max()) + tree.clear() + assertNull(tree.max()) + } + + @Test + fun findMin(){ + assertEquals(tree.findByKey(0), tree.min()) + tree.clear() + assertNull(tree.min()) + } + + @Test + fun countNodes() { + assertEquals(11, tree.countNodes()) + tree.remove(7) + assertEquals(10, tree.countNodes()) + tree.clear() + assertEquals(0, tree.countNodes()) + } + + @Test + fun height() { + assertEquals(4, tree.height()) + tree.clear() + assertEquals(0, tree.height()) + } + } +} \ No newline at end of file From 2887570edb2be2727912ee848d65dad7820dedc5 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 13:22:02 +0300 Subject: [PATCH 123/186] detekt setting up detekt integration --- .github/workflows/main.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..35db95f --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,20 @@ +## 1 +name: detekt +## 2 +on: + push: + branches: + - main + pull_request: + branches: + - main +## 3 +jobs: + detekt: + ## 4 + runs-on: ubuntu-latest + steps: + - name: "checkout" + uses: actions/checkout@v2 + - name: "detekt" + uses: natiginfo/action-detekt-all@1.17.0 From dc72345f10fe24ae16caf93acaab1b5d39af4c5e Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 14:25:44 +0300 Subject: [PATCH 124/186] ci: create workflow for running tests with coverage --- .github/workflows/test_with_coverage.yml | 53 ++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/workflows/test_with_coverage.yml diff --git a/.github/workflows/test_with_coverage.yml b/.github/workflows/test_with_coverage.yml new file mode 100644 index 0000000..7fe6929 --- /dev/null +++ b/.github/workflows/test_with_coverage.yml @@ -0,0 +1,53 @@ +# This is a basic workflow to help you get started with Actions + +name: Test with Coverage + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the "main" branch + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + name: Build Tests + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - name: Checkout sources + - uses: actions/checkout@v3 + + - name: Setup JDK 11 + - uses: actions/setup-java@v4 + with: + java-version: '11' + distribution: 'temurin' + - name: Setup Gradle + - uses: gradle/actions/setup-gradle@v3 + - name: Build with Gradle + run: ./gradlew build + - name: Run With Coverage + run: | + chmod +x gradlew + ./gradlew testCoverage + + - name: Add coverage to PR + id: jacoco + uses: madrapps/jacoco-report@v1.6.1 + with: + paths: | + ${{ github.workspace }}/**/build/reports/jacoco/prodNormalDebugCoverage/prodNormalDebugCoverage.xml, + ${{ github.workspace }}/**/build/reports/jacoco/**/debugCoverage.xml + token: ${{ secrets.GITHUB_TOKEN }} + min-coverage-overall: 40 + min-coverage-changed-files: 60 From 729e7bdb96621db0aa5ba181b4cb3f9ab7fabae2 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 14:29:07 +0300 Subject: [PATCH 125/186] fix: test workflow file --- .github/workflows/test_with_coverage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_with_coverage.yml b/.github/workflows/test_with_coverage.yml index 7fe6929..6d5e7b1 100644 --- a/.github/workflows/test_with_coverage.yml +++ b/.github/workflows/test_with_coverage.yml @@ -39,11 +39,11 @@ jobs: - name: Run With Coverage run: | chmod +x gradlew - ./gradlew testCoverage + ./gradlew test - name: Add coverage to PR id: jacoco - uses: madrapps/jacoco-report@v1.6.1 + - uses: madrapps/jacoco-report@v1.6.1 with: paths: | ${{ github.workspace }}/**/build/reports/jacoco/prodNormalDebugCoverage/prodNormalDebugCoverage.xml, From a49ed7429fed576554d4d24d7e9cc69d00a3b6b9 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Mon, 1 Apr 2024 14:30:15 +0300 Subject: [PATCH 126/186] feat: add tests for RBTree --- src/test/kotlin/RBTreeTest.kt | 220 ++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 src/test/kotlin/RBTreeTest.kt diff --git a/src/test/kotlin/RBTreeTest.kt b/src/test/kotlin/RBTreeTest.kt new file mode 100644 index 0000000..1fcf3d1 --- /dev/null +++ b/src/test/kotlin/RBTreeTest.kt @@ -0,0 +1,220 @@ +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import treeLib.bintrees.RBTree +import treeLib.nodes.RBNode +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class RBTreeTest { + private var emptyTree = RBTree() + + @BeforeEach + fun init() { + emptyTree = RBTree() + } + + @Nested + @DisplayName("Add method tests") + inner class AddMethod { + @Test + @DisplayName("Add node to the root") + fun addRoot() { + val root = emptyTree.add(1, 1974) + assertEquals(RBNode(1, 1974), root) + assertEquals(root, emptyTree.root) + } + + @Test + @DisplayName("Add node that already exist") + fun addExisted() { + emptyTree.add(1, 1974) + assertEquals(null, emptyTree.add(1, 9999)) + assertEquals(RBNode(1, 1974), emptyTree.root) + } + + @Test + @DisplayName("Add without uncle, right ver") + fun add1R() { + val root = emptyTree.add(0, 0)!! + val right = emptyTree.add(1, 1)!! + val right2 = emptyTree.add(2, 2)!! + assertEquals(root, emptyTree.root!!.left) + assertEquals(right, emptyTree.root) + assertEquals(right2, emptyTree.root!!.right) + assertTrue { root.isRed && !right.isRed && right2.isRed } + } + + @Test + @DisplayName("Add without uncle, left ver") + fun add1L() { + val root = emptyTree.add(0, 0)!! + val left = emptyTree.add(-1, -1)!! + val left2 = emptyTree.add(-2, -2)!! + assertEquals(left, emptyTree.root) + assertTrue { root.isRed && !left.isRed && left2.isRed } + } + + + @Test + @DisplayName("Add with red uncle, right ver") + fun add2R() { + val root = emptyTree.add(0, 0)!! + val left = emptyTree.add(-1, -1)!! + val right = emptyTree.add(1, 1)!! + val right2 = emptyTree.add(2, 2)!! + assertEquals(root, emptyTree.root) + assertEquals(left, emptyTree.root!!.left) + assertEquals(right, emptyTree.root!!.right) + assertEquals(right2, emptyTree.root!!.right!!.right) + assertTrue(!root.isRed && !left.isRed && !right.isRed && right2.isRed) + } + + @Test + @DisplayName("Add with red uncle, left ver") + fun add2L() { + val root = emptyTree.add(0, 0)!! + val right = emptyTree.add(1, 1)!! + val left = emptyTree.add(-1, -1)!! + val left2 = emptyTree.add(-2, -2)!! + assertEquals(root, emptyTree.root) + assertEquals(right, emptyTree.root!!.right) + assertEquals(left, emptyTree.root!!.left) + assertEquals(left2, emptyTree.root!!.left!!.left) + assertTrue(!root.isRed && !right.isRed && !left.isRed && left2.isRed) + } + + @Test + @DisplayName("Add with black uncle, right ver") + fun add3R() { + val root = emptyTree.add(0, 0)!! + val left = emptyTree.add(-1, -1)!! + val right = emptyTree.add(1, 1)!! + val right2 = emptyTree.add(3, 3)!! + val right15 = emptyTree.add(2, 2)!! + assertEquals(root, emptyTree.root) + assertEquals(left, emptyTree.root!!.left) + assertEquals(right, emptyTree.root!!.right!!.left) + assertEquals(right2, emptyTree.root!!.right!!.right) + assertEquals(right15, emptyTree.root!!.right) + assertTrue( + !root.isRed && !left.isRed && + right.isRed && !right15.isRed && right2.isRed + ) + } + + @Test + @DisplayName("Add with black uncle, left ver") + fun add3L() { + val root = emptyTree.add(0, 0)!! + val right = emptyTree.add(1, 1)!! + val left = emptyTree.add(-1, -1)!! + val left2 = emptyTree.add(-3, -3)!! + val left15 = emptyTree.add(-2, -2)!! + assertEquals(root, emptyTree.root) + assertEquals(right, emptyTree.root!!.right) + assertEquals(left, emptyTree.root!!.left!!.right) + assertEquals(left2, emptyTree.root!!.left!!.left) + assertEquals(left15, emptyTree.root!!.left) + assertTrue( + !root.isRed && !right.isRed && + left.isRed && !left15.isRed && left2.isRed + ) + } + } + + @Nested + @DisplayName("Remove method tests") + inner class RemoveMethod { + @Test + @DisplayName("Remove from empty tree") + fun removeEmpty() { + assertEquals(null, emptyTree.remove(Int.MAX_VALUE)) + } + + @Test + @DisplayName("Remove nonexistent node") + fun removeNothing() { + emptyTree.add(1, 1) + emptyTree.add(2, 2) + emptyTree.add(3, 3) + emptyTree.add(4, 4) + assertEquals(null, emptyTree.remove(0)) + } + + @Test + @DisplayName("Remove root") + fun removeRoot() { + emptyTree.add(1, 1) + val root = emptyTree.remove(1) + assertEquals(1, root) + assertEquals(null, emptyTree.root()) + } + + @Test + @DisplayName("Remove node without children") + fun remove1R() { + emptyTree.add(0, 0) + emptyTree.add(1, 999) + assertEquals(999, emptyTree.remove(1)) + assertTrue { emptyTree.root!!.right == null && emptyTree.root!!.left == null } + } + + @Test + @DisplayName("Remove node without children") + fun remove1L() { + emptyTree.add(0, 0) + emptyTree.add(-1, 666) + assertEquals(666, emptyTree.remove(-1)) + assertTrue { emptyTree.root!!.right == null && emptyTree.root!!.left == null } + } + + @Test + @DisplayName("") + fun remove2R() { + } + + @Test + @DisplayName("") + fun remove2L() { + + } + + @Test + @DisplayName("") + fun remove3R() { + + } + + @Test + @DisplayName("") + fun remove3L() { + + } + + @Test + @DisplayName("") + fun remove4r() { + + } + + @Test + @DisplayName("") + fun remove4l() { + + } + + @Test + @DisplayName("") + fun remove5r() { + + } + + @Test + @DisplayName("") + fun remove5l() { + + } + } +} \ No newline at end of file From e8f7a5a307f2d2adaaaf8002ce7569aa18ecabf9 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 14:38:42 +0300 Subject: [PATCH 127/186] build: add build.gradle.kts --- build.gradle.kts | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..e8e6a63 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,38 @@ +plugins { + kotlin("jvm") version "1.9.23" + jacoco +} + +group = "org.example" +version = "1.0-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencies { + testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") + testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.2") +} + +tasks.test { + useJUnitPlatform() + finalizedBy(tasks.jacocoTestReport) +} +tasks.jacocoTestReport { + dependsOn(tasks.test) + reports { + xml.required = false + csv.required = false + html.outputLocation = layout.buildDirectory.dir("jacocoHtml") + } +} + +kotlin { + jvmToolchain(21) +} + +jacoco { + toolVersion = "0.8.11" + reportsDirectory = layout.buildDirectory.dir("customJacocoReportDir") +} From d79bd8c637693c5cb6ef4cedc39de901dca95601 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 14:45:27 +0300 Subject: [PATCH 128/186] fix: test workflow file --- .github/workflows/test_with_coverage.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test_with_coverage.yml b/.github/workflows/test_with_coverage.yml index 6d5e7b1..06c5fec 100644 --- a/.github/workflows/test_with_coverage.yml +++ b/.github/workflows/test_with_coverage.yml @@ -25,15 +25,15 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout sources - - uses: actions/checkout@v3 + uses: actions/checkout@v3 - name: Setup JDK 11 - - uses: actions/setup-java@v4 + uses: actions/setup-java@v4 with: java-version: '11' distribution: 'temurin' - name: Setup Gradle - - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v3 - name: Build with Gradle run: ./gradlew build - name: Run With Coverage @@ -43,7 +43,7 @@ jobs: - name: Add coverage to PR id: jacoco - - uses: madrapps/jacoco-report@v1.6.1 + uses: madrapps/jacoco-report@v1.6.1 with: paths: | ${{ github.workspace }}/**/build/reports/jacoco/prodNormalDebugCoverage/prodNormalDebugCoverage.xml, From 5a64af8b8d56f75a1155b6eef37c351c3866fe37 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 15:01:32 +0300 Subject: [PATCH 129/186] ci: rename detekt workflow test --- .github/workflows/{main.yml => format_check.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{main.yml => format_check.yml} (94%) diff --git a/.github/workflows/main.yml b/.github/workflows/format_check.yml similarity index 94% rename from .github/workflows/main.yml rename to .github/workflows/format_check.yml index 35db95f..196149a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/format_check.yml @@ -1,5 +1,5 @@ ## 1 -name: detekt +name: Run detekt ## 2 on: push: From bbc4c60de67b86e1434a1c9d9e26a5db23167003 Mon Sep 17 00:00:00 2001 From: Islam Date: Mon, 1 Apr 2024 15:25:46 +0300 Subject: [PATCH 130/186] fix: fixed huge amount of mistakes and added nessecary file THAT SOMEONE DIDN'T ADD BEFORE --- build.gradle.kts | 38 +++++++++++++ src/main/kotlin/treeLib/bintrees/BSTree.kt | 54 ++++++++----------- .../treeLib/bintrees/interfaces/BinTree.kt | 2 +- src/main/kotlin/treeLib/nodes/BSTNode.kt | 2 +- 4 files changed, 61 insertions(+), 35 deletions(-) create mode 100644 build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..e8e6a63 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,38 @@ +plugins { + kotlin("jvm") version "1.9.23" + jacoco +} + +group = "org.example" +version = "1.0-SNAPSHOT" + +repositories { + mavenCentral() +} + +dependencies { + testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") + testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.2") +} + +tasks.test { + useJUnitPlatform() + finalizedBy(tasks.jacocoTestReport) +} +tasks.jacocoTestReport { + dependsOn(tasks.test) + reports { + xml.required = false + csv.required = false + html.outputLocation = layout.buildDirectory.dir("jacocoHtml") + } +} + +kotlin { + jvmToolchain(21) +} + +jacoco { + toolVersion = "0.8.11" + reportsDirectory = layout.buildDirectory.dir("customJacocoReportDir") +} diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index a8ffb07..1db8fce 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -5,18 +5,18 @@ import treeLib.nodes.BSTNode class BSTree, V> : BinTree>() { override var root: BSTNode? = null - override var amountOfNodes = 1 + override var amountOfNodes = 0 fun addPairs(keys: List, values: List): Boolean { if (keys.size != values.size) return false for (curKey in keys.indices) { - this.add(keys[currentKey], values[currentKey]) + this.add(keys[curKey], values[curKey]) } return true } - override fun add(key: K, value: V): Node_T? { + override fun add(key: K, value: V): BSTNode? { if (root == null) this.root = BSTNode(key, value) var curNode = this.root while (curNode != null) { @@ -43,55 +43,42 @@ class BSTree, V> : BinTree>() { var curNode: BSTNode? = null var parent = this.findParent(key) if(parent == null) return null - if(parent.right != null && parent.right.key == key) curNode = parent.right + if(parent.right != null && parent.right?.key == key) curNode = parent.right else curNode = parent.left - if (curNode.right != null) count++ - if (curNode.left != null) count++ + if (curNode?.right != null) count++ + if (curNode?.left != null) count++ if (count == 0) { if (parent.right === curNode) parent.right = null else parent.left = null } else if (count == 1) { - if (curNode.left == null) { - if (parent.right === x) parent_x.right = curNode.right - else parent.left = curNode.right + if (curNode?.left == null) { + if (parent.right === curNode) parent.right = curNode?.right + else parent.left = curNode?.right } else { if (parent.right === curNode) parent.right = curNode.left else parent.left = curNode.left } } else { - var child = curNode.right + var child = curNode?.right var parent_child = curNode while (child!!.left != null) { if (child.left!!.left == null) parent_child = child child = child.left } - curNode.key = child.key - curNode.value = child.value + curNode?.key = child.key + curNode?.value = child.value parent_child!!.left = child.right } this.amountOfNodes -= 1 - return curNode.value + return curNode?.value } - fun changeVal(key: K, newValue: V): Boolean { - var curNode = this.root - while (curNode != null) { - curNode = if (key > curNode.key) curNode.right - else if (key < curNode.key) curNode.left - else { - curNode.value = newValue - return true - } - } - return false - } - - fun findParent(key: K): Node_T?{ + fun findParent(key: K): BSTNode?{ var parent = this.root - if(parent == null || root.key == key) return null - while(parent.isThereChild == true){ - if( (parent.right != null && parent.right.key == key) || (parent.left != null && parent.left.key == key)) return parent + if(parent == null || root!!.key == key) return null + while(parent?.isThereChild() == true){ + if( (parent.right != null && parent.right?.key == key) || (parent.left != null && parent.left?.key == key)) return parent else{ if(key > parent.key){ if(parent.right == null) return null @@ -103,12 +90,13 @@ class BSTree, V> : BinTree>() { } } } + return null } fun deleteSubTree(key: K): Boolean{ var parent: BSTNode? = this.findParent(key) if(parent == null) return false - if(parent.right != null && parent.right.key == key) parent.right = null + if(parent.right != null && parent.right?.key == key) parent.right = null else parent.left = null return true } @@ -117,8 +105,8 @@ class BSTree, V> : BinTree>() { var parent: BSTNode? = this.findParent(key) var child: BSTree = BSTree() if(parent == null) return null - if(parent.right != null && parent.right.key == key) child.add(key, parent.right.value) - else child.add(key, parent.left.value) + if(parent.right != null && parent.right?.key == key) child.add(key, parent.right!!.value) + else child.add(key, parent.left!!.value) return child } } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 06b1492..89e6006 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -77,7 +77,7 @@ abstract class BinTree, V, Node_T : TreeNode> : } - fun height(): Int { + fun height(): Int? { return countHeight(root) } } diff --git a/src/main/kotlin/treeLib/nodes/BSTNode.kt b/src/main/kotlin/treeLib/nodes/BSTNode.kt index 35eaec2..2de9d15 100644 --- a/src/main/kotlin/treeLib/nodes/BSTNode.kt +++ b/src/main/kotlin/treeLib/nodes/BSTNode.kt @@ -8,6 +8,6 @@ class BSTNode, V>( ) : TreeNode>(key, value, right, left){ internal fun isThereChild(): Boolean{ if(this.left != null || this.right != null) return true - else false + else return false } } From efd8517e286891b8332ce17167649906d712516d Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Mon, 1 Apr 2024 16:23:48 +0300 Subject: [PATCH 131/186] feat: add fun toPair() --- src/main/kotlin/treeLib/nodes/TreeNode.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index 711e401..04d5efc 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -17,6 +17,8 @@ abstract class TreeNode, V, Node_T : TreeNode>( override fun toString() = Pair(key, value).toString() + fun toPair() = Pair(key, value) + internal fun attach(node: Node_T?): Boolean { if (node == null) return false when { From ae7e6a18fb1cd63f899f16444804a3e48ce6a4dd Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Mon, 1 Apr 2024 16:26:07 +0300 Subject: [PATCH 132/186] fix: change the way nodes replace each other in remove() --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index 4cf3f08..c63b396 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -99,15 +99,15 @@ class RBTree, V> : BinTree>(), TreeBalancer else /*sonRight and sonLeft != null*/ -> { val replace = removedNode //Will rewrite this node with other one treeBranch.addFirst(replace) - removedNode = sonRight - while (removedNode?.left != null) { + removedNode = sonLeft + while (removedNode?.right != null) { treeBranch.addFirst(removedNode) - removedNode = removedNode.left + removedNode = removedNode.right } parent = treeBranch.first() replace.key = removedNode?.key ?: throw Exception("well...") replace.value = removedNode?.value ?: throw Exception("that's bad") - removedNode.right + removedNode.left } } From 8ca1a6d2427c2e9df32fd55f45d256d02f13e01d Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Mon, 1 Apr 2024 20:00:12 +0300 Subject: [PATCH 133/186] refactor: add return types --- src/main/kotlin/treeLib/nodes/TreeNode.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index 04d5efc..d3e6e91 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -7,17 +7,17 @@ abstract class TreeNode, V, Node_T : TreeNode>( internal var left: Node_T? = null, ) : Comparable { - override fun compareTo(other: Node_T) = key.compareTo(other.key) + override fun compareTo(other: Node_T): Int = key.compareTo(other.key) - override fun hashCode() = Pair(key, value).hashCode() + override fun hashCode(): Int = Pair(key, value).hashCode() override fun equals(other: Any?): Boolean { return (other as? Node_T != null) && (key == other.key) && (value == other.value) } - override fun toString() = Pair(key, value).toString() + override fun toString(): String = Pair(key, value).toString() - fun toPair() = Pair(key, value) + fun toPair(): Pair = Pair(key, value) internal fun attach(node: Node_T?): Boolean { if (node == null) return false @@ -29,7 +29,7 @@ abstract class TreeNode, V, Node_T : TreeNode>( return true } - internal fun moveOn(otherKey: K) = when { + internal fun moveOn(otherKey: K): Node_T? = when { key > otherKey -> left key < otherKey -> right else -> this as? Node_T From 9e09724d800465dfa69faec2334fca55fc126228 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 20:01:26 +0300 Subject: [PATCH 134/186] ci: change jacoco reports paths --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index e8e6a63..51d2889 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -24,7 +24,7 @@ tasks.jacocoTestReport { reports { xml.required = false csv.required = false - html.outputLocation = layout.buildDirectory.dir("jacocoHtml") + html.outputLocation = layout.buildDirectory.dir("jacoco") } } @@ -34,5 +34,5 @@ kotlin { jacoco { toolVersion = "0.8.11" - reportsDirectory = layout.buildDirectory.dir("customJacocoReportDir") + reportsDirectory = layout.buildDirectory.dir("reports/jacoco") } From e11256331ff20cf8cc8415d936c7b45f132e578d Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 20:18:17 +0300 Subject: [PATCH 135/186] Update test_with_coverage.yml --- .github/workflows/test_with_coverage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_with_coverage.yml b/.github/workflows/test_with_coverage.yml index 06c5fec..4b998d0 100644 --- a/.github/workflows/test_with_coverage.yml +++ b/.github/workflows/test_with_coverage.yml @@ -46,8 +46,8 @@ jobs: uses: madrapps/jacoco-report@v1.6.1 with: paths: | - ${{ github.workspace }}/**/build/reports/jacoco/prodNormalDebugCoverage/prodNormalDebugCoverage.xml, - ${{ github.workspace }}/**/build/reports/jacoco/**/debugCoverage.xml + ${{ github.workspace }}/**/build/reports/jacoco/treeLib.bintrees.interfaces/index.html, + ${{ github.workspace }}/**/build/reports/jacoco/treeLib.bintrees/index.html token: ${{ secrets.GITHUB_TOKEN }} min-coverage-overall: 40 min-coverage-changed-files: 60 From b70f34a454bfd5ef79955313a4572c1efebd54c4 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 21:09:26 +0300 Subject: [PATCH 136/186] fix: setting up the test workflow --- .github/workflows/test_with_coverage.yml | 29 ++++-------------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/.github/workflows/test_with_coverage.yml b/.github/workflows/test_with_coverage.yml index 4b998d0..2a81acb 100644 --- a/.github/workflows/test_with_coverage.yml +++ b/.github/workflows/test_with_coverage.yml @@ -1,29 +1,14 @@ -# This is a basic workflow to help you get started with Actions - name: Test with Coverage -# Controls when the workflow will run on: - # Triggers the workflow on push or pull request events but only for the "main" branch push: - branches: [ "main" ] pull_request: - branches: [ "main" ] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel + jobs: - # This workflow contains a single job called "build" build: - # The type of runner that the job will run on - name: Build Tests runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job + steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - name: Checkout sources uses: actions/checkout@v3 @@ -41,13 +26,9 @@ jobs: chmod +x gradlew ./gradlew test - - name: Add coverage to PR - id: jacoco - uses: madrapps/jacoco-report@v1.6.1 + - name: JaCoCo Report + uses: Madrapps/jacoco-report@v1.6.1 with: paths: | - ${{ github.workspace }}/**/build/reports/jacoco/treeLib.bintrees.interfaces/index.html, - ${{ github.workspace }}/**/build/reports/jacoco/treeLib.bintrees/index.html + ${{ github.workspace }}/**/build/reports/jacoco/test/jacocoTestReport.xml, token: ${{ secrets.GITHUB_TOKEN }} - min-coverage-overall: 40 - min-coverage-changed-files: 60 From b6cd58f7540b21195245bce49b80d7a3a9f86aec Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 21:13:21 +0300 Subject: [PATCH 137/186] fix: enable xml reports --- build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 51d2889..b0eff4b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,8 +22,9 @@ tasks.test { tasks.jacocoTestReport { dependsOn(tasks.test) reports { - xml.required = false + xml.required = true csv.required = false + html.required = false html.outputLocation = layout.buildDirectory.dir("jacoco") } } From 446e327a3496b30bc8d2b7ca45a4813a0ed99234 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 21:26:11 +0300 Subject: [PATCH 138/186] fix: split test and coverage --- .github/workflows/test_with_coverage.yml | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/.github/workflows/test_with_coverage.yml b/.github/workflows/test_with_coverage.yml index 2a81acb..cb71daf 100644 --- a/.github/workflows/test_with_coverage.yml +++ b/.github/workflows/test_with_coverage.yml @@ -1,4 +1,4 @@ -name: Test with Coverage +name: Test on: push: @@ -21,14 +21,3 @@ jobs: uses: gradle/actions/setup-gradle@v3 - name: Build with Gradle run: ./gradlew build - - name: Run With Coverage - run: | - chmod +x gradlew - ./gradlew test - - - name: JaCoCo Report - uses: Madrapps/jacoco-report@v1.6.1 - with: - paths: | - ${{ github.workspace }}/**/build/reports/jacoco/test/jacocoTestReport.xml, - token: ${{ secrets.GITHUB_TOKEN }} From 5d068e9516cc3bcfadf8cdf3af7df071cb48538a Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 21:42:46 +0300 Subject: [PATCH 139/186] fix: rename workflow yml file for test --- .github/workflows/{test_with_coverage.yml => test.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{test_with_coverage.yml => test.yml} (100%) diff --git a/.github/workflows/test_with_coverage.yml b/.github/workflows/test.yml similarity index 100% rename from .github/workflows/test_with_coverage.yml rename to .github/workflows/test.yml From 34db48fd2ee7fff59937e585ee6166f9ad48c150 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Mon, 1 Apr 2024 21:59:42 +0300 Subject: [PATCH 140/186] ci: JaCoCo PR coverage workflow --- .github/workflows/coverage.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/coverage.yml diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000..89757eb --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,31 @@ +name: Measure coverage + +on: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - name: Checkout sources + uses: actions/checkout@v3 + - name: Set up JDK 11 + uses: actions/setup-java@v4 + with: + java-version: '11' + distribution: 'temurin' + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + - name: Run Test + run: | + chmod +x gradlew + ./gradlew test + - name: JaCoCO Coverage + id: jacoco + uses: Madrapps/jacoco-report@v1.6.1 + with: + paths: | + ${{ github.workspace }}/build/reports/jacoco/test/jacocoTestReport.xml + token: ${{ secrets.GITHUB_TOKEN }} From 96e36432037507b369f5307542c7bcfa7e421e2a Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 2 Apr 2024 00:01:10 +0300 Subject: [PATCH 141/186] reformat: auto code reformat --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 12 +++---- src/main/kotlin/treeLib/bintrees/BSTree.kt | 36 +++++++++---------- src/main/kotlin/treeLib/bintrees/RBTree.kt | 6 ++-- .../treeLib/bintrees/interfaces/BinTree.kt | 6 ++-- .../bintrees/interfaces/IterationOrder.kt | 2 +- .../bintrees/interfaces/TreeIterator.kt | 2 +- src/main/kotlin/treeLib/nodes/BSTNode.kt | 7 ++-- src/main/kotlin/treeLib/nodes/TreeNode.kt | 2 +- 8 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index ceb1a83..1aec2ac 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -39,7 +39,7 @@ class AVLTree, V> : BinTree>() { if (node?.left != null) { return findMin(node.left) } - return (node) + return node } private fun removeMin(node: AVLNode?): AVLNode? { @@ -73,7 +73,7 @@ class AVLTree, V> : BinTree>() { private fun rotateLeft(nodeA: AVLNode?): AVLNode? { if (nodeA != null) { - if ((nodeA.right) != null) { + if (nodeA.right != null) { val nodeB = nodeA.right nodeA.right = nodeB?.left nodeB?.left = nodeA @@ -90,7 +90,7 @@ class AVLTree, V> : BinTree>() { private fun rotateRight(nodeA: AVLNode?): AVLNode? { if (nodeA != null) { - if ((nodeA.left) != null) { + if (nodeA.left != null) { val nodeB = nodeA.left nodeA.left = nodeB?.right nodeB?.right = nodeA @@ -161,10 +161,10 @@ class AVLTree, V> : BinTree>() { } override fun height(): Int? { - if (root == null) { - return 0 + return if (root == null) { + 0 } else { - return root?.height + root?.height } } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index f1ce79f..70c33d9 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -43,8 +43,8 @@ class BSTree, V> : BinTree>() { var count = 0 var curNode: BSTNode? = null var parent = this.findParent(key) - if(parent == null) return null - if(parent.right != null && parent.right?.key == key) curNode = parent.right + if (parent == null) return null + if (parent.right != null && parent.right?.key == key) curNode = parent.right else curNode = parent.left if (curNode?.right != null) count++ if (curNode?.left != null) count++ @@ -75,19 +75,17 @@ class BSTree, V> : BinTree>() { } - - fun findParent(key: K): BSTNode?{ + fun findParent(key: K): BSTNode? { var parent = this.root - if(parent == null || root!!.key == key) return null - while(parent?.isThereChild() == true){ - if( (parent.right != null && parent.right?.key == key) || (parent.left != null && parent.left?.key == key)) return parent - else{ - if(key > parent.key){ - if(parent.right == null) return null + if (parent == null || root!!.key == key) return null + while (parent?.isThereChild() == true) { + if ((parent.right != null && parent.right?.key == key) || (parent.left != null && parent.left?.key == key)) return parent + else { + if (key > parent.key) { + if (parent.right == null) return null parent = parent.right - } - else{ - if(parent.left == null) return null + } else { + if (parent.left == null) return null parent = parent.left } } @@ -95,19 +93,19 @@ class BSTree, V> : BinTree>() { return null } - fun deleteSubTree(key: K): Boolean{ + fun deleteSubTree(key: K): Boolean { var parent: BSTNode? = this.findParent(key) - if(parent == null) return false - if(parent.right != null && parent.right?.key == key) parent.right = null + if (parent == null) return false + if (parent.right != null && parent.right?.key == key) parent.right = null else parent.left = null return true } - fun getSubTree(key: K): BSTree?{ + fun getSubTree(key: K): BSTree? { var parent: BSTNode? = this.findParent(key) var child: BSTree = BSTree() - if(parent == null) return null - if(parent.right != null && parent.right?.key == key) child.add(key, parent.right!!.value) + if (parent == null) return null + if (parent.right != null && parent.right?.key == key) child.add(key, parent.right!!.value) else child.add(key, parent.left!!.value) return child diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index fdf8759..fb708e4 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -27,7 +27,7 @@ class RBTree, V> : BinTree>(), TreeBalancer while (curNode != null) { treeBranch.addFirst(curNode) val nextNode = curNode.moveOn(key) - if (nextNode === curNode) return null //node with given key already exist + if (nextNode === curNode) return null //node with given key already exist curNode = nextNode } val parent = treeBranch.first() @@ -89,7 +89,7 @@ class RBTree, V> : BinTree>(), TreeBalancer val treeBranch = ArrayDeque>() var removedNode = if (root != null) root else return null while (removedNode?.key != key) { - if (removedNode == null) return null //node with given key doesn't exist + if (removedNode == null) return null //node with given key doesn't exist treeBranch.addFirst(removedNode) removedNode = removedNode.moveOn(key) } @@ -102,7 +102,7 @@ class RBTree, V> : BinTree>(), TreeBalancer sonRight != null && sonLeft == null -> sonRight sonRight == null && sonLeft != null -> sonLeft else /*sonRight and sonLeft != null*/ -> { - val replace = removedNode //Will rewrite this node with other one + val replace = removedNode //Will rewrite this node with other one treeBranch.addFirst(replace) removedNode = sonRight while (removedNode?.left != null) { diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index d4a5a8f..4b6a6e5 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -13,11 +13,11 @@ abstract class BinTree, V, Node_T : TreeNode> : fun findByKey(key: K): Node_T? { var curNode = root while (curNode != null) - curNode = when { + curNode = when { key > curNode.key -> curNode.right key < curNode.key -> curNode.left else -> return curNode - } + } return null } @@ -80,7 +80,7 @@ abstract class BinTree, V, Node_T : TreeNode> : } - fun height(): Int? { + open fun height(): Int? { return countHeight(root) } } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/IterationOrder.kt b/src/main/kotlin/treeLib/bintrees/interfaces/IterationOrder.kt index 9d8b151..7371dee 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/IterationOrder.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/IterationOrder.kt @@ -1,5 +1,5 @@ package treeLib.bintrees.interfaces enum class IterationOrder { - IN_ORDER, PRE_ORDER, POST_ORDER, + IN_ORDER, PRE_ORDER, POST_ORDER, } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt index c6d061e..2a1e8b0 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt @@ -5,7 +5,7 @@ import treeLib.nodes.TreeNode class TreeIterator, V, Node_T : TreeNode>( private val root: Node_T?, private val order: IterationOrder, - ): Iterator> { +) : Iterator> { private val stack: ArrayDeque = ArrayDeque() init { diff --git a/src/main/kotlin/treeLib/nodes/BSTNode.kt b/src/main/kotlin/treeLib/nodes/BSTNode.kt index 2de9d15..4328b12 100644 --- a/src/main/kotlin/treeLib/nodes/BSTNode.kt +++ b/src/main/kotlin/treeLib/nodes/BSTNode.kt @@ -5,9 +5,8 @@ class BSTNode, V>( value: V, right: BSTNode? = null, left: BSTNode? = null -) : TreeNode>(key, value, right, left){ - internal fun isThereChild(): Boolean{ - if(this.left != null || this.right != null) return true - else return false +) : TreeNode>(key, value, right, left) { + internal fun isThereChild(): Boolean { + return this.left != null || this.right != null } } diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index 711e401..9db5733 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -12,7 +12,7 @@ abstract class TreeNode, V, Node_T : TreeNode>( override fun hashCode() = Pair(key, value).hashCode() override fun equals(other: Any?): Boolean { - return (other as? Node_T != null) && (key == other.key) && (value == other.value) + return (other as? Node_T != null) && key == other.key && value == other.value } override fun toString() = Pair(key, value).toString() From a52e866da31c43f83396ac3cc0d97fb4dce2db61 Mon Sep 17 00:00:00 2001 From: Islam Date: Tue, 2 Apr 2024 03:24:10 +0300 Subject: [PATCH 142/186] feat and fix: added not-done test and fixed mistakes that test showed q --- src/main/kotlin/treeLib/bintrees/BSTree.kt | 37 ++- .../treeLib/bintrees/interfaces/BinTree.kt | 2 +- src/test/kotlin/BSTreeTest.kt | 229 ++++++++++++++++++ 3 files changed, 255 insertions(+), 13 deletions(-) create mode 100644 src/test/kotlin/BSTreeTest.kt diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index f1ce79f..c7ccbd6 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -2,40 +2,51 @@ package treeLib.bintrees import treeLib.bintrees.interfaces.BinTree import treeLib.nodes.BSTNode +import treeLib.nodes.TreeNode class BSTree, V> : BinTree>() { override var root: BSTNode? = null override var amountOfNodes = 0 - fun addPairs(keys: List, values: List): Boolean { - if (keys.size != values.size) return false - for (curKey in keys.indices) { - this.add(keys[curKey], values[curKey]) + fun addPairs(vararg pairs: Pair): Boolean { + for(pair in pairs){ + if( this.add(pair.first, pair.second) == null ) return false + } + return true + } + + fun removePairs(vararg keys: K): Boolean{ + for(key in keys){ + if( this.remove(key) == null ) return false } return true } override fun add(key: K, value: V): BSTNode? { - if (root == null) this.root = BSTNode(key, value) + if (root == null){ + this.root = BSTNode(key, value) + this.amountOfNodes += 1 + return root + } var curNode = this.root while (curNode != null) { if (key > curNode.key) { if (curNode.right == null) { curNode.right = BSTNode(key, value) + this.amountOfNodes += 1 return curNode.right - } curNode = curNode.right } else if (key < curNode.key) { if (curNode.left == null) { curNode.left = BSTNode(key, value) + this.amountOfNodes += 1 return curNode.left } curNode = curNode.left } else return null } - this.amountOfNodes += 1 return null } @@ -43,6 +54,7 @@ class BSTree, V> : BinTree>() { var count = 0 var curNode: BSTNode? = null var parent = this.findParent(key) + if(this.root?.key == key) parent = BSTNode(root!!.key, root!!.value, root) if(parent == null) return null if(parent.right != null && parent.right?.key == key) curNode = parent.right else curNode = parent.left @@ -68,7 +80,8 @@ class BSTree, V> : BinTree>() { } curNode?.key = child.key curNode?.value = child.value - parent_child!!.left = child.right + if(curNode?.right != child) parent_child!!.left = child.right + else curNode.right = child.right } this.amountOfNodes -= 1 return curNode?.value @@ -96,7 +109,7 @@ class BSTree, V> : BinTree>() { } fun deleteSubTree(key: K): Boolean{ - var parent: BSTNode? = this.findParent(key) + val parent: BSTNode? = this.findParent(key) if(parent == null) return false if(parent.right != null && parent.right?.key == key) parent.right = null else parent.left = null @@ -104,12 +117,12 @@ class BSTree, V> : BinTree>() { } fun getSubTree(key: K): BSTree?{ - var parent: BSTNode? = this.findParent(key) - var child: BSTree = BSTree() + val parent: BSTNode? = this.findParent(key) + val child: BSTree = BSTree() if(parent == null) return null + //На будущее, нужно добавить детей к child.add() if(parent.right != null && parent.right?.key == key) child.add(key, parent.right!!.value) else child.add(key, parent.left!!.value) return child - } } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index d4a5a8f..eb965f1 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -80,7 +80,7 @@ abstract class BinTree, V, Node_T : TreeNode> : } - fun height(): Int? { + open fun height(): Int? { return countHeight(root) } } diff --git a/src/test/kotlin/BSTreeTest.kt b/src/test/kotlin/BSTreeTest.kt new file mode 100644 index 0000000..fd5d751 --- /dev/null +++ b/src/test/kotlin/BSTreeTest.kt @@ -0,0 +1,229 @@ +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Nested +import treeLib.bintrees.BSTree +import treeLib.nodes.BSTNode +import kotlin.math.abs +import org.junit.jupiter.api.Test + +class BSTreeTest { + var baum = BSTree() + + + @Test + fun findParent() { + + } + + + + + + + @Nested + inner class TestingAddMethods { + + @Test + fun addToEmptyTree() { + assertEquals("qwerty", baum.root()?.value) + assertEquals(4, baum.root()?.key) + } + + @BeforeEach + fun setUp() { + baum.add(4, "qwerty") + baum.add(2, "Ge") + baum.add(5, "rma") + baum.add(-1, "ny") + baum.add(3, "the") + baum.add(40, "best") + baum.add(44, "Ja") + } + + @Test + fun checkWaysToNodes() { + val rt = baum.root() + assertEquals(BSTNode(5,"rma"), rt?.right) + assertEquals(BSTNode(3, "the"), rt?.left?.right) + assertEquals(BSTNode(-1, "ny"), rt?.left?.left) + assertEquals(BSTNode(44, "Ja"), rt?.right?.right?.right) + } + + @Test + fun checkAmountsOfNodes() { + assertEquals(7, baum.countNodes()) + assertEquals(BSTNode(10, "Was"),baum.add(10, "Was")) + assertEquals(8, baum.countNodes()) + } + + @Test + fun addPairs() { + baum.addPairs(Pair(1, "ein"), Pair(7, "sieben"), Pair(6, "sechs")) + assertEquals(10, baum.countNodes()) + assertEquals(1, baum.root()?.left?.left?.right?.key) + assertEquals(6, baum.root()?.right?.right?.left?.left?.key) + } + + @Test + fun addAlreadyExistingNodes() { + assertNull(baum.add(5, "rma")) + assertNull(baum.add(3, "the")) + assertNull(baum.add(40, "best")) + assertNull(baum.add(44, "Ja")) + assertEquals(7, baum.countNodes()) + } + + @Test + fun orderMatters() { + baum.clear() + assertTrue(baum.addPairs(Pair(4, "Vier"), Pair(5, "Funf"), Pair(40, "Vierzig"), Pair(44,"Vierundvierzig"))) + var rt = baum.root() + assertEquals(5, rt?.right?.key) + assertEquals(44, rt?.right?.right?.right?.key) + baum.clear() + baum.addPairs(Pair(4, "Vier"), Pair(44,"Vierundvierzig"), Pair(40, "Vierzig"), Pair(5, "Funf")) + rt = baum.root() + assertEquals(5, rt?.right?.left?.left?.key) + assertEquals(44, rt?.right?.key) + //In other words, with different order we have different ways to nodes + } + } + + @Nested + inner class Remove { + @BeforeEach + fun setUp() { + for(key in listOf(10, 13, 12, 11, 20, 15, 25, -7, 5, -10, 9)){ + baum.add(key, "test") + } + } + + @Test + fun removeNodesWithNoKinder() { + val rt = baum.root() + assertTrue(baum.removePairs(-10, 11)) + baum.remove(9) + assertNull(rt?.left?.left) + assertNull(rt?.right?.left?.left) + assertNull(rt?.left?.right?.right) + } + + @Test + fun removeNodesWithEinKind() { + val rt = baum.root() + baum.removePairs(12) + baum.remove(5) + assertEquals(9, rt?.left?.right?.key) + assertNull(rt?.left?.right?.right) + assertEquals(11, rt?.right?.left?.key) + assertNull(rt?.right?.left?.left) + } + + @Test + fun removeNodeWithZweiKinderFirstCase() { + //I don't know how to describe any of these cases, just image current tree and I hope you'll get it + val rt = baum.root() + baum.remove(-7) + assertEquals(5, rt?.left?.key) + assertEquals(-10, rt?.left?.left?.key) + assertEquals(9, rt?.left?.right?.key) + assertNull(rt?.left?.right?.right) + } + + @Test + fun removeNodeWithZweiKinderSecondCase() { + val rt = baum.root() + assertEquals("test", baum.remove(13)) + assertEquals(15, rt?.right?.key) + assertEquals(12, rt?.right?.left?.key) + assertEquals(20, rt?.right?.right?.key) + assertEquals(25, rt?.right?.right?.right?.key) + assertNull(rt?.right?.right?.left) + } + + @Test + fun removeNodeWithZweiKinderThirdCase() { + val rt = baum.root() + baum.addPairs(Pair(16, "test")) + baum.remove(13) + assertEquals(16, rt?.right?.right?.left?.key) + } + + @Test + fun removeNodeWithZweiKinderFourthCase() { + val rt = baum.root() + baum.changeVal(25, "Sieg") + baum.remove(20) + assertNull(rt?.right?.right?.right) + assertEquals(BSTNode(25, "Sieg"), rt?.right?.right) + assertEquals(BSTNode(15,"test"), rt?.right?.right?.left) + } + + @Test + fun removeNodeWithZweiKinderFifthCase() { + baum.clear() + baum.addPairs(Pair(-50, "Notf"), Pair(2, "Zwei"), Pair(101, "One hundred and One")) + for(key in listOf(-30, 99, 95, 90, 78, 56, 45, 34, 23, 14, 7, 3, 5, 8)){ + baum.add(key, "test") + } + val rt = baum.root() + baum.remove(2) + assertEquals(BSTNode(3, "test"), rt?.right) + baum.remove(3) + assertEquals(BSTNode(5, "test"), rt?.right) + val ls = listOf(99, 95, 90, 78, 56, 45, 34, 23, 14, 7, 8, 5).sorted() + for(i in 0..(ls.size-2) ){ + baum.remove(ls[i]) + assertEquals(BSTNode(ls[i + 1], "test"), rt?.right) + } + assertNull(rt?.right?.right?.left) + } + + @Test + fun removeNotExistingOderAlreadyRemovedNode() { + assertNull(baum.remove(62)) + assertNull(baum.remove(-24)) + assertFalse(baum.removePairs(5,6,8,3)) + assertEquals("test", baum.remove(13)) + assertNull(baum.remove(13)) + } + + @Test + fun removeAndChangingAmountOfNode() { + val rt = baum.root() + assertEquals(11, baum.countNodes()) + baum.remove(11) + assertEquals(10, baum.countNodes()) + baum.remove(20) + assertEquals(9, baum.countNodes()) + baum.remove(5) + assertEquals(8, baum.countNodes()) + baum.remove(-7) + assertEquals(7, baum.countNodes()) + } + + @Test + fun removeRoot() { + baum.remove(10) + assertEquals(BSTNode(11, "test"), baum.root()) + baum.remove(11) + assertEquals(BSTNode(12, "test"), baum.root()) + baum.remove(12) + assertEquals(BSTNode(13, "test"), baum.root()) + baum.remove(13) + assertEquals(BSTNode(15, "test"), baum.root()) + } + + @Test + fun howMuchDoWeNeedToDeleteTheWholeTreeByRemovingEachSingleNode() { + val len = 11 + for(i in 0..5){ + assertNotNull(baum.root()) + baum.remove(baum.root()?.key!!.toInt()) + } + baum.remove(25) + assertEquals(BSTNode(-7, "test"), baum.root()?.left) + assertNull(baum.root()) + } + } +} \ No newline at end of file From a12d0b5b45a0167fd0128fe508e0a552c310a9ee Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 2 Apr 2024 09:36:58 +0300 Subject: [PATCH 143/186] fix(avl): now remove deletes root node properly --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 3 +++ src/test/kotlin/AVLTreeTest.kt | 23 +++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 1aec2ac..5848123 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -26,6 +26,9 @@ class AVLTree, V> : BinTree>() { val min = findMin(nodeB) min?.right = removeMin(nodeB) min?.left = nodeA + if (root?.key == key){ + root = min + } return balanceNode(min) } return balanceNode(node) diff --git a/src/test/kotlin/AVLTreeTest.kt b/src/test/kotlin/AVLTreeTest.kt index d358686..748af45 100644 --- a/src/test/kotlin/AVLTreeTest.kt +++ b/src/test/kotlin/AVLTreeTest.kt @@ -56,11 +56,18 @@ class AVLTreeTest { } @Test - fun removeRoot() { + fun removeOnRoot() { val key : Int? = tree.root()?.key if (key != null) { tree.remove(key) assertNotNull(tree.root()) + for (i in 0..10) { + if (i == key) { + assertNull(tree.findByKey(key)) + } else { + assertNotNull(tree.findByKey(i)) + } + } } else { fail() } @@ -76,7 +83,7 @@ class AVLTreeTest { } @Test - fun removeNodeWithChildren(){ + fun removeNodeWithTwoChildren(){ tree.remove(7) assertNull(tree.findByKey(7)) for (i in 0..10) { @@ -89,6 +96,9 @@ class AVLTreeTest { @Test fun removeNonExistentNode() { assertNull(tree.remove(999)) + for (i in 0..10) { + assertNotNull(tree.findByKey(i)) + } } } @@ -137,6 +147,15 @@ class AVLTreeTest { tree.root()?.left?.let { tree.remove(it.key) } assertTrue(isBalanced(tree.root())) } + + @Test + fun afterRootRemoveAVLIsBalanced(){ + val key : Int? = tree.root()?.key + if (key != null) { + tree.remove(key) + assertTrue(isBalanced(tree.root())) + } + } } @Nested From 1be3a548b11e6843f139333619ddedec3a6205dc Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 2 Apr 2024 10:43:26 +0300 Subject: [PATCH 144/186] fix(avl): now remove deletes root node properly --- src/test/kotlin/AVLTreeTest.kt | 22 ++-- src/test/kotlin/BSTreeTest.kt | 229 --------------------------------- 2 files changed, 10 insertions(+), 241 deletions(-) delete mode 100644 src/test/kotlin/BSTreeTest.kt diff --git a/src/test/kotlin/AVLTreeTest.kt b/src/test/kotlin/AVLTreeTest.kt index 748af45..eba4fdc 100644 --- a/src/test/kotlin/AVLTreeTest.kt +++ b/src/test/kotlin/AVLTreeTest.kt @@ -12,13 +12,6 @@ class AVLTreeTest { @Nested inner class InsertionTests { - @Test - fun useAddOnEmptyTree() { - tree.clear() - tree.add(0, "a") - assertEquals(0, tree.root()?.key) - assertEquals("a", tree.root()?.value) - } @BeforeEach fun setUp() { @@ -27,6 +20,14 @@ class AVLTreeTest { tree.add(-1, "b") } + @Test + fun useAddOnEmptyTree() { + tree.clear() + tree.add(0, "a") + assertEquals(0, tree.root()?.key) + assertEquals("a", tree.root()?.value) + } + @Test fun addByKey () { assertEquals(-1, tree.root()?.left?.key) @@ -36,10 +37,7 @@ class AVLTreeTest { } @Test - fun addDoesNothingWhenKeyExists() { - tree.add(0, "a") - tree.add(1, "b") - tree.add(-1, "b") + fun addDoesNothingIfKeyExists() { assertEquals(null, tree.root()?.right?.right) assertEquals(null, tree.root()?.right?.left) } @@ -56,7 +54,7 @@ class AVLTreeTest { } @Test - fun removeOnRoot() { + fun removeRoot() { val key : Int? = tree.root()?.key if (key != null) { tree.remove(key) diff --git a/src/test/kotlin/BSTreeTest.kt b/src/test/kotlin/BSTreeTest.kt deleted file mode 100644 index fd5d751..0000000 --- a/src/test/kotlin/BSTreeTest.kt +++ /dev/null @@ -1,229 +0,0 @@ -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Nested -import treeLib.bintrees.BSTree -import treeLib.nodes.BSTNode -import kotlin.math.abs -import org.junit.jupiter.api.Test - -class BSTreeTest { - var baum = BSTree() - - - @Test - fun findParent() { - - } - - - - - - - @Nested - inner class TestingAddMethods { - - @Test - fun addToEmptyTree() { - assertEquals("qwerty", baum.root()?.value) - assertEquals(4, baum.root()?.key) - } - - @BeforeEach - fun setUp() { - baum.add(4, "qwerty") - baum.add(2, "Ge") - baum.add(5, "rma") - baum.add(-1, "ny") - baum.add(3, "the") - baum.add(40, "best") - baum.add(44, "Ja") - } - - @Test - fun checkWaysToNodes() { - val rt = baum.root() - assertEquals(BSTNode(5,"rma"), rt?.right) - assertEquals(BSTNode(3, "the"), rt?.left?.right) - assertEquals(BSTNode(-1, "ny"), rt?.left?.left) - assertEquals(BSTNode(44, "Ja"), rt?.right?.right?.right) - } - - @Test - fun checkAmountsOfNodes() { - assertEquals(7, baum.countNodes()) - assertEquals(BSTNode(10, "Was"),baum.add(10, "Was")) - assertEquals(8, baum.countNodes()) - } - - @Test - fun addPairs() { - baum.addPairs(Pair(1, "ein"), Pair(7, "sieben"), Pair(6, "sechs")) - assertEquals(10, baum.countNodes()) - assertEquals(1, baum.root()?.left?.left?.right?.key) - assertEquals(6, baum.root()?.right?.right?.left?.left?.key) - } - - @Test - fun addAlreadyExistingNodes() { - assertNull(baum.add(5, "rma")) - assertNull(baum.add(3, "the")) - assertNull(baum.add(40, "best")) - assertNull(baum.add(44, "Ja")) - assertEquals(7, baum.countNodes()) - } - - @Test - fun orderMatters() { - baum.clear() - assertTrue(baum.addPairs(Pair(4, "Vier"), Pair(5, "Funf"), Pair(40, "Vierzig"), Pair(44,"Vierundvierzig"))) - var rt = baum.root() - assertEquals(5, rt?.right?.key) - assertEquals(44, rt?.right?.right?.right?.key) - baum.clear() - baum.addPairs(Pair(4, "Vier"), Pair(44,"Vierundvierzig"), Pair(40, "Vierzig"), Pair(5, "Funf")) - rt = baum.root() - assertEquals(5, rt?.right?.left?.left?.key) - assertEquals(44, rt?.right?.key) - //In other words, with different order we have different ways to nodes - } - } - - @Nested - inner class Remove { - @BeforeEach - fun setUp() { - for(key in listOf(10, 13, 12, 11, 20, 15, 25, -7, 5, -10, 9)){ - baum.add(key, "test") - } - } - - @Test - fun removeNodesWithNoKinder() { - val rt = baum.root() - assertTrue(baum.removePairs(-10, 11)) - baum.remove(9) - assertNull(rt?.left?.left) - assertNull(rt?.right?.left?.left) - assertNull(rt?.left?.right?.right) - } - - @Test - fun removeNodesWithEinKind() { - val rt = baum.root() - baum.removePairs(12) - baum.remove(5) - assertEquals(9, rt?.left?.right?.key) - assertNull(rt?.left?.right?.right) - assertEquals(11, rt?.right?.left?.key) - assertNull(rt?.right?.left?.left) - } - - @Test - fun removeNodeWithZweiKinderFirstCase() { - //I don't know how to describe any of these cases, just image current tree and I hope you'll get it - val rt = baum.root() - baum.remove(-7) - assertEquals(5, rt?.left?.key) - assertEquals(-10, rt?.left?.left?.key) - assertEquals(9, rt?.left?.right?.key) - assertNull(rt?.left?.right?.right) - } - - @Test - fun removeNodeWithZweiKinderSecondCase() { - val rt = baum.root() - assertEquals("test", baum.remove(13)) - assertEquals(15, rt?.right?.key) - assertEquals(12, rt?.right?.left?.key) - assertEquals(20, rt?.right?.right?.key) - assertEquals(25, rt?.right?.right?.right?.key) - assertNull(rt?.right?.right?.left) - } - - @Test - fun removeNodeWithZweiKinderThirdCase() { - val rt = baum.root() - baum.addPairs(Pair(16, "test")) - baum.remove(13) - assertEquals(16, rt?.right?.right?.left?.key) - } - - @Test - fun removeNodeWithZweiKinderFourthCase() { - val rt = baum.root() - baum.changeVal(25, "Sieg") - baum.remove(20) - assertNull(rt?.right?.right?.right) - assertEquals(BSTNode(25, "Sieg"), rt?.right?.right) - assertEquals(BSTNode(15,"test"), rt?.right?.right?.left) - } - - @Test - fun removeNodeWithZweiKinderFifthCase() { - baum.clear() - baum.addPairs(Pair(-50, "Notf"), Pair(2, "Zwei"), Pair(101, "One hundred and One")) - for(key in listOf(-30, 99, 95, 90, 78, 56, 45, 34, 23, 14, 7, 3, 5, 8)){ - baum.add(key, "test") - } - val rt = baum.root() - baum.remove(2) - assertEquals(BSTNode(3, "test"), rt?.right) - baum.remove(3) - assertEquals(BSTNode(5, "test"), rt?.right) - val ls = listOf(99, 95, 90, 78, 56, 45, 34, 23, 14, 7, 8, 5).sorted() - for(i in 0..(ls.size-2) ){ - baum.remove(ls[i]) - assertEquals(BSTNode(ls[i + 1], "test"), rt?.right) - } - assertNull(rt?.right?.right?.left) - } - - @Test - fun removeNotExistingOderAlreadyRemovedNode() { - assertNull(baum.remove(62)) - assertNull(baum.remove(-24)) - assertFalse(baum.removePairs(5,6,8,3)) - assertEquals("test", baum.remove(13)) - assertNull(baum.remove(13)) - } - - @Test - fun removeAndChangingAmountOfNode() { - val rt = baum.root() - assertEquals(11, baum.countNodes()) - baum.remove(11) - assertEquals(10, baum.countNodes()) - baum.remove(20) - assertEquals(9, baum.countNodes()) - baum.remove(5) - assertEquals(8, baum.countNodes()) - baum.remove(-7) - assertEquals(7, baum.countNodes()) - } - - @Test - fun removeRoot() { - baum.remove(10) - assertEquals(BSTNode(11, "test"), baum.root()) - baum.remove(11) - assertEquals(BSTNode(12, "test"), baum.root()) - baum.remove(12) - assertEquals(BSTNode(13, "test"), baum.root()) - baum.remove(13) - assertEquals(BSTNode(15, "test"), baum.root()) - } - - @Test - fun howMuchDoWeNeedToDeleteTheWholeTreeByRemovingEachSingleNode() { - val len = 11 - for(i in 0..5){ - assertNotNull(baum.root()) - baum.remove(baum.root()?.key!!.toInt()) - } - baum.remove(25) - assertEquals(BSTNode(-7, "test"), baum.root()?.left) - assertNull(baum.root()) - } - } -} \ No newline at end of file From 4f02c3cfb17d5f2a1ce24ad45d640f9729e9f4f8 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 2 Apr 2024 10:49:10 +0300 Subject: [PATCH 145/186] built: Create README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..2132c10 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +[![CodeFactor](https://www.codefactor.io/repository/github/spbu-coding-2023/trees-4/badge)](https://www.codefactor.io/repository/github/spbu-coding-2023/trees-4) + +/// заготовка /// From 1976c84b38d5b84642d7898005fe31cf76c8e947 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 2 Apr 2024 10:54:50 +0300 Subject: [PATCH 146/186] fix: no more test workflow doubles --- .github/workflows/test.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cb71daf..baa45ea 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,7 +2,6 @@ name: Test on: push: - pull_request: jobs: build: From 31a9583e92fe83925df23d51e79ffbb34ef4e07e Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 2 Apr 2024 10:58:52 +0300 Subject: [PATCH 147/186] fix: now coverage updates report, not creates a new one --- .github/workflows/coverage.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 89757eb..3d11ec0 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -29,3 +29,5 @@ jobs: paths: | ${{ github.workspace }}/build/reports/jacoco/test/jacocoTestReport.xml token: ${{ secrets.GITHUB_TOKEN }} + update-comment: true + From d861065b2aaa2c350f01b19d16ca3aa78c5c0ccb Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Tue, 2 Apr 2024 11:01:24 +0300 Subject: [PATCH 148/186] fix: fix title in coverage report --- .github/workflows/coverage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 3d11ec0..b397d66 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -30,4 +30,5 @@ jobs: ${{ github.workspace }}/build/reports/jacoco/test/jacocoTestReport.xml token: ${{ secrets.GITHUB_TOKEN }} update-comment: true + title: Coverage Report From 53c45a323079a618c52e2b491fbd6bb4a654e9b2 Mon Sep 17 00:00:00 2001 From: Islam Date: Tue, 2 Apr 2024 14:09:10 +0300 Subject: [PATCH 149/186] fix: ended tests on remove and added ability to remove root by remove method --- src/main/kotlin/treeLib/bintrees/BSTree.kt | 20 +++++--- src/test/kotlin/BSTreeTest.kt | 56 ++++++++++++++++++++-- 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 9da6807..4966c76 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -8,7 +8,6 @@ class BSTree, V> : BinTree>() { override var root: BSTNode? = null override var amountOfNodes = 0 - fun addPairs(vararg pairs: Pair): Boolean { for(pair in pairs){ if( this.add(pair.first, pair.second) == null ) return false @@ -56,19 +55,28 @@ class BSTree, V> : BinTree>() { var parent = this.findParent(key) if(this.root?.key == key) parent = BSTNode(root!!.key, root!!.value, root) if(parent == null) return null - if(parent.right != null && parent.right?.key == key) curNode = parent.right - else curNode = parent.left + curNode = if(parent.right != null && parent.right?.key == key) parent.right + else parent.left if (curNode?.right != null) count++ if (curNode?.left != null) count++ if (count == 0) { - if (parent.right === curNode) parent.right = null + if (parent.right === curNode){ + if(curNode == root) this.root = null + else parent.right = null + } else parent.left = null } else if (count == 1) { if (curNode?.left == null) { - if (parent.right === curNode) parent.right = curNode?.right + if (parent.right === curNode){ + if(curNode == root) this.root = root?.right + else parent.right = curNode?.right + } else parent.left = curNode?.right } else { - if (parent.right === curNode) parent.right = curNode.left + if (parent.right === curNode){ + if(curNode == root) this.root = this.root?.left + else parent.right = curNode.left + } else parent.left = curNode.left } } else { diff --git a/src/test/kotlin/BSTreeTest.kt b/src/test/kotlin/BSTreeTest.kt index fd5d751..33d4f35 100644 --- a/src/test/kotlin/BSTreeTest.kt +++ b/src/test/kotlin/BSTreeTest.kt @@ -73,6 +73,16 @@ class BSTreeTest { assertEquals(7, baum.countNodes()) } + @Test + fun addingExistingNodeButWithDifferentValues() { + assertNull(baum.add(5, "Deutschland")) + assertNotEquals("Deutschland", baum.root()?.right?.value) + assertNull(baum.add(-1, "Deutschland")) + assertNotEquals("Deutschland", baum.root()?.left?.left?.value) + assertNull(baum.add(4, "Deutschland")) + assertNotEquals("Deutschland", baum.root()?.value) + } + @Test fun orderMatters() { baum.clear() @@ -183,9 +193,11 @@ class BSTreeTest { fun removeNotExistingOderAlreadyRemovedNode() { assertNull(baum.remove(62)) assertNull(baum.remove(-24)) - assertFalse(baum.removePairs(5,6,8,3)) + assertFalse(baum.removePairs(-5,6,8,3)) + assertEquals(11, baum.countNodes()) assertEquals("test", baum.remove(13)) assertNull(baum.remove(13)) + assertEquals(10, baum.countNodes()) } @Test @@ -203,7 +215,42 @@ class BSTreeTest { } @Test - fun removeRoot() { + fun removeRootWithoutKinder() { + baum.clear() + baum.add(4, "Heil") + baum.remove(4) + assertNull(baum.root()) + } + + @Test + fun removeRootWithOnlyRightKinder() { + baum.clear() + for(key in 0..10) baum.add(key, "test") + for(i in 0..9){ + baum.remove(i) + assertEquals(BSTNode(i + 1, "test"), baum.root()) + } + baum.remove(10) + assertNull(baum.root()) + assertEquals(0, baum.countNodes()) + } + + @Test + fun removeRootWithOnlyLeftKinder() { + baum.clear() + for(key in 0 downTo -10) baum.add(key, "test") + for(i in 0 downTo -9){ + baum.remove(i) + assertEquals(BSTNode(i-1, "test"), baum.root()) + assertEquals(10 + i, baum.countNodes()) + } + baum.remove(-10) + assertNull(baum.root()) + assertEquals(0, baum.countNodes()) + } + + @Test + fun removeRootWithTwoKinder() { baum.remove(10) assertEquals(BSTNode(11, "test"), baum.root()) baum.remove(11) @@ -217,13 +264,12 @@ class BSTreeTest { @Test fun howMuchDoWeNeedToDeleteTheWholeTreeByRemovingEachSingleNode() { val len = 11 - for(i in 0..5){ + for(i in 0..10){ assertNotNull(baum.root()) baum.remove(baum.root()?.key!!.toInt()) } - baum.remove(25) - assertEquals(BSTNode(-7, "test"), baum.root()?.left) assertNull(baum.root()) + assertEquals(0, baum.countNodes()) } } } \ No newline at end of file From f6925554b187d7c307a5695b28535cb6ec92bfee Mon Sep 17 00:00:00 2001 From: Islam Date: Tue, 2 Apr 2024 15:10:17 +0300 Subject: [PATCH 150/186] feat and fix: added test on findParent and SubTree methods and fixed SubTree methods --- src/main/kotlin/treeLib/bintrees/BSTree.kt | 24 +++- src/test/kotlin/BSTreeTest.kt | 157 ++++++++++++++++++++- 2 files changed, 172 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 4966c76..80feae8 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -119,20 +119,32 @@ class BSTree, V> : BinTree>() { val parent: BSTNode? = this.findParent(key) if(parent == null) return false if(parent.right != null && parent.right?.key == key) parent.right = null - else parent.left = null + var nodes = 0 + for(i in this) nodes++ + amountOfNodes = nodes return true } fun getSubTree(key: K): BSTree?{ val parent: BSTNode? = this.findParent(key) - val child: BSTree = BSTree() + val childTree: BSTree = BSTree() if(parent == null) return null //На будущее, нужно добавить детей к child.add() - if(parent.right != null && parent.right?.key == key) child.add(key, parent.right!!.value) - - else child.add(key, parent.left!!.value) - return child + var child: BSTNode? = null + if(parent.right != null && parent.right?.key == key){ + child = childTree.add(key, parent.right!!.value) + child?.right = parent.right!!.right + child?.left = parent.right!!.left + } else { + child = childTree.add(key, parent.left!!.value) + child?.right = parent.left!!.right + child?.left = parent.left!!.left + } + var nodes = 0 + for(i in childTree) nodes++ + childTree.amountOfNodes = nodes + return childTree } } diff --git a/src/test/kotlin/BSTreeTest.kt b/src/test/kotlin/BSTreeTest.kt index 33d4f35..6f6cc33 100644 --- a/src/test/kotlin/BSTreeTest.kt +++ b/src/test/kotlin/BSTreeTest.kt @@ -12,11 +12,25 @@ class BSTreeTest { @Test fun findParent() { + baum.add(4, "qwerty") + baum.add(2, "Ge") + baum.add(5, "rma") + baum.add(-1, "ny") + baum.add(3, "the") + baum.add(40, "best") + baum.add(44, "Ja") - } + assertEquals(BSTNode(5, "rma"), baum.findParent(40)) //Parent with ein Kind + + assertEquals(BSTNode(2, "Ge"), baum.findParent(3)) //Parent with zwei Kinder + assertEquals(baum.root(), baum.findParent(5)) //When Parent + assertEquals(baum.root(), baum.findParent(2)) //is root + assertNull(baum.findParent(4)) //Parent where child is root + assertNull(baum.findParent(34)) //Finding No existing node's parent + } @@ -25,8 +39,7 @@ class BSTreeTest { @Test fun addToEmptyTree() { - assertEquals("qwerty", baum.root()?.value) - assertEquals(4, baum.root()?.key) + assertEquals(BSTNode(4, "qwerty"), baum.root()) } @BeforeEach @@ -59,6 +72,7 @@ class BSTreeTest { @Test fun addPairs() { baum.addPairs(Pair(1, "ein"), Pair(7, "sieben"), Pair(6, "sechs")) + assertEquals(10, baum.countNodes()) assertEquals(1, baum.root()?.left?.left?.right?.key) assertEquals(6, baum.root()?.right?.right?.left?.left?.key) @@ -70,6 +84,7 @@ class BSTreeTest { assertNull(baum.add(3, "the")) assertNull(baum.add(40, "best")) assertNull(baum.add(44, "Ja")) + assertEquals(7, baum.countNodes()) } @@ -77,8 +92,10 @@ class BSTreeTest { fun addingExistingNodeButWithDifferentValues() { assertNull(baum.add(5, "Deutschland")) assertNotEquals("Deutschland", baum.root()?.right?.value) + assertNull(baum.add(-1, "Deutschland")) assertNotEquals("Deutschland", baum.root()?.left?.left?.value) + assertNull(baum.add(4, "Deutschland")) assertNotEquals("Deutschland", baum.root()?.value) } @@ -88,11 +105,14 @@ class BSTreeTest { baum.clear() assertTrue(baum.addPairs(Pair(4, "Vier"), Pair(5, "Funf"), Pair(40, "Vierzig"), Pair(44,"Vierundvierzig"))) var rt = baum.root() + assertEquals(5, rt?.right?.key) assertEquals(44, rt?.right?.right?.right?.key) + baum.clear() baum.addPairs(Pair(4, "Vier"), Pair(44,"Vierundvierzig"), Pair(40, "Vierzig"), Pair(5, "Funf")) rt = baum.root() + assertEquals(5, rt?.right?.left?.left?.key) assertEquals(44, rt?.right?.key) //In other words, with different order we have different ways to nodes @@ -111,8 +131,10 @@ class BSTreeTest { @Test fun removeNodesWithNoKinder() { val rt = baum.root() + assertTrue(baum.removePairs(-10, 11)) baum.remove(9) + assertNull(rt?.left?.left) assertNull(rt?.right?.left?.left) assertNull(rt?.left?.right?.right) @@ -123,8 +145,10 @@ class BSTreeTest { val rt = baum.root() baum.removePairs(12) baum.remove(5) + assertEquals(9, rt?.left?.right?.key) assertNull(rt?.left?.right?.right) + assertEquals(11, rt?.right?.left?.key) assertNull(rt?.right?.left?.left) } @@ -134,9 +158,11 @@ class BSTreeTest { //I don't know how to describe any of these cases, just image current tree and I hope you'll get it val rt = baum.root() baum.remove(-7) + assertEquals(5, rt?.left?.key) assertEquals(-10, rt?.left?.left?.key) assertEquals(9, rt?.left?.right?.key) + assertNull(rt?.left?.right?.right) } @@ -144,18 +170,22 @@ class BSTreeTest { fun removeNodeWithZweiKinderSecondCase() { val rt = baum.root() assertEquals("test", baum.remove(13)) + assertEquals(15, rt?.right?.key) assertEquals(12, rt?.right?.left?.key) assertEquals(20, rt?.right?.right?.key) assertEquals(25, rt?.right?.right?.right?.key) + assertNull(rt?.right?.right?.left) } @Test fun removeNodeWithZweiKinderThirdCase() { val rt = baum.root() + baum.addPairs(Pair(16, "test")) baum.remove(13) + assertEquals(16, rt?.right?.right?.left?.key) } @@ -164,7 +194,9 @@ class BSTreeTest { val rt = baum.root() baum.changeVal(25, "Sieg") baum.remove(20) + assertNull(rt?.right?.right?.right) + assertEquals(BSTNode(25, "Sieg"), rt?.right?.right) assertEquals(BSTNode(15,"test"), rt?.right?.right?.left) } @@ -172,20 +204,26 @@ class BSTreeTest { @Test fun removeNodeWithZweiKinderFifthCase() { baum.clear() + baum.addPairs(Pair(-50, "Notf"), Pair(2, "Zwei"), Pair(101, "One hundred and One")) for(key in listOf(-30, 99, 95, 90, 78, 56, 45, 34, 23, 14, 7, 3, 5, 8)){ baum.add(key, "test") } + val rt = baum.root() + baum.remove(2) assertEquals(BSTNode(3, "test"), rt?.right) + baum.remove(3) assertEquals(BSTNode(5, "test"), rt?.right) + val ls = listOf(99, 95, 90, 78, 56, 45, 34, 23, 14, 7, 8, 5).sorted() for(i in 0..(ls.size-2) ){ baum.remove(ls[i]) assertEquals(BSTNode(ls[i + 1], "test"), rt?.right) } + assertNull(rt?.right?.right?.left) } @@ -194,22 +232,30 @@ class BSTreeTest { assertNull(baum.remove(62)) assertNull(baum.remove(-24)) assertFalse(baum.removePairs(-5,6,8,3)) + assertEquals(11, baum.countNodes()) + assertEquals("test", baum.remove(13)) assertNull(baum.remove(13)) + assertEquals(10, baum.countNodes()) } @Test fun removeAndChangingAmountOfNode() { val rt = baum.root() + assertEquals(11, baum.countNodes()) + baum.remove(11) assertEquals(10, baum.countNodes()) + baum.remove(20) assertEquals(9, baum.countNodes()) + baum.remove(5) assertEquals(8, baum.countNodes()) + baum.remove(-7) assertEquals(7, baum.countNodes()) } @@ -217,20 +263,26 @@ class BSTreeTest { @Test fun removeRootWithoutKinder() { baum.clear() + baum.add(4, "Heil") baum.remove(4) + assertNull(baum.root()) } @Test fun removeRootWithOnlyRightKinder() { baum.clear() + for(key in 0..10) baum.add(key, "test") + for(i in 0..9){ baum.remove(i) assertEquals(BSTNode(i + 1, "test"), baum.root()) } + baum.remove(10) + assertNull(baum.root()) assertEquals(0, baum.countNodes()) } @@ -238,13 +290,17 @@ class BSTreeTest { @Test fun removeRootWithOnlyLeftKinder() { baum.clear() + for(key in 0 downTo -10) baum.add(key, "test") + for(i in 0 downTo -9){ baum.remove(i) assertEquals(BSTNode(i-1, "test"), baum.root()) assertEquals(10 + i, baum.countNodes()) } + baum.remove(-10) + assertNull(baum.root()) assertEquals(0, baum.countNodes()) } @@ -253,10 +309,13 @@ class BSTreeTest { fun removeRootWithTwoKinder() { baum.remove(10) assertEquals(BSTNode(11, "test"), baum.root()) + baum.remove(11) assertEquals(BSTNode(12, "test"), baum.root()) + baum.remove(12) assertEquals(BSTNode(13, "test"), baum.root()) + baum.remove(13) assertEquals(BSTNode(15, "test"), baum.root()) } @@ -264,12 +323,104 @@ class BSTreeTest { @Test fun howMuchDoWeNeedToDeleteTheWholeTreeByRemovingEachSingleNode() { val len = 11 + for(i in 0..10){ assertNotNull(baum.root()) baum.remove(baum.root()?.key!!.toInt()) } + assertNull(baum.root()) assertEquals(0, baum.countNodes()) } } + + @Nested + inner class SubTree() { + @BeforeEach + fun setUp() { + for(key in listOf(10, 13, 12, 11, 20, 15, 25, -7, 5, -10, 9)){ + baum.add(key, "test") + } + } + + @Test + fun deleteTheWholeRightAndLeftSubtee() { + + assertTrue(baum.deleteSubTree(13)) + assertNull(baum.root()?.right) + + assertTrue(baum.deleteSubTree(-7)) + assertNull(baum.root()?.left) + + assertEquals(1, baum.countNodes()) + } + + @Test + fun deleteRootSubTree() { + //You can't delete root in this way + assertFalse(baum.deleteSubTree(10)) + + assertEquals(BSTNode(10, "test"), baum.root()) + assertEquals(11, baum.countNodes()) + } + + @Test + fun deleteSubTreeWithOnlyEinNode() { + val rt = baum.root() + + baum.deleteSubTree(-10) + assertEquals(BSTNode(-7, "test"), rt?.left) + assertNull(rt?.left?.left) + + baum.deleteSubTree(25) + assertEquals(BSTNode(20, "test"), rt?.right?.right) + assertNull(rt?.right?.right?.right) + + baum.deleteSubTree(11) + assertEquals(BSTNode(12, "test"), rt?.right?.left) + assertNull(rt?.right?.left?.left) + } + + @Test + fun deleteNotExistingSubTree() { + assertFalse(baum.deleteSubTree(34)) + assertEquals(11, baum.countNodes()) + } + + @Test + fun deleteSubTreeByAlreadyRemovedKey() { + baum.remove(-7) + assertFalse(baum.deleteSubTree(-7)) + assertEquals(10, baum.countNodes()) + } + + @Test + fun getSubTree() { + var neuBaum = baum.getSubTree(13) + + assertEquals(BSTNode(13,"test"), neuBaum?.root()) + assertEquals(6, neuBaum?.countNodes()) + + + neuBaum = baum.getSubTree(-7) + + assertEquals(BSTNode(-7,"test"), neuBaum?.root()) + assertEquals(4, neuBaum?.countNodes()) + + assertEquals(11, baum.countNodes()) + } + + @Test + fun getRootSubTree() { + //You can't get SubTree where current tree's root is new root + assertNull(baum.getSubTree(10)) + } + + @Test + fun getSubTreeByNotExistingKey() { + assertNull(baum.getSubTree(23)) + assertNull(baum.getSubTree(-5)) + assertNull(baum.getSubTree(0)) + } + } } \ No newline at end of file From ccf2d03611b1718f3d6aedf31998605299049803 Mon Sep 17 00:00:00 2001 From: Islam Date: Tue, 2 Apr 2024 15:47:37 +0300 Subject: [PATCH 151/186] fix: removed unnecessary code --- src/main/kotlin/treeLib/bintrees/BSTree.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 80feae8..63a47ac 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -2,7 +2,6 @@ package treeLib.bintrees import treeLib.bintrees.interfaces.BinTree import treeLib.nodes.BSTNode -import treeLib.nodes.TreeNode class BSTree, V> : BinTree>() { override var root: BSTNode? = null @@ -131,7 +130,6 @@ class BSTree, V> : BinTree>() { val parent: BSTNode? = this.findParent(key) val childTree: BSTree = BSTree() if(parent == null) return null - //На будущее, нужно добавить детей к child.add() var child: BSTNode? = null if(parent.right != null && parent.right?.key == key){ child = childTree.add(key, parent.right!!.value) From 61ed903844e0725c9037cc6e6c05ed421278f56f Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 2 Apr 2024 18:11:16 +0300 Subject: [PATCH 152/186] fix and refactor!: balanceRemove works correctly now also add better descriptions --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 181 +++++++++++---------- 1 file changed, 98 insertions(+), 83 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index c63b396..97fad11 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -14,12 +14,12 @@ class RBTree, V> : BinTree>(), TreeBalancer /** * Adds or replaces node to the tree depending on given key: - * 1. Adds node to the tree and returns VALUE, - * 2. If node with given key already exist, it does nothing - * (to actually change value check changeVal) + * 1. Adds node to the tree and returns node, + * 2. If node with given key already exist, it does nothing and returns null + * (to actually change value use changeVal) */ override fun add(key: K, value: V): RBNode? { - val treeBranch = ArrayDeque>() + val treeBranch = ArrayDeque>() //to know who's the parent val newNode = RBNode(key, value) if (root == null) { root = newNode @@ -28,15 +28,17 @@ class RBTree, V> : BinTree>(), TreeBalancer while (curNode != null) { treeBranch.addFirst(curNode) val nextNode = curNode.moveOn(key) - if (nextNode === curNode) return null //node with given key already exist + if (nextNode == curNode) return null //node with given key already exist curNode = nextNode } val parent = treeBranch.first() parent.attach(newNode) } + amountOfNodes++ treeBranch.addFirst(newNode) balancerAdd(treeBranch) + return newNode } @@ -58,18 +60,21 @@ class RBTree, V> : BinTree>(), TreeBalancer son = grandparent parent = treeBranch.removeFirstOrNull() grandparent = treeBranch.removeFirstOrNull() - } else { - if (parent === grandparent.right && son === parent.left) { + } else /*uncle is black or null */ { + if (parent == grandparent.right && son == parent.left) { rotateRight(parent, grandparent) parent = son - } else if (parent === grandparent.left && son === parent.right) { + } else if (parent == grandparent.left && son == parent.right) { rotateLeft(parent, grandparent) parent = son } parent.isRed = false grandparent.isRed = true - if (parent === grandparent.right) rotateLeft(grandparent, treeBranch.firstOrNull()) - else rotateRight(grandparent, treeBranch.firstOrNull()) + if (parent == grandparent.right) { + rotateLeft(grandparent, treeBranch.firstOrNull()) + } else { + rotateRight(grandparent, treeBranch.firstOrNull()) + } } } @@ -78,115 +83,125 @@ class RBTree, V> : BinTree>(), TreeBalancer /** * Removes node with the same key and returns node's value. - * Or returns null if there's no such node. + * Or does nothing and returns null if there's no such node. */ override fun remove(key: K): V? { - val treeBranch = ArrayDeque>() - var removedNode = root - while (removedNode?.key != key) { - if (removedNode == null) return null //node with given key doesn't exist - treeBranch.addFirst(removedNode) - removedNode = removedNode.moveOn(key) + val treeBranch = ArrayDeque?>() //to know who's the parent + var curNode = root ?: return null + while (curNode.key != key) { + treeBranch.addFirst(curNode) + val nextNode = curNode.moveOn(key) ?: return null //node with given key doesn't exist + curNode = nextNode } var parent = treeBranch.firstOrNull() - val sonRight = removedNode.right - val sonLeft = removedNode.left - val sonRemoved = when { - sonRight == null && sonLeft == null -> null - sonRight != null && sonLeft == null -> sonRight - sonRight == null && sonLeft != null -> sonLeft - else /*sonRight and sonLeft != null*/ -> { - val replace = removedNode //Will rewrite this node with other one - treeBranch.addFirst(replace) - removedNode = sonLeft - while (removedNode?.right != null) { - treeBranch.addFirst(removedNode) - removedNode = removedNode.right + val sonRight = curNode.right + val sonLeft = curNode.left + val sonOfRemovedNode = when { + sonRight != null && sonLeft != null -> { + treeBranch.addFirst(curNode) + val copyTo = curNode //Will copy from curNode + curNode = sonLeft + while (curNode.right != null) { + treeBranch.addFirst(curNode) + curNode = curNode.right ?: throw NullPointerException("Removing node cannot be null.") } + parent = treeBranch.first() - replace.key = removedNode?.key ?: throw Exception("well...") - replace.value = removedNode?.value ?: throw Exception("that's bad") - removedNode.left + val temp = copyTo.value + copyTo.key = curNode.key + copyTo.value = curNode.value + curNode.value = temp //to save deleted node's value + curNode.left } + sonRight != null -> sonRight + else /*sonLeft != null*/ -> sonLeft } amountOfNodes-- - when (removedNode) { - parent?.right -> parent.right = sonRemoved - parent?.left -> parent.left = sonRemoved - else -> root = null //only root doesn't have parent - } - if (sonRemoved != null && !removedNode.isRed) { - treeBranch.addFirst(sonRemoved) - balancerRemove(treeBranch) + when (curNode) { + parent?.right -> parent.right = sonOfRemovedNode + parent?.left -> parent.left = sonOfRemovedNode + else -> root = sonOfRemovedNode //only root doesn't have parent } + treeBranch.addFirst(sonOfRemovedNode) + if (!curNode.isRed) balancerRemove(treeBranch) - return removedNode.value + return curNode.value } /** * Used in remove() method to balance tree :( */ - private fun balancerRemove(treeBranch: ArrayDeque>) { - val son = treeBranch.removeFirstOrNull() + private fun balancerRemove(treeBranch: ArrayDeque?>) { + var son = treeBranch.removeFirstOrNull() var parent = treeBranch.removeFirstOrNull() var grandparent = treeBranch.removeFirstOrNull() - - while (parent != null && son?.isRed == false) { - if (son === parent.right) { - var brother = parent.left - if (brother?.isRed == true) { - brother.isRed = false - parent.isRed = true + if (son?.isRed == true) { + son.isRed = false + return + } + while (parent != null) { + var brother = if (son == parent.right) parent.left else parent.right + if (brother?.isRed == true) { + brother.isRed = false + parent.isRed = true + if (son == parent.right) { rotateRight(parent, grandparent) grandparent = brother brother = parent.left } + if (son == parent.left) { + rotateLeft(parent, grandparent) + grandparent = brother + brother = parent.right + } + } - val nephewRight = brother?.right - val nephewLeft = brother?.left - if (nephewRight?.isRed == false && nephewLeft?.isRed == false) { - brother?.isRed = true + var nephewRight = brother?.right + var nephewLeft = brother?.left + if ((nephewRight == null || !nephewRight.isRed) && (nephewLeft == null || !nephewLeft.isRed)) { + brother?.isRed = true + if (!parent.isRed) { + parent.isRed = false + son = parent + parent = grandparent + grandparent = treeBranch.removeFirstOrNull() } else { - if (nephewLeft?.isRed == false) { - nephewRight?.isRed = false - brother?.isRed = true + parent.isRed = false + break + } + } else { + if (son == parent.right) { + if (nephewRight?.isRed == true && (nephewLeft == null || !nephewLeft.isRed)) { rotateLeft(brother, parent) - parent = nephewLeft + brother = parent.left + nephewLeft = brother?.left + brother?.isRed = false + nephewLeft?.isRed = true } + + rotateRight(parent, grandparent) brother?.isRed = parent.isRed parent.isRed = false - nephewRight?.isRed = false - rotateLeft(parent, grandparent) - } - } else if (son === parent.left) { - var brother = parent.right - if (brother?.isRed == true) { - brother.isRed = false - parent.isRed = true - rotateLeft(parent, grandparent) - grandparent = brother - brother = parent.right + nephewLeft?.isRed = false } - - val nephewRight = brother?.right - val nephewLeft = brother?.left - if (nephewRight?.isRed == false && nephewLeft?.isRed == false) { - brother?.isRed = true - } else { - if (nephewRight?.isRed == false) { - nephewLeft?.isRed = false - brother?.isRed = true + if (son == parent.left) { + if (nephewLeft?.isRed == true && (nephewRight == null || !nephewRight.isRed)) { rotateRight(brother, parent) + brother = parent.right + nephewRight = brother?.right + brother?.isRed = false + nephewRight?.isRed = true } - brother?.isRed = parent.isRed == true + + rotateLeft(parent, grandparent) + brother?.isRed = parent.isRed parent.isRed = false nephewRight?.isRed = false - rotateLeft(parent, grandparent) - break - } + } + break } } From 579145eeddf27129e154ee2c0387372712c7cc90 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 2 Apr 2024 18:12:44 +0300 Subject: [PATCH 153/186] feat: add tests for remove() and balancerRemove() --- src/test/kotlin/RBTreeTest.kt | 149 +++++++++++++++++++++++++++------- 1 file changed, 119 insertions(+), 30 deletions(-) diff --git a/src/test/kotlin/RBTreeTest.kt b/src/test/kotlin/RBTreeTest.kt index 1fcf3d1..6c00d55 100644 --- a/src/test/kotlin/RBTreeTest.kt +++ b/src/test/kotlin/RBTreeTest.kt @@ -3,12 +3,10 @@ import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested import treeLib.bintrees.RBTree import treeLib.nodes.RBNode -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue +import kotlin.test.* class RBTreeTest { - private var emptyTree = RBTree() + var emptyTree = RBTree() @BeforeEach fun init() { @@ -127,72 +125,163 @@ class RBTreeTest { @Nested @DisplayName("Remove method tests") inner class RemoveMethod { + var tree3Node = RBTree() + var bft15 = RBTree() + + @BeforeEach + fun initTree() { + tree3Node = RBTree() + tree3Node.add(0, 0) + tree3Node.add(10, 10) + tree3Node.add(-10, -10) + + bft15 = RBTree() //15 node tree (balanced) + var k = 16 + for (i in listOf(1, 2, 4, 8)) { //amount of nodes on level + for (j in 0.. Date: Tue, 2 Apr 2024 21:12:34 +0300 Subject: [PATCH 154/186] refactor: new commentaries --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 49 ++++++++++++---------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index 97fad11..29f5278 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -51,8 +51,9 @@ class RBTree, V> : BinTree>(), TreeBalancer var grandparent = treeBranch.removeFirstOrNull() while (parent != null && parent.isRed && grandparent != null) { - val uncle = if (parent != grandparent.right) grandparent.right else grandparent.left + val uncle = if (parent == grandparent.right) grandparent.left else grandparent.right + //uncle is red -> recolor nodes and go higher up the treeBranch if (uncle?.isRed == true) { parent.isRed = false uncle.isRed = false @@ -60,19 +61,22 @@ class RBTree, V> : BinTree>(), TreeBalancer son = grandparent parent = treeBranch.removeFirstOrNull() grandparent = treeBranch.removeFirstOrNull() - } else /*uncle is black or null */ { - if (parent == grandparent.right && son == parent.left) { - rotateRight(parent, grandparent) - parent = son - } else if (parent == grandparent.left && son == parent.right) { - rotateLeft(parent, grandparent) - parent = son - } - parent.isRed = false - grandparent.isRed = true + } else /*uncle is black or null -> do few rotations, recoloring and magic will happen*/ { if (parent == grandparent.right) { + if (son == parent.left) { //we want co-directional parent and son + rotateRight(parent, grandparent) + parent = son + } + parent.isRed = false + grandparent.isRed = true rotateLeft(grandparent, treeBranch.firstOrNull()) - } else { + } else /*parent == grandparent.left*/ { + if (son == parent.right) { //we want co-directional parent and son too + rotateLeft(parent, grandparent) + parent = son + } + parent.isRed = false + grandparent.isRed = true rotateRight(grandparent, treeBranch.firstOrNull()) } } @@ -90,7 +94,7 @@ class RBTree, V> : BinTree>(), TreeBalancer var curNode = root ?: return null while (curNode.key != key) { treeBranch.addFirst(curNode) - val nextNode = curNode.moveOn(key) ?: return null //node with given key doesn't exist + val nextNode = curNode.moveOn(key) ?: return null //nextNode == null => removing node doesn't exist curNode = nextNode } @@ -119,12 +123,13 @@ class RBTree, V> : BinTree>(), TreeBalancer } amountOfNodes-- - when (curNode) { + when (curNode) { //here we are "deleting" the node and replace it with his son parent?.right -> parent.right = sonOfRemovedNode parent?.left -> parent.left = sonOfRemovedNode else -> root = sonOfRemovedNode //only root doesn't have parent } treeBranch.addFirst(sonOfRemovedNode) + //curNode.isRed -> no balancing needed if (!curNode.isRed) balancerRemove(treeBranch) return curNode.value @@ -138,12 +143,14 @@ class RBTree, V> : BinTree>(), TreeBalancer var parent = treeBranch.removeFirstOrNull() var grandparent = treeBranch.removeFirstOrNull() + //son == son of removed node if (son?.isRed == true) { son.isRed = false return } while (parent != null) { var brother = if (son == parent.right) parent.left else parent.right + //we want for brother to be black (´。_。`) if (brother?.isRed == true) { brother.isRed = false parent.isRed = true @@ -151,21 +158,20 @@ class RBTree, V> : BinTree>(), TreeBalancer rotateRight(parent, grandparent) grandparent = brother brother = parent.left - } - if (son == parent.left) { + } else /*son == parent.left*/ { rotateLeft(parent, grandparent) grandparent = brother brother = parent.right } } + //depending on nephew's colors, doing magic for balancing purposes var nephewRight = brother?.right var nephewLeft = brother?.left if ((nephewRight == null || !nephewRight.isRed) && (nephewLeft == null || !nephewLeft.isRed)) { brother?.isRed = true - if (!parent.isRed) { - parent.isRed = false - son = parent + if (!parent.isRed) { //parent is black --> go higher up + son = parent //the treeBranch and balance again parent = grandparent grandparent = treeBranch.removeFirstOrNull() } else { @@ -186,8 +192,7 @@ class RBTree, V> : BinTree>(), TreeBalancer brother?.isRed = parent.isRed parent.isRed = false nephewLeft?.isRed = false - } - if (son == parent.left) { + } else /*son == parent.left*/ { if (nephewLeft?.isRed == true && (nephewRight == null || !nephewRight.isRed)) { rotateRight(brother, parent) brother = parent.right @@ -207,4 +212,4 @@ class RBTree, V> : BinTree>(), TreeBalancer root?.isRed = false } -} \ No newline at end of file +} From 448850a4348e43a824d0d887b4f3021708c99910 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 2 Apr 2024 23:31:55 +0300 Subject: [PATCH 155/186] feat: add more tests for remove() --- src/test/kotlin/RBTreeTest.kt | 95 ++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 8 deletions(-) diff --git a/src/test/kotlin/RBTreeTest.kt b/src/test/kotlin/RBTreeTest.kt index 6c00d55..4ea8a2c 100644 --- a/src/test/kotlin/RBTreeTest.kt +++ b/src/test/kotlin/RBTreeTest.kt @@ -254,6 +254,7 @@ class RBTreeTest { assertTrue { root!!.left!!.left!!.left!!.isRed } } + //in next remove tests brother means brother of the removed node's son @Test @DisplayName("Black brother don't have children, right ver") fun remove2R() { @@ -280,30 +281,108 @@ class RBTreeTest { assertTrue { root.left!!.left!!.right!!.isRed } } + @Test + @DisplayName("Black brother have 2 black children, right ver") + fun remove3R() { + } @Test - @DisplayName("") - fun remove4r() { + @DisplayName("Black brother have 2 black children, left ver") + fun remove3L() { } @Test - @DisplayName("") - fun remove4l() { + @DisplayName("Black brother have only right red child, right ver") + fun remove4R() { + bft15.remove(7) + bft15.remove(5) + bft15.remove(1) + val removeResult = bft15.remove(6) + assertEquals(6, removeResult) + val colorResultComparison = arrayListOf(false, true, false, false, true, false, + true, true, true, false, true) + for (node in bft15) + assertEquals(colorResultComparison.removeFirst(), node.isRed) + } + @Test + @DisplayName("Black brother have only right red child, left ver") + fun remove4L() { + bft15.remove(9) + bft15.remove(11) + bft15.remove(15) + val removeResult = bft15.remove(10) + assertEquals(10, removeResult) + val colorResultComparison = arrayListOf(true, false, true, true, true, false, + true, false, false, true, false) + for (node in bft15) + assertEquals(colorResultComparison.removeFirst(), node.isRed) } @Test - @DisplayName("") - fun remove5r() { + @DisplayName("Black brother have only left red child, right ver") + fun remove5R() { + bft15.remove(7) + bft15.remove(5) + bft15.remove(3) + val removeResult = bft15.remove(6) + assertEquals(6, removeResult) + val colorResultComparison = arrayListOf(false, true, false, false, true, false, + true, true, true, false, true) + for (node in bft15) + assertEquals(colorResultComparison.removeFirst(), node.isRed) + } + @Test + @DisplayName("Black brother have only left red child, left ver") + fun remove5L() { + bft15.remove(9) + bft15.remove(11) + bft15.remove(13) + val removeResult = bft15.remove(10) + assertEquals(10, removeResult) + val colorResultComparison = arrayListOf(true, false, true, true, true, false, + true, false, false, true, false) + for (node in bft15) + assertEquals(colorResultComparison.removeFirst(), node.isRed) } @Test - @DisplayName("") - fun remove5l() { + @DisplayName("Black brother have 2 red children, right ver") + fun remove6R() { + bft15.add(16, 16) + bft15.add(17, 17) + val removeResult = bft15.remove(13) + assertEquals(13, removeResult) + val root = bft15.root + assertTrue { root!!.right!!.right!!.isRed } + assertTrue { !root!!.right!!.right!!.right!!.isRed } + assertTrue { !root!!.right!!.right!!.left!!.isRed } + assertTrue { root!!.right!!.right!!.left!!.right!!.isRed } + assertEquals(RBNode(16, 16), root!!.right!!.right) + assertEquals(RBNode(17, 17), root!!.right!!.right!!.right) + assertEquals(RBNode(14, 14), root!!.right!!.right!!.left) + assertEquals(RBNode(15, 15), root!!.right!!.right!!.left!!.right) + } + @Test + @DisplayName("Black brother have 2 red children, left ver") + fun remove6L() { + bft15.add(0, 0) + bft15.add(-1, -1) + val removeResult = bft15.remove(3) + assertEquals(3, removeResult) + val root = bft15.root + assertTrue { root!!.left!!.left!!.isRed } + assertTrue { !root!!.left!!.left!!.left!!.isRed } + assertTrue { !root!!.left!!.left!!.right!!.isRed } + assertTrue { root!!.left!!.left!!.right!!.left!!.isRed } + assertEquals(RBNode(0, 0), root!!.left!!.left) + assertEquals(RBNode(-1, -1), root.left!!.left!!.left) + assertEquals(RBNode(2, 2), root.left!!.left!!.right) + assertEquals(RBNode(1, 1), root.left!!.left!!.right!!.left) } } } \ No newline at end of file From 9cc8eaa00cfec55ca1279a744f26ce753d3033b4 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Tue, 2 Apr 2024 23:41:23 +0300 Subject: [PATCH 156/186] feat: add fun key() and value() --- src/main/kotlin/treeLib/nodes/TreeNode.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index f404738..0a623c0 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -19,6 +19,10 @@ abstract class TreeNode, V, Node_T : TreeNode>( fun toPair(): Pair = Pair(key, value) + fun key(): K = key + + fun value(): V = value + internal fun attach(node: Node_T?): Boolean { if (node == null) return false when { From 6b32a005b575ab6c90a4f7c93384e72b5903ca32 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Wed, 3 Apr 2024 00:11:08 +0300 Subject: [PATCH 157/186] feat: tests for nodes --- src/test/kotlin/NodeTest.kt | 97 +++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/test/kotlin/NodeTest.kt diff --git a/src/test/kotlin/NodeTest.kt b/src/test/kotlin/NodeTest.kt new file mode 100644 index 0000000..986bb41 --- /dev/null +++ b/src/test/kotlin/NodeTest.kt @@ -0,0 +1,97 @@ +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import treeLib.nodes.BSTNode +import kotlin.test.* + +class NodeTest { + var node01 = BSTNode(1, 123) + var node02 = BSTNode(2, 321, right = node01) + var node2L = BSTNode(2, 321, left = node02) + var node03 = BSTNode(3, "node02 и node2L отличаются лишь ссылками") + + @BeforeEach + fun init() { + node01 = BSTNode(1, 123) + node02 = BSTNode(2, 321) + node03 = BSTNode(3, "waiting for something to happen?") + } + + @Test + @DisplayName("Compare to ==") + fun compare0() { + assertEquals(0, node02.compareTo(node2L)) + } + + @Test + @DisplayName("Compare to >") + fun compare1() { + assertTrue(node02.compareTo(node01) > 0) + } + + @Test + @DisplayName("Compare to <") + fun compare2() { + assertTrue(node01.compareTo(node2L) < 0) + } + + @Test + @DisplayName("Hash code on one node twice") + fun hashCode1() { + assertEquals(node03.hashCode(), node03.hashCode()) + } + + @Test + @DisplayName("Hash code on two equal nodes") + fun hashCode2() { + assertEquals(node02.hashCode(), node2L.hashCode()) + } + + @Test + @DisplayName("Hash code on two different nodes") + fun hashCode3() { + assertNotEquals(node01.hashCode(), node02.hashCode()) + } + + @Test + @DisplayName("Equals is true on one node") + fun equals1() { + assertTrue(node03.equals(node03)) + } + + @Test + @DisplayName("Equals is true if node's key and value are equals") + fun equals2() { + assertTrue(node2L.equals(node02) and node02.equals(node2L)) + } + + @Test + @DisplayName("Equals is not equal to null") + fun equals3() { + assertFalse(node03.equals(null)) + } + + @Test + @DisplayName("Equals is false if nodes are different") + fun equals4() { + assertFalse(node01.equals(node02)) + } + + @Test + @DisplayName("To string") + fun toString1() { + assertEquals(node01.toString(), "(1, 123)") + } + + @Test + @DisplayName("To pair") + fun toPair1() { + assertEquals(node01.toPair(), Pair(1, 123)) + } + + @Test + @DisplayName("I mean we I believe that key() and value() works correctly, whatever") + fun keyValue() { + assertEquals(node03.key(), 3) + assertEquals(node03.value(), "waiting for something to happen?") + } +} From 5f44d7aeb7620331ad4cb55fd7ac89f3facc6ff2 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Wed, 3 Apr 2024 00:15:56 +0300 Subject: [PATCH 158/186] refactor: nested tests --- src/test/kotlin/NodeTest.kt | 134 +++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 65 deletions(-) diff --git a/src/test/kotlin/NodeTest.kt b/src/test/kotlin/NodeTest.kt index 986bb41..60aa055 100644 --- a/src/test/kotlin/NodeTest.kt +++ b/src/test/kotlin/NodeTest.kt @@ -1,5 +1,6 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested import treeLib.nodes.BSTNode import kotlin.test.* @@ -16,82 +17,85 @@ class NodeTest { node03 = BSTNode(3, "waiting for something to happen?") } - @Test - @DisplayName("Compare to ==") - fun compare0() { - assertEquals(0, node02.compareTo(node2L)) - } + @Nested + inner class PublicNodeMethods { + @Test + @DisplayName("Compare to ==") + fun compare0() { + assertEquals(0, node02.compareTo(node2L)) + } - @Test - @DisplayName("Compare to >") - fun compare1() { - assertTrue(node02.compareTo(node01) > 0) - } + @Test + @DisplayName("Compare to >") + fun compare1() { + assertTrue(node02.compareTo(node01) > 0) + } - @Test - @DisplayName("Compare to <") - fun compare2() { - assertTrue(node01.compareTo(node2L) < 0) - } + @Test + @DisplayName("Compare to <") + fun compare2() { + assertTrue(node01.compareTo(node2L) < 0) + } - @Test - @DisplayName("Hash code on one node twice") - fun hashCode1() { - assertEquals(node03.hashCode(), node03.hashCode()) - } + @Test + @DisplayName("Hash code on one node twice") + fun hashCode1() { + assertEquals(node03.hashCode(), node03.hashCode()) + } - @Test - @DisplayName("Hash code on two equal nodes") - fun hashCode2() { - assertEquals(node02.hashCode(), node2L.hashCode()) - } + @Test + @DisplayName("Hash code on two equal nodes") + fun hashCode2() { + assertEquals(node02.hashCode(), node2L.hashCode()) + } - @Test - @DisplayName("Hash code on two different nodes") - fun hashCode3() { - assertNotEquals(node01.hashCode(), node02.hashCode()) - } + @Test + @DisplayName("Hash code on two different nodes") + fun hashCode3() { + assertNotEquals(node01.hashCode(), node02.hashCode()) + } - @Test - @DisplayName("Equals is true on one node") - fun equals1() { - assertTrue(node03.equals(node03)) - } + @Test + @DisplayName("Equals is true on one node") + fun equals1() { + assertTrue(node03.equals(node03)) + } - @Test - @DisplayName("Equals is true if node's key and value are equals") - fun equals2() { - assertTrue(node2L.equals(node02) and node02.equals(node2L)) - } + @Test + @DisplayName("Equals is true if node's key and value are equals") + fun equals2() { + assertTrue(node2L.equals(node02) and node02.equals(node2L)) + } - @Test - @DisplayName("Equals is not equal to null") - fun equals3() { - assertFalse(node03.equals(null)) - } + @Test + @DisplayName("Equals is not equal to null") + fun equals3() { + assertFalse(node03.equals(null)) + } - @Test - @DisplayName("Equals is false if nodes are different") - fun equals4() { - assertFalse(node01.equals(node02)) - } + @Test + @DisplayName("Equals is false if nodes are different") + fun equals4() { + assertFalse(node01.equals(node02)) + } - @Test - @DisplayName("To string") - fun toString1() { - assertEquals(node01.toString(), "(1, 123)") - } + @Test + @DisplayName("To string") + fun toString1() { + assertEquals(node01.toString(), "(1, 123)") + } - @Test - @DisplayName("To pair") - fun toPair1() { - assertEquals(node01.toPair(), Pair(1, 123)) - } + @Test + @DisplayName("To pair") + fun toPair1() { + assertEquals(node01.toPair(), Pair(1, 123)) + } - @Test - @DisplayName("I mean we I believe that key() and value() works correctly, whatever") - fun keyValue() { - assertEquals(node03.key(), 3) - assertEquals(node03.value(), "waiting for something to happen?") + @Test + @DisplayName("I mean we I believe that key() and value() works correctly, whatever") + fun keyValue() { + assertEquals(node03.key(), 3) + assertEquals(node03.value(), "waiting for something to happen?") + } } } From 450d30128c0fd28c735a6a420e8622ffd441f164 Mon Sep 17 00:00:00 2001 From: Islam Date: Wed, 3 Apr 2024 00:47:09 +0300 Subject: [PATCH 159/186] fix: covered more code and fixed unreachable code --- src/main/kotlin/treeLib/bintrees/BSTree.kt | 6 +++--- src/test/kotlin/BSTreeTest.kt | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 63a47ac..edc2edb 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -43,7 +43,7 @@ class BSTree, V> : BinTree>() { return curNode.left } curNode = curNode.left - } else return null + } else break } return null } @@ -66,13 +66,13 @@ class BSTree, V> : BinTree>() { else parent.left = null } else if (count == 1) { if (curNode?.left == null) { - if (parent.right === curNode){ + if (parent.right == curNode){ if(curNode == root) this.root = root?.right else parent.right = curNode?.right } else parent.left = curNode?.right } else { - if (parent.right === curNode){ + if (parent.right == curNode){ if(curNode == root) this.root = this.root?.left else parent.right = curNode.left } diff --git a/src/test/kotlin/BSTreeTest.kt b/src/test/kotlin/BSTreeTest.kt index 6f6cc33..14acb61 100644 --- a/src/test/kotlin/BSTreeTest.kt +++ b/src/test/kotlin/BSTreeTest.kt @@ -151,6 +151,14 @@ class BSTreeTest { assertEquals(11, rt?.right?.left?.key) assertNull(rt?.right?.left?.left) + + baum.add(12, "test") + baum.remove(11) + assertEquals(BSTNode(12, "test"), rt?.right?.left) + + baum.remove(25) + baum.remove(20) + assertEquals(BSTNode(15, "test"), rt?.right?.right) } @Test @@ -332,8 +340,10 @@ class BSTreeTest { assertNull(baum.root()) assertEquals(0, baum.countNodes()) } + } + @Nested inner class SubTree() { @BeforeEach From 3b693eede537380540c207db919b1a22e8480547 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Wed, 3 Apr 2024 00:50:49 +0300 Subject: [PATCH 160/186] feat: add tests for iterator --- src/test/kotlin/TreeIteratorTest.kt | 85 +++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/test/kotlin/TreeIteratorTest.kt diff --git a/src/test/kotlin/TreeIteratorTest.kt b/src/test/kotlin/TreeIteratorTest.kt new file mode 100644 index 0000000..d2da0bd --- /dev/null +++ b/src/test/kotlin/TreeIteratorTest.kt @@ -0,0 +1,85 @@ +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import treeLib.bintrees.BSTree +import treeLib.nodes.BSTNode +import kotlin.test.assertEquals +import kotlin.test.assertFalse + +class TreeIteratorTest { + var bft31 = BSTree() + + @BeforeEach + fun init() { + bft31 = BSTree() + var k = 32 + for (i in listOf(1, 2, 4, 8, 16)) { + for (j in 0.. Date: Wed, 3 Apr 2024 00:55:25 +0300 Subject: [PATCH 161/186] fix: little changes and test on BSTNode single method --- src/test/kotlin/BSTreeTest.kt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/test/kotlin/BSTreeTest.kt b/src/test/kotlin/BSTreeTest.kt index 14acb61..87db899 100644 --- a/src/test/kotlin/BSTreeTest.kt +++ b/src/test/kotlin/BSTreeTest.kt @@ -3,12 +3,26 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Nested import treeLib.bintrees.BSTree import treeLib.nodes.BSTNode -import kotlin.math.abs import org.junit.jupiter.api.Test class BSTreeTest { var baum = BSTree() + @Test + fun isThereChild() { + baum.add(4, "qwerty") + baum.add(2, "Ge") + baum.add(5, "rma") + baum.add(3, "ny") + baum.add(-1, "ny") + + val rt = baum.root() + + assertFalse(rt?.right!!.isThereChild()) + assertFalse(rt.left?.right!!.isThereChild()) + assertTrue(rt.isThereChild()) + assertTrue(rt.left!!.isThereChild()) + } @Test fun findParent() { From 07e8e2f90c51be3d2ba81dda0e6a331c6009c789 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 3 Apr 2024 10:38:28 +0300 Subject: [PATCH 162/186] ci: coverage.yml minor fix --- .github/workflows/coverage.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index b397d66..0e58a70 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -29,6 +29,5 @@ jobs: paths: | ${{ github.workspace }}/build/reports/jacoco/test/jacocoTestReport.xml token: ${{ secrets.GITHUB_TOKEN }} - update-comment: true - title: Coverage Report + From a6d86bc1593b35dfcdbb75df2f8a47b267764ac1 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 3 Apr 2024 13:19:21 +0300 Subject: [PATCH 163/186] Add LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3d2a9f2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Magomedov Islam, Damir Yunusov, Sofya Grishkova + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From d9439666b3f72409df5454db2ebce1ef69fb8cd2 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Wed, 3 Apr 2024 13:17:19 +0300 Subject: [PATCH 164/186] refactor: add few more descriptions --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 32 ++++++++++--------- .../bintrees/interfaces/TreeBalancer.kt | 1 + 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index 29f5278..29f7aa7 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -164,12 +164,14 @@ class RBTree, V> : BinTree>(), TreeBalancer brother = parent.right } } + brother ?: throw IllegalStateException("Balance of red-black tree violated:" + + " parent node have subtrees with black height 2 and black height 1") //depending on nephew's colors, doing magic for balancing purposes - var nephewRight = brother?.right - var nephewLeft = brother?.left + var nephewRight = brother.right + var nephewLeft = brother.left if ((nephewRight == null || !nephewRight.isRed) && (nephewLeft == null || !nephewLeft.isRed)) { - brother?.isRed = true + brother.isRed = true if (!parent.isRed) { //parent is black --> go higher up son = parent //the treeBranch and balance again parent = grandparent @@ -181,28 +183,28 @@ class RBTree, V> : BinTree>(), TreeBalancer } else { if (son == parent.right) { if (nephewRight?.isRed == true && (nephewLeft == null || !nephewLeft.isRed)) { - rotateLeft(brother, parent) - brother = parent.left - nephewLeft = brother?.left - brother?.isRed = false - nephewLeft?.isRed = true + rotateLeft(brother, parent) // B /nL == new brother + nephewLeft = brother // / \ -> /B == new left nephew + brother = nephewRight // nL nR /nR + brother.isRed = false + nephewLeft.isRed = true } rotateRight(parent, grandparent) - brother?.isRed = parent.isRed + brother.isRed = parent.isRed parent.isRed = false nephewLeft?.isRed = false } else /*son == parent.left*/ { if (nephewLeft?.isRed == true && (nephewRight == null || !nephewRight.isRed)) { - rotateRight(brother, parent) - brother = parent.right - nephewRight = brother?.right - brother?.isRed = false - nephewRight?.isRed = true + rotateRight(brother, parent) // B \nR == new brother + nephewRight = brother // / \ -> \B == new right nephew + brother = nephewLeft // nL nR \nL + brother.isRed = false + nephewRight.isRed = true } rotateLeft(parent, grandparent) - brother?.isRed = parent.isRed + brother.isRed = parent.isRed parent.isRed = false nephewRight?.isRed = false } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt index ad76200..0dce327 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt @@ -5,6 +5,7 @@ import treeLib.nodes.TreeNode internal interface TreeBalancer, V, Node_T : TreeNode> { var root: Node_T? + //We must provide parent, because don't have link to him in node fun rotateRight(node: Node_T?, parent: Node_T?) { if (node == null) return val nodeLeft = node.left From 185cf63a7ac00e2f51d1b0eac1bbdb4ab8eb5324 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 3 Apr 2024 13:42:50 +0300 Subject: [PATCH 165/186] Update readme --- README.md | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2132c10..9cc2415 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,70 @@ -[![CodeFactor](https://www.codefactor.io/repository/github/spbu-coding-2023/trees-4/badge)](https://www.codefactor.io/repository/github/spbu-coding-2023/trees-4) +[![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](https://choosealicense.com/licenses/mit/) [![CodeFactor](https://www.codefactor.io/repository/github/spbu-coding-2023/trees-4/badge)](https://www.codefactor.io/repository/github/spbu-coding-2023/trees-4) -/// заготовка /// +## About The Project + +/ шаблон / + +

(back to top)

+ +## Getting Started + +### Prerequisites + +* code + ```sh + code + ``` + +### Installation + +

(back to top)

+ + +## Usage + +

(back to top)

+ + +## Roadmap + +- [ ] Feature 1 +- [ ] Feature 2 +- [ ] Feature 3 + - [ ] Nested Feature + +

(back to top)

+ +## Contributing + +Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. + +If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". +Don't forget to give the project a star! Thanks again! + +1. Fork the Project +2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) +3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) +4. Push to the Branch (`git push origin feature/AmazingFeature`) +5. Open a Pull Request + +

(back to top)

+ +## License + +Distributed under the MIT License. See `LICENSE.txt` for more information. + +

(back to top)

+ +## Contact + +Your Name - - email@email_client.com + +Project Link: [https://github.com/github_username/repo_name](https://github.com/github_username/repo_name) + +

(back to top)

+ +## Acknowledgments + +* [README Template](https://github.com/othneildrew/Best-README-Template) + +

(back to top)

From 063c4ee15a6ce96d3cb1dcf7e4834bae8e9991f8 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Wed, 3 Apr 2024 14:30:14 +0300 Subject: [PATCH 166/186] refactor: better tests --- src/test/kotlin/RBTreeTest.kt | 277 ++++++++++++++++++++++------------ 1 file changed, 177 insertions(+), 100 deletions(-) diff --git a/src/test/kotlin/RBTreeTest.kt b/src/test/kotlin/RBTreeTest.kt index 4ea8a2c..b3bb909 100644 --- a/src/test/kotlin/RBTreeTest.kt +++ b/src/test/kotlin/RBTreeTest.kt @@ -41,7 +41,9 @@ class RBTreeTest { assertEquals(root, emptyTree.root!!.left) assertEquals(right, emptyTree.root) assertEquals(right2, emptyTree.root!!.right) - assertTrue { root.isRed && !right.isRed && right2.isRed } + assertTrue(root.isRed) + assertFalse(right.isRed) + assertTrue(right2.isRed) } @Test @@ -50,8 +52,12 @@ class RBTreeTest { val root = emptyTree.add(0, 0)!! val left = emptyTree.add(-1, -1)!! val left2 = emptyTree.add(-2, -2)!! + assertEquals(root, emptyTree.root!!.right) assertEquals(left, emptyTree.root) - assertTrue { root.isRed && !left.isRed && left2.isRed } + assertEquals(left2, emptyTree.root!!.left) + assertTrue(root.isRed) + assertFalse(left.isRed) + assertTrue(left2.isRed) } @@ -66,7 +72,10 @@ class RBTreeTest { assertEquals(left, emptyTree.root!!.left) assertEquals(right, emptyTree.root!!.right) assertEquals(right2, emptyTree.root!!.right!!.right) - assertTrue(!root.isRed && !left.isRed && !right.isRed && right2.isRed) + assertFalse(root.isRed) + assertFalse(left.isRed) + assertFalse(right.isRed) + assertTrue(right2.isRed) } @Test @@ -80,7 +89,10 @@ class RBTreeTest { assertEquals(right, emptyTree.root!!.right) assertEquals(left, emptyTree.root!!.left) assertEquals(left2, emptyTree.root!!.left!!.left) - assertTrue(!root.isRed && !right.isRed && !left.isRed && left2.isRed) + assertFalse(root.isRed) + assertFalse(right.isRed) + assertFalse(left.isRed) + assertTrue(left2.isRed) } @Test @@ -96,10 +108,11 @@ class RBTreeTest { assertEquals(right, emptyTree.root!!.right!!.left) assertEquals(right2, emptyTree.root!!.right!!.right) assertEquals(right15, emptyTree.root!!.right) - assertTrue( - !root.isRed && !left.isRed && - right.isRed && !right15.isRed && right2.isRed - ) + assertFalse(root.isRed) + assertFalse(left.isRed) + assertTrue(right.isRed) + assertFalse(right15.isRed) + assertTrue(right2.isRed) } @Test @@ -115,10 +128,27 @@ class RBTreeTest { assertEquals(left, emptyTree.root!!.left!!.right) assertEquals(left2, emptyTree.root!!.left!!.left) assertEquals(left15, emptyTree.root!!.left) - assertTrue( - !root.isRed && !right.isRed && - left.isRed && !left15.isRed && left2.isRed + assertFalse(root.isRed) + assertFalse(right.isRed) + assertTrue(left.isRed) + assertFalse(left15.isRed) + assertTrue(left2.isRed) + } + + @Test + @DisplayName("Add multiple nodes") + fun addMany() { + val nodesResult = MutableList(20) { emptyTree.add(it, it) } + val colorResult = arrayListOf( + false, false, false, true, false, + false, false, false, false, false, + false, true, false, true, false, + false, false, true, false, true, ) + for (node in emptyTree) { + assertEquals(nodesResult.removeFirst(), node) + assertEquals(colorResult.removeFirst(), node.isRed) + } } } @@ -130,18 +160,18 @@ class RBTreeTest { @BeforeEach fun initTree() { - tree3Node = RBTree() - tree3Node.add(0, 0) - tree3Node.add(10, 10) + tree3Node = RBTree() // 0 + tree3Node.add(0, 0) // / \ + tree3Node.add(10, 10) // -10 10 tree3Node.add(-10, -10) - bft15 = RBTree() //15 node tree (balanced) - var k = 16 - for (i in listOf(1, 2, 4, 8)) { //amount of nodes on level - for (j in 0.. Date: Wed, 3 Apr 2024 14:49:01 +0300 Subject: [PATCH 167/186] fix: assert height in addMany() test --- src/test/kotlin/RBTreeTest.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/test/kotlin/RBTreeTest.kt b/src/test/kotlin/RBTreeTest.kt index b3bb909..b136d3a 100644 --- a/src/test/kotlin/RBTreeTest.kt +++ b/src/test/kotlin/RBTreeTest.kt @@ -9,8 +9,8 @@ class RBTreeTest { var emptyTree = RBTree() @BeforeEach - fun init() { - emptyTree = RBTree() + fun emptyTree() { + emptyTree.clear() } @Nested @@ -138,7 +138,11 @@ class RBTreeTest { @Test @DisplayName("Add multiple nodes") fun addMany() { - val nodesResult = MutableList(20) { emptyTree.add(it, it) } + val nodesResult = MutableList(10) { emptyTree.add(it, it) } + assertEquals(5, emptyTree.height()) + for (keyValue in 10..19) + nodesResult.addLast(emptyTree.add(keyValue, keyValue)) + assertEquals(6, emptyTree.height()) val colorResult = arrayListOf( false, false, false, true, false, false, false, false, false, false, From 387bff2c394101fe031a3723a4d47e148b95282a Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Wed, 3 Apr 2024 14:57:26 +0300 Subject: [PATCH 168/186] refactor: add brackets in equals() --- src/main/kotlin/treeLib/nodes/TreeNode.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index 0a623c0..03f72a1 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -12,7 +12,7 @@ abstract class TreeNode, V, Node_T : TreeNode>( override fun hashCode(): Int = Pair(key, value).hashCode() override fun equals(other: Any?): Boolean { - return (other as? Node_T != null) && key == other.key && value == other.value + return (other as? Node_T != null) && (key == other.key) && (value == other.value) } override fun toString(): String = Pair(key, value).toString() From 50bcccc48efa72f11942b2ad5d2901623565c0d1 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 3 Apr 2024 15:22:34 +0300 Subject: [PATCH 169/186] ci: rename run detekt workflow --- .github/workflows/format_check.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/format_check.yml b/.github/workflows/format_check.yml index 196149a..2ac9957 100644 --- a/.github/workflows/format_check.yml +++ b/.github/workflows/format_check.yml @@ -1,17 +1,9 @@ -## 1 -name: Run detekt -## 2 +name: Run detekt - static code analyzer on: push: - branches: - - main pull_request: - branches: - - main -## 3 jobs: detekt: - ## 4 runs-on: ubuntu-latest steps: - name: "checkout" From ace3896bcc750f9cd61737f3b1e30cac3e58dd95 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Wed, 3 Apr 2024 16:36:22 +0300 Subject: [PATCH 170/186] feat: add description README.md --- README.md | 72 +++++++++++++++++-------------------------------------- 1 file changed, 22 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 9cc2415..1fa344d 100644 --- a/README.md +++ b/README.md @@ -1,69 +1,41 @@ [![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](https://choosealicense.com/licenses/mit/) [![CodeFactor](https://www.codefactor.io/repository/github/spbu-coding-2023/trees-4/badge)](https://www.codefactor.io/repository/github/spbu-coding-2023/trees-4) -## About The Project +## About Lib Tree -/ шаблон / +Lib tree is the kotlin library for working with 3 different binary tree implementations +such as Binary Search Tree(BST), AVL-Tree(AVL) and Red-Black Tree(RB). -

(back to top)

+All trees supports basic operations: +- Add node to tree +- Change node's value +- Remove node from tree +- Find node by key +- Iterate in tree +- ...and much more! ## Getting Started -### Prerequisites - -* code - ```sh - code - ``` - -### Installation - -

(back to top)

- - -## Usage - -

(back to top)

- - -## Roadmap - -- [ ] Feature 1 -- [ ] Feature 2 -- [ ] Feature 3 - - [ ] Nested Feature - -

(back to top)

- -## Contributing - -Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. - -If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". -Don't forget to give the project a star! Thanks again! - -1. Fork the Project -2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) -3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) -4. Push to the Branch (`git push origin feature/AmazingFeature`) -5. Open a Pull Request - -

(back to top)

+??? ## License Distributed under the MIT License. See `LICENSE.txt` for more information. -

(back to top)

- ## Contact +This library was created by: +Magomedov Islam(tg @JapEmpLove) - BST +Damir Yunusov(tg @TopographicOcean) - RB +Sofya Grishkova(tg @tea_jack) -AVL -Your Name - - email@email_client.com - -Project Link: [https://github.com/github_username/repo_name](https://github.com/github_username/repo_name) +## Acknowledgments -

(back to top)

+Links to english Wikipages about binary trees: +[Binary Tree](https://en.wikipedia.org/wiki/Binary_tree) +[Binary Search Tree](https://en.wikipedia.org/wiki/Binary_search_tree) +[Red-Black Tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) +[AVL-Tree](https://en.wikipedia.org/wiki/AVL_tree) -## Acknowledgments +[Here](https://www.geeksforgeeks.org/applications-advantages-and-disadvantages-of-binary-search-tree/) are provided applications, advantages and disadvantages of Binary Search Tree * [README Template](https://github.com/othneildrew/Best-README-Template) From bfa3d61d51c3b211316d501f42dbd6aea306af7c Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Wed, 3 Apr 2024 16:40:40 +0300 Subject: [PATCH 171/186] fix: better looks --- README.md | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 1fa344d..d70fd4d 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ ## About Lib Tree -Lib tree is the kotlin library for working with 3 different binary tree implementations -such as Binary Search Tree(BST), AVL-Tree(AVL) and Red-Black Tree(RB). +Lib tree is the kotlin library for working with 3 different binary tree implementations: +Binary Search Tree(BST), AVL-Tree(AVL) and Red-Black Tree(RB). All trees supports basic operations: - Add node to tree @@ -23,20 +23,18 @@ Distributed under the MIT License. See `LICENSE.txt` for more information. ## Contact This library was created by: -Magomedov Islam(tg @JapEmpLove) - BST -Damir Yunusov(tg @TopographicOcean) - RB -Sofya Grishkova(tg @tea_jack) -AVL +* Magomedov Islam(tg @JapEmpLove) - BST +* Damir Yunusov(tg @TopographicOcean) - RB +* Sofya Grishkova(tg @tea_jack) - AVL ## Acknowledgments Links to english Wikipages about binary trees: -[Binary Tree](https://en.wikipedia.org/wiki/Binary_tree) -[Binary Search Tree](https://en.wikipedia.org/wiki/Binary_search_tree) -[Red-Black Tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) -[AVL-Tree](https://en.wikipedia.org/wiki/AVL_tree) - -[Here](https://www.geeksforgeeks.org/applications-advantages-and-disadvantages-of-binary-search-tree/) are provided applications, advantages and disadvantages of Binary Search Tree - +* [Binary Tree](https://en.wikipedia.org/wiki/Binary_tree) +* [Binary Search Tree](https://en.wikipedia.org/wiki/Binary_search_tree) +* [Red-Black Tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) +* [AVL-Tree](https://en.wikipedia.org/wiki/AVL_tree) +* [Here](https://www.geeksforgeeks.org/applications-advantages-and-disadvantages-of-binary-search-tree/) are provided applications, advantages and disadvantages of Binary Search Tree * [README Template](https://github.com/othneildrew/Best-README-Template)

(back to top)

From 677d8feb6f1204a4dea9ce31e8009ed755ba9589 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Wed, 3 Apr 2024 18:59:40 +0300 Subject: [PATCH 172/186] feat: add 'how to use' article --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index d70fd4d..d6b21d4 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,46 @@ [![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](https://choosealicense.com/licenses/mit/) [![CodeFactor](https://www.codefactor.io/repository/github/spbu-coding-2023/trees-4/badge)](https://www.codefactor.io/repository/github/spbu-coding-2023/trees-4) -## About Lib Tree +## About Tree Lib -Lib tree is the kotlin library for working with 3 different binary tree implementations: -Binary Search Tree(BST), AVL-Tree(AVL) and Red-Black Tree(RB). +Tree Lib is the kotlin library for working with 3 different binary tree implementations: Binary Search Tree(BST), AVL-Tree(AVL) and Red-Black Tree(RB). -All trees supports basic operations: -- Add node to tree -- Change node's value -- Remove node from tree -- Find node by key -- Iterate in tree -- ...and much more! +## How to use +To init an object, you must provide key and value type +``` +val treeExample: BSTree<, > +``` +for example +``` +val treeExample = BSTree() +``` -## Getting Started +All trees supports basic methods: +- Add values and keys as nodes to the tree: + + `treeExample.add("abc", 1.0)` + +- Change node's value: + + `treeExample.changeVal("abc", 37.7)` + +- Remove node from the tree: + + `treeExample.remove("key of node")` + +- Find node by key: + + `treeExample.find("meaning of life")` + +- Iterate in tree: + + `for(node in treeExample) { ...` + +- ...and much more! -??? +With binary trees, Tree Lib provides a node type for each of them. +You can read node's key and value(with key() and value() methods), compare +them between each other(although they must share same type), convert them to +pair(toPair()) or string(toString()). ## License @@ -29,12 +54,14 @@ This library was created by: ## Acknowledgments +[README Template](https://github.com/othneildrew/Best-README-Template) + Links to english Wikipages about binary trees: * [Binary Tree](https://en.wikipedia.org/wiki/Binary_tree) * [Binary Search Tree](https://en.wikipedia.org/wiki/Binary_search_tree) * [Red-Black Tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) * [AVL-Tree](https://en.wikipedia.org/wiki/AVL_tree) -* [Here](https://www.geeksforgeeks.org/applications-advantages-and-disadvantages-of-binary-search-tree/) are provided applications, advantages and disadvantages of Binary Search Tree -* [README Template](https://github.com/othneildrew/Best-README-Template) + +[Here](https://www.geeksforgeeks.org/applications-advantages-and-disadvantages-of-binary-search-tree/) are provided applications, advantages and disadvantages of Binary Search Tree -

(back to top)

+Good [Habr article](https://habr.com/ru/articles/150732/) about AVL-Trees From ef2ddb55c1e4a03c562750bba464aa9016a50f97 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 3 Apr 2024 18:59:47 +0300 Subject: [PATCH 173/186] fix: no more test doubles --- .github/workflows/format_check.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/format_check.yml b/.github/workflows/format_check.yml index 2ac9957..f9da449 100644 --- a/.github/workflows/format_check.yml +++ b/.github/workflows/format_check.yml @@ -1,7 +1,6 @@ name: Run detekt - static code analyzer on: push: - pull_request: jobs: detekt: runs-on: ubuntu-latest From 65a1410cad17b3f69f19721b1229b0f1eac810a3 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 3 Apr 2024 19:11:29 +0300 Subject: [PATCH 174/186] ci: config coverage output --- .github/workflows/coverage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 0e58a70..543f93e 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -29,5 +29,6 @@ jobs: paths: | ${{ github.workspace }}/build/reports/jacoco/test/jacocoTestReport.xml token: ${{ secrets.GITHUB_TOKEN }} + skip-if-no-changes: true From e584f22169b82d99ff9ccc1abd875051285cdb6f Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Wed, 3 Apr 2024 19:29:17 +0300 Subject: [PATCH 175/186] fix: minor fixes in readme --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index d6b21d4..7cc7e6e 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ ## About Tree Lib -Tree Lib is the kotlin library for working with 3 different binary tree implementations: Binary Search Tree(BST), AVL-Tree(AVL) and Red-Black Tree(RB). +Tree Lib is the kotlin library for working with 3 different binary tree implementations: Binary Search Tree (BST), AVL-Tree (AVL) and Red-Black Tree (RB). ## How to use -To init an object, you must provide key and value type +To init an object, you must provide key and value type. ``` val treeExample: BSTree<, > ``` @@ -17,23 +17,23 @@ val treeExample = BSTree() All trees supports basic methods: - Add values and keys as nodes to the tree: - `treeExample.add("abc", 1.0)` + `treeExample.add(key: "abc", value: 1.0)` - Change node's value: - `treeExample.changeVal("abc", 37.7)` + `treeExample.changeVal(key: "abc", value: 37.7)` - Remove node from the tree: - `treeExample.remove("key of node")` + `treeExample.remove(key: "Choose wisely.")` - Find node by key: - `treeExample.find("meaning of life")` + `treeExample.findByKey(key: "Anything you can compare!")` - Iterate in tree: - `for(node in treeExample) { ...` + `for (node in treeExample) { ...` - ...and much more! @@ -48,15 +48,15 @@ Distributed under the MIT License. See `LICENSE.txt` for more information. ## Contact This library was created by: -* Magomedov Islam(tg @JapEmpLove) - BST -* Damir Yunusov(tg @TopographicOcean) - RB -* Sofya Grishkova(tg @tea_jack) - AVL +* Magomedov Islam (tg @JapEmpLove) - BST +* Damir Yunusov (tg @TopographicOcean) - RB +* Sofya Grishkova (tg @tea_jack) - AVL ## Acknowledgments [README Template](https://github.com/othneildrew/Best-README-Template) -Links to english Wikipages about binary trees: +Links to Wikipages about binary trees: * [Binary Tree](https://en.wikipedia.org/wiki/Binary_tree) * [Binary Search Tree](https://en.wikipedia.org/wiki/Binary_search_tree) * [Red-Black Tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) From e03be3580073571bfac0d9813d399a99580727b8 Mon Sep 17 00:00:00 2001 From: Islam Date: Wed, 3 Apr 2024 22:29:09 +0300 Subject: [PATCH 176/186] fix: deleted method isThereChild because I was forced to do this --- src/main/kotlin/treeLib/bintrees/BSTree.kt | 2 +- src/main/kotlin/treeLib/nodes/BSTNode.kt | 6 +----- src/test/kotlin/BSTreeTest.kt | 16 ---------------- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index edc2edb..6892934 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -98,7 +98,7 @@ class BSTree, V> : BinTree>() { fun findParent(key: K): BSTNode? { var parent = this.root if (parent == null || root!!.key == key) return null - while (parent?.isThereChild() == true) { + while (parent?.right != null || parent?.left != null) { if ((parent.right != null && parent.right?.key == key) || (parent.left != null && parent.left?.key == key)) return parent else { if (key > parent.key) { diff --git a/src/main/kotlin/treeLib/nodes/BSTNode.kt b/src/main/kotlin/treeLib/nodes/BSTNode.kt index 4328b12..c64e6a4 100644 --- a/src/main/kotlin/treeLib/nodes/BSTNode.kt +++ b/src/main/kotlin/treeLib/nodes/BSTNode.kt @@ -5,8 +5,4 @@ class BSTNode, V>( value: V, right: BSTNode? = null, left: BSTNode? = null -) : TreeNode>(key, value, right, left) { - internal fun isThereChild(): Boolean { - return this.left != null || this.right != null - } -} +) : TreeNode>(key, value, right, left) diff --git a/src/test/kotlin/BSTreeTest.kt b/src/test/kotlin/BSTreeTest.kt index 87db899..b237887 100644 --- a/src/test/kotlin/BSTreeTest.kt +++ b/src/test/kotlin/BSTreeTest.kt @@ -8,22 +8,6 @@ import org.junit.jupiter.api.Test class BSTreeTest { var baum = BSTree() - @Test - fun isThereChild() { - baum.add(4, "qwerty") - baum.add(2, "Ge") - baum.add(5, "rma") - baum.add(3, "ny") - baum.add(-1, "ny") - - val rt = baum.root() - - assertFalse(rt?.right!!.isThereChild()) - assertFalse(rt.left?.right!!.isThereChild()) - assertTrue(rt.isThereChild()) - assertTrue(rt.left!!.isThereChild()) - } - @Test fun findParent() { baum.add(4, "qwerty") From 745ce4837912cd42cfb9d260af65d3757299f783 Mon Sep 17 00:00:00 2001 From: Sofya Grishkova Date: Thu, 4 Apr 2024 12:31:58 +0300 Subject: [PATCH 177/186] fix!: rbt root no longer public --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 5 +- src/main/kotlin/treeLib/bintrees/BSTree.kt | 59 +- src/main/kotlin/treeLib/bintrees/RBTree.kt | 24 +- .../{TreeBalancer.kt => BalancedTree.kt} | 9 +- .../bintrees/interfaces/TreeIterator.kt | 2 +- src/main/kotlin/treeLib/nodes/RBNode.kt | 2 +- src/test/kotlin/AVLTreeTest.kt | 20 +- src/test/kotlin/BSTreeTest.kt | 719 +++++++------- src/test/kotlin/RBTreeTest.kt | 922 +++++++++--------- 9 files changed, 884 insertions(+), 878 deletions(-) rename src/main/kotlin/treeLib/bintrees/interfaces/{TreeBalancer.kt => BalancedTree.kt} (62%) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index 5848123..e4dcf73 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -1,10 +1,11 @@ package treeLib.bintrees +import treeLib.bintrees.interfaces.BalancedTree import treeLib.bintrees.interfaces.BinTree import treeLib.nodes.AVLNode -class AVLTree, V> : BinTree>() { +class AVLTree, V> : BalancedTree>(){ override var root: AVLNode? = null override var amountOfNodes = 0 @@ -26,7 +27,7 @@ class AVLTree, V> : BinTree>() { val min = findMin(nodeB) min?.right = removeMin(nodeB) min?.left = nodeA - if (root?.key == key){ + if (root?.key == key) { root = min } return balanceNode(min) diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 6892934..017b928 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -8,21 +8,21 @@ class BSTree, V> : BinTree>() { override var amountOfNodes = 0 fun addPairs(vararg pairs: Pair): Boolean { - for(pair in pairs){ - if( this.add(pair.first, pair.second) == null ) return false + for (pair in pairs) { + if (this.add(pair.first, pair.second) == null) return false } return true } - fun removePairs(vararg keys: K): Boolean{ - for(key in keys){ - if( this.remove(key) == null ) return false + fun removePairs(vararg keys: K): Boolean { + for (key in keys) { + if (this.remove(key) == null) return false } return true } override fun add(key: K, value: V): BSTNode? { - if (root == null){ + if (root == null) { this.root = BSTNode(key, value) this.amountOfNodes += 1 return root @@ -52,31 +52,28 @@ class BSTree, V> : BinTree>() { var count = 0 var curNode: BSTNode? = null var parent = this.findParent(key) - if(this.root?.key == key) parent = BSTNode(root!!.key, root!!.value, root) - if(parent == null) return null - curNode = if(parent.right != null && parent.right?.key == key) parent.right + if (this.root?.key == key) parent = BSTNode(root!!.key, root!!.value, root) + if (parent == null) return null + curNode = if (parent.right != null && parent.right?.key == key) parent.right else parent.left if (curNode?.right != null) count++ if (curNode?.left != null) count++ if (count == 0) { - if (parent.right === curNode){ - if(curNode == root) this.root = null + if (parent.right === curNode) { + if (curNode == root) this.root = null else parent.right = null - } - else parent.left = null + } else parent.left = null } else if (count == 1) { if (curNode?.left == null) { - if (parent.right == curNode){ - if(curNode == root) this.root = root?.right + if (parent.right == curNode) { + if (curNode == root) this.root = root?.right else parent.right = curNode?.right - } - else parent.left = curNode?.right + } else parent.left = curNode?.right } else { - if (parent.right == curNode){ - if(curNode == root) this.root = this.root?.left + if (parent.right == curNode) { + if (curNode == root) this.root = this.root?.left else parent.right = curNode.left - } - else parent.left = curNode.left + } else parent.left = curNode.left } } else { var child = curNode?.right @@ -87,7 +84,7 @@ class BSTree, V> : BinTree>() { } curNode?.key = child.key curNode?.value = child.value - if(curNode?.right != child) parent_child!!.left = child.right + if (curNode?.right != child) parent_child!!.left = child.right else curNode.right = child.right } this.amountOfNodes -= 1 @@ -95,7 +92,7 @@ class BSTree, V> : BinTree>() { } - fun findParent(key: K): BSTNode? { + internal fun findParent(key: K): BSTNode? { var parent = this.root if (parent == null || root!!.key == key) return null while (parent?.right != null || parent?.left != null) { @@ -114,24 +111,24 @@ class BSTree, V> : BinTree>() { } - fun deleteSubTree(key: K): Boolean{ + fun deleteSubTree(key: K): Boolean { val parent: BSTNode? = this.findParent(key) - if(parent == null) return false - if(parent.right != null && parent.right?.key == key) parent.right = null + if (parent == null) return false + if (parent.right != null && parent.right?.key == key) parent.right = null else parent.left = null var nodes = 0 - for(i in this) nodes++ + for (i in this) nodes++ amountOfNodes = nodes return true } - fun getSubTree(key: K): BSTree?{ + fun getSubTree(key: K): BSTree? { val parent: BSTNode? = this.findParent(key) val childTree: BSTree = BSTree() - if(parent == null) return null + if (parent == null) return null var child: BSTNode? = null - if(parent.right != null && parent.right?.key == key){ + if (parent.right != null && parent.right?.key == key) { child = childTree.add(key, parent.right!!.value) child?.right = parent.right!!.right child?.left = parent.right!!.left @@ -141,7 +138,7 @@ class BSTree, V> : BinTree>() { child?.left = parent.left!!.left } var nodes = 0 - for(i in childTree) nodes++ + for (i in childTree) nodes++ childTree.amountOfNodes = nodes return childTree } diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index 29f7aa7..0967ed6 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -1,14 +1,13 @@ package treeLib.bintrees -import treeLib.bintrees.interfaces.BinTree -import treeLib.bintrees.interfaces.TreeBalancer +import treeLib.bintrees.interfaces.BalancedTree import treeLib.nodes.RBNode /** * Class which implements... Red-Black Tree :O * Takes two types: for key(K) and for value(V) */ -class RBTree, V> : BinTree>(), TreeBalancer> { +class RBTree, V> : BalancedTree>() { override var root: RBNode? = null override var amountOfNodes: Int = 0 @@ -37,7 +36,7 @@ class RBTree, V> : BinTree>(), TreeBalancer amountOfNodes++ treeBranch.addFirst(newNode) - balancerAdd(treeBranch) + balancedAdd(treeBranch) return newNode } @@ -45,7 +44,7 @@ class RBTree, V> : BinTree>(), TreeBalancer /** * Used in add() method to balance tree :) */ - private fun balancerAdd(treeBranch: ArrayDeque>) { + private fun balancedAdd(treeBranch: ArrayDeque>) { var son = treeBranch.removeFirst() var parent = treeBranch.removeFirstOrNull() var grandparent = treeBranch.removeFirstOrNull() @@ -118,6 +117,7 @@ class RBTree, V> : BinTree>(), TreeBalancer curNode.value = temp //to save deleted node's value curNode.left } + sonRight != null -> sonRight else /*sonLeft != null*/ -> sonLeft } @@ -130,7 +130,7 @@ class RBTree, V> : BinTree>(), TreeBalancer } treeBranch.addFirst(sonOfRemovedNode) //curNode.isRed -> no balancing needed - if (!curNode.isRed) balancerRemove(treeBranch) + if (!curNode.isRed) balancedRemove(treeBranch) return curNode.value } @@ -138,7 +138,7 @@ class RBTree, V> : BinTree>(), TreeBalancer /** * Used in remove() method to balance tree :( */ - private fun balancerRemove(treeBranch: ArrayDeque?>) { + private fun balancedRemove(treeBranch: ArrayDeque?>) { var son = treeBranch.removeFirstOrNull() var parent = treeBranch.removeFirstOrNull() var grandparent = treeBranch.removeFirstOrNull() @@ -164,8 +164,10 @@ class RBTree, V> : BinTree>(), TreeBalancer brother = parent.right } } - brother ?: throw IllegalStateException("Balance of red-black tree violated:" + - " parent node have subtrees with black height 2 and black height 1") + brother ?: throw IllegalStateException( + "Balance of red-black tree violated:" + + " parent node have subtrees with black height 2 and black height 1" + ) //depending on nephew's colors, doing magic for balancing purposes var nephewRight = brother.right @@ -184,7 +186,7 @@ class RBTree, V> : BinTree>(), TreeBalancer if (son == parent.right) { if (nephewRight?.isRed == true && (nephewLeft == null || !nephewLeft.isRed)) { rotateLeft(brother, parent) // B /nL == new brother - nephewLeft = brother // / \ -> /B == new left nephew + nephewLeft = brother // / \ -> /B == new left nephew brother = nephewRight // nL nR /nR brother.isRed = false nephewLeft.isRed = true @@ -207,7 +209,7 @@ class RBTree, V> : BinTree>(), TreeBalancer brother.isRed = parent.isRed parent.isRed = false nephewRight?.isRed = false - } + } break } } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BalancedTree.kt similarity index 62% rename from src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt rename to src/main/kotlin/treeLib/bintrees/interfaces/BalancedTree.kt index 0dce327..00bff08 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/TreeBalancer.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BalancedTree.kt @@ -2,11 +2,10 @@ package treeLib.bintrees.interfaces import treeLib.nodes.TreeNode -internal interface TreeBalancer, V, Node_T : TreeNode> { - var root: Node_T? +abstract class BalancedTree, V, Node_T : TreeNode> : BinTree() { - //We must provide parent, because don't have link to him in node - fun rotateRight(node: Node_T?, parent: Node_T?) { + //We must provide parent, because don't have link to it in node + protected fun rotateRight(node: Node_T?, parent: Node_T?) { if (node == null) return val nodeLeft = node.left node.left = nodeLeft?.right @@ -15,7 +14,7 @@ internal interface TreeBalancer, V, Node_T : TreeNode, V, Node_T : TreeNode>( private val root: Node_T?, private val order: IterationOrder, - ): Iterator { +) : Iterator { private val stack: ArrayDeque = ArrayDeque() init { diff --git a/src/main/kotlin/treeLib/nodes/RBNode.kt b/src/main/kotlin/treeLib/nodes/RBNode.kt index a730563..b4ff5ce 100644 --- a/src/main/kotlin/treeLib/nodes/RBNode.kt +++ b/src/main/kotlin/treeLib/nodes/RBNode.kt @@ -5,5 +5,5 @@ class RBNode, V>( value: V, right: RBNode? = null, left: RBNode? = null, - var isRed: Boolean = true, + internal var isRed: Boolean = true, ) : TreeNode>(key, value, right, left) \ No newline at end of file diff --git a/src/test/kotlin/AVLTreeTest.kt b/src/test/kotlin/AVLTreeTest.kt index eba4fdc..08453a4 100644 --- a/src/test/kotlin/AVLTreeTest.kt +++ b/src/test/kotlin/AVLTreeTest.kt @@ -1,10 +1,10 @@ import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test import treeLib.bintrees.AVLTree import treeLib.nodes.AVLNode import kotlin.math.abs -import org.junit.jupiter.api.Test class AVLTreeTest { @@ -29,7 +29,7 @@ class AVLTreeTest { } @Test - fun addByKey () { + fun addByKey() { assertEquals(-1, tree.root()?.left?.key) assertEquals("b", tree.root()?.left?.value) assertEquals(1, tree.root()?.right?.key) @@ -55,7 +55,7 @@ class AVLTreeTest { @Test fun removeRoot() { - val key : Int? = tree.root()?.key + val key: Int? = tree.root()?.key if (key != null) { tree.remove(key) assertNotNull(tree.root()) @@ -72,7 +72,7 @@ class AVLTreeTest { } @Test - fun removeNodeWithNoChildren(){ + fun removeNodeWithNoChildren() { tree.remove(10) assertNull(tree.findByKey(10)) for (i in 0..9) { @@ -81,7 +81,7 @@ class AVLTreeTest { } @Test - fun removeNodeWithTwoChildren(){ + fun removeNodeWithTwoChildren() { tree.remove(7) assertNull(tree.findByKey(7)) for (i in 0..10) { @@ -127,7 +127,7 @@ class AVLTreeTest { } @BeforeEach - fun setUpRandomTree(){ + fun setUpRandomTree() { val ranLen = (2..100).random() for (i in 1..ranLen) { val ranItem = (1..10000).random() @@ -147,8 +147,8 @@ class AVLTreeTest { } @Test - fun afterRootRemoveAVLIsBalanced(){ - val key : Int? = tree.root()?.key + fun afterRootRemoveAVLIsBalanced() { + val key: Int? = tree.root()?.key if (key != null) { tree.remove(key) assertTrue(isBalanced(tree.root())) @@ -188,14 +188,14 @@ class AVLTreeTest { } @Test - fun findMax(){ + fun findMax() { assertEquals(tree.findByKey(10), tree.max()) tree.clear() assertNull(tree.max()) } @Test - fun findMin(){ + fun findMin() { assertEquals(tree.findByKey(0), tree.min()) tree.clear() assertNull(tree.min()) diff --git a/src/test/kotlin/BSTreeTest.kt b/src/test/kotlin/BSTreeTest.kt index b237887..7f18eab 100644 --- a/src/test/kotlin/BSTreeTest.kt +++ b/src/test/kotlin/BSTreeTest.kt @@ -1,434 +1,433 @@ import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test import treeLib.bintrees.BSTree import treeLib.nodes.BSTNode -import org.junit.jupiter.api.Test class BSTreeTest { - var baum = BSTree() - - @Test - fun findParent() { - baum.add(4, "qwerty") - baum.add(2, "Ge") - baum.add(5, "rma") - baum.add(-1, "ny") - baum.add(3, "the") - baum.add(40, "best") - baum.add(44, "Ja") - - assertEquals(BSTNode(5, "rma"), baum.findParent(40)) //Parent with ein Kind - - assertEquals(BSTNode(2, "Ge"), baum.findParent(3)) //Parent with zwei Kinder - - assertEquals(baum.root(), baum.findParent(5)) //When Parent - assertEquals(baum.root(), baum.findParent(2)) //is root - - assertNull(baum.findParent(4)) //Parent where child is root - - assertNull(baum.findParent(34)) //Finding No existing node's parent - } - - - - @Nested - inner class TestingAddMethods { - - @Test - fun addToEmptyTree() { - assertEquals(BSTNode(4, "qwerty"), baum.root()) - } - - @BeforeEach - fun setUp() { - baum.add(4, "qwerty") - baum.add(2, "Ge") - baum.add(5, "rma") - baum.add(-1, "ny") - baum.add(3, "the") - baum.add(40, "best") - baum.add(44, "Ja") - } - - @Test - fun checkWaysToNodes() { - val rt = baum.root() - assertEquals(BSTNode(5,"rma"), rt?.right) - assertEquals(BSTNode(3, "the"), rt?.left?.right) - assertEquals(BSTNode(-1, "ny"), rt?.left?.left) - assertEquals(BSTNode(44, "Ja"), rt?.right?.right?.right) - } - - @Test - fun checkAmountsOfNodes() { - assertEquals(7, baum.countNodes()) - assertEquals(BSTNode(10, "Was"),baum.add(10, "Was")) - assertEquals(8, baum.countNodes()) - } - - @Test - fun addPairs() { - baum.addPairs(Pair(1, "ein"), Pair(7, "sieben"), Pair(6, "sechs")) - - assertEquals(10, baum.countNodes()) - assertEquals(1, baum.root()?.left?.left?.right?.key) - assertEquals(6, baum.root()?.right?.right?.left?.left?.key) - } - - @Test - fun addAlreadyExistingNodes() { - assertNull(baum.add(5, "rma")) - assertNull(baum.add(3, "the")) - assertNull(baum.add(40, "best")) - assertNull(baum.add(44, "Ja")) - - assertEquals(7, baum.countNodes()) - } - - @Test - fun addingExistingNodeButWithDifferentValues() { - assertNull(baum.add(5, "Deutschland")) - assertNotEquals("Deutschland", baum.root()?.right?.value) - - assertNull(baum.add(-1, "Deutschland")) - assertNotEquals("Deutschland", baum.root()?.left?.left?.value) - - assertNull(baum.add(4, "Deutschland")) - assertNotEquals("Deutschland", baum.root()?.value) - } - - @Test - fun orderMatters() { - baum.clear() - assertTrue(baum.addPairs(Pair(4, "Vier"), Pair(5, "Funf"), Pair(40, "Vierzig"), Pair(44,"Vierundvierzig"))) - var rt = baum.root() - - assertEquals(5, rt?.right?.key) - assertEquals(44, rt?.right?.right?.right?.key) - - baum.clear() - baum.addPairs(Pair(4, "Vier"), Pair(44,"Vierundvierzig"), Pair(40, "Vierzig"), Pair(5, "Funf")) - rt = baum.root() - - assertEquals(5, rt?.right?.left?.left?.key) - assertEquals(44, rt?.right?.key) - //In other words, with different order we have different ways to nodes - } - } - - @Nested - inner class Remove { - @BeforeEach - fun setUp() { - for(key in listOf(10, 13, 12, 11, 20, 15, 25, -7, 5, -10, 9)){ - baum.add(key, "test") - } - } - - @Test - fun removeNodesWithNoKinder() { - val rt = baum.root() - - assertTrue(baum.removePairs(-10, 11)) - baum.remove(9) - - assertNull(rt?.left?.left) - assertNull(rt?.right?.left?.left) - assertNull(rt?.left?.right?.right) - } - - @Test - fun removeNodesWithEinKind() { - val rt = baum.root() - baum.removePairs(12) - baum.remove(5) - - assertEquals(9, rt?.left?.right?.key) - assertNull(rt?.left?.right?.right) - - assertEquals(11, rt?.right?.left?.key) - assertNull(rt?.right?.left?.left) - - baum.add(12, "test") - baum.remove(11) - assertEquals(BSTNode(12, "test"), rt?.right?.left) - - baum.remove(25) - baum.remove(20) - assertEquals(BSTNode(15, "test"), rt?.right?.right) - } - - @Test - fun removeNodeWithZweiKinderFirstCase() { - //I don't know how to describe any of these cases, just image current tree and I hope you'll get it - val rt = baum.root() - baum.remove(-7) - - assertEquals(5, rt?.left?.key) - assertEquals(-10, rt?.left?.left?.key) - assertEquals(9, rt?.left?.right?.key) - - assertNull(rt?.left?.right?.right) - } - - @Test - fun removeNodeWithZweiKinderSecondCase() { - val rt = baum.root() - assertEquals("test", baum.remove(13)) + var baum = BSTree() + + @Test + fun findParent() { + baum.add(4, "qwerty") + baum.add(2, "Ge") + baum.add(5, "rma") + baum.add(-1, "ny") + baum.add(3, "the") + baum.add(40, "best") + baum.add(44, "Ja") + + assertEquals(BSTNode(5, "rma"), baum.findParent(40)) //Parent with ein Kind + + assertEquals(BSTNode(2, "Ge"), baum.findParent(3)) //Parent with zwei Kinder + + assertEquals(baum.root(), baum.findParent(5)) //When Parent + assertEquals(baum.root(), baum.findParent(2)) //is root + + assertNull(baum.findParent(4)) //Parent where child is root + + assertNull(baum.findParent(34)) //Finding No existing node's parent + } + + + @Nested + inner class TestingAddMethods { + + @Test + fun addToEmptyTree() { + assertEquals(BSTNode(4, "qwerty"), baum.root()) + } + + @BeforeEach + fun setUp() { + baum.add(4, "qwerty") + baum.add(2, "Ge") + baum.add(5, "rma") + baum.add(-1, "ny") + baum.add(3, "the") + baum.add(40, "best") + baum.add(44, "Ja") + } + + @Test + fun checkWaysToNodes() { + val rt = baum.root() + assertEquals(BSTNode(5, "rma"), rt?.right) + assertEquals(BSTNode(3, "the"), rt?.left?.right) + assertEquals(BSTNode(-1, "ny"), rt?.left?.left) + assertEquals(BSTNode(44, "Ja"), rt?.right?.right?.right) + } + + @Test + fun checkAmountsOfNodes() { + assertEquals(7, baum.countNodes()) + assertEquals(BSTNode(10, "Was"), baum.add(10, "Was")) + assertEquals(8, baum.countNodes()) + } + + @Test + fun addPairs() { + baum.addPairs(Pair(1, "ein"), Pair(7, "sieben"), Pair(6, "sechs")) + + assertEquals(10, baum.countNodes()) + assertEquals(1, baum.root()?.left?.left?.right?.key) + assertEquals(6, baum.root()?.right?.right?.left?.left?.key) + } + + @Test + fun addAlreadyExistingNodes() { + assertNull(baum.add(5, "rma")) + assertNull(baum.add(3, "the")) + assertNull(baum.add(40, "best")) + assertNull(baum.add(44, "Ja")) + + assertEquals(7, baum.countNodes()) + } + + @Test + fun addingExistingNodeButWithDifferentValues() { + assertNull(baum.add(5, "Deutschland")) + assertNotEquals("Deutschland", baum.root()?.right?.value) + + assertNull(baum.add(-1, "Deutschland")) + assertNotEquals("Deutschland", baum.root()?.left?.left?.value) + + assertNull(baum.add(4, "Deutschland")) + assertNotEquals("Deutschland", baum.root()?.value) + } + + @Test + fun orderMatters() { + baum.clear() + assertTrue(baum.addPairs(Pair(4, "Vier"), Pair(5, "Funf"), Pair(40, "Vierzig"), Pair(44, "Vierundvierzig"))) + var rt = baum.root() + + assertEquals(5, rt?.right?.key) + assertEquals(44, rt?.right?.right?.right?.key) + + baum.clear() + baum.addPairs(Pair(4, "Vier"), Pair(44, "Vierundvierzig"), Pair(40, "Vierzig"), Pair(5, "Funf")) + rt = baum.root() + + assertEquals(5, rt?.right?.left?.left?.key) + assertEquals(44, rt?.right?.key) + //In other words, with different order we have different ways to nodes + } + } + + @Nested + inner class Remove { + @BeforeEach + fun setUp() { + for (key in listOf(10, 13, 12, 11, 20, 15, 25, -7, 5, -10, 9)) { + baum.add(key, "test") + } + } + + @Test + fun removeNodesWithNoKinder() { + val rt = baum.root() + + assertTrue(baum.removePairs(-10, 11)) + baum.remove(9) + + assertNull(rt?.left?.left) + assertNull(rt?.right?.left?.left) + assertNull(rt?.left?.right?.right) + } + + @Test + fun removeNodesWithEinKind() { + val rt = baum.root() + baum.removePairs(12) + baum.remove(5) + + assertEquals(9, rt?.left?.right?.key) + assertNull(rt?.left?.right?.right) + + assertEquals(11, rt?.right?.left?.key) + assertNull(rt?.right?.left?.left) + + baum.add(12, "test") + baum.remove(11) + assertEquals(BSTNode(12, "test"), rt?.right?.left) + + baum.remove(25) + baum.remove(20) + assertEquals(BSTNode(15, "test"), rt?.right?.right) + } + + @Test + fun removeNodeWithZweiKinderFirstCase() { + //I don't know how to describe any of these cases, just image current tree and I hope you'll get it + val rt = baum.root() + baum.remove(-7) + + assertEquals(5, rt?.left?.key) + assertEquals(-10, rt?.left?.left?.key) + assertEquals(9, rt?.left?.right?.key) + + assertNull(rt?.left?.right?.right) + } + + @Test + fun removeNodeWithZweiKinderSecondCase() { + val rt = baum.root() + assertEquals("test", baum.remove(13)) - assertEquals(15, rt?.right?.key) - assertEquals(12, rt?.right?.left?.key) - assertEquals(20, rt?.right?.right?.key) - assertEquals(25, rt?.right?.right?.right?.key) + assertEquals(15, rt?.right?.key) + assertEquals(12, rt?.right?.left?.key) + assertEquals(20, rt?.right?.right?.key) + assertEquals(25, rt?.right?.right?.right?.key) - assertNull(rt?.right?.right?.left) - } + assertNull(rt?.right?.right?.left) + } - @Test - fun removeNodeWithZweiKinderThirdCase() { - val rt = baum.root() + @Test + fun removeNodeWithZweiKinderThirdCase() { + val rt = baum.root() - baum.addPairs(Pair(16, "test")) - baum.remove(13) + baum.addPairs(Pair(16, "test")) + baum.remove(13) - assertEquals(16, rt?.right?.right?.left?.key) - } + assertEquals(16, rt?.right?.right?.left?.key) + } - @Test - fun removeNodeWithZweiKinderFourthCase() { - val rt = baum.root() - baum.changeVal(25, "Sieg") - baum.remove(20) + @Test + fun removeNodeWithZweiKinderFourthCase() { + val rt = baum.root() + baum.changeVal(25, "Sieg") + baum.remove(20) - assertNull(rt?.right?.right?.right) + assertNull(rt?.right?.right?.right) - assertEquals(BSTNode(25, "Sieg"), rt?.right?.right) - assertEquals(BSTNode(15,"test"), rt?.right?.right?.left) - } + assertEquals(BSTNode(25, "Sieg"), rt?.right?.right) + assertEquals(BSTNode(15, "test"), rt?.right?.right?.left) + } - @Test - fun removeNodeWithZweiKinderFifthCase() { - baum.clear() + @Test + fun removeNodeWithZweiKinderFifthCase() { + baum.clear() - baum.addPairs(Pair(-50, "Notf"), Pair(2, "Zwei"), Pair(101, "One hundred and One")) - for(key in listOf(-30, 99, 95, 90, 78, 56, 45, 34, 23, 14, 7, 3, 5, 8)){ - baum.add(key, "test") - } + baum.addPairs(Pair(-50, "Notf"), Pair(2, "Zwei"), Pair(101, "One hundred and One")) + for (key in listOf(-30, 99, 95, 90, 78, 56, 45, 34, 23, 14, 7, 3, 5, 8)) { + baum.add(key, "test") + } - val rt = baum.root() + val rt = baum.root() - baum.remove(2) - assertEquals(BSTNode(3, "test"), rt?.right) + baum.remove(2) + assertEquals(BSTNode(3, "test"), rt?.right) - baum.remove(3) - assertEquals(BSTNode(5, "test"), rt?.right) + baum.remove(3) + assertEquals(BSTNode(5, "test"), rt?.right) - val ls = listOf(99, 95, 90, 78, 56, 45, 34, 23, 14, 7, 8, 5).sorted() - for(i in 0..(ls.size-2) ){ - baum.remove(ls[i]) - assertEquals(BSTNode(ls[i + 1], "test"), rt?.right) - } + val ls = listOf(99, 95, 90, 78, 56, 45, 34, 23, 14, 7, 8, 5).sorted() + for (i in 0..(ls.size - 2)) { + baum.remove(ls[i]) + assertEquals(BSTNode(ls[i + 1], "test"), rt?.right) + } - assertNull(rt?.right?.right?.left) - } + assertNull(rt?.right?.right?.left) + } - @Test - fun removeNotExistingOderAlreadyRemovedNode() { - assertNull(baum.remove(62)) - assertNull(baum.remove(-24)) - assertFalse(baum.removePairs(-5,6,8,3)) + @Test + fun removeNotExistingOderAlreadyRemovedNode() { + assertNull(baum.remove(62)) + assertNull(baum.remove(-24)) + assertFalse(baum.removePairs(-5, 6, 8, 3)) - assertEquals(11, baum.countNodes()) + assertEquals(11, baum.countNodes()) - assertEquals("test", baum.remove(13)) - assertNull(baum.remove(13)) + assertEquals("test", baum.remove(13)) + assertNull(baum.remove(13)) - assertEquals(10, baum.countNodes()) - } + assertEquals(10, baum.countNodes()) + } - @Test - fun removeAndChangingAmountOfNode() { - val rt = baum.root() + @Test + fun removeAndChangingAmountOfNode() { + val rt = baum.root() - assertEquals(11, baum.countNodes()) + assertEquals(11, baum.countNodes()) - baum.remove(11) - assertEquals(10, baum.countNodes()) + baum.remove(11) + assertEquals(10, baum.countNodes()) - baum.remove(20) - assertEquals(9, baum.countNodes()) + baum.remove(20) + assertEquals(9, baum.countNodes()) - baum.remove(5) - assertEquals(8, baum.countNodes()) + baum.remove(5) + assertEquals(8, baum.countNodes()) - baum.remove(-7) - assertEquals(7, baum.countNodes()) - } + baum.remove(-7) + assertEquals(7, baum.countNodes()) + } - @Test - fun removeRootWithoutKinder() { - baum.clear() + @Test + fun removeRootWithoutKinder() { + baum.clear() - baum.add(4, "Heil") - baum.remove(4) + baum.add(4, "Heil") + baum.remove(4) - assertNull(baum.root()) - } + assertNull(baum.root()) + } - @Test - fun removeRootWithOnlyRightKinder() { - baum.clear() + @Test + fun removeRootWithOnlyRightKinder() { + baum.clear() - for(key in 0..10) baum.add(key, "test") + for (key in 0..10) baum.add(key, "test") - for(i in 0..9){ - baum.remove(i) - assertEquals(BSTNode(i + 1, "test"), baum.root()) - } + for (i in 0..9) { + baum.remove(i) + assertEquals(BSTNode(i + 1, "test"), baum.root()) + } - baum.remove(10) + baum.remove(10) - assertNull(baum.root()) - assertEquals(0, baum.countNodes()) - } + assertNull(baum.root()) + assertEquals(0, baum.countNodes()) + } - @Test - fun removeRootWithOnlyLeftKinder() { - baum.clear() + @Test + fun removeRootWithOnlyLeftKinder() { + baum.clear() - for(key in 0 downTo -10) baum.add(key, "test") + for (key in 0 downTo -10) baum.add(key, "test") - for(i in 0 downTo -9){ - baum.remove(i) - assertEquals(BSTNode(i-1, "test"), baum.root()) - assertEquals(10 + i, baum.countNodes()) - } + for (i in 0 downTo -9) { + baum.remove(i) + assertEquals(BSTNode(i - 1, "test"), baum.root()) + assertEquals(10 + i, baum.countNodes()) + } - baum.remove(-10) + baum.remove(-10) - assertNull(baum.root()) - assertEquals(0, baum.countNodes()) - } + assertNull(baum.root()) + assertEquals(0, baum.countNodes()) + } - @Test - fun removeRootWithTwoKinder() { - baum.remove(10) - assertEquals(BSTNode(11, "test"), baum.root()) + @Test + fun removeRootWithTwoKinder() { + baum.remove(10) + assertEquals(BSTNode(11, "test"), baum.root()) - baum.remove(11) - assertEquals(BSTNode(12, "test"), baum.root()) + baum.remove(11) + assertEquals(BSTNode(12, "test"), baum.root()) - baum.remove(12) - assertEquals(BSTNode(13, "test"), baum.root()) + baum.remove(12) + assertEquals(BSTNode(13, "test"), baum.root()) - baum.remove(13) - assertEquals(BSTNode(15, "test"), baum.root()) - } + baum.remove(13) + assertEquals(BSTNode(15, "test"), baum.root()) + } - @Test - fun howMuchDoWeNeedToDeleteTheWholeTreeByRemovingEachSingleNode() { - val len = 11 + @Test + fun howMuchDoWeNeedToDeleteTheWholeTreeByRemovingEachSingleNode() { + val len = 11 - for(i in 0..10){ - assertNotNull(baum.root()) - baum.remove(baum.root()?.key!!.toInt()) - } + for (i in 0..10) { + assertNotNull(baum.root()) + baum.remove(baum.root()?.key!!.toInt()) + } - assertNull(baum.root()) - assertEquals(0, baum.countNodes()) - } + assertNull(baum.root()) + assertEquals(0, baum.countNodes()) + } - } + } - @Nested - inner class SubTree() { - @BeforeEach - fun setUp() { - for(key in listOf(10, 13, 12, 11, 20, 15, 25, -7, 5, -10, 9)){ - baum.add(key, "test") - } - } + @Nested + inner class SubTree { + @BeforeEach + fun setUp() { + for (key in listOf(10, 13, 12, 11, 20, 15, 25, -7, 5, -10, 9)) { + baum.add(key, "test") + } + } - @Test - fun deleteTheWholeRightAndLeftSubtee() { + @Test + fun deleteTheWholeRightAndLeftSubtee() { - assertTrue(baum.deleteSubTree(13)) - assertNull(baum.root()?.right) + assertTrue(baum.deleteSubTree(13)) + assertNull(baum.root()?.right) - assertTrue(baum.deleteSubTree(-7)) - assertNull(baum.root()?.left) + assertTrue(baum.deleteSubTree(-7)) + assertNull(baum.root()?.left) - assertEquals(1, baum.countNodes()) - } + assertEquals(1, baum.countNodes()) + } - @Test - fun deleteRootSubTree() { - //You can't delete root in this way - assertFalse(baum.deleteSubTree(10)) + @Test + fun deleteRootSubTree() { + //You can't delete root in this way + assertFalse(baum.deleteSubTree(10)) - assertEquals(BSTNode(10, "test"), baum.root()) - assertEquals(11, baum.countNodes()) - } + assertEquals(BSTNode(10, "test"), baum.root()) + assertEquals(11, baum.countNodes()) + } - @Test - fun deleteSubTreeWithOnlyEinNode() { - val rt = baum.root() + @Test + fun deleteSubTreeWithOnlyEinNode() { + val rt = baum.root() - baum.deleteSubTree(-10) - assertEquals(BSTNode(-7, "test"), rt?.left) - assertNull(rt?.left?.left) + baum.deleteSubTree(-10) + assertEquals(BSTNode(-7, "test"), rt?.left) + assertNull(rt?.left?.left) - baum.deleteSubTree(25) - assertEquals(BSTNode(20, "test"), rt?.right?.right) - assertNull(rt?.right?.right?.right) + baum.deleteSubTree(25) + assertEquals(BSTNode(20, "test"), rt?.right?.right) + assertNull(rt?.right?.right?.right) - baum.deleteSubTree(11) - assertEquals(BSTNode(12, "test"), rt?.right?.left) - assertNull(rt?.right?.left?.left) - } + baum.deleteSubTree(11) + assertEquals(BSTNode(12, "test"), rt?.right?.left) + assertNull(rt?.right?.left?.left) + } - @Test - fun deleteNotExistingSubTree() { - assertFalse(baum.deleteSubTree(34)) - assertEquals(11, baum.countNodes()) - } + @Test + fun deleteNotExistingSubTree() { + assertFalse(baum.deleteSubTree(34)) + assertEquals(11, baum.countNodes()) + } - @Test - fun deleteSubTreeByAlreadyRemovedKey() { - baum.remove(-7) - assertFalse(baum.deleteSubTree(-7)) - assertEquals(10, baum.countNodes()) - } + @Test + fun deleteSubTreeByAlreadyRemovedKey() { + baum.remove(-7) + assertFalse(baum.deleteSubTree(-7)) + assertEquals(10, baum.countNodes()) + } - @Test - fun getSubTree() { - var neuBaum = baum.getSubTree(13) + @Test + fun getSubTree() { + var neuBaum = baum.getSubTree(13) - assertEquals(BSTNode(13,"test"), neuBaum?.root()) - assertEquals(6, neuBaum?.countNodes()) + assertEquals(BSTNode(13, "test"), neuBaum?.root()) + assertEquals(6, neuBaum?.countNodes()) - neuBaum = baum.getSubTree(-7) - - assertEquals(BSTNode(-7,"test"), neuBaum?.root()) - assertEquals(4, neuBaum?.countNodes()) + neuBaum = baum.getSubTree(-7) + + assertEquals(BSTNode(-7, "test"), neuBaum?.root()) + assertEquals(4, neuBaum?.countNodes()) - assertEquals(11, baum.countNodes()) - } + assertEquals(11, baum.countNodes()) + } - @Test - fun getRootSubTree() { - //You can't get SubTree where current tree's root is new root - assertNull(baum.getSubTree(10)) - } - - @Test - fun getSubTreeByNotExistingKey() { - assertNull(baum.getSubTree(23)) - assertNull(baum.getSubTree(-5)) - assertNull(baum.getSubTree(0)) - } - } + @Test + fun getRootSubTree() { + //You can't get SubTree where current tree's root is new root + assertNull(baum.getSubTree(10)) + } + + @Test + fun getSubTreeByNotExistingKey() { + assertNull(baum.getSubTree(23)) + assertNull(baum.getSubTree(-5)) + assertNull(baum.getSubTree(0)) + } + } } \ No newline at end of file diff --git a/src/test/kotlin/RBTreeTest.kt b/src/test/kotlin/RBTreeTest.kt index b136d3a..1e7590a 100644 --- a/src/test/kotlin/RBTreeTest.kt +++ b/src/test/kotlin/RBTreeTest.kt @@ -6,464 +6,472 @@ import treeLib.nodes.RBNode import kotlin.test.* class RBTreeTest { - var emptyTree = RBTree() + var emptyTree = RBTree() - @BeforeEach - fun emptyTree() { - emptyTree.clear() - } + @BeforeEach + fun emptyTree() { + emptyTree.clear() + } - @Nested - @DisplayName("Add method tests") + @Nested + @DisplayName("Add method tests") inner class AddMethod { - @Test - @DisplayName("Add node to the root") - fun addRoot() { - val root = emptyTree.add(1, 1974) - assertEquals(RBNode(1, 1974), root) - assertEquals(root, emptyTree.root) - } - - @Test - @DisplayName("Add node that already exist") - fun addExisted() { - emptyTree.add(1, 1974) - assertEquals(null, emptyTree.add(1, 9999)) - assertEquals(RBNode(1, 1974), emptyTree.root) - } - - @Test - @DisplayName("Add without uncle, right ver") - fun add1R() { - val root = emptyTree.add(0, 0)!! - val right = emptyTree.add(1, 1)!! - val right2 = emptyTree.add(2, 2)!! - assertEquals(root, emptyTree.root!!.left) - assertEquals(right, emptyTree.root) - assertEquals(right2, emptyTree.root!!.right) - assertTrue(root.isRed) - assertFalse(right.isRed) - assertTrue(right2.isRed) - } - - @Test - @DisplayName("Add without uncle, left ver") - fun add1L() { - val root = emptyTree.add(0, 0)!! - val left = emptyTree.add(-1, -1)!! - val left2 = emptyTree.add(-2, -2)!! - assertEquals(root, emptyTree.root!!.right) - assertEquals(left, emptyTree.root) - assertEquals(left2, emptyTree.root!!.left) - assertTrue(root.isRed) - assertFalse(left.isRed) - assertTrue(left2.isRed) - } - - - @Test - @DisplayName("Add with red uncle, right ver") - fun add2R() { - val root = emptyTree.add(0, 0)!! - val left = emptyTree.add(-1, -1)!! - val right = emptyTree.add(1, 1)!! - val right2 = emptyTree.add(2, 2)!! - assertEquals(root, emptyTree.root) - assertEquals(left, emptyTree.root!!.left) - assertEquals(right, emptyTree.root!!.right) - assertEquals(right2, emptyTree.root!!.right!!.right) - assertFalse(root.isRed) - assertFalse(left.isRed) - assertFalse(right.isRed) - assertTrue(right2.isRed) - } - - @Test - @DisplayName("Add with red uncle, left ver") - fun add2L() { - val root = emptyTree.add(0, 0)!! - val right = emptyTree.add(1, 1)!! - val left = emptyTree.add(-1, -1)!! - val left2 = emptyTree.add(-2, -2)!! - assertEquals(root, emptyTree.root) - assertEquals(right, emptyTree.root!!.right) - assertEquals(left, emptyTree.root!!.left) - assertEquals(left2, emptyTree.root!!.left!!.left) - assertFalse(root.isRed) - assertFalse(right.isRed) - assertFalse(left.isRed) - assertTrue(left2.isRed) - } - - @Test - @DisplayName("Add with black uncle, right ver") - fun add3R() { - val root = emptyTree.add(0, 0)!! - val left = emptyTree.add(-1, -1)!! - val right = emptyTree.add(1, 1)!! - val right2 = emptyTree.add(3, 3)!! - val right15 = emptyTree.add(2, 2)!! - assertEquals(root, emptyTree.root) - assertEquals(left, emptyTree.root!!.left) - assertEquals(right, emptyTree.root!!.right!!.left) - assertEquals(right2, emptyTree.root!!.right!!.right) - assertEquals(right15, emptyTree.root!!.right) - assertFalse(root.isRed) - assertFalse(left.isRed) - assertTrue(right.isRed) - assertFalse(right15.isRed) - assertTrue(right2.isRed) - } - - @Test - @DisplayName("Add with black uncle, left ver") - fun add3L() { - val root = emptyTree.add(0, 0)!! - val right = emptyTree.add(1, 1)!! - val left = emptyTree.add(-1, -1)!! - val left2 = emptyTree.add(-3, -3)!! - val left15 = emptyTree.add(-2, -2)!! - assertEquals(root, emptyTree.root) - assertEquals(right, emptyTree.root!!.right) - assertEquals(left, emptyTree.root!!.left!!.right) - assertEquals(left2, emptyTree.root!!.left!!.left) - assertEquals(left15, emptyTree.root!!.left) - assertFalse(root.isRed) - assertFalse(right.isRed) - assertTrue(left.isRed) - assertFalse(left15.isRed) - assertTrue(left2.isRed) - } - - @Test - @DisplayName("Add multiple nodes") - fun addMany() { - val nodesResult = MutableList(10) { emptyTree.add(it, it) } - assertEquals(5, emptyTree.height()) - for (keyValue in 10..19) - nodesResult.addLast(emptyTree.add(keyValue, keyValue)) - assertEquals(6, emptyTree.height()) - val colorResult = arrayListOf( - false, false, false, true, false, - false, false, false, false, false, - false, true, false, true, false, - false, false, true, false, true, - ) - for (node in emptyTree) { - assertEquals(nodesResult.removeFirst(), node) - assertEquals(colorResult.removeFirst(), node.isRed) - } - } - } - - @Nested - @DisplayName("Remove method tests") - inner class RemoveMethod { - var tree3Node = RBTree() - var bft15 = RBTree() - - @BeforeEach - fun initTree() { - tree3Node = RBTree() // 0 - tree3Node.add(0, 0) // / \ - tree3Node.add(10, 10) // -10 10 - tree3Node.add(-10, -10) - - bft15 = RBTree() //15 node tree (balanced) // 8 - var k = 16 // / \ - for (i in listOf(1, 2, 4, 8)) { // 4 12 - for (j in 0..() + var bft15 = RBTree() + + @BeforeEach + fun initTree() { + tree3Node = RBTree() // 0 + tree3Node.add(0, 0) // / \ + tree3Node.add(10, 10) // -10 10 + tree3Node.add(-10, -10) + + bft15 = RBTree() //15 node tree (balanced) // 8 + var k = 16 // / \ + for (i in listOf(1, 2, 4, 8)) { // 4 12 + for (j in 0.. Date: Thu, 4 Apr 2024 16:48:46 +0300 Subject: [PATCH 178/186] refactor: code format --- .github/workflows/format_check.yml | 8 +- .github/workflows/test.yml | 2 +- README.md | 48 +- build.gradle.kts | 34 +- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 310 +++--- src/main/kotlin/treeLib/bintrees/BSTree.kt | 256 ++--- src/main/kotlin/treeLib/bintrees/RBTree.kt | 401 ++++---- .../bintrees/interfaces/BalancedTree.kt | 30 +- .../treeLib/bintrees/interfaces/BinTree.kt | 160 +-- .../bintrees/interfaces/IterationOrder.kt | 2 +- .../bintrees/interfaces/TreeIterator.kt | 86 +- src/main/kotlin/treeLib/nodes/AVLNode.kt | 10 +- src/main/kotlin/treeLib/nodes/BSTNode.kt | 8 +- src/main/kotlin/treeLib/nodes/RBNode.kt | 10 +- src/main/kotlin/treeLib/nodes/TreeNode.kt | 54 +- src/test/kotlin/AVLTreeTest.kt | 418 ++++---- src/test/kotlin/BSTreeTest.kt | 716 +++++++------- src/test/kotlin/NodeTest.kt | 158 +-- src/test/kotlin/RBTreeTest.kt | 930 +++++++++--------- src/test/kotlin/TreeIteratorTest.kt | 136 +-- 20 files changed, 1883 insertions(+), 1894 deletions(-) diff --git a/.github/workflows/format_check.yml b/.github/workflows/format_check.yml index f9da449..fcc613e 100644 --- a/.github/workflows/format_check.yml +++ b/.github/workflows/format_check.yml @@ -1,10 +1,10 @@ name: Run detekt - static code analyzer on: - push: + push: jobs: - detekt: - runs-on: ubuntu-latest - steps: + detekt: + runs-on: ubuntu-latest + steps: - name: "checkout" uses: actions/checkout@v2 - name: "detekt" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index baa45ea..76034f9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,7 +2,7 @@ name: Test on: push: - + jobs: build: runs-on: ubuntu-latest diff --git a/README.md b/README.md index 7cc7e6e..3f2ae74 100644 --- a/README.md +++ b/README.md @@ -2,44 +2,50 @@ ## About Tree Lib -Tree Lib is the kotlin library for working with 3 different binary tree implementations: Binary Search Tree (BST), AVL-Tree (AVL) and Red-Black Tree (RB). +Tree Lib is the kotlin library for working with 3 different binary tree implementations: Binary Search Tree (BST), +AVL-Tree (AVL) and Red-Black Tree (RB). ## How to use + To init an object, you must provide key and value type. + ``` val treeExample: BSTree<, > ``` + for example + ``` val treeExample = BSTree() ``` All trees supports basic methods: + - Add values and keys as nodes to the tree: - + `treeExample.add(key: "abc", value: 1.0)` - + - Change node's value: - + `treeExample.changeVal(key: "abc", value: 37.7)` - + - Remove node from the tree: - + `treeExample.remove(key: "Choose wisely.")` - + - Find node by key: - + `treeExample.findByKey(key: "Anything you can compare!")` - + - Iterate in tree: - + `for (node in treeExample) { ...` - + - ...and much more! -With binary trees, Tree Lib provides a node type for each of them. -You can read node's key and value(with key() and value() methods), compare -them between each other(although they must share same type), convert them to +With binary trees, Tree Lib provides a node type for each of them. +You can read node's key and value(with key() and value() methods), compare +them between each other(although they must share same type), convert them to pair(toPair()) or string(toString()). ## License @@ -47,21 +53,25 @@ pair(toPair()) or string(toString()). Distributed under the MIT License. See `LICENSE.txt` for more information. ## Contact + This library was created by: -* Magomedov Islam (tg @JapEmpLove) - BST -* Damir Yunusov (tg @TopographicOcean) - RB -* Sofya Grishkova (tg @tea_jack) - AVL + +* Magomedov Islam (tg @JapEmpLove) - BST +* Damir Yunusov (tg @TopographicOcean) - RB +* Sofya Grishkova (tg @tea_jack) - AVL ## Acknowledgments [README Template](https://github.com/othneildrew/Best-README-Template) Links to Wikipages about binary trees: + * [Binary Tree](https://en.wikipedia.org/wiki/Binary_tree) * [Binary Search Tree](https://en.wikipedia.org/wiki/Binary_search_tree) * [Red-Black Tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) * [AVL-Tree](https://en.wikipedia.org/wiki/AVL_tree) - -[Here](https://www.geeksforgeeks.org/applications-advantages-and-disadvantages-of-binary-search-tree/) are provided applications, advantages and disadvantages of Binary Search Tree + +[Here](https://www.geeksforgeeks.org/applications-advantages-and-disadvantages-of-binary-search-tree/) are provided +applications, advantages and disadvantages of Binary Search Tree Good [Habr article](https://habr.com/ru/articles/150732/) about AVL-Trees diff --git a/build.gradle.kts b/build.gradle.kts index 9ffefea..b0eff4b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,39 +1,39 @@ plugins { - kotlin("jvm") version "1.9.23" - jacoco + kotlin("jvm") version "1.9.23" + jacoco } group = "org.example" version = "1.0-SNAPSHOT" repositories { - mavenCentral() + mavenCentral() } dependencies { - testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") - testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.2") + testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") + testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.2") } tasks.test { - useJUnitPlatform() - finalizedBy(tasks.jacocoTestReport) + useJUnitPlatform() + finalizedBy(tasks.jacocoTestReport) } tasks.jacocoTestReport { - dependsOn(tasks.test) - reports { - xml.required = true - csv.required = false - html.required = false - html.outputLocation = layout.buildDirectory.dir("jacoco") - } + dependsOn(tasks.test) + reports { + xml.required = true + csv.required = false + html.required = false + html.outputLocation = layout.buildDirectory.dir("jacoco") + } } kotlin { - jvmToolchain(21) + jvmToolchain(21) } jacoco { - toolVersion = "0.8.11" - reportsDirectory = layout.buildDirectory.dir("reports/jacoco") + toolVersion = "0.8.11" + reportsDirectory = layout.buildDirectory.dir("reports/jacoco") } diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index e4dcf73..494931e 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -5,170 +5,170 @@ import treeLib.bintrees.interfaces.BinTree import treeLib.nodes.AVLNode -class AVLTree, V> : BalancedTree>(){ - override var root: AVLNode? = null - override var amountOfNodes = 0 +class AVLTree, V> : BalancedTree>() { + override var root: AVLNode? = null + override var amountOfNodes = 0 - override fun remove(key: K): V? { - var value: V? = null - fun removeRec(node: AVLNode?, key: K): AVLNode? { - if (node == null) return null - if (key < node.key) { - node.left = removeRec(node.left, key) - } else if (key > node.key) { - node.right = removeRec(node.right, key) - } else { - val nodeA = node.left - val nodeB = node.right - value = node.value - if (nodeB == null) { - return nodeA - } - val min = findMin(nodeB) - min?.right = removeMin(nodeB) - min?.left = nodeA - if (root?.key == key) { - root = min - } - return balanceNode(min) - } - return balanceNode(node) - } - removeRec(root, key) - amountOfNodes -= 1 - return value - } + override fun remove(key: K): V? { + var value: V? = null + fun removeRec(node: AVLNode?, key: K): AVLNode? { + if (node == null) return null + if (key < node.key) { + node.left = removeRec(node.left, key) + } else if (key > node.key) { + node.right = removeRec(node.right, key) + } else { + val nodeA = node.left + val nodeB = node.right + value = node.value + if (nodeB == null) { + return nodeA + } + val min = findMin(nodeB) + min?.right = removeMin(nodeB) + min?.left = nodeA + if (root?.key == key) { + root = min + } + return balanceNode(min) + } + return balanceNode(node) + } + removeRec(root, key) + amountOfNodes -= 1 + return value + } - private fun findMin(node: AVLNode?): AVLNode? { - if (node?.left != null) { - return findMin(node.left) - } - return node - } + private fun findMin(node: AVLNode?): AVLNode? { + if (node?.left != null) { + return findMin(node.left) + } + return node + } - private fun removeMin(node: AVLNode?): AVLNode? { - if (node?.left == null) { - return node?.right - } - node.left = removeMin(node.left) - return balanceNode(node) - } + private fun removeMin(node: AVLNode?): AVLNode? { + if (node?.left == null) { + return node?.right + } + node.left = removeMin(node.left) + return balanceNode(node) + } - override fun add(key: K, value: V): AVLNode? { - fun addRec(node: AVLNode?, key: K, value: V): AVLNode? { - if (node == null) { - return AVLNode(key, value) - } - if (key < node.key) { - node.left = addRec(node.left, key, value) - } else if (key > node.key) { - node.right = addRec(node.right, key, value) - } - return balanceNode(node) - } - if (root == null) { - root = AVLNode(key, value) - amountOfNodes += 1 - return root - } - amountOfNodes += 1 - return addRec(root, key, value) - } + override fun add(key: K, value: V): AVLNode? { + fun addRec(node: AVLNode?, key: K, value: V): AVLNode? { + if (node == null) { + return AVLNode(key, value) + } + if (key < node.key) { + node.left = addRec(node.left, key, value) + } else if (key > node.key) { + node.right = addRec(node.right, key, value) + } + return balanceNode(node) + } + if (root == null) { + root = AVLNode(key, value) + amountOfNodes += 1 + return root + } + amountOfNodes += 1 + return addRec(root, key, value) + } - private fun rotateLeft(nodeA: AVLNode?): AVLNode? { - if (nodeA != null) { - if (nodeA.right != null) { - val nodeB = nodeA.right - nodeA.right = nodeB?.left - nodeB?.left = nodeA - fixHeight(nodeA) - fixHeight(nodeB) - return nodeB - } else { - throw NullPointerException("Right child node cannot be null.") - } - } else { - throw NullPointerException("Node cannot be null.") - } - } + private fun rotateLeft(nodeA: AVLNode?): AVLNode? { + if (nodeA != null) { + if (nodeA.right != null) { + val nodeB = nodeA.right + nodeA.right = nodeB?.left + nodeB?.left = nodeA + fixHeight(nodeA) + fixHeight(nodeB) + return nodeB + } else { + throw NullPointerException("Right child node cannot be null.") + } + } else { + throw NullPointerException("Node cannot be null.") + } + } - private fun rotateRight(nodeA: AVLNode?): AVLNode? { - if (nodeA != null) { - if (nodeA.left != null) { - val nodeB = nodeA.left - nodeA.left = nodeB?.right - nodeB?.right = nodeA - fixHeight(nodeA) - fixHeight(nodeB) - return nodeB - } else { - throw NullPointerException("Left child node cannot be null.") - } - } else { - throw NullPointerException("Node cannot be null.") - } - } + private fun rotateRight(nodeA: AVLNode?): AVLNode? { + if (nodeA != null) { + if (nodeA.left != null) { + val nodeB = nodeA.left + nodeA.left = nodeB?.right + nodeB?.right = nodeA + fixHeight(nodeA) + fixHeight(nodeB) + return nodeB + } else { + throw NullPointerException("Left child node cannot be null.") + } + } else { + throw NullPointerException("Node cannot be null.") + } + } - private fun height(node: AVLNode?): Int { - if (node == null) { - return 0 - } - return node.height - } + private fun height(node: AVLNode?): Int { + if (node == null) { + return 0 + } + return node.height + } - private fun balanceFactor(node: AVLNode?): Int { - if (node == null) { - throw NullPointerException("Node cannot be null.") - } - return height(node.right) - height(node.left) - } + private fun balanceFactor(node: AVLNode?): Int { + if (node == null) { + throw NullPointerException("Node cannot be null.") + } + return height(node.right) - height(node.left) + } - private fun fixHeight(node: AVLNode?) { - if (node != null) { - val heightLeft = height(node.left) - val heightRight = height(node.right) - if (heightLeft > heightRight) { - node.height = heightLeft + 1 - } else { - node.height = heightRight + 1 - } - } - } + private fun fixHeight(node: AVLNode?) { + if (node != null) { + val heightLeft = height(node.left) + val heightRight = height(node.right) + if (heightLeft > heightRight) { + node.height = heightLeft + 1 + } else { + node.height = heightRight + 1 + } + } + } - private fun balanceNode(node: AVLNode?): AVLNode? { - fixHeight(node) - if (balanceFactor(node) == 2) { - if (node != null) { - if (balanceFactor(node.right) < 0) { - node.right = rotateRight(node.right) - } - if (node == root) { - root = rotateLeft(node) - return root - } - return rotateLeft(node) - } - } - if (balanceFactor(node) == -2) { - if (node != null) { - if (balanceFactor(node.left) > 0) { - node.left = rotateLeft(node.left) - } - if (node == root) { - root = rotateRight(node) - return root - } - return rotateRight(node) - } - } - return node - } + private fun balanceNode(node: AVLNode?): AVLNode? { + fixHeight(node) + if (balanceFactor(node) == 2) { + if (node != null) { + if (balanceFactor(node.right) < 0) { + node.right = rotateRight(node.right) + } + if (node == root) { + root = rotateLeft(node) + return root + } + return rotateLeft(node) + } + } + if (balanceFactor(node) == -2) { + if (node != null) { + if (balanceFactor(node.left) > 0) { + node.left = rotateLeft(node.left) + } + if (node == root) { + root = rotateRight(node) + return root + } + return rotateRight(node) + } + } + return node + } - override fun height(): Int? { - return if (root == null) { - 0 - } else { - root?.height - } - } + override fun height(): Int? { + return if (root == null) { + 0 + } else { + root?.height + } + } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 017b928..74ed01f 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -4,142 +4,142 @@ import treeLib.bintrees.interfaces.BinTree import treeLib.nodes.BSTNode class BSTree, V> : BinTree>() { - override var root: BSTNode? = null - override var amountOfNodes = 0 + override var root: BSTNode? = null + override var amountOfNodes = 0 - fun addPairs(vararg pairs: Pair): Boolean { - for (pair in pairs) { - if (this.add(pair.first, pair.second) == null) return false - } - return true - } + fun addPairs(vararg pairs: Pair): Boolean { + for (pair in pairs) { + if (this.add(pair.first, pair.second) == null) return false + } + return true + } - fun removePairs(vararg keys: K): Boolean { - for (key in keys) { - if (this.remove(key) == null) return false - } - return true - } + fun removePairs(vararg keys: K): Boolean { + for (key in keys) { + if (this.remove(key) == null) return false + } + return true + } - override fun add(key: K, value: V): BSTNode? { - if (root == null) { - this.root = BSTNode(key, value) - this.amountOfNodes += 1 - return root - } - var curNode = this.root - while (curNode != null) { - if (key > curNode.key) { - if (curNode.right == null) { - curNode.right = BSTNode(key, value) - this.amountOfNodes += 1 - return curNode.right - } - curNode = curNode.right - } else if (key < curNode.key) { - if (curNode.left == null) { - curNode.left = BSTNode(key, value) - this.amountOfNodes += 1 - return curNode.left - } - curNode = curNode.left - } else break - } - return null - } + override fun add(key: K, value: V): BSTNode? { + if (root == null) { + this.root = BSTNode(key, value) + this.amountOfNodes += 1 + return root + } + var curNode = this.root + while (curNode != null) { + if (key > curNode.key) { + if (curNode.right == null) { + curNode.right = BSTNode(key, value) + this.amountOfNodes += 1 + return curNode.right + } + curNode = curNode.right + } else if (key < curNode.key) { + if (curNode.left == null) { + curNode.left = BSTNode(key, value) + this.amountOfNodes += 1 + return curNode.left + } + curNode = curNode.left + } else break + } + return null + } - override fun remove(key: K): V? { - var count = 0 - var curNode: BSTNode? = null - var parent = this.findParent(key) - if (this.root?.key == key) parent = BSTNode(root!!.key, root!!.value, root) - if (parent == null) return null - curNode = if (parent.right != null && parent.right?.key == key) parent.right - else parent.left - if (curNode?.right != null) count++ - if (curNode?.left != null) count++ - if (count == 0) { - if (parent.right === curNode) { - if (curNode == root) this.root = null - else parent.right = null - } else parent.left = null - } else if (count == 1) { - if (curNode?.left == null) { - if (parent.right == curNode) { - if (curNode == root) this.root = root?.right - else parent.right = curNode?.right - } else parent.left = curNode?.right - } else { - if (parent.right == curNode) { - if (curNode == root) this.root = this.root?.left - else parent.right = curNode.left - } else parent.left = curNode.left - } - } else { - var child = curNode?.right - var parent_child = curNode - while (child!!.left != null) { - if (child.left!!.left == null) parent_child = child - child = child.left - } - curNode?.key = child.key - curNode?.value = child.value - if (curNode?.right != child) parent_child!!.left = child.right - else curNode.right = child.right - } - this.amountOfNodes -= 1 - return curNode?.value - } + override fun remove(key: K): V? { + var count = 0 + var curNode: BSTNode? = null + var parent = this.findParent(key) + if (this.root?.key == key) parent = BSTNode(root!!.key, root!!.value, root) + if (parent == null) return null + curNode = if (parent.right != null && parent.right?.key == key) parent.right + else parent.left + if (curNode?.right != null) count++ + if (curNode?.left != null) count++ + if (count == 0) { + if (parent.right === curNode) { + if (curNode == root) this.root = null + else parent.right = null + } else parent.left = null + } else if (count == 1) { + if (curNode?.left == null) { + if (parent.right == curNode) { + if (curNode == root) this.root = root?.right + else parent.right = curNode?.right + } else parent.left = curNode?.right + } else { + if (parent.right == curNode) { + if (curNode == root) this.root = this.root?.left + else parent.right = curNode.left + } else parent.left = curNode.left + } + } else { + var child = curNode?.right + var parent_child = curNode + while (child!!.left != null) { + if (child.left!!.left == null) parent_child = child + child = child.left + } + curNode?.key = child.key + curNode?.value = child.value + if (curNode?.right != child) parent_child!!.left = child.right + else curNode.right = child.right + } + this.amountOfNodes -= 1 + return curNode?.value + } - internal fun findParent(key: K): BSTNode? { - var parent = this.root - if (parent == null || root!!.key == key) return null - while (parent?.right != null || parent?.left != null) { - if ((parent.right != null && parent.right?.key == key) || (parent.left != null && parent.left?.key == key)) return parent - else { - if (key > parent.key) { - if (parent.right == null) return null - parent = parent.right - } else { - if (parent.left == null) return null - parent = parent.left - } - } - } - return null - } + internal fun findParent(key: K): BSTNode? { + var parent = this.root + if (parent == null || root!!.key == key) return null + while (parent?.right != null || parent?.left != null) { + if (parent.right != null && parent.right?.key == key || parent.left != null && parent.left?.key == key) return parent + else { + if (key > parent.key) { + if (parent.right == null) return null + parent = parent.right + } else { + if (parent.left == null) return null + parent = parent.left + } + } + } + return null + } - fun deleteSubTree(key: K): Boolean { - val parent: BSTNode? = this.findParent(key) - if (parent == null) return false - if (parent.right != null && parent.right?.key == key) parent.right = null - else parent.left = null - var nodes = 0 - for (i in this) nodes++ - amountOfNodes = nodes - return true - } + fun deleteSubTree(key: K): Boolean { + val parent: BSTNode? = this.findParent(key) + if (parent == null) return false + if (parent.right != null && parent.right?.key == key) parent.right = null + else parent.left = null + var nodes = 0 + for (i in this) nodes++ + amountOfNodes = nodes + return true + } - fun getSubTree(key: K): BSTree? { - val parent: BSTNode? = this.findParent(key) - val childTree: BSTree = BSTree() - if (parent == null) return null - var child: BSTNode? = null - if (parent.right != null && parent.right?.key == key) { - child = childTree.add(key, parent.right!!.value) - child?.right = parent.right!!.right - child?.left = parent.right!!.left - } else { - child = childTree.add(key, parent.left!!.value) - child?.right = parent.left!!.right - child?.left = parent.left!!.left - } - var nodes = 0 - for (i in childTree) nodes++ - childTree.amountOfNodes = nodes - return childTree - } + fun getSubTree(key: K): BSTree? { + val parent: BSTNode? = this.findParent(key) + val childTree: BSTree = BSTree() + if (parent == null) return null + var child: BSTNode? = null + if (parent.right != null && parent.right?.key == key) { + child = childTree.add(key, parent.right!!.value) + child?.right = parent.right!!.right + child?.left = parent.right!!.left + } else { + child = childTree.add(key, parent.left!!.value) + child?.right = parent.left!!.right + child?.left = parent.left!!.left + } + var nodes = 0 + for (i in childTree) nodes++ + childTree.amountOfNodes = nodes + return childTree + } } diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index 0967ed6..0ebd71f 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -8,212 +8,197 @@ import treeLib.nodes.RBNode * Takes two types: for key(K) and for value(V) */ class RBTree, V> : BalancedTree>() { - override var root: RBNode? = null - override var amountOfNodes: Int = 0 - - /** - * Adds or replaces node to the tree depending on given key: - * 1. Adds node to the tree and returns node, - * 2. If node with given key already exist, it does nothing and returns null - * (to actually change value use changeVal) - */ - override fun add(key: K, value: V): RBNode? { - val treeBranch = ArrayDeque>() //to know who's the parent - val newNode = RBNode(key, value) - if (root == null) { - root = newNode - } else { - var curNode = root - while (curNode != null) { - treeBranch.addFirst(curNode) - val nextNode = curNode.moveOn(key) - if (nextNode == curNode) return null //node with given key already exist - curNode = nextNode - } - val parent = treeBranch.first() - parent.attach(newNode) - } - - amountOfNodes++ - treeBranch.addFirst(newNode) - balancedAdd(treeBranch) - - return newNode - } - - /** - * Used in add() method to balance tree :) - */ - private fun balancedAdd(treeBranch: ArrayDeque>) { - var son = treeBranch.removeFirst() - var parent = treeBranch.removeFirstOrNull() - var grandparent = treeBranch.removeFirstOrNull() - - while (parent != null && parent.isRed && grandparent != null) { - val uncle = if (parent == grandparent.right) grandparent.left else grandparent.right - - //uncle is red -> recolor nodes and go higher up the treeBranch - if (uncle?.isRed == true) { - parent.isRed = false - uncle.isRed = false - grandparent.isRed = true - son = grandparent - parent = treeBranch.removeFirstOrNull() - grandparent = treeBranch.removeFirstOrNull() - } else /*uncle is black or null -> do few rotations, recoloring and magic will happen*/ { - if (parent == grandparent.right) { - if (son == parent.left) { //we want co-directional parent and son - rotateRight(parent, grandparent) - parent = son - } - parent.isRed = false - grandparent.isRed = true - rotateLeft(grandparent, treeBranch.firstOrNull()) - } else /*parent == grandparent.left*/ { - if (son == parent.right) { //we want co-directional parent and son too - rotateLeft(parent, grandparent) - parent = son - } - parent.isRed = false - grandparent.isRed = true - rotateRight(grandparent, treeBranch.firstOrNull()) - } - } - } - - root?.isRed = false - } - - /** - * Removes node with the same key and returns node's value. - * Or does nothing and returns null if there's no such node. - */ - override fun remove(key: K): V? { - val treeBranch = ArrayDeque?>() //to know who's the parent - var curNode = root ?: return null - while (curNode.key != key) { - treeBranch.addFirst(curNode) - val nextNode = curNode.moveOn(key) ?: return null //nextNode == null => removing node doesn't exist - curNode = nextNode - } - - var parent = treeBranch.firstOrNull() - val sonRight = curNode.right - val sonLeft = curNode.left - val sonOfRemovedNode = when { - sonRight != null && sonLeft != null -> { - treeBranch.addFirst(curNode) - val copyTo = curNode //Will copy from curNode - curNode = sonLeft - while (curNode.right != null) { - treeBranch.addFirst(curNode) - curNode = curNode.right ?: throw NullPointerException("Removing node cannot be null.") - } - - parent = treeBranch.first() - val temp = copyTo.value - copyTo.key = curNode.key - copyTo.value = curNode.value - curNode.value = temp //to save deleted node's value - curNode.left - } - - sonRight != null -> sonRight - else /*sonLeft != null*/ -> sonLeft - } - - amountOfNodes-- - when (curNode) { //here we are "deleting" the node and replace it with his son - parent?.right -> parent.right = sonOfRemovedNode - parent?.left -> parent.left = sonOfRemovedNode - else -> root = sonOfRemovedNode //only root doesn't have parent - } - treeBranch.addFirst(sonOfRemovedNode) - //curNode.isRed -> no balancing needed - if (!curNode.isRed) balancedRemove(treeBranch) - - return curNode.value - } - - /** - * Used in remove() method to balance tree :( - */ - private fun balancedRemove(treeBranch: ArrayDeque?>) { - var son = treeBranch.removeFirstOrNull() - var parent = treeBranch.removeFirstOrNull() - var grandparent = treeBranch.removeFirstOrNull() - - //son == son of removed node - if (son?.isRed == true) { - son.isRed = false - return - } - while (parent != null) { - var brother = if (son == parent.right) parent.left else parent.right - //we want for brother to be black (´。_。`) - if (brother?.isRed == true) { - brother.isRed = false - parent.isRed = true - if (son == parent.right) { - rotateRight(parent, grandparent) - grandparent = brother - brother = parent.left - } else /*son == parent.left*/ { - rotateLeft(parent, grandparent) - grandparent = brother - brother = parent.right - } - } - brother ?: throw IllegalStateException( - "Balance of red-black tree violated:" + - " parent node have subtrees with black height 2 and black height 1" - ) - - //depending on nephew's colors, doing magic for balancing purposes - var nephewRight = brother.right - var nephewLeft = brother.left - if ((nephewRight == null || !nephewRight.isRed) && (nephewLeft == null || !nephewLeft.isRed)) { - brother.isRed = true - if (!parent.isRed) { //parent is black --> go higher up - son = parent //the treeBranch and balance again - parent = grandparent - grandparent = treeBranch.removeFirstOrNull() - } else { - parent.isRed = false - break - } - } else { - if (son == parent.right) { - if (nephewRight?.isRed == true && (nephewLeft == null || !nephewLeft.isRed)) { - rotateLeft(brother, parent) // B /nL == new brother - nephewLeft = brother // / \ -> /B == new left nephew - brother = nephewRight // nL nR /nR - brother.isRed = false - nephewLeft.isRed = true - } - - rotateRight(parent, grandparent) - brother.isRed = parent.isRed - parent.isRed = false - nephewLeft?.isRed = false - } else /*son == parent.left*/ { - if (nephewLeft?.isRed == true && (nephewRight == null || !nephewRight.isRed)) { - rotateRight(brother, parent) // B \nR == new brother - nephewRight = brother // / \ -> \B == new right nephew - brother = nephewLeft // nL nR \nL - brother.isRed = false - nephewRight.isRed = true - } - - rotateLeft(parent, grandparent) - brother.isRed = parent.isRed - parent.isRed = false - nephewRight?.isRed = false - } - break - } - } - - root?.isRed = false - } + override var root: RBNode? = null + override var amountOfNodes: Int = 0 + + /** + * Adds or replaces node to the tree depending on given key: + * 1. Adds node to the tree and returns node, + * 2. If node with given key already exist, it does nothing and returns null + * (to actually change value use changeVal) + */ + override fun add(key: K, value: V): RBNode? { + val treeBranch = ArrayDeque>() //to know who's the parent + val newNode = RBNode(key, value) + if (root == null) { + root = newNode + } else { + var curNode = root + while (curNode != null) { + treeBranch.addFirst(curNode) + val nextNode = curNode.moveOn(key) + if (nextNode == curNode) return null //node with given key already exist + curNode = nextNode + } + val parent = treeBranch.first() + parent.attach(newNode) + } + amountOfNodes++ + treeBranch.addFirst(newNode) + balancedAdd(treeBranch) + return newNode + } + + /** + * Used in add() method to balance tree :) + */ + private fun balancedAdd(treeBranch: ArrayDeque>) { + var son = treeBranch.removeFirst() + var parent = treeBranch.removeFirstOrNull() + var grandparent = treeBranch.removeFirstOrNull() + while (parent != null && parent.isRed && grandparent != null) { + val uncle = if (parent == grandparent.right) grandparent.left else grandparent.right + //uncle is red -> recolor nodes and go higher up the treeBranch + if (uncle?.isRed == true) { + parent.isRed = false + uncle.isRed = false + grandparent.isRed = true + son = grandparent + parent = treeBranch.removeFirstOrNull() + grandparent = treeBranch.removeFirstOrNull() + } else /*uncle is black or null -> do few rotations, recoloring and magic will happen*/ { + if (parent == grandparent.right) { + if (son == parent.left) { //we want co-directional parent and son + rotateRight(parent, grandparent) + parent = son + } + parent.isRed = false + grandparent.isRed = true + rotateLeft(grandparent, treeBranch.firstOrNull()) + } else /*parent == grandparent.left*/ { + if (son == parent.right) { //we want co-directional parent and son too + rotateLeft(parent, grandparent) + parent = son + } + parent.isRed = false + grandparent.isRed = true + rotateRight(grandparent, treeBranch.firstOrNull()) + } + } + } + root?.isRed = false + } + + /** + * Removes node with the same key and returns node's value. + * Or does nothing and returns null if there's no such node. + */ + override fun remove(key: K): V? { + val treeBranch = ArrayDeque?>() //to know who's the parent + var curNode = root ?: return null + while (curNode.key != key) { + treeBranch.addFirst(curNode) + val nextNode = curNode.moveOn(key) ?: return null //nextNode == null => removing node doesn't exist + curNode = nextNode + } + var parent = treeBranch.firstOrNull() + val sonRight = curNode.right + val sonLeft = curNode.left + val sonOfRemovedNode = when { + sonRight != null && sonLeft != null -> { + treeBranch.addFirst(curNode) + val copyTo = curNode //Will copy from curNode + curNode = sonLeft + while (curNode.right != null) { + treeBranch.addFirst(curNode) + curNode = curNode.right ?: throw NullPointerException("Removing node cannot be null.") + } + parent = treeBranch.first() + val temp = copyTo.value + copyTo.key = curNode.key + copyTo.value = curNode.value + curNode.value = temp //to save deleted node's value + curNode.left + } + sonRight != null -> sonRight + else /*sonLeft != null*/ -> sonLeft + } + amountOfNodes-- + when (curNode) { //here we are "deleting" the node and replace it with his son + parent?.right -> parent.right = sonOfRemovedNode + parent?.left -> parent.left = sonOfRemovedNode + else -> root = sonOfRemovedNode //only root doesn't have parent + } + treeBranch.addFirst(sonOfRemovedNode) + //curNode.isRed -> no balancing needed + if (!curNode.isRed) balancedRemove(treeBranch) + return curNode.value + } + + /** + * Used in remove() method to balance tree :( + */ + private fun balancedRemove(treeBranch: ArrayDeque?>) { + var son = treeBranch.removeFirstOrNull() + var parent = treeBranch.removeFirstOrNull() + var grandparent = treeBranch.removeFirstOrNull() + //son == son of removed node + if (son?.isRed == true) { + son.isRed = false + return + } + while (parent != null) { + var brother = if (son == parent.right) parent.left else parent.right + //we want for brother to be black (´。_。`) + if (brother?.isRed == true) { + brother.isRed = false + parent.isRed = true + if (son == parent.right) { + rotateRight(parent, grandparent) + grandparent = brother + brother = parent.left + } else /*son == parent.left*/ { + rotateLeft(parent, grandparent) + grandparent = brother + brother = parent.right + } + } + brother ?: throw IllegalStateException( + "Balance of red-black tree violated:" + + " parent node have subtrees with black height 2 and black height 1" + ) + //depending on nephew's colors, doing magic for balancing purposes + var nephewRight = brother.right + var nephewLeft = brother.left + if ((nephewRight == null || !nephewRight.isRed) && (nephewLeft == null || !nephewLeft.isRed)) { + brother.isRed = true + if (!parent.isRed) { //parent is black --> go higher up + son = parent //the treeBranch and balance again + parent = grandparent + grandparent = treeBranch.removeFirstOrNull() + } else { + parent.isRed = false + break + } + } else { + if (son == parent.right) { + if (nephewRight?.isRed == true && (nephewLeft == null || !nephewLeft.isRed)) { + rotateLeft(brother, parent) // B /nL == new brother + nephewLeft = brother // / \ -> /B == new left nephew + brother = nephewRight // nL nR /nR + brother.isRed = false + nephewLeft.isRed = true + } + rotateRight(parent, grandparent) + brother.isRed = parent.isRed + parent.isRed = false + nephewLeft?.isRed = false + } else /*son == parent.left*/ { + if (nephewLeft?.isRed == true && (nephewRight == null || !nephewRight.isRed)) { + rotateRight(brother, parent) // B \nR == new brother + nephewRight = brother // / \ -> \B == new right nephew + brother = nephewLeft // nL nR \nL + brother.isRed = false + nephewRight.isRed = true + } + rotateLeft(parent, grandparent) + brother.isRed = parent.isRed + parent.isRed = false + nephewRight?.isRed = false + } + break + } + } + root?.isRed = false + } } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BalancedTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BalancedTree.kt index 00bff08..09f594c 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BalancedTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BalancedTree.kt @@ -4,22 +4,22 @@ import treeLib.nodes.TreeNode abstract class BalancedTree, V, Node_T : TreeNode> : BinTree() { - //We must provide parent, because don't have link to it in node - protected fun rotateRight(node: Node_T?, parent: Node_T?) { - if (node == null) return - val nodeLeft = node.left - node.left = nodeLeft?.right - nodeLeft?.right = node + //We must provide parent, because don't have link to it in node + protected fun rotateRight(node: Node_T?, parent: Node_T?) { + if (node == null) return + val nodeLeft = node.left + node.left = nodeLeft?.right + nodeLeft?.right = node - if (parent != null) parent.attach(nodeLeft) else root = nodeLeft //root doesn't have parent - } + if (parent != null) parent.attach(nodeLeft) else root = nodeLeft //root doesn't have parent + } - protected fun rotateLeft(node: Node_T?, parent: Node_T?) { - if (node == null) return - val nodeRight = node.right - node.right = nodeRight?.left - nodeRight?.left = node + protected fun rotateLeft(node: Node_T?, parent: Node_T?) { + if (node == null) return + val nodeRight = node.right + node.right = nodeRight?.left + nodeRight?.left = node - if (parent != null) parent.attach(nodeRight) else root = nodeRight //root doesn't have parent - } + if (parent != null) parent.attach(nodeRight) else root = nodeRight //root doesn't have parent + } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 258b094..b280667 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -3,84 +3,84 @@ package treeLib.bintrees.interfaces import treeLib.nodes.TreeNode abstract class BinTree, V, Node_T : TreeNode> : Iterable { - protected abstract var root: Node_T? - protected abstract var amountOfNodes: Int - - abstract fun add(key: K, value: V): Node_T? - - abstract fun remove(key: K): V? - - fun findByKey(key: K): Node_T? { - var curNode = root - while (curNode != null) - curNode = when { - key > curNode.key -> curNode.right - key < curNode.key -> curNode.left - else -> return curNode - } - return null - } - - open fun changeVal(key: K, newValue: V): V? { - var curNode = root - while (curNode != null) - curNode = when { - key > curNode.key -> curNode.right - key < curNode.key -> curNode.left - else -> { - curNode.value = newValue - return newValue - } - } - return null - } - - fun max(): Node_T? { - var curNode = root - while (curNode?.right != null) - curNode = curNode.right - return curNode - } - - fun min(): Node_T? { - var curNode = root - while (curNode?.left != null) - curNode = curNode.left - return curNode - } - - open fun root(): Node_T? { - return root - } - - fun clear() { - root?.let { root = null } - amountOfNodes = 0 - } - - fun countNodes(): Int { - return amountOfNodes - } - - /** - * basic In-order iterator - */ - override fun iterator(): Iterator = TreeIterator(root, IterationOrder.IN_ORDER) - - fun preOrderIterator(): Iterator = TreeIterator(root, IterationOrder.PRE_ORDER) - - fun postOrderIterator(): Iterator = TreeIterator(root, IterationOrder.POST_ORDER) - - - private fun countHeight(tNode: Node_T?): Int { - if (tNode == null) return 0 - val leftChild = countHeight(tNode.left) - val rightChild = countHeight(tNode.right) - return kotlin.math.max(leftChild, rightChild) + 1 - } - - - open fun height(): Int? { - return countHeight(root) - } + protected abstract var root: Node_T? + protected abstract var amountOfNodes: Int + + abstract fun add(key: K, value: V): Node_T? + + abstract fun remove(key: K): V? + + fun findByKey(key: K): Node_T? { + var curNode = root + while (curNode != null) + curNode = when { + key > curNode.key -> curNode.right + key < curNode.key -> curNode.left + else -> return curNode + } + return null + } + + open fun changeVal(key: K, newValue: V): V? { + var curNode = root + while (curNode != null) + curNode = when { + key > curNode.key -> curNode.right + key < curNode.key -> curNode.left + else -> { + curNode.value = newValue + return newValue + } + } + return null + } + + fun max(): Node_T? { + var curNode = root + while (curNode?.right != null) + curNode = curNode.right + return curNode + } + + fun min(): Node_T? { + var curNode = root + while (curNode?.left != null) + curNode = curNode.left + return curNode + } + + open fun root(): Node_T? { + return root + } + + fun clear() { + root?.let { root = null } + amountOfNodes = 0 + } + + fun countNodes(): Int { + return amountOfNodes + } + + /** + * basic In-order iterator + */ + override fun iterator(): Iterator = TreeIterator(root, IterationOrder.IN_ORDER) + + fun preOrderIterator(): Iterator = TreeIterator(root, IterationOrder.PRE_ORDER) + + fun postOrderIterator(): Iterator = TreeIterator(root, IterationOrder.POST_ORDER) + + + private fun countHeight(tNode: Node_T?): Int { + if (tNode == null) return 0 + val leftChild = countHeight(tNode.left) + val rightChild = countHeight(tNode.right) + return kotlin.math.max(leftChild, rightChild) + 1 + } + + + open fun height(): Int? { + return countHeight(root) + } } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/IterationOrder.kt b/src/main/kotlin/treeLib/bintrees/interfaces/IterationOrder.kt index 7371dee..9d8b151 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/IterationOrder.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/IterationOrder.kt @@ -1,5 +1,5 @@ package treeLib.bintrees.interfaces enum class IterationOrder { - IN_ORDER, PRE_ORDER, POST_ORDER, + IN_ORDER, PRE_ORDER, POST_ORDER, } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt index 650424c..d602505 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt @@ -3,48 +3,48 @@ package treeLib.bintrees.interfaces import treeLib.nodes.TreeNode class TreeIterator, V, Node_T : TreeNode>( - private val root: Node_T?, - private val order: IterationOrder, + private val root: Node_T?, + private val order: IterationOrder, ) : Iterator { - private val stack: ArrayDeque = ArrayDeque() - - init { - root?.let { treeToStack(root) } - } - - private fun treeToStack(start: Node_T) { - when (order) { - IterationOrder.IN_ORDER -> inOrder(start) - IterationOrder.PRE_ORDER -> preOrder(start) - IterationOrder.POST_ORDER -> postOrder(start) - } - } - - private fun inOrder(curNode: Node_T) { - val leftNode = curNode.left - val rightNode = curNode.right - leftNode?.let { inOrder(leftNode) } - stack.add(curNode) - rightNode?.let { inOrder(rightNode) } - } - - private fun preOrder(curNode: Node_T) { - val leftNode = curNode.left - val rightNode = curNode.right - stack.add(curNode) - leftNode?.let { preOrder(leftNode) } - rightNode?.let { preOrder(rightNode) } - } - - private fun postOrder(curNode: Node_T) { - val leftNode = curNode.left - val rightNode = curNode.right - leftNode?.let { postOrder(leftNode) } - rightNode?.let { postOrder(rightNode) } - stack.add(curNode) - } - - override fun hasNext() = stack.isNotEmpty() - - override fun next() = stack.removeFirst() + private val stack: ArrayDeque = ArrayDeque() + + init { + root?.let { treeToStack(root) } + } + + private fun treeToStack(start: Node_T) { + when (order) { + IterationOrder.IN_ORDER -> inOrder(start) + IterationOrder.PRE_ORDER -> preOrder(start) + IterationOrder.POST_ORDER -> postOrder(start) + } + } + + private fun inOrder(curNode: Node_T) { + val leftNode = curNode.left + val rightNode = curNode.right + leftNode?.let { inOrder(leftNode) } + stack.add(curNode) + rightNode?.let { inOrder(rightNode) } + } + + private fun preOrder(curNode: Node_T) { + val leftNode = curNode.left + val rightNode = curNode.right + stack.add(curNode) + leftNode?.let { preOrder(leftNode) } + rightNode?.let { preOrder(rightNode) } + } + + private fun postOrder(curNode: Node_T) { + val leftNode = curNode.left + val rightNode = curNode.right + leftNode?.let { postOrder(leftNode) } + rightNode?.let { postOrder(rightNode) } + stack.add(curNode) + } + + override fun hasNext() = stack.isNotEmpty() + + override fun next() = stack.removeFirst() } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/nodes/AVLNode.kt b/src/main/kotlin/treeLib/nodes/AVLNode.kt index 2226ea8..edff837 100644 --- a/src/main/kotlin/treeLib/nodes/AVLNode.kt +++ b/src/main/kotlin/treeLib/nodes/AVLNode.kt @@ -1,10 +1,10 @@ package treeLib.nodes class AVLNode, V>( - key: K, - value: V, - right: AVLNode? = null, - left: AVLNode? = null + key: K, + value: V, + right: AVLNode? = null, + left: AVLNode? = null ) : TreeNode>(key, value, right, left) { - internal var height: Int = 1 + internal var height: Int = 1 } diff --git a/src/main/kotlin/treeLib/nodes/BSTNode.kt b/src/main/kotlin/treeLib/nodes/BSTNode.kt index c64e6a4..0313542 100644 --- a/src/main/kotlin/treeLib/nodes/BSTNode.kt +++ b/src/main/kotlin/treeLib/nodes/BSTNode.kt @@ -1,8 +1,8 @@ package treeLib.nodes class BSTNode, V>( - key: K, - value: V, - right: BSTNode? = null, - left: BSTNode? = null + key: K, + value: V, + right: BSTNode? = null, + left: BSTNode? = null ) : TreeNode>(key, value, right, left) diff --git a/src/main/kotlin/treeLib/nodes/RBNode.kt b/src/main/kotlin/treeLib/nodes/RBNode.kt index b4ff5ce..93c5360 100644 --- a/src/main/kotlin/treeLib/nodes/RBNode.kt +++ b/src/main/kotlin/treeLib/nodes/RBNode.kt @@ -1,9 +1,9 @@ package treeLib.nodes class RBNode, V>( - key: K, - value: V, - right: RBNode? = null, - left: RBNode? = null, - internal var isRed: Boolean = true, + key: K, + value: V, + right: RBNode? = null, + left: RBNode? = null, + internal var isRed: Boolean = true, ) : TreeNode>(key, value, right, left) \ No newline at end of file diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index 03f72a1..997a420 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -1,41 +1,41 @@ package treeLib.nodes abstract class TreeNode, V, Node_T : TreeNode>( - internal var key: K, - internal var value: V, - internal var right: Node_T? = null, - internal var left: Node_T? = null, + internal var key: K, + internal var value: V, + internal var right: Node_T? = null, + internal var left: Node_T? = null, ) : Comparable { - override fun compareTo(other: Node_T): Int = key.compareTo(other.key) + override fun compareTo(other: Node_T): Int = key.compareTo(other.key) - override fun hashCode(): Int = Pair(key, value).hashCode() + override fun hashCode(): Int = Pair(key, value).hashCode() - override fun equals(other: Any?): Boolean { - return (other as? Node_T != null) && (key == other.key) && (value == other.value) - } + override fun equals(other: Any?): Boolean { + return other as? Node_T != null && key == other.key && value == other.value + } - override fun toString(): String = Pair(key, value).toString() + override fun toString(): String = Pair(key, value).toString() - fun toPair(): Pair = Pair(key, value) + fun toPair(): Pair = Pair(key, value) - fun key(): K = key + fun key(): K = key - fun value(): V = value + fun value(): V = value - internal fun attach(node: Node_T?): Boolean { - if (node == null) return false - when { - this > node -> left = node - this < node -> right = node - else -> return false - } - return true - } + internal fun attach(node: Node_T?): Boolean { + if (node == null) return false + when { + this > node -> left = node + this < node -> right = node + else -> return false + } + return true + } - internal fun moveOn(otherKey: K): Node_T? = when { - key > otherKey -> left - key < otherKey -> right - else -> this as? Node_T - } + internal fun moveOn(otherKey: K): Node_T? = when { + key > otherKey -> left + key < otherKey -> right + else -> this as? Node_T + } } diff --git a/src/test/kotlin/AVLTreeTest.kt b/src/test/kotlin/AVLTreeTest.kt index 08453a4..c957045 100644 --- a/src/test/kotlin/AVLTreeTest.kt +++ b/src/test/kotlin/AVLTreeTest.kt @@ -8,213 +8,213 @@ import kotlin.math.abs class AVLTreeTest { - var tree = AVLTree() - - @Nested - inner class InsertionTests { - - @BeforeEach - fun setUp() { - tree.add(0, "a") - tree.add(1, "b") - tree.add(-1, "b") - } - - @Test - fun useAddOnEmptyTree() { - tree.clear() - tree.add(0, "a") - assertEquals(0, tree.root()?.key) - assertEquals("a", tree.root()?.value) - } - - @Test - fun addByKey() { - assertEquals(-1, tree.root()?.left?.key) - assertEquals("b", tree.root()?.left?.value) - assertEquals(1, tree.root()?.right?.key) - assertEquals("b", tree.root()?.right?.value) - } - - @Test - fun addDoesNothingIfKeyExists() { - assertEquals(null, tree.root()?.right?.right) - assertEquals(null, tree.root()?.right?.left) - } - } - - @Nested - inner class RemoveTests { - - @BeforeEach - fun setUp() { - for (i in 0..10) { - tree.add(i, "test") - } - } - - @Test - fun removeRoot() { - val key: Int? = tree.root()?.key - if (key != null) { - tree.remove(key) - assertNotNull(tree.root()) - for (i in 0..10) { - if (i == key) { - assertNull(tree.findByKey(key)) - } else { - assertNotNull(tree.findByKey(i)) - } - } - } else { - fail() - } - } - - @Test - fun removeNodeWithNoChildren() { - tree.remove(10) - assertNull(tree.findByKey(10)) - for (i in 0..9) { - assertNotNull(tree.findByKey(i)) - } - } - - @Test - fun removeNodeWithTwoChildren() { - tree.remove(7) - assertNull(tree.findByKey(7)) - for (i in 0..10) { - if (i != 7) { - assertNotNull(tree.findByKey(i)) - } - } - } - - @Test - fun removeNonExistentNode() { - assertNull(tree.remove(999)) - for (i in 0..10) { - assertNotNull(tree.findByKey(i)) - } - } - } - - @Nested - inner class BalanceTests { - private fun isBalanced(node: AVLNode?): Boolean { - fun height(node: AVLNode?): Int { - if (node == null) { - return 0 - } - return node.height - } - - fun balanceFactor(node: AVLNode?): Int { - if (node == null) { - throw NullPointerException("Node cannot be null.") - } - return height(node.right) - height(node.left) - } - - if (node == null) return true - - if (abs(balanceFactor(node)) <= 1 && isBalanced(node.left) && isBalanced(node.right)) { - return true - } - - return false - } - - @BeforeEach - fun setUpRandomTree() { - val ranLen = (2..100).random() - for (i in 1..ranLen) { - val ranItem = (1..10000).random() - tree.add(ranItem, "test") - } - } - - @Test - fun afterInsertAVLIsBalanced() { - assertTrue(isBalanced(tree.root())) - } - - @Test - fun afterRemoveAVLIsBalanced() { - tree.root()?.left?.let { tree.remove(it.key) } - assertTrue(isBalanced(tree.root())) - } - - @Test - fun afterRootRemoveAVLIsBalanced() { - val key: Int? = tree.root()?.key - if (key != null) { - tree.remove(key) - assertTrue(isBalanced(tree.root())) - } - } - } - - @Nested - inner class InterfaceMethods { - - @BeforeEach - fun setUp() { - for (i in 0..10) { - tree.add(i, "test") - } - } - - @Test - fun findReturnsTrueNode() { - val rightNode = tree.findByKey(7) - val leftNode = tree.findByKey(1) - assertEquals(tree.root()?.right, rightNode) - assertEquals(tree.root()?.left, leftNode) - assertNull(tree.findByKey(999)) - } - - @Test - fun changeValChangesVal() { - tree.changeVal(3, "tomato") - tree.changeVal(7, "banana") - tree.changeVal(1, "tea") - - assertEquals("tomato", tree.root()?.value) - assertEquals("banana", tree.root()?.right?.value) - assertEquals("tea", tree.root()?.left?.value) - assertNull(tree.changeVal(99999, "tea")) - } - - @Test - fun findMax() { - assertEquals(tree.findByKey(10), tree.max()) - tree.clear() - assertNull(tree.max()) - } - - @Test - fun findMin() { - assertEquals(tree.findByKey(0), tree.min()) - tree.clear() - assertNull(tree.min()) - } - - @Test - fun countNodes() { - assertEquals(11, tree.countNodes()) - tree.remove(7) - assertEquals(10, tree.countNodes()) - tree.clear() - assertEquals(0, tree.countNodes()) - } - - @Test - fun height() { - assertEquals(4, tree.height()) - tree.clear() - assertEquals(0, tree.height()) - } - } + var tree = AVLTree() + + @Nested + inner class InsertionTests { + + @BeforeEach + fun setUp() { + tree.add(0, "a") + tree.add(1, "b") + tree.add(-1, "b") + } + + @Test + fun useAddOnEmptyTree() { + tree.clear() + tree.add(0, "a") + assertEquals(0, tree.root()?.key) + assertEquals("a", tree.root()?.value) + } + + @Test + fun addByKey() { + assertEquals(-1, tree.root()?.left?.key) + assertEquals("b", tree.root()?.left?.value) + assertEquals(1, tree.root()?.right?.key) + assertEquals("b", tree.root()?.right?.value) + } + + @Test + fun addDoesNothingIfKeyExists() { + assertEquals(null, tree.root()?.right?.right) + assertEquals(null, tree.root()?.right?.left) + } + } + + @Nested + inner class RemoveTests { + + @BeforeEach + fun setUp() { + for (i in 0..10) { + tree.add(i, "test") + } + } + + @Test + fun removeRoot() { + val key: Int? = tree.root()?.key + if (key != null) { + tree.remove(key) + assertNotNull(tree.root()) + for (i in 0..10) { + if (i == key) { + assertNull(tree.findByKey(key)) + } else { + assertNotNull(tree.findByKey(i)) + } + } + } else { + fail() + } + } + + @Test + fun removeNodeWithNoChildren() { + tree.remove(10) + assertNull(tree.findByKey(10)) + for (i in 0..9) { + assertNotNull(tree.findByKey(i)) + } + } + + @Test + fun removeNodeWithTwoChildren() { + tree.remove(7) + assertNull(tree.findByKey(7)) + for (i in 0..10) { + if (i != 7) { + assertNotNull(tree.findByKey(i)) + } + } + } + + @Test + fun removeNonExistentNode() { + assertNull(tree.remove(999)) + for (i in 0..10) { + assertNotNull(tree.findByKey(i)) + } + } + } + + @Nested + inner class BalanceTests { + private fun isBalanced(node: AVLNode?): Boolean { + fun height(node: AVLNode?): Int { + if (node == null) { + return 0 + } + return node.height + } + + fun balanceFactor(node: AVLNode?): Int { + if (node == null) { + throw NullPointerException("Node cannot be null.") + } + return height(node.right) - height(node.left) + } + + if (node == null) return true + + if (abs(balanceFactor(node)) <= 1 && isBalanced(node.left) && isBalanced(node.right)) { + return true + } + + return false + } + + @BeforeEach + fun setUpRandomTree() { + val ranLen = (2..100).random() + for (i in 1..ranLen) { + val ranItem = (1..10000).random() + tree.add(ranItem, "test") + } + } + + @Test + fun afterInsertAVLIsBalanced() { + assertTrue(isBalanced(tree.root())) + } + + @Test + fun afterRemoveAVLIsBalanced() { + tree.root()?.left?.let { tree.remove(it.key) } + assertTrue(isBalanced(tree.root())) + } + + @Test + fun afterRootRemoveAVLIsBalanced() { + val key: Int? = tree.root()?.key + if (key != null) { + tree.remove(key) + assertTrue(isBalanced(tree.root())) + } + } + } + + @Nested + inner class InterfaceMethods { + + @BeforeEach + fun setUp() { + for (i in 0..10) { + tree.add(i, "test") + } + } + + @Test + fun findReturnsTrueNode() { + val rightNode = tree.findByKey(7) + val leftNode = tree.findByKey(1) + assertEquals(tree.root()?.right, rightNode) + assertEquals(tree.root()?.left, leftNode) + assertNull(tree.findByKey(999)) + } + + @Test + fun changeValChangesVal() { + tree.changeVal(3, "tomato") + tree.changeVal(7, "banana") + tree.changeVal(1, "tea") + + assertEquals("tomato", tree.root()?.value) + assertEquals("banana", tree.root()?.right?.value) + assertEquals("tea", tree.root()?.left?.value) + assertNull(tree.changeVal(99999, "tea")) + } + + @Test + fun findMax() { + assertEquals(tree.findByKey(10), tree.max()) + tree.clear() + assertNull(tree.max()) + } + + @Test + fun findMin() { + assertEquals(tree.findByKey(0), tree.min()) + tree.clear() + assertNull(tree.min()) + } + + @Test + fun countNodes() { + assertEquals(11, tree.countNodes()) + tree.remove(7) + assertEquals(10, tree.countNodes()) + tree.clear() + assertEquals(0, tree.countNodes()) + } + + @Test + fun height() { + assertEquals(4, tree.height()) + tree.clear() + assertEquals(0, tree.height()) + } + } } \ No newline at end of file diff --git a/src/test/kotlin/BSTreeTest.kt b/src/test/kotlin/BSTreeTest.kt index 7f18eab..a8260db 100644 --- a/src/test/kotlin/BSTreeTest.kt +++ b/src/test/kotlin/BSTreeTest.kt @@ -6,428 +6,428 @@ import treeLib.bintrees.BSTree import treeLib.nodes.BSTNode class BSTreeTest { - var baum = BSTree() - - @Test - fun findParent() { - baum.add(4, "qwerty") - baum.add(2, "Ge") - baum.add(5, "rma") - baum.add(-1, "ny") - baum.add(3, "the") - baum.add(40, "best") - baum.add(44, "Ja") - - assertEquals(BSTNode(5, "rma"), baum.findParent(40)) //Parent with ein Kind - - assertEquals(BSTNode(2, "Ge"), baum.findParent(3)) //Parent with zwei Kinder - - assertEquals(baum.root(), baum.findParent(5)) //When Parent - assertEquals(baum.root(), baum.findParent(2)) //is root - - assertNull(baum.findParent(4)) //Parent where child is root - - assertNull(baum.findParent(34)) //Finding No existing node's parent - } - - - @Nested - inner class TestingAddMethods { - - @Test - fun addToEmptyTree() { - assertEquals(BSTNode(4, "qwerty"), baum.root()) - } - - @BeforeEach - fun setUp() { - baum.add(4, "qwerty") - baum.add(2, "Ge") - baum.add(5, "rma") - baum.add(-1, "ny") - baum.add(3, "the") - baum.add(40, "best") - baum.add(44, "Ja") - } - - @Test - fun checkWaysToNodes() { - val rt = baum.root() - assertEquals(BSTNode(5, "rma"), rt?.right) - assertEquals(BSTNode(3, "the"), rt?.left?.right) - assertEquals(BSTNode(-1, "ny"), rt?.left?.left) - assertEquals(BSTNode(44, "Ja"), rt?.right?.right?.right) - } - - @Test - fun checkAmountsOfNodes() { - assertEquals(7, baum.countNodes()) - assertEquals(BSTNode(10, "Was"), baum.add(10, "Was")) - assertEquals(8, baum.countNodes()) - } - - @Test - fun addPairs() { - baum.addPairs(Pair(1, "ein"), Pair(7, "sieben"), Pair(6, "sechs")) - - assertEquals(10, baum.countNodes()) - assertEquals(1, baum.root()?.left?.left?.right?.key) - assertEquals(6, baum.root()?.right?.right?.left?.left?.key) - } - - @Test - fun addAlreadyExistingNodes() { - assertNull(baum.add(5, "rma")) - assertNull(baum.add(3, "the")) - assertNull(baum.add(40, "best")) - assertNull(baum.add(44, "Ja")) - - assertEquals(7, baum.countNodes()) - } - - @Test - fun addingExistingNodeButWithDifferentValues() { - assertNull(baum.add(5, "Deutschland")) - assertNotEquals("Deutschland", baum.root()?.right?.value) - - assertNull(baum.add(-1, "Deutschland")) - assertNotEquals("Deutschland", baum.root()?.left?.left?.value) - - assertNull(baum.add(4, "Deutschland")) - assertNotEquals("Deutschland", baum.root()?.value) - } - - @Test - fun orderMatters() { - baum.clear() - assertTrue(baum.addPairs(Pair(4, "Vier"), Pair(5, "Funf"), Pair(40, "Vierzig"), Pair(44, "Vierundvierzig"))) - var rt = baum.root() - - assertEquals(5, rt?.right?.key) - assertEquals(44, rt?.right?.right?.right?.key) - - baum.clear() - baum.addPairs(Pair(4, "Vier"), Pair(44, "Vierundvierzig"), Pair(40, "Vierzig"), Pair(5, "Funf")) - rt = baum.root() - - assertEquals(5, rt?.right?.left?.left?.key) - assertEquals(44, rt?.right?.key) - //In other words, with different order we have different ways to nodes - } - } - - @Nested - inner class Remove { - @BeforeEach - fun setUp() { - for (key in listOf(10, 13, 12, 11, 20, 15, 25, -7, 5, -10, 9)) { - baum.add(key, "test") - } - } - - @Test - fun removeNodesWithNoKinder() { - val rt = baum.root() - - assertTrue(baum.removePairs(-10, 11)) - baum.remove(9) - - assertNull(rt?.left?.left) - assertNull(rt?.right?.left?.left) - assertNull(rt?.left?.right?.right) - } - - @Test - fun removeNodesWithEinKind() { - val rt = baum.root() - baum.removePairs(12) - baum.remove(5) - - assertEquals(9, rt?.left?.right?.key) - assertNull(rt?.left?.right?.right) - - assertEquals(11, rt?.right?.left?.key) - assertNull(rt?.right?.left?.left) - - baum.add(12, "test") - baum.remove(11) - assertEquals(BSTNode(12, "test"), rt?.right?.left) - - baum.remove(25) - baum.remove(20) - assertEquals(BSTNode(15, "test"), rt?.right?.right) - } - - @Test - fun removeNodeWithZweiKinderFirstCase() { - //I don't know how to describe any of these cases, just image current tree and I hope you'll get it - val rt = baum.root() - baum.remove(-7) - - assertEquals(5, rt?.left?.key) - assertEquals(-10, rt?.left?.left?.key) - assertEquals(9, rt?.left?.right?.key) - - assertNull(rt?.left?.right?.right) - } - - @Test - fun removeNodeWithZweiKinderSecondCase() { - val rt = baum.root() - assertEquals("test", baum.remove(13)) + var baum = BSTree() + + @Test + fun findParent() { + baum.add(4, "qwerty") + baum.add(2, "Ge") + baum.add(5, "rma") + baum.add(-1, "ny") + baum.add(3, "the") + baum.add(40, "best") + baum.add(44, "Ja") + + assertEquals(BSTNode(5, "rma"), baum.findParent(40)) //Parent with ein Kind + + assertEquals(BSTNode(2, "Ge"), baum.findParent(3)) //Parent with zwei Kinder + + assertEquals(baum.root(), baum.findParent(5)) //When Parent + assertEquals(baum.root(), baum.findParent(2)) //is root + + assertNull(baum.findParent(4)) //Parent where child is root + + assertNull(baum.findParent(34)) //Finding No existing node's parent + } + + + @Nested + inner class TestingAddMethods { + + @Test + fun addToEmptyTree() { + assertEquals(BSTNode(4, "qwerty"), baum.root()) + } + + @BeforeEach + fun setUp() { + baum.add(4, "qwerty") + baum.add(2, "Ge") + baum.add(5, "rma") + baum.add(-1, "ny") + baum.add(3, "the") + baum.add(40, "best") + baum.add(44, "Ja") + } + + @Test + fun checkWaysToNodes() { + val rt = baum.root() + assertEquals(BSTNode(5, "rma"), rt?.right) + assertEquals(BSTNode(3, "the"), rt?.left?.right) + assertEquals(BSTNode(-1, "ny"), rt?.left?.left) + assertEquals(BSTNode(44, "Ja"), rt?.right?.right?.right) + } + + @Test + fun checkAmountsOfNodes() { + assertEquals(7, baum.countNodes()) + assertEquals(BSTNode(10, "Was"), baum.add(10, "Was")) + assertEquals(8, baum.countNodes()) + } + + @Test + fun addPairs() { + baum.addPairs(Pair(1, "ein"), Pair(7, "sieben"), Pair(6, "sechs")) + + assertEquals(10, baum.countNodes()) + assertEquals(1, baum.root()?.left?.left?.right?.key) + assertEquals(6, baum.root()?.right?.right?.left?.left?.key) + } + + @Test + fun addAlreadyExistingNodes() { + assertNull(baum.add(5, "rma")) + assertNull(baum.add(3, "the")) + assertNull(baum.add(40, "best")) + assertNull(baum.add(44, "Ja")) + + assertEquals(7, baum.countNodes()) + } + + @Test + fun addingExistingNodeButWithDifferentValues() { + assertNull(baum.add(5, "Deutschland")) + assertNotEquals("Deutschland", baum.root()?.right?.value) + + assertNull(baum.add(-1, "Deutschland")) + assertNotEquals("Deutschland", baum.root()?.left?.left?.value) + + assertNull(baum.add(4, "Deutschland")) + assertNotEquals("Deutschland", baum.root()?.value) + } + + @Test + fun orderMatters() { + baum.clear() + assertTrue(baum.addPairs(Pair(4, "Vier"), Pair(5, "Funf"), Pair(40, "Vierzig"), Pair(44, "Vierundvierzig"))) + var rt = baum.root() + + assertEquals(5, rt?.right?.key) + assertEquals(44, rt?.right?.right?.right?.key) + + baum.clear() + baum.addPairs(Pair(4, "Vier"), Pair(44, "Vierundvierzig"), Pair(40, "Vierzig"), Pair(5, "Funf")) + rt = baum.root() + + assertEquals(5, rt?.right?.left?.left?.key) + assertEquals(44, rt?.right?.key) + //In other words, with different order we have different ways to nodes + } + } + + @Nested + inner class Remove { + @BeforeEach + fun setUp() { + for (key in listOf(10, 13, 12, 11, 20, 15, 25, -7, 5, -10, 9)) { + baum.add(key, "test") + } + } + + @Test + fun removeNodesWithNoKinder() { + val rt = baum.root() + + assertTrue(baum.removePairs(-10, 11)) + baum.remove(9) + + assertNull(rt?.left?.left) + assertNull(rt?.right?.left?.left) + assertNull(rt?.left?.right?.right) + } + + @Test + fun removeNodesWithEinKind() { + val rt = baum.root() + baum.removePairs(12) + baum.remove(5) + + assertEquals(9, rt?.left?.right?.key) + assertNull(rt?.left?.right?.right) + + assertEquals(11, rt?.right?.left?.key) + assertNull(rt?.right?.left?.left) + + baum.add(12, "test") + baum.remove(11) + assertEquals(BSTNode(12, "test"), rt?.right?.left) + + baum.remove(25) + baum.remove(20) + assertEquals(BSTNode(15, "test"), rt?.right?.right) + } + + @Test + fun removeNodeWithZweiKinderFirstCase() { + //I don't know how to describe any of these cases, just image current tree and I hope you'll get it + val rt = baum.root() + baum.remove(-7) + + assertEquals(5, rt?.left?.key) + assertEquals(-10, rt?.left?.left?.key) + assertEquals(9, rt?.left?.right?.key) + + assertNull(rt?.left?.right?.right) + } + + @Test + fun removeNodeWithZweiKinderSecondCase() { + val rt = baum.root() + assertEquals("test", baum.remove(13)) - assertEquals(15, rt?.right?.key) - assertEquals(12, rt?.right?.left?.key) - assertEquals(20, rt?.right?.right?.key) - assertEquals(25, rt?.right?.right?.right?.key) + assertEquals(15, rt?.right?.key) + assertEquals(12, rt?.right?.left?.key) + assertEquals(20, rt?.right?.right?.key) + assertEquals(25, rt?.right?.right?.right?.key) - assertNull(rt?.right?.right?.left) - } + assertNull(rt?.right?.right?.left) + } - @Test - fun removeNodeWithZweiKinderThirdCase() { - val rt = baum.root() + @Test + fun removeNodeWithZweiKinderThirdCase() { + val rt = baum.root() - baum.addPairs(Pair(16, "test")) - baum.remove(13) + baum.addPairs(Pair(16, "test")) + baum.remove(13) - assertEquals(16, rt?.right?.right?.left?.key) - } + assertEquals(16, rt?.right?.right?.left?.key) + } - @Test - fun removeNodeWithZweiKinderFourthCase() { - val rt = baum.root() - baum.changeVal(25, "Sieg") - baum.remove(20) + @Test + fun removeNodeWithZweiKinderFourthCase() { + val rt = baum.root() + baum.changeVal(25, "Sieg") + baum.remove(20) - assertNull(rt?.right?.right?.right) + assertNull(rt?.right?.right?.right) - assertEquals(BSTNode(25, "Sieg"), rt?.right?.right) - assertEquals(BSTNode(15, "test"), rt?.right?.right?.left) - } + assertEquals(BSTNode(25, "Sieg"), rt?.right?.right) + assertEquals(BSTNode(15, "test"), rt?.right?.right?.left) + } - @Test - fun removeNodeWithZweiKinderFifthCase() { - baum.clear() + @Test + fun removeNodeWithZweiKinderFifthCase() { + baum.clear() - baum.addPairs(Pair(-50, "Notf"), Pair(2, "Zwei"), Pair(101, "One hundred and One")) - for (key in listOf(-30, 99, 95, 90, 78, 56, 45, 34, 23, 14, 7, 3, 5, 8)) { - baum.add(key, "test") - } + baum.addPairs(Pair(-50, "Notf"), Pair(2, "Zwei"), Pair(101, "One hundred and One")) + for (key in listOf(-30, 99, 95, 90, 78, 56, 45, 34, 23, 14, 7, 3, 5, 8)) { + baum.add(key, "test") + } - val rt = baum.root() + val rt = baum.root() - baum.remove(2) - assertEquals(BSTNode(3, "test"), rt?.right) + baum.remove(2) + assertEquals(BSTNode(3, "test"), rt?.right) - baum.remove(3) - assertEquals(BSTNode(5, "test"), rt?.right) + baum.remove(3) + assertEquals(BSTNode(5, "test"), rt?.right) - val ls = listOf(99, 95, 90, 78, 56, 45, 34, 23, 14, 7, 8, 5).sorted() - for (i in 0..(ls.size - 2)) { - baum.remove(ls[i]) - assertEquals(BSTNode(ls[i + 1], "test"), rt?.right) - } + val ls = listOf(99, 95, 90, 78, 56, 45, 34, 23, 14, 7, 8, 5).sorted() + for (i in 0..ls.size - 2) { + baum.remove(ls[i]) + assertEquals(BSTNode(ls[i + 1], "test"), rt?.right) + } - assertNull(rt?.right?.right?.left) - } + assertNull(rt?.right?.right?.left) + } - @Test - fun removeNotExistingOderAlreadyRemovedNode() { - assertNull(baum.remove(62)) - assertNull(baum.remove(-24)) - assertFalse(baum.removePairs(-5, 6, 8, 3)) + @Test + fun removeNotExistingOderAlreadyRemovedNode() { + assertNull(baum.remove(62)) + assertNull(baum.remove(-24)) + assertFalse(baum.removePairs(-5, 6, 8, 3)) - assertEquals(11, baum.countNodes()) + assertEquals(11, baum.countNodes()) - assertEquals("test", baum.remove(13)) - assertNull(baum.remove(13)) + assertEquals("test", baum.remove(13)) + assertNull(baum.remove(13)) - assertEquals(10, baum.countNodes()) - } + assertEquals(10, baum.countNodes()) + } - @Test - fun removeAndChangingAmountOfNode() { - val rt = baum.root() + @Test + fun removeAndChangingAmountOfNode() { + val rt = baum.root() - assertEquals(11, baum.countNodes()) + assertEquals(11, baum.countNodes()) - baum.remove(11) - assertEquals(10, baum.countNodes()) + baum.remove(11) + assertEquals(10, baum.countNodes()) - baum.remove(20) - assertEquals(9, baum.countNodes()) + baum.remove(20) + assertEquals(9, baum.countNodes()) - baum.remove(5) - assertEquals(8, baum.countNodes()) + baum.remove(5) + assertEquals(8, baum.countNodes()) - baum.remove(-7) - assertEquals(7, baum.countNodes()) - } + baum.remove(-7) + assertEquals(7, baum.countNodes()) + } - @Test - fun removeRootWithoutKinder() { - baum.clear() + @Test + fun removeRootWithoutKinder() { + baum.clear() - baum.add(4, "Heil") - baum.remove(4) + baum.add(4, "Heil") + baum.remove(4) - assertNull(baum.root()) - } + assertNull(baum.root()) + } - @Test - fun removeRootWithOnlyRightKinder() { - baum.clear() + @Test + fun removeRootWithOnlyRightKinder() { + baum.clear() - for (key in 0..10) baum.add(key, "test") + for (key in 0..10) baum.add(key, "test") - for (i in 0..9) { - baum.remove(i) - assertEquals(BSTNode(i + 1, "test"), baum.root()) - } + for (i in 0..9) { + baum.remove(i) + assertEquals(BSTNode(i + 1, "test"), baum.root()) + } - baum.remove(10) + baum.remove(10) - assertNull(baum.root()) - assertEquals(0, baum.countNodes()) - } + assertNull(baum.root()) + assertEquals(0, baum.countNodes()) + } - @Test - fun removeRootWithOnlyLeftKinder() { - baum.clear() + @Test + fun removeRootWithOnlyLeftKinder() { + baum.clear() - for (key in 0 downTo -10) baum.add(key, "test") + for (key in 0 downTo -10) baum.add(key, "test") - for (i in 0 downTo -9) { - baum.remove(i) - assertEquals(BSTNode(i - 1, "test"), baum.root()) - assertEquals(10 + i, baum.countNodes()) - } + for (i in 0 downTo -9) { + baum.remove(i) + assertEquals(BSTNode(i - 1, "test"), baum.root()) + assertEquals(10 + i, baum.countNodes()) + } - baum.remove(-10) + baum.remove(-10) - assertNull(baum.root()) - assertEquals(0, baum.countNodes()) - } + assertNull(baum.root()) + assertEquals(0, baum.countNodes()) + } - @Test - fun removeRootWithTwoKinder() { - baum.remove(10) - assertEquals(BSTNode(11, "test"), baum.root()) + @Test + fun removeRootWithTwoKinder() { + baum.remove(10) + assertEquals(BSTNode(11, "test"), baum.root()) - baum.remove(11) - assertEquals(BSTNode(12, "test"), baum.root()) + baum.remove(11) + assertEquals(BSTNode(12, "test"), baum.root()) - baum.remove(12) - assertEquals(BSTNode(13, "test"), baum.root()) + baum.remove(12) + assertEquals(BSTNode(13, "test"), baum.root()) - baum.remove(13) - assertEquals(BSTNode(15, "test"), baum.root()) - } + baum.remove(13) + assertEquals(BSTNode(15, "test"), baum.root()) + } - @Test - fun howMuchDoWeNeedToDeleteTheWholeTreeByRemovingEachSingleNode() { - val len = 11 + @Test + fun howMuchDoWeNeedToDeleteTheWholeTreeByRemovingEachSingleNode() { + val len = 11 - for (i in 0..10) { - assertNotNull(baum.root()) - baum.remove(baum.root()?.key!!.toInt()) - } + for (i in 0..10) { + assertNotNull(baum.root()) + baum.remove(baum.root()?.key!!.toInt()) + } - assertNull(baum.root()) - assertEquals(0, baum.countNodes()) - } + assertNull(baum.root()) + assertEquals(0, baum.countNodes()) + } - } + } - @Nested - inner class SubTree { - @BeforeEach - fun setUp() { - for (key in listOf(10, 13, 12, 11, 20, 15, 25, -7, 5, -10, 9)) { - baum.add(key, "test") - } - } + @Nested + inner class SubTree { + @BeforeEach + fun setUp() { + for (key in listOf(10, 13, 12, 11, 20, 15, 25, -7, 5, -10, 9)) { + baum.add(key, "test") + } + } - @Test - fun deleteTheWholeRightAndLeftSubtee() { + @Test + fun deleteTheWholeRightAndLeftSubtee() { - assertTrue(baum.deleteSubTree(13)) - assertNull(baum.root()?.right) + assertTrue(baum.deleteSubTree(13)) + assertNull(baum.root()?.right) - assertTrue(baum.deleteSubTree(-7)) - assertNull(baum.root()?.left) + assertTrue(baum.deleteSubTree(-7)) + assertNull(baum.root()?.left) - assertEquals(1, baum.countNodes()) - } + assertEquals(1, baum.countNodes()) + } - @Test - fun deleteRootSubTree() { - //You can't delete root in this way - assertFalse(baum.deleteSubTree(10)) + @Test + fun deleteRootSubTree() { + //You can't delete root in this way + assertFalse(baum.deleteSubTree(10)) - assertEquals(BSTNode(10, "test"), baum.root()) - assertEquals(11, baum.countNodes()) - } + assertEquals(BSTNode(10, "test"), baum.root()) + assertEquals(11, baum.countNodes()) + } - @Test - fun deleteSubTreeWithOnlyEinNode() { - val rt = baum.root() + @Test + fun deleteSubTreeWithOnlyEinNode() { + val rt = baum.root() - baum.deleteSubTree(-10) - assertEquals(BSTNode(-7, "test"), rt?.left) - assertNull(rt?.left?.left) + baum.deleteSubTree(-10) + assertEquals(BSTNode(-7, "test"), rt?.left) + assertNull(rt?.left?.left) - baum.deleteSubTree(25) - assertEquals(BSTNode(20, "test"), rt?.right?.right) - assertNull(rt?.right?.right?.right) + baum.deleteSubTree(25) + assertEquals(BSTNode(20, "test"), rt?.right?.right) + assertNull(rt?.right?.right?.right) - baum.deleteSubTree(11) - assertEquals(BSTNode(12, "test"), rt?.right?.left) - assertNull(rt?.right?.left?.left) - } + baum.deleteSubTree(11) + assertEquals(BSTNode(12, "test"), rt?.right?.left) + assertNull(rt?.right?.left?.left) + } - @Test - fun deleteNotExistingSubTree() { - assertFalse(baum.deleteSubTree(34)) - assertEquals(11, baum.countNodes()) - } + @Test + fun deleteNotExistingSubTree() { + assertFalse(baum.deleteSubTree(34)) + assertEquals(11, baum.countNodes()) + } - @Test - fun deleteSubTreeByAlreadyRemovedKey() { - baum.remove(-7) - assertFalse(baum.deleteSubTree(-7)) - assertEquals(10, baum.countNodes()) - } + @Test + fun deleteSubTreeByAlreadyRemovedKey() { + baum.remove(-7) + assertFalse(baum.deleteSubTree(-7)) + assertEquals(10, baum.countNodes()) + } - @Test - fun getSubTree() { - var neuBaum = baum.getSubTree(13) + @Test + fun getSubTree() { + var neuBaum = baum.getSubTree(13) - assertEquals(BSTNode(13, "test"), neuBaum?.root()) - assertEquals(6, neuBaum?.countNodes()) + assertEquals(BSTNode(13, "test"), neuBaum?.root()) + assertEquals(6, neuBaum?.countNodes()) - neuBaum = baum.getSubTree(-7) - - assertEquals(BSTNode(-7, "test"), neuBaum?.root()) - assertEquals(4, neuBaum?.countNodes()) + neuBaum = baum.getSubTree(-7) + + assertEquals(BSTNode(-7, "test"), neuBaum?.root()) + assertEquals(4, neuBaum?.countNodes()) - assertEquals(11, baum.countNodes()) - } + assertEquals(11, baum.countNodes()) + } - @Test - fun getRootSubTree() { - //You can't get SubTree where current tree's root is new root - assertNull(baum.getSubTree(10)) - } - - @Test - fun getSubTreeByNotExistingKey() { - assertNull(baum.getSubTree(23)) - assertNull(baum.getSubTree(-5)) - assertNull(baum.getSubTree(0)) - } - } + @Test + fun getRootSubTree() { + //You can't get SubTree where current tree's root is new root + assertNull(baum.getSubTree(10)) + } + + @Test + fun getSubTreeByNotExistingKey() { + assertNull(baum.getSubTree(23)) + assertNull(baum.getSubTree(-5)) + assertNull(baum.getSubTree(0)) + } + } } \ No newline at end of file diff --git a/src/test/kotlin/NodeTest.kt b/src/test/kotlin/NodeTest.kt index 60aa055..7881ed1 100644 --- a/src/test/kotlin/NodeTest.kt +++ b/src/test/kotlin/NodeTest.kt @@ -5,97 +5,97 @@ import treeLib.nodes.BSTNode import kotlin.test.* class NodeTest { - var node01 = BSTNode(1, 123) - var node02 = BSTNode(2, 321, right = node01) - var node2L = BSTNode(2, 321, left = node02) - var node03 = BSTNode(3, "node02 и node2L отличаются лишь ссылками") + var node01 = BSTNode(1, 123) + var node02 = BSTNode(2, 321, right = node01) + var node2L = BSTNode(2, 321, left = node02) + var node03 = BSTNode(3, "node02 и node2L отличаются лишь ссылками") - @BeforeEach - fun init() { - node01 = BSTNode(1, 123) - node02 = BSTNode(2, 321) - node03 = BSTNode(3, "waiting for something to happen?") - } + @BeforeEach + fun init() { + node01 = BSTNode(1, 123) + node02 = BSTNode(2, 321) + node03 = BSTNode(3, "waiting for something to happen?") + } - @Nested - inner class PublicNodeMethods { - @Test - @DisplayName("Compare to ==") - fun compare0() { - assertEquals(0, node02.compareTo(node2L)) - } + @Nested + inner class PublicNodeMethods { + @Test + @DisplayName("Compare to ==") + fun compare0() { + assertEquals(0, node02.compareTo(node2L)) + } - @Test - @DisplayName("Compare to >") - fun compare1() { - assertTrue(node02.compareTo(node01) > 0) - } + @Test + @DisplayName("Compare to >") + fun compare1() { + assertTrue(node02.compareTo(node01) > 0) + } - @Test - @DisplayName("Compare to <") - fun compare2() { - assertTrue(node01.compareTo(node2L) < 0) - } + @Test + @DisplayName("Compare to <") + fun compare2() { + assertTrue(node01.compareTo(node2L) < 0) + } - @Test - @DisplayName("Hash code on one node twice") - fun hashCode1() { - assertEquals(node03.hashCode(), node03.hashCode()) - } + @Test + @DisplayName("Hash code on one node twice") + fun hashCode1() { + assertEquals(node03.hashCode(), node03.hashCode()) + } - @Test - @DisplayName("Hash code on two equal nodes") - fun hashCode2() { - assertEquals(node02.hashCode(), node2L.hashCode()) - } + @Test + @DisplayName("Hash code on two equal nodes") + fun hashCode2() { + assertEquals(node02.hashCode(), node2L.hashCode()) + } - @Test - @DisplayName("Hash code on two different nodes") - fun hashCode3() { - assertNotEquals(node01.hashCode(), node02.hashCode()) - } + @Test + @DisplayName("Hash code on two different nodes") + fun hashCode3() { + assertNotEquals(node01.hashCode(), node02.hashCode()) + } - @Test - @DisplayName("Equals is true on one node") - fun equals1() { - assertTrue(node03.equals(node03)) - } + @Test + @DisplayName("Equals is true on one node") + fun equals1() { + assertTrue(node03.equals(node03)) + } - @Test - @DisplayName("Equals is true if node's key and value are equals") - fun equals2() { - assertTrue(node2L.equals(node02) and node02.equals(node2L)) - } + @Test + @DisplayName("Equals is true if node's key and value are equals") + fun equals2() { + assertTrue(node2L.equals(node02) and node02.equals(node2L)) + } - @Test - @DisplayName("Equals is not equal to null") - fun equals3() { - assertFalse(node03.equals(null)) - } + @Test + @DisplayName("Equals is not equal to null") + fun equals3() { + assertFalse(node03.equals(null)) + } - @Test - @DisplayName("Equals is false if nodes are different") - fun equals4() { - assertFalse(node01.equals(node02)) - } + @Test + @DisplayName("Equals is false if nodes are different") + fun equals4() { + assertFalse(node01.equals(node02)) + } - @Test - @DisplayName("To string") - fun toString1() { - assertEquals(node01.toString(), "(1, 123)") - } + @Test + @DisplayName("To string") + fun toString1() { + assertEquals(node01.toString(), "(1, 123)") + } - @Test - @DisplayName("To pair") - fun toPair1() { - assertEquals(node01.toPair(), Pair(1, 123)) - } + @Test + @DisplayName("To pair") + fun toPair1() { + assertEquals(node01.toPair(), Pair(1, 123)) + } - @Test - @DisplayName("I mean we I believe that key() and value() works correctly, whatever") - fun keyValue() { - assertEquals(node03.key(), 3) - assertEquals(node03.value(), "waiting for something to happen?") - } - } + @Test + @DisplayName("I mean we I believe that key() and value() works correctly, whatever") + fun keyValue() { + assertEquals(node03.key(), 3) + assertEquals(node03.value(), "waiting for something to happen?") + } + } } diff --git a/src/test/kotlin/RBTreeTest.kt b/src/test/kotlin/RBTreeTest.kt index 1e7590a..6b20567 100644 --- a/src/test/kotlin/RBTreeTest.kt +++ b/src/test/kotlin/RBTreeTest.kt @@ -6,472 +6,466 @@ import treeLib.nodes.RBNode import kotlin.test.* class RBTreeTest { - var emptyTree = RBTree() - - @BeforeEach - fun emptyTree() { - emptyTree.clear() - } - - @Nested - @DisplayName("Add method tests") - inner class AddMethod { - @Test - @DisplayName("Add node to the root") - fun addRoot() { - val root = emptyTree.add(1, 1974) - assertEquals(RBNode(1, 1974), root) - assertEquals(root, emptyTree.root()) - } - - @Test - @DisplayName("Add node that already exist") - fun addExisted() { - emptyTree.add(1, 1974) - assertEquals(null, emptyTree.add(1, 9999)) - assertEquals(RBNode(1, 1974), emptyTree.root()) - } - - @Test - @DisplayName("Add without uncle, right ver") - fun add1R() { - val root = emptyTree.add(0, 0)!! - val right = emptyTree.add(1, 1)!! - val right2 = emptyTree.add(2, 2)!! - assertEquals(root, emptyTree.root()!!.left) - assertEquals(right, emptyTree.root()) - assertEquals(right2, emptyTree.root()!!.right) - assertTrue(root.isRed) - assertFalse(right.isRed) - assertTrue(right2.isRed) - } - - @Test - @DisplayName("Add without uncle, left ver") - fun add1L() { - val root = emptyTree.add(0, 0)!! - val left = emptyTree.add(-1, -1)!! - val left2 = emptyTree.add(-2, -2)!! - assertEquals(root, emptyTree.root()!!.right) - assertEquals(left, emptyTree.root()) - assertEquals(left2, emptyTree.root()!!.left) - assertTrue(root.isRed) - assertFalse(left.isRed) - assertTrue(left2.isRed) - } - - - @Test - @DisplayName("Add with red uncle, right ver") - fun add2R() { - val root = emptyTree.add(0, 0)!! - val left = emptyTree.add(-1, -1)!! - val right = emptyTree.add(1, 1)!! - val right2 = emptyTree.add(2, 2)!! - assertEquals(root, emptyTree.root()) - assertEquals(left, emptyTree.root()!!.left) - assertEquals(right, emptyTree.root()!!.right) - assertEquals(right2, emptyTree.root()!!.right!!.right) - assertFalse(root.isRed) - assertFalse(left.isRed) - assertFalse(right.isRed) - assertTrue(right2.isRed) - } - - @Test - @DisplayName("Add with red uncle, left ver") - fun add2L() { - val root = emptyTree.add(0, 0)!! - val right = emptyTree.add(1, 1)!! - val left = emptyTree.add(-1, -1)!! - val left2 = emptyTree.add(-2, -2)!! - assertEquals(root, emptyTree.root()) - assertEquals(right, emptyTree.root()!!.right) - assertEquals(left, emptyTree.root()!!.left) - assertEquals(left2, emptyTree.root()!!.left!!.left) - assertFalse(root.isRed) - assertFalse(right.isRed) - assertFalse(left.isRed) - assertTrue(left2.isRed) - } - - @Test - @DisplayName("Add with black uncle, right ver") - fun add3R() { - val root = emptyTree.add(0, 0)!! - val left = emptyTree.add(-1, -1)!! - val right = emptyTree.add(1, 1)!! - val right2 = emptyTree.add(3, 3)!! - val right15 = emptyTree.add(2, 2)!! - assertEquals(root, emptyTree.root()) - assertEquals(left, emptyTree.root()!!.left) - assertEquals(right, emptyTree.root()!!.right!!.left) - assertEquals(right2, emptyTree.root()!!.right!!.right) - assertEquals(right15, emptyTree.root()!!.right) - assertFalse(root.isRed) - assertFalse(left.isRed) - assertTrue(right.isRed) - assertFalse(right15.isRed) - assertTrue(right2.isRed) - } - - @Test - @DisplayName("Add with black uncle, left ver") - fun add3L() { - val root = emptyTree.add(0, 0)!! - val right = emptyTree.add(1, 1)!! - val left = emptyTree.add(-1, -1)!! - val left2 = emptyTree.add(-3, -3)!! - val left15 = emptyTree.add(-2, -2)!! - assertEquals(root, emptyTree.root()) - assertEquals(right, emptyTree.root()!!.right) - assertEquals(left, emptyTree.root()!!.left!!.right) - assertEquals(left2, emptyTree.root()!!.left!!.left) - assertEquals(left15, emptyTree.root()!!.left) - assertFalse(root.isRed) - assertFalse(right.isRed) - assertTrue(left.isRed) - assertFalse(left15.isRed) - assertTrue(left2.isRed) - } - - @Test - @DisplayName("Add multiple nodes") - fun addMany() { - val nodesResult = MutableList(10) { emptyTree.add(it, it) } - assertEquals(5, emptyTree.height()) - for (keyValue in 10..19) - nodesResult.addLast(emptyTree.add(keyValue, keyValue)) - assertEquals(6, emptyTree.height()) - val colorResult = arrayListOf( - false, false, false, true, false, - false, false, false, false, false, - false, true, false, true, false, - false, false, true, false, true, - ) - for (node in emptyTree) { - assertEquals(nodesResult.removeFirst(), node) - assertEquals(colorResult.removeFirst(), node.isRed) - } - } - } - - @Nested - @DisplayName("Remove method tests") - inner class RemoveMethod { - var tree3Node = RBTree() - var bft15 = RBTree() - - @BeforeEach - fun initTree() { - tree3Node = RBTree() // 0 - tree3Node.add(0, 0) // / \ - tree3Node.add(10, 10) // -10 10 - tree3Node.add(-10, -10) - - bft15 = RBTree() //15 node tree (balanced) // 8 - var k = 16 // / \ - for (i in listOf(1, 2, 4, 8)) { // 4 12 - for (j in 0..() + + @BeforeEach + fun emptyTree() { + emptyTree.clear() + } + + @Nested + @DisplayName("Add method tests") + inner class AddMethod { + @Test + @DisplayName("Add node to the root") + fun addRoot() { + val root = emptyTree.add(1, 1974) + assertEquals(RBNode(1, 1974), root) + assertEquals(root, emptyTree.root()) + } + + @Test + @DisplayName("Add node that already exist") + fun addExisted() { + emptyTree.add(1, 1974) + assertEquals(null, emptyTree.add(1, 9999)) + assertEquals(RBNode(1, 1974), emptyTree.root()) + } + + @Test + @DisplayName("Add without uncle, right ver") + fun add1R() { + val root = emptyTree.add(0, 0)!! + val right = emptyTree.add(1, 1)!! + val right2 = emptyTree.add(2, 2)!! + assertEquals(root, emptyTree.root()!!.left) + assertEquals(right, emptyTree.root()) + assertEquals(right2, emptyTree.root()!!.right) + assertTrue(root.isRed) + assertFalse(right.isRed) + assertTrue(right2.isRed) + } + + @Test + @DisplayName("Add without uncle, left ver") + fun add1L() { + val root = emptyTree.add(0, 0)!! + val left = emptyTree.add(-1, -1)!! + val left2 = emptyTree.add(-2, -2)!! + assertEquals(root, emptyTree.root()!!.right) + assertEquals(left, emptyTree.root()) + assertEquals(left2, emptyTree.root()!!.left) + assertTrue(root.isRed) + assertFalse(left.isRed) + assertTrue(left2.isRed) + } + + + @Test + @DisplayName("Add with red uncle, right ver") + fun add2R() { + val root = emptyTree.add(0, 0)!! + val left = emptyTree.add(-1, -1)!! + val right = emptyTree.add(1, 1)!! + val right2 = emptyTree.add(2, 2)!! + assertEquals(root, emptyTree.root()) + assertEquals(left, emptyTree.root()!!.left) + assertEquals(right, emptyTree.root()!!.right) + assertEquals(right2, emptyTree.root()!!.right!!.right) + assertFalse(root.isRed) + assertFalse(left.isRed) + assertFalse(right.isRed) + assertTrue(right2.isRed) + } + + @Test + @DisplayName("Add with red uncle, left ver") + fun add2L() { + val root = emptyTree.add(0, 0)!! + val right = emptyTree.add(1, 1)!! + val left = emptyTree.add(-1, -1)!! + val left2 = emptyTree.add(-2, -2)!! + assertEquals(root, emptyTree.root()) + assertEquals(right, emptyTree.root()!!.right) + assertEquals(left, emptyTree.root()!!.left) + assertEquals(left2, emptyTree.root()!!.left!!.left) + assertFalse(root.isRed) + assertFalse(right.isRed) + assertFalse(left.isRed) + assertTrue(left2.isRed) + } + + @Test + @DisplayName("Add with black uncle, right ver") + fun add3R() { + val root = emptyTree.add(0, 0)!! + val left = emptyTree.add(-1, -1)!! + val right = emptyTree.add(1, 1)!! + val right2 = emptyTree.add(3, 3)!! + val right15 = emptyTree.add(2, 2)!! + assertEquals(root, emptyTree.root()) + assertEquals(left, emptyTree.root()!!.left) + assertEquals(right, emptyTree.root()!!.right!!.left) + assertEquals(right2, emptyTree.root()!!.right!!.right) + assertEquals(right15, emptyTree.root()!!.right) + assertFalse(root.isRed) + assertFalse(left.isRed) + assertTrue(right.isRed) + assertFalse(right15.isRed) + assertTrue(right2.isRed) + } + + @Test + @DisplayName("Add with black uncle, left ver") + fun add3L() { + val root = emptyTree.add(0, 0)!! + val right = emptyTree.add(1, 1)!! + val left = emptyTree.add(-1, -1)!! + val left2 = emptyTree.add(-3, -3)!! + val left15 = emptyTree.add(-2, -2)!! + assertEquals(root, emptyTree.root()) + assertEquals(right, emptyTree.root()!!.right) + assertEquals(left, emptyTree.root()!!.left!!.right) + assertEquals(left2, emptyTree.root()!!.left!!.left) + assertEquals(left15, emptyTree.root()!!.left) + assertFalse(root.isRed) + assertFalse(right.isRed) + assertTrue(left.isRed) + assertFalse(left15.isRed) + assertTrue(left2.isRed) + } + + @Test + @DisplayName("Add multiple nodes") + fun addMany() { + val nodesResult = MutableList(10) { emptyTree.add(it, it) } + assertEquals(5, emptyTree.height()) + for (keyValue in 10..19) + nodesResult.addLast(emptyTree.add(keyValue, keyValue)) + assertEquals(6, emptyTree.height()) + val colorResult = arrayListOf( + false, false, false, true, false, + false, false, false, false, false, + false, true, false, true, false, + false, false, true, false, true, + ) + for (node in emptyTree) { + assertEquals(nodesResult.removeFirst(), node) + assertEquals(colorResult.removeFirst(), node.isRed) + } + } + } + + @Nested + @DisplayName("Remove method tests") + inner class RemoveMethod { + var tree3Node = RBTree() + var bft15 = RBTree() + + @BeforeEach + fun initTree() { + tree3Node = RBTree() // 0 + tree3Node.add(0, 0) // / \ + tree3Node.add(10, 10) // -10 10 + tree3Node.add(-10, -10) // + + bft15 = RBTree() //15 node tree (balanced) // 8 + var k = 16 // / \ + for (i in listOf(1, 2, 4, 8)) { // 4 12 + for (j in 0..() + var bft31 = BSTree() - @BeforeEach - fun init() { - bft31 = BSTree() - var k = 32 - for (i in listOf(1, 2, 4, 8, 16)) { - for (j in 0.. Date: Sat, 6 Apr 2024 13:51:27 +0300 Subject: [PATCH 179/186] Apply suggestions from code review (AVL, abstract node and interfaces) --- src/main/kotlin/treeLib/bintrees/AVLTree.kt | 353 +++++++++--------- .../bintrees/interfaces/BalancedTree.kt | 39 +- .../treeLib/bintrees/interfaces/BinTree.kt | 170 +++++---- .../bintrees/interfaces/TreeIterator.kt | 91 ++--- src/main/kotlin/treeLib/nodes/AVLNode.kt | 10 +- src/main/kotlin/treeLib/nodes/TreeNode.kt | 56 +-- 6 files changed, 379 insertions(+), 340 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/AVLTree.kt b/src/main/kotlin/treeLib/bintrees/AVLTree.kt index e4dcf73..80af9ee 100644 --- a/src/main/kotlin/treeLib/bintrees/AVLTree.kt +++ b/src/main/kotlin/treeLib/bintrees/AVLTree.kt @@ -1,174 +1,193 @@ package treeLib.bintrees import treeLib.bintrees.interfaces.BalancedTree -import treeLib.bintrees.interfaces.BinTree import treeLib.nodes.AVLNode +class AVLTree, V> : BalancedTree>() { + override var root: AVLNode? = null + override var amountOfNodes = 0 -class AVLTree, V> : BalancedTree>(){ - override var root: AVLNode? = null - override var amountOfNodes = 0 - - override fun remove(key: K): V? { - var value: V? = null - fun removeRec(node: AVLNode?, key: K): AVLNode? { - if (node == null) return null - if (key < node.key) { - node.left = removeRec(node.left, key) - } else if (key > node.key) { - node.right = removeRec(node.right, key) - } else { - val nodeA = node.left - val nodeB = node.right - value = node.value - if (nodeB == null) { - return nodeA - } - val min = findMin(nodeB) - min?.right = removeMin(nodeB) - min?.left = nodeA - if (root?.key == key) { - root = min - } - return balanceNode(min) - } - return balanceNode(node) - } - removeRec(root, key) - amountOfNodes -= 1 - return value - } - - private fun findMin(node: AVLNode?): AVLNode? { - if (node?.left != null) { - return findMin(node.left) - } - return node - } - - private fun removeMin(node: AVLNode?): AVLNode? { - if (node?.left == null) { - return node?.right - } - node.left = removeMin(node.left) - return balanceNode(node) - } - - override fun add(key: K, value: V): AVLNode? { - fun addRec(node: AVLNode?, key: K, value: V): AVLNode? { - if (node == null) { - return AVLNode(key, value) - } - if (key < node.key) { - node.left = addRec(node.left, key, value) - } else if (key > node.key) { - node.right = addRec(node.right, key, value) - } - return balanceNode(node) - } - if (root == null) { - root = AVLNode(key, value) - amountOfNodes += 1 - return root - } - amountOfNodes += 1 - return addRec(root, key, value) - } - - private fun rotateLeft(nodeA: AVLNode?): AVLNode? { - if (nodeA != null) { - if (nodeA.right != null) { - val nodeB = nodeA.right - nodeA.right = nodeB?.left - nodeB?.left = nodeA - fixHeight(nodeA) - fixHeight(nodeB) - return nodeB - } else { - throw NullPointerException("Right child node cannot be null.") - } - } else { - throw NullPointerException("Node cannot be null.") - } - } - - private fun rotateRight(nodeA: AVLNode?): AVLNode? { - if (nodeA != null) { - if (nodeA.left != null) { - val nodeB = nodeA.left - nodeA.left = nodeB?.right - nodeB?.right = nodeA - fixHeight(nodeA) - fixHeight(nodeB) - return nodeB - } else { - throw NullPointerException("Left child node cannot be null.") - } - } else { - throw NullPointerException("Node cannot be null.") - } - } - - private fun height(node: AVLNode?): Int { - if (node == null) { - return 0 - } - return node.height - } - - private fun balanceFactor(node: AVLNode?): Int { - if (node == null) { - throw NullPointerException("Node cannot be null.") - } - return height(node.right) - height(node.left) - } - - private fun fixHeight(node: AVLNode?) { - if (node != null) { - val heightLeft = height(node.left) - val heightRight = height(node.right) - if (heightLeft > heightRight) { - node.height = heightLeft + 1 - } else { - node.height = heightRight + 1 - } - } - } - - private fun balanceNode(node: AVLNode?): AVLNode? { - fixHeight(node) - if (balanceFactor(node) == 2) { - if (node != null) { - if (balanceFactor(node.right) < 0) { - node.right = rotateRight(node.right) - } - if (node == root) { - root = rotateLeft(node) - return root - } - return rotateLeft(node) - } - } - if (balanceFactor(node) == -2) { - if (node != null) { - if (balanceFactor(node.left) > 0) { - node.left = rotateLeft(node.left) - } - if (node == root) { - root = rotateRight(node) - return root - } - return rotateRight(node) - } - } - return node - } - - override fun height(): Int? { - return if (root == null) { - 0 - } else { - root?.height - } - } + override fun remove(key: K): V? { + var value: V? = null + + fun removeRec(node: AVLNode?, key: K): AVLNode? { + if (node == null) return null + + if (key < node.key) { + node.left = removeRec(node.left, key) + } else if (key > node.key) { + node.right = removeRec(node.right, key) + } else { + val nodeLeft = node.left + val nodeRight = node.right + + value = node.value + + if (nodeRight == null) { + return nodeLeft + } + + val min = findMin(nodeRight) + + min?.right = removeMin(nodeRight) + min?.left = nodeLeft + + if (root?.key == key) { + root = min + } + + return balanceNode(min) + } + + return balanceNode(node) + } + + removeRec(root, key) + amountOfNodes -= 1 + + return value + } + + private fun findMin(node: AVLNode?): AVLNode? { + if (node?.left != null) { + return findMin(node.left) + } + + return node + } + + private fun removeMin(node: AVLNode?): AVLNode? { + if (node?.left == null) { + return node?.right + } + + node.left = removeMin(node.left) + + return balanceNode(node) + } + + override fun add(key: K, value: V): AVLNode? { + fun addRec(node: AVLNode?, key: K, value: V): AVLNode? { + if (node == null) { + return AVLNode(key, value) + } + + if (key < node.key) { + node.left = addRec(node.left, key, value) + } else if (key > node.key) { + node.right = addRec(node.right, key, value) + } + + return balanceNode(node) + } + + if (root == null) { + root = AVLNode(key, value) + amountOfNodes += 1 + return root + } + + amountOfNodes += 1 + + return addRec(root, key, value) + } + + private fun rotateLeft(nodeA: AVLNode?): AVLNode? { + if (nodeA != null) { + if (nodeA.right != null) { + val nodeB = nodeA.right + + nodeA.right = nodeB?.left + nodeB?.left = nodeA + + fixHeight(nodeA) + fixHeight(nodeB) + + return nodeB + } else { + throw NullPointerException("Right child node cannot be null.") + } + } else { + throw NullPointerException("Node cannot be null.") + } + } + + private fun rotateRight(nodeA: AVLNode?): AVLNode? { + if (nodeA != null) { + if (nodeA.left != null) { + val nodeB = nodeA.left + + nodeA.left = nodeB?.right + nodeB?.right = nodeA + + fixHeight(nodeA) + fixHeight(nodeB) + + return nodeB + } else { + throw NullPointerException("Left child node cannot be null.") + } + } else { + throw NullPointerException("Node cannot be null.") + } + } + + private fun height(node: AVLNode?): Int { + return node?.height ?: 0 + } + + private fun balanceFactor(node: AVLNode?): Int { + if (node == null) { + throw NullPointerException("Node cannot be null.") + } + + return height(node.right) - height(node.left) + } + + private fun fixHeight(node: AVLNode?) { + if (node != null) { + val heightLeft = height(node.left) + val heightRight = height(node.right) + + if (heightLeft > heightRight) { + node.height = heightLeft + 1 + } else { + node.height = heightRight + 1 + } + } + } + + private fun balanceNode(node: AVLNode?): AVLNode? { + fixHeight(node) + + if (balanceFactor(node) == 2 && node != null) { + if (balanceFactor(node.right) < 0) { + node.right = rotateRight(node.right) + } + + if (node == root) { + root = rotateLeft(node) + return root + } + + return rotateLeft(node) + } + if (balanceFactor(node) == -2 && node != null) { + if (balanceFactor(node.left) > 0) { + node.left = rotateLeft(node.left) + } + + if (node == root) { + root = rotateRight(node) + return root + } + + return rotateRight(node) + } + return node + } + + override fun height(): Int { + return root?.height ?: 0 + } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BalancedTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BalancedTree.kt index 00bff08..177672e 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BalancedTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BalancedTree.kt @@ -4,22 +4,25 @@ import treeLib.nodes.TreeNode abstract class BalancedTree, V, Node_T : TreeNode> : BinTree() { - //We must provide parent, because don't have link to it in node - protected fun rotateRight(node: Node_T?, parent: Node_T?) { - if (node == null) return - val nodeLeft = node.left - node.left = nodeLeft?.right - nodeLeft?.right = node - - if (parent != null) parent.attach(nodeLeft) else root = nodeLeft //root doesn't have parent - } - - protected fun rotateLeft(node: Node_T?, parent: Node_T?) { - if (node == null) return - val nodeRight = node.right - node.right = nodeRight?.left - nodeRight?.left = node - - if (parent != null) parent.attach(nodeRight) else root = nodeRight //root doesn't have parent - } + //We must provide parent, because don't have link to it in node + protected fun rotateRight(node: Node_T?, parent: Node_T?) { + if (node == null) return + + val nodeLeft = node.left + + node.left = nodeLeft?.right + nodeLeft?.right = node + + if (parent != null) parent.attach(nodeLeft) else root = nodeLeft //root doesn't have parent + } + + protected fun rotateLeft(node: Node_T?, parent: Node_T?) { + if (node == null) return + + val nodeRight = node.right + node.right = nodeRight?.left + nodeRight?.left = node + + if (parent != null) parent.attach(nodeRight) else root = nodeRight //root doesn't have parent + } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt index 258b094..3b81bf4 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/BinTree.kt @@ -3,84 +3,94 @@ package treeLib.bintrees.interfaces import treeLib.nodes.TreeNode abstract class BinTree, V, Node_T : TreeNode> : Iterable { - protected abstract var root: Node_T? - protected abstract var amountOfNodes: Int - - abstract fun add(key: K, value: V): Node_T? - - abstract fun remove(key: K): V? - - fun findByKey(key: K): Node_T? { - var curNode = root - while (curNode != null) - curNode = when { - key > curNode.key -> curNode.right - key < curNode.key -> curNode.left - else -> return curNode - } - return null - } - - open fun changeVal(key: K, newValue: V): V? { - var curNode = root - while (curNode != null) - curNode = when { - key > curNode.key -> curNode.right - key < curNode.key -> curNode.left - else -> { - curNode.value = newValue - return newValue - } - } - return null - } - - fun max(): Node_T? { - var curNode = root - while (curNode?.right != null) - curNode = curNode.right - return curNode - } - - fun min(): Node_T? { - var curNode = root - while (curNode?.left != null) - curNode = curNode.left - return curNode - } - - open fun root(): Node_T? { - return root - } - - fun clear() { - root?.let { root = null } - amountOfNodes = 0 - } - - fun countNodes(): Int { - return amountOfNodes - } - - /** - * basic In-order iterator - */ - override fun iterator(): Iterator = TreeIterator(root, IterationOrder.IN_ORDER) - - fun preOrderIterator(): Iterator = TreeIterator(root, IterationOrder.PRE_ORDER) - - fun postOrderIterator(): Iterator = TreeIterator(root, IterationOrder.POST_ORDER) - - - private fun countHeight(tNode: Node_T?): Int { - if (tNode == null) return 0 - val leftChild = countHeight(tNode.left) - val rightChild = countHeight(tNode.right) - return kotlin.math.max(leftChild, rightChild) + 1 - } - - - open fun height(): Int? { - return countHeight(root) - } + protected abstract var root: Node_T? + protected abstract var amountOfNodes: Int + + abstract fun add(key: K, value: V): Node_T? + + abstract fun remove(key: K): V? + + fun findByKey(key: K): Node_T? { + var curNode = root + + while (curNode != null) + curNode = when { + key > curNode.key -> curNode.right + key < curNode.key -> curNode.left + else -> return curNode + } + + return null + } + + open fun changeVal(key: K, newValue: V): V? { + var curNode = root + + while (curNode != null) + curNode = when { + key > curNode.key -> curNode.right + key < curNode.key -> curNode.left + else -> { + curNode.value = newValue + return newValue + } + } + + return null + } + + fun max(): Node_T? { + var curNode = root + + while (curNode?.right != null) + curNode = curNode.right + + return curNode + } + + fun min(): Node_T? { + var curNode = root + + while (curNode?.left != null) + curNode = curNode.left + + return curNode + } + + open fun root(): Node_T? { + return root + } + + fun clear() { + root = null + amountOfNodes = 0 + } + + fun countNodes(): Int { + return amountOfNodes + } + + /** + * basic In-order iterator + */ + override fun iterator(): Iterator = TreeIterator(root, IterationOrder.IN_ORDER) + + fun preOrderIterator(): Iterator = TreeIterator(root, IterationOrder.PRE_ORDER) + + fun postOrderIterator(): Iterator = TreeIterator(root, IterationOrder.POST_ORDER) + + + private fun countHeight(tNode: Node_T?): Int { + if (tNode == null) return 0 + + val leftChild = countHeight(tNode.left) + val rightChild = countHeight(tNode.right) + + return kotlin.math.max(leftChild, rightChild) + 1 + } + + + open fun height(): Int? { + return countHeight(root) + } } diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt index 650424c..40aa11d 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/TreeIterator.kt @@ -3,48 +3,53 @@ package treeLib.bintrees.interfaces import treeLib.nodes.TreeNode class TreeIterator, V, Node_T : TreeNode>( - private val root: Node_T?, - private val order: IterationOrder, + private val root: Node_T?, + private val order: IterationOrder, ) : Iterator { - private val stack: ArrayDeque = ArrayDeque() - - init { - root?.let { treeToStack(root) } - } - - private fun treeToStack(start: Node_T) { - when (order) { - IterationOrder.IN_ORDER -> inOrder(start) - IterationOrder.PRE_ORDER -> preOrder(start) - IterationOrder.POST_ORDER -> postOrder(start) - } - } - - private fun inOrder(curNode: Node_T) { - val leftNode = curNode.left - val rightNode = curNode.right - leftNode?.let { inOrder(leftNode) } - stack.add(curNode) - rightNode?.let { inOrder(rightNode) } - } - - private fun preOrder(curNode: Node_T) { - val leftNode = curNode.left - val rightNode = curNode.right - stack.add(curNode) - leftNode?.let { preOrder(leftNode) } - rightNode?.let { preOrder(rightNode) } - } - - private fun postOrder(curNode: Node_T) { - val leftNode = curNode.left - val rightNode = curNode.right - leftNode?.let { postOrder(leftNode) } - rightNode?.let { postOrder(rightNode) } - stack.add(curNode) - } - - override fun hasNext() = stack.isNotEmpty() - - override fun next() = stack.removeFirst() + private val stack: ArrayDeque = ArrayDeque() + + init { + root?.let { treeToStack(root) } + } + + private fun treeToStack(start: Node_T) { + when (order) { + IterationOrder.IN_ORDER -> inOrder(start) + IterationOrder.PRE_ORDER -> preOrder(start) + IterationOrder.POST_ORDER -> postOrder(start) + } + } + + private fun inOrder(curNode: Node_T) { + val leftNode = curNode.left + val rightNode = curNode.right + + leftNode?.let { inOrder(leftNode) } + stack.add(curNode) + rightNode?.let { inOrder(rightNode) } + } + + private fun preOrder(curNode: Node_T) { + val leftNode = curNode.left + val rightNode = curNode.right + + stack.add(curNode) + + leftNode?.let { preOrder(leftNode) } + rightNode?.let { preOrder(rightNode) } + } + + private fun postOrder(curNode: Node_T) { + val leftNode = curNode.left + val rightNode = curNode.right + + leftNode?.let { postOrder(leftNode) } + rightNode?.let { postOrder(rightNode) } + + stack.add(curNode) + } + + override fun hasNext() = stack.isNotEmpty() + + override fun next() = stack.removeFirst() } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/nodes/AVLNode.kt b/src/main/kotlin/treeLib/nodes/AVLNode.kt index 2226ea8..edff837 100644 --- a/src/main/kotlin/treeLib/nodes/AVLNode.kt +++ b/src/main/kotlin/treeLib/nodes/AVLNode.kt @@ -1,10 +1,10 @@ package treeLib.nodes class AVLNode, V>( - key: K, - value: V, - right: AVLNode? = null, - left: AVLNode? = null + key: K, + value: V, + right: AVLNode? = null, + left: AVLNode? = null ) : TreeNode>(key, value, right, left) { - internal var height: Int = 1 + internal var height: Int = 1 } diff --git a/src/main/kotlin/treeLib/nodes/TreeNode.kt b/src/main/kotlin/treeLib/nodes/TreeNode.kt index 03f72a1..f940cc9 100644 --- a/src/main/kotlin/treeLib/nodes/TreeNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreeNode.kt @@ -1,41 +1,43 @@ package treeLib.nodes abstract class TreeNode, V, Node_T : TreeNode>( - internal var key: K, - internal var value: V, - internal var right: Node_T? = null, - internal var left: Node_T? = null, + internal var key: K, + internal var value: V, + internal var right: Node_T? = null, + internal var left: Node_T? = null, ) : Comparable { - override fun compareTo(other: Node_T): Int = key.compareTo(other.key) + override fun compareTo(other: Node_T): Int = key.compareTo(other.key) - override fun hashCode(): Int = Pair(key, value).hashCode() + override fun hashCode(): Int = Pair(key, value).hashCode() - override fun equals(other: Any?): Boolean { - return (other as? Node_T != null) && (key == other.key) && (value == other.value) - } + override fun equals(other: Any?): Boolean { + return (other as? Node_T != null) && (key == other.key) && (value == other.value) + } - override fun toString(): String = Pair(key, value).toString() + override fun toString(): String = Pair(key, value).toString() - fun toPair(): Pair = Pair(key, value) + fun toPair(): Pair = Pair(key, value) - fun key(): K = key + fun key(): K = key - fun value(): V = value + fun value(): V = value - internal fun attach(node: Node_T?): Boolean { - if (node == null) return false - when { - this > node -> left = node - this < node -> right = node - else -> return false - } - return true - } + internal fun attach(node: Node_T?): Boolean { + if (node == null) return false - internal fun moveOn(otherKey: K): Node_T? = when { - key > otherKey -> left - key < otherKey -> right - else -> this as? Node_T - } + when { + this > node -> left = node + this < node -> right = node + else -> return false + } + + return true + } + + internal fun moveOn(otherKey: K): Node_T? = when { + key > otherKey -> left + key < otherKey -> right + else -> this as? Node_T + } } From acc5f642bde17756c573b817e6e5625eeb217204 Mon Sep 17 00:00:00 2001 From: Islam Date: Sat, 6 Apr 2024 18:35:57 +0300 Subject: [PATCH 180/186] fix: fix cod according to review's critic --- src/main/kotlin/treeLib/bintrees/BSTree.kt | 126 ++++++++++++++------- 1 file changed, 82 insertions(+), 44 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/BSTree.kt b/src/main/kotlin/treeLib/bintrees/BSTree.kt index 74ed01f..b7d1775 100644 --- a/src/main/kotlin/treeLib/bintrees/BSTree.kt +++ b/src/main/kotlin/treeLib/bintrees/BSTree.kt @@ -8,17 +8,23 @@ class BSTree, V> : BinTree>() { override var amountOfNodes = 0 fun addPairs(vararg pairs: Pair): Boolean { + var flag = true + for (pair in pairs) { - if (this.add(pair.first, pair.second) == null) return false + if (this.add(pair.first, pair.second) == null) flag = false } - return true + + return flag } fun removePairs(vararg keys: K): Boolean { + var flag = true + for (key in keys) { - if (this.remove(key) == null) return false + if (this.remove(key) == null) flag = false } - return true + + return flag } override fun add(key: K, value: V): BSTNode? { @@ -27,66 +33,96 @@ class BSTree, V> : BinTree>() { this.amountOfNodes += 1 return root } + var curNode = this.root - while (curNode != null) { - if (key > curNode.key) { + + while (curNode != null && curNode.key != key) { + curNode = if (key > curNode.key) { if (curNode.right == null) { curNode.right = BSTNode(key, value) this.amountOfNodes += 1 + return curNode.right } - curNode = curNode.right - } else if (key < curNode.key) { + + curNode.right + } + + else{ if (curNode.left == null) { curNode.left = BSTNode(key, value) this.amountOfNodes += 1 + return curNode.left } - curNode = curNode.left - } else break + + curNode.left + } } return null } override fun remove(key: K): V? { var count = 0 - var curNode: BSTNode? = null + val curNode: BSTNode? var parent = this.findParent(key) - if (this.root?.key == key) parent = BSTNode(root!!.key, root!!.value, root) + + if (this.root?.key == key) parent = root?.let { BSTNode(it.key, it.value, it) } if (parent == null) return null + curNode = if (parent.right != null && parent.right?.key == key) parent.right else parent.left + + // Hier wir count amount of children if (curNode?.right != null) count++ if (curNode?.left != null) count++ + + //We have no children if (count == 0) { - if (parent.right === curNode) { + + if (parent.right == curNode) { if (curNode == root) this.root = null else parent.right = null - } else parent.left = null - } else if (count == 1) { + } + + else parent.left = null + } + + //We've got ein child + else if (count == 1) { if (curNode?.left == null) { if (parent.right == curNode) { if (curNode == root) this.root = root?.right else parent.right = curNode?.right } else parent.left = curNode?.right - } else { + } + + else { if (parent.right == curNode) { if (curNode == root) this.root = this.root?.left else parent.right = curNode.left } else parent.left = curNode.left } - } else { - var child = curNode?.right + } + + //Wir haben zwei kinder + else { + var child: BSTNode? = curNode?.right var parent_child = curNode - while (child!!.left != null) { - if (child.left!!.left == null) parent_child = child + + while (child?.left != null) { + if (child.left?.left == null) parent_child = child child = child.left } + + if(child == null) return null curNode?.key = child.key curNode?.value = child.value - if (curNode?.right != child) parent_child!!.left = child.right + + if (curNode?.right != child) parent_child?.left = child.right else curNode.right = child.right } + this.amountOfNodes -= 1 return curNode?.value } @@ -94,52 +130,54 @@ class BSTree, V> : BinTree>() { internal fun findParent(key: K): BSTNode? { var parent = this.root - if (parent == null || root!!.key == key) return null - while (parent?.right != null || parent?.left != null) { + if (root?.key == key) return null + + while (parent != null && (parent.right != null || parent.left != null)) { if (parent.right != null && parent.right?.key == key || parent.left != null && parent.left?.key == key) return parent - else { - if (key > parent.key) { - if (parent.right == null) return null - parent = parent.right - } else { - if (parent.left == null) return null - parent = parent.left - } - } + + parent = if (key > parent.key) parent.right + else parent.left } + return null } fun deleteSubTree(key: K): Boolean { - val parent: BSTNode? = this.findParent(key) - if (parent == null) return false + val parent: BSTNode = this.findParent(key) ?: return false + if (parent.right != null && parent.right?.key == key) parent.right = null else parent.left = null + var nodes = 0 for (i in this) nodes++ amountOfNodes = nodes + return true } fun getSubTree(key: K): BSTree? { - val parent: BSTNode? = this.findParent(key) + val parent: BSTNode = this.findParent(key) ?: return null val childTree: BSTree = BSTree() - if (parent == null) return null - var child: BSTNode? = null + val child: BSTNode? + if (parent.right != null && parent.right?.key == key) { - child = childTree.add(key, parent.right!!.value) - child?.right = parent.right!!.right - child?.left = parent.right!!.left - } else { - child = childTree.add(key, parent.left!!.value) - child?.right = parent.left!!.right - child?.left = parent.left!!.left + child = childTree.add(key, parent.right?.value ?: return null) + child?.right = parent.right?.right + child?.left = parent.right?.left + } + + else { + child = parent.left?.let { childTree.add(key, it.value)} + child?.right = parent.left?.right + child?.left = parent.left?.left } + var nodes = 0 for (i in childTree) nodes++ childTree.amountOfNodes = nodes + return childTree } } From 228e03690d639d1d8f836aa7731077c422545628 Mon Sep 17 00:00:00 2001 From: Damir Yunusov Date: Sun, 7 Apr 2024 12:29:39 +0300 Subject: [PATCH 181/186] refactor: add spaces between logical blocks in code, less nesting in methods --- src/main/kotlin/treeLib/bintrees/RBTree.kt | 137 ++++++++++++--------- 1 file changed, 80 insertions(+), 57 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/RBTree.kt b/src/main/kotlin/treeLib/bintrees/RBTree.kt index 0ebd71f..58ce4dd 100644 --- a/src/main/kotlin/treeLib/bintrees/RBTree.kt +++ b/src/main/kotlin/treeLib/bintrees/RBTree.kt @@ -20,19 +20,23 @@ class RBTree, V> : BalancedTree>() { override fun add(key: K, value: V): RBNode? { val treeBranch = ArrayDeque>() //to know who's the parent val newNode = RBNode(key, value) + if (root == null) { root = newNode } else { var curNode = root + while (curNode != null) { treeBranch.addFirst(curNode) val nextNode = curNode.moveOn(key) if (nextNode == curNode) return null //node with given key already exist curNode = nextNode } + val parent = treeBranch.first() parent.attach(newNode) } + amountOfNodes++ treeBranch.addFirst(newNode) balancedAdd(treeBranch) @@ -46,8 +50,10 @@ class RBTree, V> : BalancedTree>() { var son = treeBranch.removeFirst() var parent = treeBranch.removeFirstOrNull() var grandparent = treeBranch.removeFirstOrNull() + while (parent != null && parent.isRed && grandparent != null) { val uncle = if (parent == grandparent.right) grandparent.left else grandparent.right + //uncle is red -> recolor nodes and go higher up the treeBranch if (uncle?.isRed == true) { parent.isRed = false @@ -56,26 +62,31 @@ class RBTree, V> : BalancedTree>() { son = grandparent parent = treeBranch.removeFirstOrNull() grandparent = treeBranch.removeFirstOrNull() - } else /*uncle is black or null -> do few rotations, recoloring and magic will happen*/ { - if (parent == grandparent.right) { - if (son == parent.left) { //we want co-directional parent and son - rotateRight(parent, grandparent) - parent = son - } - parent.isRed = false - grandparent.isRed = true - rotateLeft(grandparent, treeBranch.firstOrNull()) - } else /*parent == grandparent.left*/ { - if (son == parent.right) { //we want co-directional parent and son too - rotateLeft(parent, grandparent) - parent = son - } - parent.isRed = false - grandparent.isRed = true - rotateRight(grandparent, treeBranch.firstOrNull()) + continue + } + + //uncle is black or null -> do few rotations, recoloring and magic will happen + if (parent == grandparent.right) { + if (son == parent.left) { //we want co-directional parent and son + rotateRight(parent, grandparent) + parent = son + } + + parent.isRed = false + grandparent.isRed = true + rotateLeft(grandparent, treeBranch.firstOrNull()) + } else /*parent == grandparent.left*/ { + if (son == parent.right) { //we want co-directional parent and son too + rotateLeft(parent, grandparent) + parent = son } + + parent.isRed = false + grandparent.isRed = true + rotateRight(grandparent, treeBranch.firstOrNull()) } } + root?.isRed = false } @@ -86,11 +97,13 @@ class RBTree, V> : BalancedTree>() { override fun remove(key: K): V? { val treeBranch = ArrayDeque?>() //to know who's the parent var curNode = root ?: return null + while (curNode.key != key) { treeBranch.addFirst(curNode) val nextNode = curNode.moveOn(key) ?: return null //nextNode == null => removing node doesn't exist curNode = nextNode } + var parent = treeBranch.firstOrNull() val sonRight = curNode.right val sonLeft = curNode.left @@ -99,10 +112,12 @@ class RBTree, V> : BalancedTree>() { treeBranch.addFirst(curNode) val copyTo = curNode //Will copy from curNode curNode = sonLeft + while (curNode.right != null) { treeBranch.addFirst(curNode) curNode = curNode.right ?: throw NullPointerException("Removing node cannot be null.") } + parent = treeBranch.first() val temp = copyTo.value copyTo.key = curNode.key @@ -113,14 +128,15 @@ class RBTree, V> : BalancedTree>() { sonRight != null -> sonRight else /*sonLeft != null*/ -> sonLeft } + amountOfNodes-- when (curNode) { //here we are "deleting" the node and replace it with his son parent?.right -> parent.right = sonOfRemovedNode parent?.left -> parent.left = sonOfRemovedNode else -> root = sonOfRemovedNode //only root doesn't have parent } + treeBranch.addFirst(sonOfRemovedNode) - //curNode.isRed -> no balancing needed if (!curNode.isRed) balancedRemove(treeBranch) return curNode.value } @@ -132,17 +148,21 @@ class RBTree, V> : BalancedTree>() { var son = treeBranch.removeFirstOrNull() var parent = treeBranch.removeFirstOrNull() var grandparent = treeBranch.removeFirstOrNull() + //son == son of removed node if (son?.isRed == true) { son.isRed = false return } + while (parent != null) { var brother = if (son == parent.right) parent.left else parent.right + //we want for brother to be black (´。_。`) if (brother?.isRed == true) { brother.isRed = false parent.isRed = true + if (son == parent.right) { rotateRight(parent, grandparent) grandparent = brother @@ -153,52 +173,55 @@ class RBTree, V> : BalancedTree>() { brother = parent.right } } - brother ?: throw IllegalStateException( - "Balance of red-black tree violated:" + - " parent node have subtrees with black height 2 and black height 1" - ) - //depending on nephew's colors, doing magic for balancing purposes + + brother ?: throw IllegalStateException("Balance of RB tree violated: different black height.") var nephewRight = brother.right var nephewLeft = brother.left - if ((nephewRight == null || !nephewRight.isRed) && (nephewLeft == null || !nephewLeft.isRed)) { + + //depending on nephew's colors, doing magic for balancing purposes + if (nephewRight?.isRed != true && nephewLeft?.isRed != true && parent.isRed) { brother.isRed = true - if (!parent.isRed) { //parent is black --> go higher up - son = parent //the treeBranch and balance again - parent = grandparent - grandparent = treeBranch.removeFirstOrNull() - } else { - parent.isRed = false - break + parent.isRed = false + break + } else if (nephewRight?.isRed != true && nephewLeft?.isRed != true && !parent.isRed) { + brother.isRed = true //parent is black --> go higher up + son = parent //the treeBranch and balance again + parent = grandparent + grandparent = treeBranch.removeFirstOrNull() + continue + } + + if (son == parent.right) { + if (nephewRight?.isRed == true && nephewLeft?.isRed != true) { + rotateLeft(brother, parent) // B /nL == new brother + nephewLeft = brother // / \ -> /B == new left nephew + brother = nephewRight // nL nR /nR + brother.isRed = false + nephewLeft.isRed = true } - } else { - if (son == parent.right) { - if (nephewRight?.isRed == true && (nephewLeft == null || !nephewLeft.isRed)) { - rotateLeft(brother, parent) // B /nL == new brother - nephewLeft = brother // / \ -> /B == new left nephew - brother = nephewRight // nL nR /nR - brother.isRed = false - nephewLeft.isRed = true - } - rotateRight(parent, grandparent) - brother.isRed = parent.isRed - parent.isRed = false - nephewLeft?.isRed = false - } else /*son == parent.left*/ { - if (nephewLeft?.isRed == true && (nephewRight == null || !nephewRight.isRed)) { - rotateRight(brother, parent) // B \nR == new brother - nephewRight = brother // / \ -> \B == new right nephew - brother = nephewLeft // nL nR \nL - brother.isRed = false - nephewRight.isRed = true - } - rotateLeft(parent, grandparent) - brother.isRed = parent.isRed - parent.isRed = false - nephewRight?.isRed = false + + rotateRight(parent, grandparent) + brother.isRed = parent.isRed + parent.isRed = false + nephewLeft?.isRed = false + } else /*son == parent.left*/ { + if (nephewLeft?.isRed == true && nephewRight?.isRed != true) { + rotateRight(brother, parent) // B \nR == new brother + nephewRight = brother // / \ -> \B == new right nephew + brother = nephewLeft // nL nR \nL + brother.isRed = false + nephewRight.isRed = true } - break + + rotateLeft(parent, grandparent) + brother.isRed = parent.isRed + parent.isRed = false + nephewRight?.isRed = false } + + break } + root?.isRed = false } } From 67f1dfa9ae91343c2a5a81c6b410d54a96efadc4 Mon Sep 17 00:00:00 2001 From: IslamZZZZ Date: Sat, 26 Oct 2024 03:48:49 +0300 Subject: [PATCH 182/186] preparing for later changes --- .../treeLib/bintrees/interfaces/Treap.kt | 86 +++++++++++++++++++ src/main/kotlin/treeLib/nodes/TreapNode.kt | 8 ++ 2 files changed, 94 insertions(+) create mode 100644 src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt create mode 100644 src/main/kotlin/treeLib/nodes/TreapNode.kt diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt b/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt new file mode 100644 index 0000000..8e29909 --- /dev/null +++ b/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt @@ -0,0 +1,86 @@ +package treeLib.bintrees.interfaces + +import treeLib.bintrees.interfaces.BinTree +import treeLib.nodes.TreapNode +import java.util.* + +class Treap, V: Comparable > : BinTree>() { + override var root: TreapNode? = null + override var amountOfNodes = 0 + private val priorQ = PriorityQueue>(compareByDescending { it.value }) + + + //Получив родителя и найдя куда он идёт, мы связываем и передаём сюда + //Он должен здесь дойти до него по обычной итерации дерева + //и параллельно должно менять maxLim и minLim, по этому мы составим новый массив + //и начнём строить дерево с нуля где node это корень + fun rebuildTree(node: TreapNode) { + var maxLim: TreapNode? = root + var minLim: TreapNode? = root + var curRoot = root + var reachedNode = false + for (curNode in priorQ){ + if(reachedNode == false) { + if (curNode.value > curRoot?.value ?: curNode.value) { //N_U_L_L-S_A_F_E_T_Y + minLim = curRoot + curRoot = curNode?.right // Тут надо подумать + } else if (curNode.value < curRoot?.value ?: curNode.value) {//N_U_L_L-S_A_F_E_T_Y + maxLim = curRoot + curRoot = curNode?.left + } else reachedNode = true + } + else { + + } + } + } + + override fun remove(key: K): V? { + if(root == null) return null + if(root?.key == key && amountOfNodes == 1) { + priorQ.remove(root) + amountOfNodes -= 1 + root = null + } + return null + } + + override fun add(key: K, priority: V): TreapNode? { + if(root == null) { + root = TreapNode(key, priority) + amountOfNodes += 1 + priorQ.add(root) + return root + } + + //Должны вызвать функцию X, отработать случаи когда куда добавляется новый ключ + //у нас нету ничего + //и далее работать в rebuildTree со случаями, когда там что-то всё ж имеется + //потому что она так и задумана, что применяется, когда нужно перестроить поддерево + //А ежли его нету, то и перестраивать ничего не надо + + return root + } + + + //Здесь мы находим родителя нашего нового ключа + //А далее по значению ключа(больше иль меньше родителя) выясняем куда оно идёт + //и работаем исходя из этого + fun x(curNode: TreapNode, parent: TreapNode, node: TreapNode): TreapNode{ + if(curNode.value < node.value) { + if(curNode.key < node.key) { + //We need to rebuild and build new tree with node.key as a root + //Иль попытайся придумать что-то со списками + } + } + if(curNode.key > node.key) { + //if(curNode.left == null) return parent + return x(curNode.left ?: return parent, curNode, node) + } + else if(curNode.key < node.key) { + //if(curNode.right == null) return parent + return x(curNode.right ?: return parent, curNode, node) + } + else return curNode + } +} \ No newline at end of file diff --git a/src/main/kotlin/treeLib/nodes/TreapNode.kt b/src/main/kotlin/treeLib/nodes/TreapNode.kt new file mode 100644 index 0000000..46ce2f4 --- /dev/null +++ b/src/main/kotlin/treeLib/nodes/TreapNode.kt @@ -0,0 +1,8 @@ +package treeLib.nodes + +class TreapNode, V: Comparable>( + key: K, + value: V, + right: TreapNode? = null, + left: TreapNode? = null +) : TreeNode>(key, priority, right, left) \ No newline at end of file From c339836ce77a70ef5bc2ab31bbaf9e60072199e3 Mon Sep 17 00:00:00 2001 From: IslamZZZZ Date: Mon, 28 Oct 2024 19:52:58 +0300 Subject: [PATCH 183/186] added test and corrected X function --- .../treeLib/bintrees/interfaces/Treap.kt | 138 ++++++++++++------ src/main/kotlin/treeLib/nodes/TreapNode.kt | 2 +- src/test/kotlin/TreapTest.kt | 52 +++++++ 3 files changed, 148 insertions(+), 44 deletions(-) create mode 100644 src/test/kotlin/TreapTest.kt diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt b/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt index 8e29909..91f5729 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt @@ -1,86 +1,138 @@ package treeLib.bintrees.interfaces +import treeLib.bintrees.BSTree import treeLib.bintrees.interfaces.BinTree +import treeLib.nodes.BSTNode import treeLib.nodes.TreapNode import java.util.* class Treap, V: Comparable > : BinTree>() { override var root: TreapNode? = null override var amountOfNodes = 0 - private val priorQ = PriorityQueue>(compareByDescending { it.value }) - - - //Получив родителя и найдя куда он идёт, мы связываем и передаём сюда - //Он должен здесь дойти до него по обычной итерации дерева - //и параллельно должно менять maxLim и minLim, по этому мы составим новый массив - //и начнём строить дерево с нуля где node это корень - fun rebuildTree(node: TreapNode) { - var maxLim: TreapNode? = root - var minLim: TreapNode? = root - var curRoot = root - var reachedNode = false - for (curNode in priorQ){ - if(reachedNode == false) { - if (curNode.value > curRoot?.value ?: curNode.value) { //N_U_L_L-S_A_F_E_T_Y - minLim = curRoot - curRoot = curNode?.right // Тут надо подумать - } else if (curNode.value < curRoot?.value ?: curNode.value) {//N_U_L_L-S_A_F_E_T_Y - maxLim = curRoot - curRoot = curNode?.left - } else reachedNode = true - } - else { + private var subTree = PriorityQueue>(compareByDescending { it.value }) - } + + fun collectNodes(node: TreapNode) { + subTree.add(node) + //Есть ощущения, что то, что снизу, не совсем корректно в плане NULL-SAFETY + if(node.right != null) node.right?.let{ collectNodes(it) } + if(node.left != null) node.left?.let{ collectNodes(it) } + } + + fun buildSubTree(): TreapNode { + var baum = Treap() + for(node in subTree) baum.add(node.key, node.value) + baum.root?.let { baum.collectNodes(it) } + subTree = baum.subTree //После такого оно сохранит свойство автоматической сортировки иль як? + return subTree.first() + /* + subTree.clean() + baum.root?.let { return it } + */ + //Может быть можно не собирать массив, а просто взять корень и уже с ним работать? + } + + internal fun findParent(key: K): TreapNode? { + var parent = this.root + if (root?.key == key) return null + + while (parent != null && (parent.right != null || parent.left != null)) { + if (parent.right != null && parent.right?.key == key || parent.left != null && parent.left?.key == key) return parent + + parent = if (key > parent.key) parent.right + else parent.left } + + return null } override fun remove(key: K): V? { if(root == null) return null - if(root?.key == key && amountOfNodes == 1) { - priorQ.remove(root) + /*if(root?.key == key && amountOfNodes == 1) { amountOfNodes -= 1 root = null + }*/ + + val parent = this.findParent(key) + var count = 0 + val curNode = if (parent?.right != null && parent.right?.key == key) parent.right + else parent?.left + if(curNode?.left != null) count++ + if(curNode?.right != null) count++ + + if(count == 0) { + if(parent?.right == curNode) parent?.right = null + else parent?.left == null + } + if(count == 1) { + if(parent?.right == curNode) parent?.right = curNode?.right ?: curNode?.left + else parent?.left = curNode?.right ?: curNode?.left + } + if(count == 2) { + curNode?.right?.let { collectNodes(it) } + curNode?.left?.let { collectNodes(it) } + val result = buildSubTree() + if(parent == root) root = result + else if(parent?.right == curNode) parent?.right = result + else parent?.left == result } return null } override fun add(key: K, priority: V): TreapNode? { + val newNode = TreapNode(key, priority) if(root == null) { - root = TreapNode(key, priority) + root = newNode amountOfNodes += 1 - priorQ.add(root) return root } + var parent: TreapNode? = null + root?.let { parent = x(it, it, newNode) } - //Должны вызвать функцию X, отработать случаи когда куда добавляется новый ключ - //у нас нету ничего - //и далее работать в rebuildTree со случаями, когда там что-то всё ж имеется - //потому что она так и задумана, что применяется, когда нужно перестроить поддерево - //А ежли его нету, то и перестраивать ничего не надо + parent?.let{ + if(it.key < key) { + if(it.right == null) it.right = newNode + else { + newNode.right = it.right + collectNodes(newNode) + it.right = buildSubTree() + } + } + else if(it.key < key)( //Не забудь подумать о случае, когда добавленный ключ вже существует + if(it.left == null) it.left = newNode + else{ + newNode.left = it.left + collectNodes(newNode) + it.left = buildSubTree() + } + ) + else { + newNode.right = root + collectNodes(newNode) + root = buildSubTree() + } + + amountOfNodes += 1 + return newNode + } return root } - //Здесь мы находим родителя нашего нового ключа - //А далее по значению ключа(больше иль меньше родителя) выясняем куда оно идёт - //и работаем исходя из этого fun x(curNode: TreapNode, parent: TreapNode, node: TreapNode): TreapNode{ if(curNode.value < node.value) { - if(curNode.key < node.key) { - //We need to rebuild and build new tree with node.key as a root - //Иль попытайся придумать что-то со списками - } + if(curNode == parent) return node + return parent } if(curNode.key > node.key) { - //if(curNode.left == null) return parent + if(curNode.left == null) return curNode return x(curNode.left ?: return parent, curNode, node) } else if(curNode.key < node.key) { - //if(curNode.right == null) return parent + if(curNode.right == null) return curNode return x(curNode.right ?: return parent, curNode, node) } - else return curNode + else return curNode //Не забыть про этот случай } } \ No newline at end of file diff --git a/src/main/kotlin/treeLib/nodes/TreapNode.kt b/src/main/kotlin/treeLib/nodes/TreapNode.kt index 46ce2f4..8278d9c 100644 --- a/src/main/kotlin/treeLib/nodes/TreapNode.kt +++ b/src/main/kotlin/treeLib/nodes/TreapNode.kt @@ -5,4 +5,4 @@ class TreapNode, V: Comparable>( value: V, right: TreapNode? = null, left: TreapNode? = null -) : TreeNode>(key, priority, right, left) \ No newline at end of file +) : TreeNode>(key, value, right, left) \ No newline at end of file diff --git a/src/test/kotlin/TreapTest.kt b/src/test/kotlin/TreapTest.kt new file mode 100644 index 0000000..9125d2f --- /dev/null +++ b/src/test/kotlin/TreapTest.kt @@ -0,0 +1,52 @@ +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import treeLib.bintrees.BSTree +import treeLib.bintrees.interfaces.Treap +import treeLib.nodes.TreapNode +import kotlin.test.assertEquals + +class TreapTest { + var baum = Treap() + + + @Nested + inner class TestingAddingMethod { + + @Test + fun addingRoot() { + baum.add(24, 50) + assertEquals(TreapNode(24, 50), baum.root()) + } + + + @Test + fun addingLikeInBST() { + baum.add(4, 60) + baum.add(7, 50) + baum.add(2, 40) + baum.add(10, 30) + baum.add(-1, 20) + baum.add(3, 10) + baum.add(1, 0) + + val rt = baum.root() + + assertEquals(TreapNode(4, 60), baum.root()) + assertEquals(TreapNode(7,50), rt?.right) + assertEquals(TreapNode(2,40), rt?.left) + assertEquals(TreapNode(10,30), rt?.right?.right) + assertEquals(TreapNode(-1,20), rt?.left?.left) + assertEquals(TreapNode(3,10), rt?.left?.right) + assertEquals(TreapNode(1,0), rt?.left?.left?.right) + } + + @Test + fun changinRoot() { + baum.add(2, 10) + baum.add(4,20) + + assertEquals(TreapNode(4,20), baum.root()) + assertEquals(TreapNode(2,10), baum.root()?.left) + } + } +} \ No newline at end of file From 3a4d514e6c96751471b66216d531d00c1d1e5be9 Mon Sep 17 00:00:00 2001 From: IslamZZZZ Date: Mon, 28 Oct 2024 21:38:42 +0300 Subject: [PATCH 184/186] Almost endded Testing adding and removing and corrected them --- .../treeLib/bintrees/interfaces/Treap.kt | 32 ++-- src/test/kotlin/TreapTest.kt | 137 +++++++++++++++++- 2 files changed, 150 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt b/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt index 91f5729..7a4a66f 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt @@ -19,16 +19,14 @@ class Treap, V: Comparable > : BinTree { - var baum = Treap() + fun buildSubTree(): TreapNode? { + val baum = Treap() for(node in subTree) baum.add(node.key, node.value) - baum.root?.let { baum.collectNodes(it) } + /*baum.root?.let { baum.collectNodes(it) } subTree = baum.subTree //После такого оно сохранит свойство автоматической сортировки иль як? - return subTree.first() - /* - subTree.clean() - baum.root?.let { return it } - */ + return subTree.first()*/ + subTree.clear() + return baum.root() //Может быть можно не собирать массив, а просто взять корень и уже с ним работать? } @@ -48,10 +46,10 @@ class Treap, V: Comparable > : BinTree, V: Comparable > : BinTree, V: Comparable > : BinTree, V: Comparable > : BinTree key)( //Не забудь подумать о случае, когда добавленный ключ вже существует if(it.left == null) it.left = newNode else{ newNode.left = it.left @@ -112,8 +109,8 @@ class Treap, V: Comparable > : BinTree, V: Comparable > : BinTree, parent: TreapNode, node: TreapNode): TreapNode{ + //Добавь ? к возвращаему значению чтоб отработать случаи одинаковости ключа и/иль приоритета if(curNode.value < node.value) { if(curNode == parent) return node return parent diff --git a/src/test/kotlin/TreapTest.kt b/src/test/kotlin/TreapTest.kt index 9125d2f..909299d 100644 --- a/src/test/kotlin/TreapTest.kt +++ b/src/test/kotlin/TreapTest.kt @@ -1,3 +1,4 @@ +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import treeLib.bintrees.BSTree @@ -8,6 +9,78 @@ import kotlin.test.assertEquals class TreapTest { var baum = Treap() + @Nested + inner class TestindRemoveMethod { + + @BeforeEach + fun setUp() { + baum.add(20,100) + baum.add(50,90) + baum.add(35,80) + baum.add(40,70) + baum.add(30,60) + baum.add(70,50) + baum.add(60,40) + baum.add(80,30) + } + + @Test + fun removeNodeWithoutChildren() { + val rt = baum.root()?.right?.left + + baum.remove(40) + assertEquals(null, rt?.right) + + baum.remove(30) + assertEquals(null, rt?.left) + + baum.remove(35) + assertEquals(null, baum.root()?.right?.left) + } + + @Test + fun removeNodeWithOnlyOneChild() { + baum.remove(60) + baum.remove(80) + baum.remove(70) + assertEquals(null, baum.root()?.right?.right) + + baum.remove(50) + assertEquals(TreapNode(35, 80), baum.root()?.right) + } + + @Test + fun removeNodeWithTwoChildrenFirstCase() { + val rt = baum.root()?.right + baum.remove(35) + + assertEquals(TreapNode(40, 70), rt?.left) + assertEquals(TreapNode(30,60), rt?.left?.left) + } + + @Test + fun removeNodeWithTwoChildrenSecondCase() { + val rt = baum.root()?.right + baum.remove(70) + + assertEquals(TreapNode(60, 40), rt?.right) + assertEquals(TreapNode(80, 30), rt?.right?.right) + } + + @Test + fun removeNodeWithTwoChildrenThirdCase() { + val rt = baum.root() + baum.remove(50) + + assertEquals(TreapNode(35,80), rt?.right) + assertEquals(TreapNode(30,60), rt?.right?.left) + assertEquals(TreapNode(40,70), rt?.right?.right) + assertEquals(TreapNode(70,50), rt?.right?.right?.right) + assertEquals(TreapNode(60,40), rt?.right?.right?.right?.left) + assertEquals(TreapNode(80,30), rt?.right?.right?.right?.right) + } + } + @Nested inner class TestingAddingMethod { @@ -20,7 +93,7 @@ class TreapTest { @Test - fun addingLikeInBST() { + fun addingLikeInBSTree() { baum.add(4, 60) baum.add(7, 50) baum.add(2, 40) @@ -41,12 +114,72 @@ class TreapTest { } @Test - fun changinRoot() { + fun changingRootToLeft() { baum.add(2, 10) baum.add(4,20) assertEquals(TreapNode(4,20), baum.root()) assertEquals(TreapNode(2,10), baum.root()?.left) } + + @Test + fun changingRootToRight() { + baum.add(4, 10) + baum.add(2,20) + + assertEquals(TreapNode(2,20), baum.root()) + assertEquals(TreapNode(4,10), baum.root()?.right) + } + + @Test + fun addingLikeInBSTreeAndChangingByAddingRootLeftAndRightChildren() { + baum.add(4, 60) + baum.add(7, 50) + baum.add(2, 40) + baum.add(10, 30) + baum.add(-1, 20) + baum.add(3, 10) + baum.add(1, 0) + baum.add(11, 55) + baum.add(0, 45) + + val rt = baum.root() + + assertEquals(TreapNode(4, 60), baum.root()) + assertEquals(TreapNode(11,55), rt?.right) + assertEquals(TreapNode(0,45), rt?.left) + assertEquals(TreapNode(7,50), rt?.right?.left) + assertEquals(TreapNode(10,30), rt?.right?.left?.right) + assertEquals(TreapNode(2,40), rt?.left?.right) + assertEquals(TreapNode(3,10), rt?.left?.right?.right) + assertEquals(TreapNode(1,0), rt?.left?.right?.left) + assertEquals(TreapNode(-1,20), rt?.left?.left) + } + + @Test + fun changingSubTreesFarFromRoot() { + baum.add(20,100) + baum.add(50,90) + baum.add(35,80) + baum.add(40,70) + baum.add(30,60) + baum.add(70,50) + baum.add(60,40) + baum.add(80,30) + baum.add(32, 85) + baum.add(75, 65) + + val rt = baum.root() + + assertEquals(TreapNode(20,100), rt) + assertEquals(TreapNode(32,85), rt?.right?.left) + assertEquals(TreapNode(75,65), rt?.right?.right) + assertEquals(TreapNode(30, 60), rt?.right?.left?.left) + assertEquals(TreapNode(35,80), rt?.right?.left?.right) + assertEquals(TreapNode(40,70), rt?.right?.left?.right?.right) + assertEquals(TreapNode(80,30), rt?.right?.right?.right) + assertEquals(TreapNode(70,50), rt?.right?.right?.left) + assertEquals(TreapNode(60,40), rt?.right?.right?.left?.left) + } } } \ No newline at end of file From 56203f3bf095744c4a22636a1e00da996a67dce2 Mon Sep 17 00:00:00 2001 From: IslamZZZZ Date: Tue, 29 Oct 2024 00:25:51 +0300 Subject: [PATCH 185/186] Almost finished tests and corrected remove and add methods --- .../treeLib/bintrees/interfaces/Treap.kt | 92 +++++++++---------- src/test/kotlin/TreapTest.kt | 68 +++++++++++++- 2 files changed, 110 insertions(+), 50 deletions(-) diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt b/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt index 7a4a66f..b24a322 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt +++ b/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt @@ -14,7 +14,6 @@ class Treap, V: Comparable > : BinTree) { subTree.add(node) - //Есть ощущения, что то, что снизу, не совсем корректно в плане NULL-SAFETY if(node.right != null) node.right?.let{ collectNodes(it) } if(node.left != null) node.left?.let{ collectNodes(it) } } @@ -22,67 +21,71 @@ class Treap, V: Comparable > : BinTree? { val baum = Treap() for(node in subTree) baum.add(node.key, node.value) - /*baum.root?.let { baum.collectNodes(it) } - subTree = baum.subTree //После такого оно сохранит свойство автоматической сортировки иль як? - return subTree.first()*/ subTree.clear() return baum.root() - //Может быть можно не собирать массив, а просто взять корень и уже с ним работать? } - internal fun findParent(key: K): TreapNode? { - var parent = this.root - if (root?.key == key) return null + fun isThereSuckKey(key: K): TreapNode? { + var curNode = root - while (parent != null && (parent.right != null || parent.left != null)) { - if (parent.right != null && parent.right?.key == key || parent.left != null && parent.left?.key == key) return parent - - parent = if (key > parent.key) parent.right - else parent.left + while(curNode != null){ + curNode.let{ + if(it.key < key) curNode = it.right + else if(it.key > key) curNode = it.left + else return curNode + } } - return null + + return curNode } override fun remove(key: K): V? { - if(root == null) return null - if(root?.key == key && amountOfNodes == 1) { - amountOfNodes -= 1 - root = null - } + val curNode = isThereSuckKey(key) ?: return null + var parent: TreapNode? = null + root?.let { parent = x(it, it, curNode) } - val parent = this.findParent(key) var count = 0 - val curNode = if (parent?.right != null && parent.right?.key == key) parent.right - else parent?.left - if(curNode?.left != null) count++ - if(curNode?.right != null) count++ + if(curNode.left != null) count++ + if(curNode.right != null) count++ + if(count == 0) { - if(parent?.right == curNode) parent?.right = null + if(curNode == root) root = null + else if(parent?.right == curNode) parent?.right = null else parent?.left = null } - if(count == 1) { - if(parent?.right == curNode) parent?.right = curNode?.right ?: curNode?.left - else parent?.left = curNode?.right ?: curNode?.left + + else if(count == 1) { + if(curNode == root) root = root?.right ?: root?.left + else if(parent?.right == curNode) parent?.right = curNode.right ?: curNode.left + else parent?.left = curNode.right ?: curNode.left } - if(count == 2) { - curNode?.right?.let { collectNodes(it) } - curNode?.left?.let { collectNodes(it) } + + else if(count == 2) { + curNode.right?.let { collectNodes(it) } + curNode.left?.let { collectNodes(it) } val result = buildSubTree() - if(parent?.right == curNode) parent?.right = result + if(curNode == root) root = result + else if(parent?.right == curNode) parent?.right = result else parent?.left = result } - return null + + + return null //Why return anything else? } override fun add(key: K, priority: V): TreapNode? { + if(isThereSuckKey(key) != null) return null val newNode = TreapNode(key, priority) + if(root == null) { root = newNode amountOfNodes += 1 + return root } + var parent: TreapNode? = null root?.let { parent = x(it, it, newNode) } @@ -95,7 +98,8 @@ class Treap, V: Comparable > : BinTree key)( //Не забудь подумать о случае, когда добавленный ключ вже существует + + else if(it.key > key)( if(it.left == null) it.left = newNode else{ newNode.left = it.left @@ -103,6 +107,7 @@ class Treap, V: Comparable > : BinTree, V: Comparable > : BinTree, parent: TreapNode, node: TreapNode): TreapNode{ - //Добавь ? к возвращаему значению чтоб отработать случаи одинаковости ключа и/иль приоритета - if(curNode.value < node.value) { - if(curNode == parent) return node + if(curNode.value <= node.value) { + if(curNode == parent && node != root) return node return parent } - if(curNode.key > node.key) { - if(curNode.left == null) return curNode - return x(curNode.left ?: return parent, curNode, node) - } - else if(curNode.key < node.key) { - if(curNode.right == null) return curNode - return x(curNode.right ?: return parent, curNode, node) - } - else return curNode //Не забыть про этот случай + if(curNode.key > node.key) return x(curNode.left ?: return curNode, curNode, node) + else if(curNode.key < node.key) return x(curNode.right ?: return parent, curNode, node) + else return curNode } } \ No newline at end of file diff --git a/src/test/kotlin/TreapTest.kt b/src/test/kotlin/TreapTest.kt index 909299d..e680aea 100644 --- a/src/test/kotlin/TreapTest.kt +++ b/src/test/kotlin/TreapTest.kt @@ -10,7 +10,7 @@ class TreapTest { var baum = Treap() @Nested - inner class TestindRemoveMethod { + inner class TestingRemoveMethod { @BeforeEach fun setUp() { @@ -79,6 +79,52 @@ class TreapTest { assertEquals(TreapNode(60,40), rt?.right?.right?.right?.left) assertEquals(TreapNode(80,30), rt?.right?.right?.right?.right) } + + @Test + fun removeTheOnlyNode() { + baum.clear() + baum.add(20, 50) + baum.remove(20) + assertEquals(null, baum.root()) + } + + @Test + fun removeRootWithOnlyRightChild() { + baum.remove(20) + assertEquals(TreapNode(50, 90), baum.root()) + } + + @Test + fun removeRootWithOnlyLeftChild() { + baum.clear() + baum.add(2, 20) + baum.add(0, 10) + baum.remove(2) + + assertEquals(TreapNode(0, 10), baum.root()) + } + + @Test + fun removeRootWithTwoChildren() { + baum.add(10, 95) + baum.add(15, 45) + baum.add(0, 65) + baum.remove(20) + val rt = baum.root() + + assertEquals(TreapNode(10, 95), rt) + assertEquals(TreapNode(0,65), rt?.left) + assertEquals(TreapNode(15,45), rt?.right?.left?.left?.left) + assertEquals(TreapNode(50, 90), rt?.right) + } + + @Test + fun removeReturnNull() { + assertEquals(null, baum.remove(20)) + assertEquals(null, baum.remove(50)) + assertEquals(null, baum.remove(60)) + assertEquals(null, baum.remove(70)) + } } @@ -158,14 +204,14 @@ class TreapTest { @Test fun changingSubTreesFarFromRoot() { - baum.add(20,100) + assertEquals(TreapNode(20,100), baum.add(20,100)) baum.add(50,90) baum.add(35,80) - baum.add(40,70) + assertEquals(TreapNode(40,70), baum.add(40,70)) baum.add(30,60) baum.add(70,50) baum.add(60,40) - baum.add(80,30) + assertEquals(TreapNode(80,30), baum.add(80,30)) baum.add(32, 85) baum.add(75, 65) @@ -181,5 +227,19 @@ class TreapTest { assertEquals(TreapNode(70,50), rt?.right?.right?.left) assertEquals(TreapNode(60,40), rt?.right?.right?.left?.left) } + + @Test + fun addingAlreadyExistingKeys() { + baum.add(20,100) + baum.add(50,90) + baum.add(35,80) + baum.add(40,70) + baum.add(30,60) + + assertEquals(null, baum.add(35, 80)) + assertEquals(null, baum.add(35, 40)) + assertEquals(null, baum.add(20, 100)) + assertEquals(null, baum.add(30, 80)) + } } } \ No newline at end of file From 177dfc921985c930a377a3bfc07761bcb911c917 Mon Sep 17 00:00:00 2001 From: IslamZZZZ Date: Thu, 31 Oct 2024 15:54:19 +0300 Subject: [PATCH 186/186] refactor --- .../bintrees/{interfaces => }/Treap.kt | 15 ++- src/test/kotlin/TreapTest.kt | 103 +++++++++++------- 2 files changed, 68 insertions(+), 50 deletions(-) rename src/main/kotlin/treeLib/bintrees/{interfaces => }/Treap.kt (87%) diff --git a/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt b/src/main/kotlin/treeLib/bintrees/Treap.kt similarity index 87% rename from src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt rename to src/main/kotlin/treeLib/bintrees/Treap.kt index b24a322..156efa4 100644 --- a/src/main/kotlin/treeLib/bintrees/interfaces/Treap.kt +++ b/src/main/kotlin/treeLib/bintrees/Treap.kt @@ -1,8 +1,6 @@ -package treeLib.bintrees.interfaces +package treeLib.bintrees -import treeLib.bintrees.BSTree import treeLib.bintrees.interfaces.BinTree -import treeLib.nodes.BSTNode import treeLib.nodes.TreapNode import java.util.* @@ -43,7 +41,7 @@ class Treap, V: Comparable > : BinTree? = null - root?.let { parent = x(it, it, curNode) } + root?.let { parent = findParent(it, it, curNode) } var count = 0 if(curNode.left != null) count++ @@ -87,7 +85,7 @@ class Treap, V: Comparable > : BinTree? = null - root?.let { parent = x(it, it, newNode) } + root?.let { parent = findParent(it, it, newNode) } parent?.let{ if(it.key < key) { @@ -124,13 +122,14 @@ class Treap, V: Comparable > : BinTree, parent: TreapNode, node: TreapNode): TreapNode{ + fun findParent(curNode: TreapNode, parent: TreapNode, node: TreapNode): TreapNode{ if(curNode.value <= node.value) { if(curNode == parent && node != root) return node return parent } - if(curNode.key > node.key) return x(curNode.left ?: return curNode, curNode, node) - else if(curNode.key < node.key) return x(curNode.right ?: return parent, curNode, node) + + if(curNode.key > node.key) return findParent(curNode.left ?: return curNode, curNode, node) + else if(curNode.key < node.key) return findParent(curNode.right ?: return parent, curNode, node) else return curNode } } \ No newline at end of file diff --git a/src/test/kotlin/TreapTest.kt b/src/test/kotlin/TreapTest.kt index e680aea..389531d 100644 --- a/src/test/kotlin/TreapTest.kt +++ b/src/test/kotlin/TreapTest.kt @@ -1,14 +1,67 @@ import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test -import treeLib.bintrees.BSTree -import treeLib.bintrees.interfaces.Treap +import treeLib.bintrees.Treap import treeLib.nodes.TreapNode import kotlin.test.assertEquals class TreapTest { var baum = Treap() + @Nested + inner class removingRoots() { + @BeforeEach + fun setUp() { + baum.add(20,100) + baum.add(50,90) + baum.add(35,80) + baum.add(40,70) + baum.add(30,60) + baum.add(70,50) + baum.add(60,40) + baum.add(80,30) + } + + @Test + fun removeTheOnlyNode() { + baum.clear() + baum.add(20, 50) + baum.remove(20) + assertEquals(null, baum.root()) + } + + @Test + fun removeRootWithOnlyRightChild() { + baum.remove(20) + assertEquals(TreapNode(50, 90), baum.root()) + } + + @Test + fun removeRootWithOnlyLeftChild() { + baum.clear() + baum.add(2, 20) + baum.add(0, 10) + baum.remove(2) + + assertEquals(TreapNode(0, 10), baum.root()) + } + + @Test + fun removeRootWithTwoChildren() { + baum.add(10, 95) + baum.add(15, 45) + baum.add(0, 65) + baum.remove(20) + val rt = baum.root() + + assertEquals(TreapNode(10, 95), rt) + assertEquals(TreapNode(0,65), rt?.left) + assertEquals(TreapNode(15,45), rt?.right?.left?.left?.left) + assertEquals(TreapNode(50, 90), rt?.right) + } + + } + @Nested inner class TestingRemoveMethod { @@ -80,43 +133,6 @@ class TreapTest { assertEquals(TreapNode(80,30), rt?.right?.right?.right?.right) } - @Test - fun removeTheOnlyNode() { - baum.clear() - baum.add(20, 50) - baum.remove(20) - assertEquals(null, baum.root()) - } - - @Test - fun removeRootWithOnlyRightChild() { - baum.remove(20) - assertEquals(TreapNode(50, 90), baum.root()) - } - - @Test - fun removeRootWithOnlyLeftChild() { - baum.clear() - baum.add(2, 20) - baum.add(0, 10) - baum.remove(2) - - assertEquals(TreapNode(0, 10), baum.root()) - } - - @Test - fun removeRootWithTwoChildren() { - baum.add(10, 95) - baum.add(15, 45) - baum.add(0, 65) - baum.remove(20) - val rt = baum.root() - - assertEquals(TreapNode(10, 95), rt) - assertEquals(TreapNode(0,65), rt?.left) - assertEquals(TreapNode(15,45), rt?.right?.left?.left?.left) - assertEquals(TreapNode(50, 90), rt?.right) - } @Test fun removeReturnNull() { @@ -127,10 +143,8 @@ class TreapTest { } } - @Nested - inner class TestingAddingMethod { - + inner class BSTadding { @Test fun addingRoot() { baum.add(24, 50) @@ -158,6 +172,11 @@ class TreapTest { assertEquals(TreapNode(3,10), rt?.left?.right) assertEquals(TreapNode(1,0), rt?.left?.left?.right) } + } + + @Nested + inner class TestingAddingMethod { + @Test fun changingRootToLeft() {