From cca981b7bf5b633a645581c3e57fd78f290b7bf7 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Tue, 21 Mar 2023 22:35:47 +0000 Subject: [PATCH 001/135] Setting up GitHub Classroom Feedback From 878d075213ad08780cfbc982b6b5233d4445e3bc Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 26 Mar 2023 17:49:29 +0300 Subject: [PATCH 002/135] feat: added .gitignore, license and pull request template --- .github/pull_request_template.md | 39 ++++++ .gitignore | 30 +++++ LICENSE | 201 +++++++++++++++++++++++++++++++ NOTICE | 2 + 4 files changed, 272 insertions(+) create mode 100644 .github/pull_request_template.md create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 NOTICE diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..9e7ba22 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,39 @@ +## Title (hint) + +Describe what you've changed or added in terms of functionality. + +For example: + +> Added the `update` function to RBTree + +> Fixed an error updating the left subtree + +## Description + +Fixes ... + +Add more info _if needed_: +* context/purpose for implementing changes +* detailed description of the changes made + +## How to test + +### Automated tests + +Please specify the _automated tests_ for your code changes: you should either mention the existing tests or add the new ones. + +### Manual tests + +If it is impossible to provide the automated tests, please reason why. Usually, it is relevant only for UI- or documentation-related PRs. +If this is your case, share the detailed _manual scenarios_ that help to verify your changes. + +## Self-check list + +Check off the item if the statement is true. Hint: [x] is a marked item. + +Please do not delete the list or its items. + +- [ ] PR **title** and **description** are clear and intelligible. +- [ ] I've added enough **comments** to my code, particularly in hard-to-understand areas. +- [ ] The functionality I've repaired, changed or added is covered with **automated tests**. +- [ ] **Manual tests** have been provided optionally. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d736a56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Gradle # +.gradle + +# Compiled Class Files # +build/ +.idea +*.class + +# Log Files # +*.log + +# Package Files # +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar +*.jar +!gradle-wrapper.jar + +# Out Package # +/out/ + +# MacOS # +*.DS_Store +.AppleDouble + +# Ignore Gradle build output directory +build diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f49a4e1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..3781a1f --- /dev/null +++ b/NOTICE @@ -0,0 +1,2 @@ +Trees-6 +Copyright 2023 Kirill Shishin, Leonid Elkin, Rostislav Borisov \ No newline at end of file From eb597c12818c5bd7b7aea3ac55aac49137d40445 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 26 Mar 2023 21:26:51 +0300 Subject: [PATCH 003/135] feat: init build system gradle --- .gitattributes | 9 + BSTrees/build.gradle.kts | 19 ++ app/build.gradle.kts | 23 +++ app/src/main/kotlin/Main.kt | 3 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61608 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 244 +++++++++++++++++++++++ gradlew.bat | 92 +++++++++ settings.gradle.kts | 3 + 9 files changed, 399 insertions(+) create mode 100644 .gitattributes create mode 100644 BSTrees/build.gradle.kts create mode 100644 app/build.gradle.kts create mode 100644 app/src/main/kotlin/Main.kt 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 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..097f9f9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + diff --git a/BSTrees/build.gradle.kts b/BSTrees/build.gradle.kts new file mode 100644 index 0000000..2cf5edd --- /dev/null +++ b/BSTrees/build.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("org.jetbrains.kotlin.jvm") version "1.8.10" +} + +repositories { + mavenCentral() +} + +dependencies { + // Use the Kotlin test library. + testImplementation("org.jetbrains.kotlin:kotlin-test") + + // Use the Kotlin JUnit integration. + testImplementation("org.jetbrains.kotlin:kotlin-test-junit") +} + +tasks.getByName("test") { + useJUnitPlatform() +} diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..cdccdd3 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,23 @@ +plugins { + id("org.jetbrains.kotlin.jvm") version "1.8.10" + + application +} + +repositories { + mavenCentral() +} + +dependencies { + // Use the Kotlin test library. + testImplementation("org.jetbrains.kotlin:kotlin-test") + + // Use the Kotlin JUnit integration. + testImplementation("org.jetbrains.kotlin:kotlin-test-junit") + +} + +application { + // Define the main class for the application. + mainClass.set("MainKt") +} diff --git a/app/src/main/kotlin/Main.kt b/app/src/main/kotlin/Main.kt new file mode 100644 index 0000000..0c704e9 --- /dev/null +++ b/app/src/main/kotlin/Main.kt @@ -0,0 +1,3 @@ +fun main(){ + println("Test gradle") +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a GIT binary patch literal 61608 zcmb5VV{~QRw)Y#`wrv{~+qP{x72B%VwzFc}c2cp;N~)5ZbDrJayPv(!dGEd-##*zr z)#n-$y^sH|_dchh3@8{H5D*j;5D<{i*8l5IFJ|DjL!e)upfGNX(kojugZ3I`oH1PvW`wFW_ske0j@lB9bX zO;2)`y+|!@X(fZ1<2n!Qx*)_^Ai@Cv-dF&(vnudG?0CsddG_&Wtae(n|K59ew)6St z#dj7_(Cfwzh$H$5M!$UDd8=4>IQsD3xV=lXUq($;(h*$0^yd+b{qq63f0r_de#!o_ zXDngc>zy`uor)4A^2M#U*DC~i+dc<)Tb1Tv&~Ev@oM)5iJ4Sn#8iRw16XXuV50BS7 zdBL5Mefch(&^{luE{*5qtCZk$oFr3RH=H!c3wGR=HJ(yKc_re_X9pD` zJ;uxPzUfVpgU>DSq?J;I@a+10l0ONXPcDkiYcihREt5~T5Gb}sT0+6Q;AWHl`S5dV>lv%-p9l#xNNy7ZCr%cyqHY%TZ8Q4 zbp&#ov1*$#grNG#1vgfFOLJCaNG@K|2!W&HSh@3@Y%T?3YI75bJp!VP*$*!< z;(ffNS_;@RJ`=c7yX04!u3JP*<8jeqLHVJu#WV&v6wA!OYJS4h<_}^QI&97-;=ojW zQ-1t)7wnxG*5I%U4)9$wlv5Fr;cIizft@&N+32O%B{R1POm$oap@&f| zh+5J{>U6ftv|vAeKGc|zC=kO(+l7_cLpV}-D#oUltScw})N>~JOZLU_0{Ka2e1evz z{^a*ZrLr+JUj;)K&u2CoCAXLC2=fVScI(m_p~0FmF>>&3DHziouln?;sxW`NB}cSX z8?IsJB)Z=aYRz!X=yJn$kyOWK%rCYf-YarNqKzmWu$ZvkP12b4qH zhS9Q>j<}(*frr?z<%9hl*i^#@*O2q(Z^CN)c2c z>1B~D;@YpG?G!Yk+*yn4vM4sO-_!&m6+`k|3zd;8DJnxsBYtI;W3We+FN@|tQ5EW= z!VU>jtim0Mw#iaT8t_<+qKIEB-WwE04lBd%Letbml9N!?SLrEG$nmn7&W(W`VB@5S zaY=sEw2}i@F_1P4OtEw?xj4@D6>_e=m=797#hg}f*l^`AB|Y0# z9=)o|%TZFCY$SzgSjS|8AI-%J4x}J)!IMxY3_KYze`_I=c1nmrk@E8c9?MVRu)7+Ue79|)rBX7tVB7U|w4*h(;Gi3D9le49B38`wuv zp7{4X^p+K4*$@gU(Tq3K1a#3SmYhvI42)GzG4f|u zwQFT1n_=n|jpi=70-yE9LA+d*T8u z`=VmmXJ_f6WmZveZPct$Cgu^~gFiyL>Lnpj*6ee>*0pz=t$IJ}+rE zsf@>jlcG%Wx;Cp5x)YSVvB1$yyY1l&o zvwX=D7k)Dn;ciX?Z)Pn8$flC8#m`nB&(8?RSdBvr?>T9?E$U3uIX7T?$v4dWCa46 z+&`ot8ZTEgp7G+c52oHJ8nw5}a^dwb_l%MOh(ebVj9>_koQP^$2B~eUfSbw9RY$_< z&DDWf2LW;b0ZDOaZ&2^i^g+5uTd;GwO(-bbo|P^;CNL-%?9mRmxEw~5&z=X^Rvbo^WJW=n_%*7974RY}JhFv46> zd}`2|qkd;89l}R;i~9T)V-Q%K)O=yfVKNM4Gbacc7AOd>#^&W&)Xx!Uy5!BHnp9kh z`a(7MO6+Ren#>R^D0K)1sE{Bv>}s6Rb9MT14u!(NpZOe-?4V=>qZ>}uS)!y~;jEUK z&!U7Fj&{WdgU#L0%bM}SYXRtM5z!6M+kgaMKt%3FkjWYh=#QUpt$XX1!*XkpSq-pl zhMe{muh#knk{9_V3%qdDcWDv}v)m4t9 zQhv{;} zc{}#V^N3H>9mFM8`i`0p+fN@GqX+kl|M94$BK3J-X`Hyj8r!#x6Vt(PXjn?N)qedP z=o1T^#?1^a{;bZ&x`U{f?}TMo8ToN zkHj5v|}r}wDEi7I@)Gj+S1aE-GdnLN+$hw!=DzglMaj#{qjXi_dwpr|HL(gcCXwGLEmi|{4&4#OZ4ChceA zKVd4K!D>_N=_X;{poT~4Q+!Le+ZV>=H7v1*l%w`|`Dx8{)McN@NDlQyln&N3@bFpV z_1w~O4EH3fF@IzJ9kDk@7@QctFq8FbkbaH7K$iX=bV~o#gfh?2JD6lZf(XP>~DACF)fGFt)X%-h1yY~MJU{nA5 ze2zxWMs{YdX3q5XU*9hOH0!_S24DOBA5usB+Ws$6{|AMe*joJ?RxfV}*7AKN9V*~J zK+OMcE@bTD>TG1*yc?*qGqjBN8mgg@h1cJLDv)0!WRPIkC` zZrWXrceVw;fB%3`6kq=a!pq|hFIsQ%ZSlo~)D z|64!aCnw-?>}AG|*iOl44KVf8@|joXi&|)1rB;EQWgm+iHfVbgllP$f!$Wf42%NO5b(j9Bw6L z;0dpUUK$5GX4QbMlTmLM_jJt!ur`_0~$b#BB7FL*%XFf<b__1o)Ao3rlobbN8-(T!1d-bR8D3S0@d zLI!*GMb5s~Q<&sjd}lBb8Nr0>PqE6_!3!2d(KAWFxa{hm`@u|a(%#i(#f8{BP2wbs zt+N_slWF4IF_O|{w`c~)Xvh&R{Au~CFmW#0+}MBd2~X}t9lz6*E7uAD`@EBDe$>7W zzPUkJx<`f$0VA$=>R57^(K^h86>09?>_@M(R4q($!Ck6GG@pnu-x*exAx1jOv|>KH zjNfG5pwm`E-=ydcb+3BJwuU;V&OS=6yM^4Jq{%AVqnTTLwV`AorIDD}T&jWr8pB&j28fVtk_y*JRP^t@l*($UZ z6(B^-PBNZ+z!p?+e8@$&jCv^EWLb$WO=}Scr$6SM*&~B95El~;W_0(Bvoha|uQ1T< zO$%_oLAwf1bW*rKWmlD+@CP&$ObiDy=nh1b2ejz%LO9937N{LDe7gle4i!{}I$;&Y zkexJ9Ybr+lrCmKWg&}p=`2&Gf10orS?4$VrzWidT=*6{KzOGMo?KI0>GL0{iFWc;C z+LPq%VH5g}6V@-tg2m{C!-$fapJ9y}c$U}aUmS{9#0CM*8pC|sfer!)nG7Ji>mfRh z+~6CxNb>6eWKMHBz-w2{mLLwdA7dA-qfTu^A2yG1+9s5k zcF=le_UPYG&q!t5Zd_*E_P3Cf5T6821bO`daa`;DODm8Ih8k89=RN;-asHIigj`n=ux>*f!OC5#;X5i;Q z+V!GUy0|&Y_*8k_QRUA8$lHP;GJ3UUD08P|ALknng|YY13)}!!HW@0z$q+kCH%xet zlWf@BXQ=b=4}QO5eNnN~CzWBbHGUivG=`&eWK}beuV*;?zt=P#pM*eTuy3 zP}c#}AXJ0OIaqXji78l;YrP4sQe#^pOqwZUiiN6^0RCd#D271XCbEKpk`HI0IsN^s zES7YtU#7=8gTn#lkrc~6)R9u&SX6*Jk4GFX7){E)WE?pT8a-%6P+zS6o&A#ml{$WX zABFz#i7`DDlo{34)oo?bOa4Z_lNH>n;f0nbt$JfAl~;4QY@}NH!X|A$KgMmEsd^&Y zt;pi=>AID7ROQfr;MsMtClr5b0)xo|fwhc=qk33wQ|}$@?{}qXcmECh>#kUQ-If0$ zseb{Wf4VFGLNc*Rax#P8ko*=`MwaR-DQ8L8V8r=2N{Gaips2_^cS|oC$+yScRo*uF zUO|5=?Q?{p$inDpx*t#Xyo6=s?bbN}y>NNVxj9NZCdtwRI70jxvm3!5R7yiWjREEd zDUjrsZhS|P&|Ng5r+f^kA6BNN#|Se}_GF>P6sy^e8kBrgMv3#vk%m}9PCwUWJg-AD zFnZ=}lbi*mN-AOm zCs)r=*YQAA!`e#1N>aHF=bb*z*hXH#Wl$z^o}x##ZrUc=kh%OHWhp=7;?8%Xj||@V?1c ziWoaC$^&04;A|T)!Zd9sUzE&$ODyJaBpvqsw19Uiuq{i#VK1!htkdRWBnb z`{rat=nHArT%^R>u#CjjCkw-7%g53|&7z-;X+ewb?OLWiV|#nuc8mp*LuGSi3IP<<*Wyo9GKV7l0Noa4Jr0g3p_$ z*R9{qn=?IXC#WU>48-k5V2Oc_>P;4_)J@bo1|pf=%Rcbgk=5m)CJZ`caHBTm3%!Z9 z_?7LHr_BXbKKr=JD!%?KhwdYSdu8XxPoA{n8^%_lh5cjRHuCY9Zlpz8g+$f@bw@0V z+6DRMT9c|>1^3D|$Vzc(C?M~iZurGH2pXPT%F!JSaAMdO%!5o0uc&iqHx?ImcX6fI zCApkzc~OOnfzAd_+-DcMp&AOQxE_EsMqKM{%dRMI5`5CT&%mQO?-@F6tE*xL?aEGZ z8^wH@wRl`Izx4sDmU>}Ym{ybUm@F83qqZPD6nFm?t?(7>h*?`fw)L3t*l%*iw0Qu#?$5eq!Qc zpQvqgSxrd83NsdO@lL6#{%lsYXWen~d3p4fGBb7&5xqNYJ)yn84!e1PmPo7ChVd%4 zHUsV0Mh?VpzZD=A6%)Qrd~i7 z96*RPbid;BN{Wh?adeD_p8YU``kOrGkNox3D9~!K?w>#kFz!4lzOWR}puS(DmfjJD z`x0z|qB33*^0mZdM&6$|+T>fq>M%yoy(BEjuh9L0>{P&XJ3enGpoQRx`v6$txXt#c z0#N?b5%srj(4xmPvJxrlF3H%OMB!jvfy z;wx8RzU~lb?h_}@V=bh6p8PSb-dG|-T#A?`c&H2`_!u+uenIZe`6f~A7r)`9m8atC zt(b|6Eg#!Q*DfRU=Ix`#B_dK)nnJ_+>Q<1d7W)eynaVn`FNuN~%B;uO2}vXr5^zi2 z!ifIF5@Zlo0^h~8+ixFBGqtweFc`C~JkSq}&*a3C}L?b5Mh-bW=e)({F_g4O3 zb@SFTK3VD9QuFgFnK4Ve_pXc3{S$=+Z;;4+;*{H}Rc;845rP?DLK6G5Y-xdUKkA6E3Dz&5f{F^FjJQ(NSpZ8q-_!L3LL@H* zxbDF{gd^U3uD;)a)sJwAVi}7@%pRM&?5IaUH%+m{E)DlA_$IA1=&jr{KrhD5q&lTC zAa3c)A(K!{#nOvenH6XrR-y>*4M#DpTTOGQEO5Jr6kni9pDW`rvY*fs|ItV;CVITh z=`rxcH2nEJpkQ^(;1c^hfb8vGN;{{oR=qNyKtR1;J>CByul*+=`NydWnSWJR#I2lN zTvgnR|MBx*XFsfdA&;tr^dYaqRZp*2NwkAZE6kV@1f{76e56eUmGrZ>MDId)oqSWw z7d&r3qfazg+W2?bT}F)4jD6sWaw`_fXZGY&wnGm$FRPFL$HzVTH^MYBHWGCOk-89y zA+n+Q6EVSSCpgC~%uHfvyg@ufE^#u?JH?<73A}jj5iILz4Qqk5$+^U(SX(-qv5agK znUkfpke(KDn~dU0>gdKqjTkVk`0`9^0n_wzXO7R!0Thd@S;U`y)VVP&mOd-2 z(hT(|$=>4FY;CBY9#_lB$;|Wd$aOMT5O_3}DYXEHn&Jrc3`2JiB`b6X@EUOD zVl0S{ijm65@n^19T3l%>*;F(?3r3s?zY{thc4%AD30CeL_4{8x6&cN}zN3fE+x<9; zt2j1RRVy5j22-8U8a6$pyT+<`f+x2l$fd_{qEp_bfxfzu>ORJsXaJn4>U6oNJ#|~p z`*ZC&NPXl&=vq2{Ne79AkQncuxvbOG+28*2wU$R=GOmns3W@HE%^r)Fu%Utj=r9t` zd;SVOnA(=MXgnOzI2@3SGKHz8HN~Vpx&!Ea+Df~`*n@8O=0!b4m?7cE^K*~@fqv9q zF*uk#1@6Re_<^9eElgJD!nTA@K9C732tV~;B`hzZ321Ph=^BH?zXddiu{Du5*IPg} zqDM=QxjT!Rp|#Bkp$(mL)aar)f(dOAXUiw81pX0DC|Y4;>Vz>>DMshoips^8Frdv} zlTD=cKa48M>dR<>(YlLPOW%rokJZNF2gp8fwc8b2sN+i6&-pHr?$rj|uFgktK@jg~ zIFS(%=r|QJ=$kvm_~@n=ai1lA{7Z}i+zj&yzY+!t$iGUy|9jH#&oTNJ;JW-3n>DF+ z3aCOzqn|$X-Olu_p7brzn`uk1F*N4@=b=m;S_C?#hy{&NE#3HkATrg?enaVGT^$qIjvgc61y!T$9<1B@?_ibtDZ{G zeXInVr5?OD_nS_O|CK3|RzzMmu+8!#Zb8Ik;rkIAR%6?$pN@d<0dKD2c@k2quB%s( zQL^<_EM6ow8F6^wJN1QcPOm|ehA+dP(!>IX=Euz5qqIq}Y3;ibQtJnkDmZ8c8=Cf3 zu`mJ!Q6wI7EblC5RvP*@)j?}W=WxwCvF3*5Up_`3*a~z$`wHwCy)2risye=1mSp%p zu+tD6NAK3o@)4VBsM!@);qgsjgB$kkCZhaimHg&+k69~drbvRTacWKH;YCK(!rC?8 zP#cK5JPHSw;V;{Yji=55X~S+)%(8fuz}O>*F3)hR;STU`z6T1aM#Wd+FP(M5*@T1P z^06O;I20Sk!bxW<-O;E081KRdHZrtsGJflFRRFS zdi5w9OVDGSL3 zNrC7GVsGN=b;YH9jp8Z2$^!K@h=r-xV(aEH@#JicPy;A0k1>g1g^XeR`YV2HfmqXY zYbRwaxHvf}OlCAwHoVI&QBLr5R|THf?nAevV-=~V8;gCsX>jndvNOcFA+DI+zbh~# zZ7`qNk&w+_+Yp!}j;OYxIfx_{f0-ONc?mHCiCUak=>j>~>YR4#w# zuKz~UhT!L~GfW^CPqG8Lg)&Rc6y^{%3H7iLa%^l}cw_8UuG;8nn9)kbPGXS}p3!L_ zd#9~5CrH8xtUd?{d2y^PJg+z(xIfRU;`}^=OlehGN2=?}9yH$4Rag}*+AWotyxfCJ zHx=r7ZH>j2kV?%7WTtp+-HMa0)_*DBBmC{sd$)np&GEJ__kEd`xB5a2A z*J+yx>4o#ZxwA{;NjhU*1KT~=ZK~GAA;KZHDyBNTaWQ1+;tOFFthnD)DrCn`DjBZ% zk$N5B4^$`n^jNSOr=t(zi8TN4fpaccsb`zOPD~iY=UEK$0Y70bG{idLx@IL)7^(pL z{??Bnu=lDeguDrd%qW1)H)H`9otsOL-f4bSu};o9OXybo6J!Lek`a4ff>*O)BDT_g z<6@SrI|C9klY(>_PfA^qai7A_)VNE4c^ZjFcE$Isp>`e5fLc)rg@8Q_d^Uk24$2bn z9#}6kZ2ZxS9sI(RqT7?El2@B+($>eBQrNi_k#CDJ8D9}8$mmm z4oSKO^F$i+NG)-HE$O6s1--6EzJa?C{x=QgK&c=)b(Q9OVoAXYEEH20G|q$}Hue%~ zO3B^bF=t7t48sN zWh_zA`w~|){-!^g?6Mqf6ieV zFx~aPUOJGR=4{KsW7I?<=J2|lY`NTU=lt=%JE9H1vBpkcn=uq(q~=?iBt_-r(PLBM zP-0dxljJO>4Wq-;stY)CLB4q`-r*T$!K2o}?E-w_i>3_aEbA^MB7P5piwt1dI-6o!qWCy0 ztYy!x9arGTS?kabkkyv*yxvsPQ7Vx)twkS6z2T@kZ|kb8yjm+^$|sEBmvACeqbz)RmxkkDQX-A*K!YFziuhwb|ym>C$}U|J)4y z$(z#)GH%uV6{ec%Zy~AhK|+GtG8u@c884Nq%w`O^wv2#A(&xH@c5M`Vjk*SR_tJnq z0trB#aY)!EKW_}{#L3lph5ow=@|D5LzJYUFD6 z7XnUeo_V0DVSIKMFD_T0AqAO|#VFDc7c?c-Q%#u00F%!_TW1@JVnsfvm@_9HKWflBOUD~)RL``-!P;(bCON_4eVdduMO>?IrQ__*zE@7(OX zUtfH@AX*53&xJW*Pu9zcqxGiM>xol0I~QL5B%Toog3Jlenc^WbVgeBvV8C8AX^Vj& z^I}H})B=VboO%q1;aU5ACMh{yK4J;xlMc`jCnZR^!~LDs_MP&8;dd@4LDWw~*>#OT zeZHwdQWS!tt5MJQI~cw|Ka^b4c|qyd_ly(+Ql2m&AAw^ zQeSXDOOH!!mAgzAp0z)DD>6Xo``b6QwzUV@w%h}Yo>)a|xRi$jGuHQhJVA%>)PUvK zBQ!l0hq<3VZ*RnrDODP)>&iS^wf64C;MGqDvx>|p;35%6(u+IHoNbK z;Gb;TneFo*`zUKS6kwF*&b!U8e5m4YAo03a_e^!5BP42+r)LFhEy?_7U1IR<; z^0v|DhCYMSj<-;MtY%R@Fg;9Kky^pz_t2nJfKWfh5Eu@_l{^ph%1z{jkg5jQrkvD< z#vdK!nku*RrH~TdN~`wDs;d>XY1PH?O<4^U4lmA|wUW{Crrv#r%N>7k#{Gc44Fr|t z@UZP}Y-TrAmnEZ39A*@6;ccsR>)$A)S>$-Cj!=x$rz7IvjHIPM(TB+JFf{ehuIvY$ zsDAwREg*%|=>Hw$`us~RP&3{QJg%}RjJKS^mC_!U;E5u>`X`jW$}P`Mf}?7G7FX#{ zE(9u1SO;3q@ZhDL9O({-RD+SqqPX)`0l5IQu4q)49TUTkxR(czeT}4`WV~pV*KY&i zAl3~X%D2cPVD^B43*~&f%+Op)wl<&|D{;=SZwImydWL6@_RJjxP2g)s=dH)u9Npki zs~z9A+3fj0l?yu4N0^4aC5x)Osnm0qrhz@?nwG_`h(71P znbIewljU%T*cC=~NJy|)#hT+lx#^5MuDDnkaMb*Efw9eThXo|*WOQzJ*#3dmRWm@! zfuSc@#kY{Um^gBc^_Xdxnl!n&y&}R4yAbK&RMc+P^Ti;YIUh|C+K1|=Z^{nZ}}rxH*v{xR!i%qO~o zTr`WDE@k$M9o0r4YUFFeQO7xCu_Zgy)==;fCJ94M_rLAv&~NhfvcLWCoaGg2ao~3e zBG?Ms9B+efMkp}7BhmISGWmJsKI@a8b}4lLI48oWKY|8?zuuNc$lt5Npr+p7a#sWu zh!@2nnLBVJK!$S~>r2-pN||^w|fY`CT{TFnJy`B|e5;=+_v4l8O-fkN&UQbA4NKTyntd zqK{xEKh}U{NHoQUf!M=2(&w+eef77VtYr;xs%^cPfKLObyOV_9q<(%76-J%vR>w9!us-0c-~Y?_EVS%v!* z15s2s3eTs$Osz$JayyH|5nPAIPEX=U;r&p;K14G<1)bvn@?bM5kC{am|C5%hyxv}a z(DeSKI5ZfZ1*%dl8frIX2?);R^^~LuDOpNpk-2R8U1w92HmG1m&|j&J{EK=|p$;f9 z7Rs5|jr4r8k5El&qcuM+YRlKny%t+1CgqEWO>3;BSRZi(LA3U%Jm{@{y+A+w(gzA< z7dBq6a1sEWa4cD0W7=Ld9z0H7RI^Z7vl(bfA;72j?SWCo`#5mVC$l1Q2--%V)-uN* z9ha*s-AdfbDZ8R8*fpwjzx=WvOtmSzGFjC#X)hD%Caeo^OWjS(3h|d9_*U)l%{Ab8 zfv$yoP{OuUl@$(-sEVNt{*=qi5P=lpxWVuz2?I7Dc%BRc+NGNw+323^ z5BXGfS71oP^%apUo(Y#xkxE)y?>BFzEBZ}UBbr~R4$%b7h3iZu3S(|A;&HqBR{nK& z$;GApNnz=kNO^FL&nYcfpB7Qg;hGJPsCW44CbkG1@l9pn0`~oKy5S777uH)l{irK!ru|X+;4&0D;VE*Ii|<3P zUx#xUqvZT5kVQxsF#~MwKnv7;1pR^0;PW@$@T7I?s`_rD1EGUdSA5Q(C<>5SzE!vw z;{L&kKFM-MO>hy#-8z`sdVx})^(Dc-dw;k-h*9O2_YZw}|9^y-|8RQ`BWJUJL(Cer zP5Z@fNc>pTXABbTRY-B5*MphpZv6#i802giwV&SkFCR zGMETyUm(KJbh+&$8X*RB#+{surjr;8^REEt`2&Dubw3$mx>|~B5IKZJ`s_6fw zKAZx9&PwBqW1Oz0r0A4GtnZd7XTKViX2%kPfv+^X3|_}RrQ2e3l=KG_VyY`H?I5&CS+lAX5HbA%TD9u6&s#v!G> zzW9n4J%d5ye7x0y`*{KZvqyXUfMEE^ZIffzI=Hh|3J}^yx7eL=s+TPH(Q2GT-sJ~3 zI463C{(ag7-hS1ETtU;_&+49ABt5!A7CwLwe z=SoA8mYZIQeU;9txI=zcQVbuO%q@E)JI+6Q!3lMc=Gbj(ASg-{V27u>z2e8n;Nc*pf}AqKz1D>p9G#QA+7mqqrEjGfw+85Uyh!=tTFTv3|O z+)-kFe_8FF_EkTw!YzwK^Hi^_dV5x-Ob*UWmD-})qKj9@aE8g240nUh=g|j28^?v7 zHRTBo{0KGaWBbyX2+lx$wgXW{3aUab6Bhm1G1{jTC7ota*JM6t+qy)c5<@ zpc&(jVdTJf(q3xB=JotgF$X>cxh7k*(T`-V~AR+`%e?YOeALQ2Qud( zz35YizXt(aW3qndR}fTw1p()Ol4t!D1pitGNL95{SX4ywzh0SF;=!wf=?Q?_h6!f* zh7<+GFi)q|XBsvXZ^qVCY$LUa{5?!CgwY?EG;*)0ceFe&=A;!~o`ae}Z+6me#^sv- z1F6=WNd6>M(~ z+092z>?Clrcp)lYNQl9jN-JF6n&Y0mp7|I0dpPx+4*RRK+VQI~>en0Dc;Zfl+x z_e_b7s`t1_A`RP3$H}y7F9_na%D7EM+**G_Z0l_nwE+&d_kc35n$Fxkd4r=ltRZhh zr9zER8>j(EdV&Jgh(+i}ltESBK62m0nGH6tCBr90!4)-`HeBmz54p~QP#dsu%nb~W z7sS|(Iydi>C@6ZM(Us!jyIiszMkd)^u<1D+R@~O>HqZIW&kearPWmT>63%_t2B{_G zX{&a(gOYJx!Hq=!T$RZ&<8LDnxsmx9+TBL0gTk$|vz9O5GkK_Yx+55^R=2g!K}NJ3 zW?C;XQCHZl7H`K5^BF!Q5X2^Mj93&0l_O3Ea3!Ave|ixx+~bS@Iv18v2ctpSt4zO{ zp#7pj!AtDmti$T`e9{s^jf(ku&E|83JIJO5Qo9weT6g?@vX!{7)cNwymo1+u(YQ94 zopuz-L@|5=h8A!(g-MXgLJC0MA|CgQF8qlonnu#j z;uCeq9ny9QSD|p)9sp3ebgY3rk#y0DA(SHdh$DUm^?GI<>%e1?&}w(b zdip1;P2Z=1wM+$q=TgLP$}svd!vk+BZ@h<^4R=GS2+sri7Z*2f`9 z5_?i)xj?m#pSVchk-SR!2&uNhzEi+#5t1Z$o0PoLGz*pT64%+|Wa+rd5Z}60(j?X= z{NLjtgRb|W?CUADqOS@(*MA-l|E342NxRaxLTDqsOyfWWe%N(jjBh}G zm7WPel6jXijaTiNita+z(5GCO0NM=Melxud57PP^d_U## zbA;9iVi<@wr0DGB8=T9Ab#2K_#zi=$igyK48@;V|W`fg~7;+!q8)aCOo{HA@vpSy-4`^!ze6-~8|QE||hC{ICKllG9fbg_Y7v z$jn{00!ob3!@~-Z%!rSZ0JO#@>|3k10mLK0JRKP-Cc8UYFu>z93=Ab-r^oL2 zl`-&VBh#=-?{l1TatC;VweM^=M7-DUE>m+xO7Xi6vTEsReyLs8KJ+2GZ&rxw$d4IT zPXy6pu^4#e;;ZTsgmG+ZPx>piodegkx2n0}SM77+Y*j^~ICvp#2wj^BuqRY*&cjmL zcKp78aZt>e{3YBb4!J_2|K~A`lN=u&5j!byw`1itV(+Q_?RvV7&Z5XS1HF)L2v6ji z&kOEPmv+k_lSXb{$)of~(BkO^py&7oOzpjdG>vI1kcm_oPFHy38%D4&A4h_CSo#lX z2#oqMCTEP7UvUR3mwkPxbl8AMW(e{ARi@HCYLPSHE^L<1I}OgZD{I#YH#GKnpRmW3 z2jkz~Sa(D)f?V?$gNi?6)Y;Sm{&?~2p=0&BUl_(@hYeX8YjaRO=IqO7neK0RsSNdYjD zaw$g2sG(>JR=8Iz1SK4`*kqd_3-?;_BIcaaMd^}<@MYbYisWZm2C2|Np_l|8r9yM|JkUngSo@?wci(7&O9a z%|V(4C1c9pps0xxzPbXH=}QTxc2rr7fXk$9`a6TbWKPCz&p=VsB8^W96W=BsB|7bc zf(QR8&Ktj*iz)wK&mW`#V%4XTM&jWNnDF56O+2bo<3|NyUhQ%#OZE8$Uv2a@J>D%t zMVMiHh?es!Ex19q&6eC&L=XDU_BA&uR^^w>fpz2_`U87q_?N2y;!Z!bjoeKrzfC)} z?m^PM=(z{%n9K`p|7Bz$LuC7!>tFOuN74MFELm}OD9?%jpT>38J;=1Y-VWtZAscaI z_8jUZ#GwWz{JqvGEUmL?G#l5E=*m>`cY?m*XOc*yOCNtpuIGD+Z|kn4Xww=BLrNYS zGO=wQh}Gtr|7DGXLF%|`G>J~l{k^*{;S-Zhq|&HO7rC_r;o`gTB7)uMZ|WWIn@e0( zX$MccUMv3ABg^$%_lNrgU{EVi8O^UyGHPNRt%R!1#MQJn41aD|_93NsBQhP80yP<9 zG4(&0u7AtJJXLPcqzjv`S~5;Q|5TVGccN=Uzm}K{v)?f7W!230C<``9(64}D2raRU zAW5bp%}VEo{4Rko`bD%Ehf=0voW?-4Mk#d3_pXTF!-TyIt6U+({6OXWVAa;s-`Ta5 zTqx&8msH3+DLrVmQOTBOAj=uoxKYT3DS1^zBXM?1W+7gI!aQNPYfUl{3;PzS9*F7g zWJN8x?KjBDx^V&6iCY8o_gslO16=kh(|Gp)kz8qlQ`dzxQv;)V&t+B}wwdi~uBs4? zu~G|}y!`3;8#vIMUdyC7YEx6bb^1o}G!Jky4cN?BV9ejBfN<&!4M)L&lRKiuMS#3} z_B}Nkv+zzxhy{dYCW$oGC&J(Ty&7%=5B$sD0bkuPmj7g>|962`(Q{ZZMDv%YMuT^KweiRDvYTEop3IgFv#)(w>1 zSzH>J`q!LK)c(AK>&Ib)A{g`Fdykxqd`Yq@yB}E{gnQV$K!}RsgMGWqC3DKE(=!{}ekB3+(1?g}xF>^icEJbc z5bdxAPkW90atZT+&*7qoLqL#p=>t-(-lsnl2XMpZcYeW|o|a322&)yO_8p(&Sw{|b zn(tY$xn5yS$DD)UYS%sP?c|z>1dp!QUD)l;aW#`%qMtQJjE!s2z`+bTSZmLK7SvCR z=@I4|U^sCwZLQSfd*ACw9B@`1c1|&i^W_OD(570SDLK`MD0wTiR8|$7+%{cF&){$G zU~|$^Ed?TIxyw{1$e|D$050n8AjJvvOWhLtLHbSB|HIfjMp+gu>DraHZJRrdO53(= z+o-f{+qNog+qSLB%KY;5>Av6X(>-qYk3IIEwZ5~6a+P9lMpC^ z8CJ0q>rEpjlsxCvJm=kms@tlN4+sv}He`xkr`S}bGih4t`+#VEIt{1veE z{ZLtb_pSbcfcYPf4=T1+|BtR!x5|X#x2TZEEkUB6kslKAE;x)*0x~ES0kl4Dex4e- zT2P~|lT^vUnMp{7e4OExfxak0EE$Hcw;D$ehTV4a6hqxru0$|Mo``>*a5=1Ym0u>BDJKO|=TEWJ5jZu!W}t$Kv{1!q`4Sn7 zrxRQOt>^6}Iz@%gA3&=5r;Lp=N@WKW;>O!eGIj#J;&>+3va^~GXRHCY2}*g#9ULab zitCJt-OV0*D_Q3Q`p1_+GbPxRtV_T`jyATjax<;zZ?;S+VD}a(aN7j?4<~>BkHK7bO8_Vqfdq1#W&p~2H z&w-gJB4?;Q&pG9%8P(oOGZ#`!m>qAeE)SeL*t8KL|1oe;#+uOK6w&PqSDhw^9-&Fa zuEzbi!!7|YhlWhqmiUm!muO(F8-F7|r#5lU8d0+=;<`{$mS=AnAo4Zb^{%p}*gZL! zeE!#-zg0FWsSnablw!9$<&K(#z!XOW z;*BVx2_+H#`1b@>RtY@=KqD)63brP+`Cm$L1@ArAddNS1oP8UE$p05R=bvZoYz+^6 z<)!v7pRvi!u_-V?!d}XWQR1~0q(H3{d^4JGa=W#^Z<@TvI6J*lk!A zZ*UIKj*hyO#5akL*Bx6iPKvR3_2-^2mw|Rh-3O_SGN3V9GRo52Q;JnW{iTGqb9W99 z7_+F(Op6>~3P-?Q8LTZ-lwB}xh*@J2Ni5HhUI3`ct|*W#pqb>8i*TXOLn~GlYECIj zhLaa_rBH|1jgi(S%~31Xm{NB!30*mcsF_wgOY2N0XjG_`kFB+uQuJbBm3bIM$qhUyE&$_u$gb zpK_r{99svp3N3p4yHHS=#csK@j9ql*>j0X=+cD2dj<^Wiu@i>c_v zK|ovi7}@4sVB#bzq$n3`EgI?~xDmkCW=2&^tD5RuaSNHf@Y!5C(Is$hd6cuyoK|;d zO}w2AqJPS`Zq+(mc*^%6qe>1d&(n&~()6-ZATASNPsJ|XnxelLkz8r1x@c2XS)R*H(_B=IN>JeQUR;T=i3<^~;$<+8W*eRKWGt7c#>N`@;#!`kZ!P!&{9J1>_g8Zj zXEXxmA=^{8A|3=Au+LfxIWra)4p<}1LYd_$1KI0r3o~s1N(x#QYgvL4#2{z8`=mXy zQD#iJ0itk1d@Iy*DtXw)Wz!H@G2St?QZFz zVPkM%H8Cd2EZS?teQN*Ecnu|PrC!a7F_XX}AzfZl3fXfhBtc2-)zaC2eKx*{XdM~QUo4IwcGgVdW69 z1UrSAqqMALf^2|(I}hgo38l|Ur=-SC*^Bo5ej`hb;C$@3%NFxx5{cxXUMnTyaX{>~ zjL~xm;*`d08bG_K3-E+TI>#oqIN2=An(C6aJ*MrKlxj?-;G zICL$hi>`F%{xd%V{$NhisHSL~R>f!F7AWR&7b~TgLu6!3s#~8|VKIX)KtqTH5aZ8j zY?wY)XH~1_a3&>#j7N}0az+HZ;is;Zw(Am{MX}YhDTe(t{ZZ;TG}2qWYO+hdX}vp9 z@uIRR8g#y~-^E`Qyem(31{H0&V?GLdq9LEOb2(ea#e-$_`5Q{T%E?W(6 z(XbX*Ck%TQM;9V2LL}*Tf`yzai{0@pYMwBu%(I@wTY!;kMrzcfq0w?X`+y@0ah510 zQX5SU(I!*Fag4U6a7Lw%LL;L*PQ}2v2WwYF(lHx_Uz2ceI$mnZ7*eZ?RFO8UvKI0H z9Pq-mB`mEqn6n_W9(s~Jt_D~j!Ln9HA)P;owD-l~9FYszs)oEKShF9Zzcmnb8kZ7% zQ`>}ki1kwUO3j~ zEmh140sOkA9v>j@#56ymn_RnSF`p@9cO1XkQy6_Kog?0ivZDb`QWOX@tjMd@^Qr(p z!sFN=A)QZm!sTh(#q%O{Ovl{IxkF!&+A)w2@50=?a-+VuZt6On1;d4YtUDW{YNDN_ zG@_jZi1IlW8cck{uHg^g=H58lPQ^HwnybWy@@8iw%G! zwB9qVGt_?~M*nFAKd|{cGg+8`+w{j_^;nD>IrPf-S%YjBslSEDxgKH{5p)3LNr!lD z4ii)^%d&cCXIU7UK?^ZQwmD(RCd=?OxmY(Ko#+#CsTLT;p#A%{;t5YpHFWgl+@)N1 zZ5VDyB;+TN+g@u~{UrWrv)&#u~k$S&GeW)G{M#&Di)LdYk?{($Cq zZGMKeYW)aMtjmKgvF0Tg>Mmkf9IB#2tYmH-s%D_9y3{tfFmX1BSMtbe<(yqAyWX60 zzkgSgKb3c{QPG2MalYp`7mIrYg|Y<4Jk?XvJK)?|Ecr+)oNf}XLPuTZK%W>;<|r+% zTNViRI|{sf1v7CsWHvFrkQ$F7+FbqPQ#Bj7XX=#M(a~9^80}~l-DueX#;b}Ajn3VE z{BWI}$q{XcQ3g{(p>IOzFcAMDG0xL)H%wA)<(gl3I-oVhK~u_m=hAr&oeo|4lZbf} z+pe)c34Am<=z@5!2;_lwya;l?xV5&kWe}*5uBvckm(d|7R>&(iJNa6Y05SvlZcWBlE{{%2- z`86)Y5?H!**?{QbzGG~|k2O%eA8q=gxx-3}&Csf6<9BsiXC)T;x4YmbBIkNf;0Nd5 z%whM^!K+9zH>on_<&>Ws?^v-EyNE)}4g$Fk?Z#748e+GFp)QrQQETx@u6(1fk2!(W zWiCF~MomG*y4@Zk;h#2H8S@&@xwBIs|82R*^K(i*0MTE%Rz4rgO&$R zo9Neb;}_ulaCcdn3i17MO3NxzyJ=l;LU*N9ztBJ30j=+?6>N4{9YXg$m=^9@Cl9VY zbo^{yS@gU=)EpQ#;UIQBpf&zfCA;00H-ee=1+TRw@(h%W=)7WYSb5a%$UqNS@oI@= zDrq|+Y9e&SmZrH^iA>Of8(9~Cf-G(P^5Xb%dDgMMIl8gk6zdyh`D3OGNVV4P9X|EvIhplXDld8d z^YWtYUz@tpg*38Xys2?zj$F8%ivA47cGSl;hjD23#*62w3+fwxNE7M7zVK?x_`dBSgPK zWY_~wF~OEZi9|~CSH8}Xi>#8G73!QLCAh58W+KMJJC81{60?&~BM_0t-u|VsPBxn* zW7viEKwBBTsn_A{g@1!wnJ8@&h&d>!qAe+j_$$Vk;OJq`hrjzEE8Wjtm)Z>h=*M25 zOgETOM9-8xuuZ&^@rLObtcz>%iWe%!uGV09nUZ*nxJAY%&KAYGY}U1WChFik7HIw% zZP$3Bx|TG_`~19XV7kfi2GaBEhKap&)Q<9`aPs#^!kMjtPb|+-fX66z3^E)iwyXK7 z8)_p<)O{|i&!qxtgBvWXx8*69WO$5zACl++1qa;)0zlXf`eKWl!0zV&I`8?sG)OD2Vy?reNN<{eK+_ za4M;Hh%&IszR%)&gpgRCP}yheQ+l#AS-GnY81M!kzhWxIR?PW`G3G?} z$d%J28uQIuK@QxzGMKU_;r8P0+oIjM+k)&lZ39i#(ntY)*B$fdJnQ3Hw3Lsi8z&V+ zZly2}(Uzpt2aOubRjttzqrvinBFH4jrN)f0hy)tj4__UTwN)#1fj3-&dC_Vh7}ri* zfJ=oqLMJ-_<#rwVyN}_a-rFBe2>U;;1(7UKH!$L??zTbbzP#bvyg7OQBGQklJ~DgP zd<1?RJ<}8lWwSL)`jM53iG+}y2`_yUvC!JkMpbZyb&50V3sR~u+lok zT0uFRS-yx@8q4fPRZ%KIpLp8R#;2%c&Ra4p(GWRT4)qLaPNxa&?8!LRVdOUZ)2vrh zBSx&kB%#Y4!+>~)<&c>D$O}!$o{<1AB$M7-^`h!eW;c(3J~ztoOgy6Ek8Pwu5Y`Xion zFl9fb!k2`3uHPAbd(D^IZmwR5d8D$495nN2`Ue&`W;M-nlb8T-OVKt|fHk zBpjX$a(IR6*-swdNk@#}G?k6F-~c{AE0EWoZ?H|ZpkBxqU<0NUtvubJtwJ1mHV%9v?GdDw; zAyXZiD}f0Zdt-cl9(P1la+vQ$Er0~v}gYJVwQazv zH#+Z%2CIfOf90fNMGos|{zf&N`c0@x0N`tkFv|_9af3~<0z@mnf*e;%r*Fbuwl-IW z{}B3=(mJ#iwLIPiUP`J3SoP~#)6v;aRXJ)A-pD2?_2_CZ#}SAZ<#v7&Vk6{*i(~|5 z9v^nC`T6o`CN*n%&9+bopj^r|E(|pul;|q6m7Tx+U|UMjWK8o-lBSgc3ZF=rP{|l9 zc&R$4+-UG6i}c==!;I#8aDIbAvgLuB66CQLRoTMu~jdw`fPlKy@AKYWS-xyZzPg&JRAa@m-H43*+ne!8B7)HkQY4 zIh}NL4Q79a-`x;I_^>s$Z4J4-Ngq=XNWQ>yAUCoe&SMAYowP>r_O}S=V+3=3&(O=h zNJDYNs*R3Y{WLmBHc?mFEeA4`0Y`_CN%?8qbDvG2m}kMAiqCv`_BK z_6a@n`$#w6Csr@e2YsMx8udNWtNt=kcqDZdWZ-lGA$?1PA*f4?X*)hjn{sSo8!bHz zb&lGdAgBx@iTNPK#T_wy`KvOIZvTWqSHb=gWUCKXAiB5ckQI`1KkPx{{%1R*F2)Oc z(9p@yG{fRSWE*M9cdbrO^)8vQ2U`H6M>V$gK*rz!&f%@3t*d-r3mSW>D;wYxOhUul zk~~&ip5B$mZ~-F1orsq<|1bc3Zpw6)Ws5;4)HilsN;1tx;N6)tuePw& z==OlmaN*ybM&-V`yt|;vDz(_+UZ0m&&9#{9O|?0I|4j1YCMW;fXm}YT$0%EZ5^YEI z4i9WV*JBmEU{qz5O{#bs`R1wU%W$qKx?bC|e-iS&d*Qm7S=l~bMT{~m3iZl+PIXq{ zn-c~|l)*|NWLM%ysfTV-oR0AJ3O>=uB-vpld{V|cWFhI~sx>ciV9sPkC*3i0Gg_9G!=4ar*-W?D9)?EFL1=;O+W8}WGdp8TT!Fgv z{HKD`W>t(`Cds_qliEzuE!r{ihwEv1l5o~iqlgjAyGBi)$%zNvl~fSlg@M=C{TE;V zQkH`zS8b&!ut(m)%4n2E6MB>p*4(oV>+PT51#I{OXs9j1vo>9I<4CL1kv1aurV*AFZ^w_qfVL*G2rG@D2 zrs87oV3#mf8^E5hd_b$IXfH6vHe&lm@7On~Nkcq~YtE!}ad~?5*?X*>y`o;6Q9lkk zmf%TYonZM`{vJg$`lt@MXsg%*&zZZ0uUSse8o=!=bfr&DV)9Y6$c!2$NHyYAQf*Rs zk{^?gl9E z5Im8wlAsvQ6C2?DyG@95gUXZ3?pPijug25g;#(esF_~3uCj3~94}b*L>N2GSk%Qst z=w|Z>UX$m!ZOd(xV*2xvWjN&c5BVEdVZ0wvmk)I+YxnyK%l~caR=7uNQ=+cnNTLZ@&M!I$Mj-r{!P=; z`C2)D=VmvK8@T5S9JZoRtN!S*D_oqOxyy!q6Zk|~4aT|*iRN)fL)c>-yycR>-is0X zKrko-iZw(f(!}dEa?hef5yl%p0-v-8#8CX8!W#n2KNyT--^3hq6r&`)5Y@>}e^4h- zlPiDT^zt}Ynk&x@F8R&=)k8j$=N{w9qUcIc&)Qo9u4Y(Ae@9tA`3oglxjj6c{^pN( zQH+Uds2=9WKjH#KBIwrQI%bbs`mP=7V>rs$KG4|}>dxl_k!}3ZSKeEen4Iswt96GGw`E6^5Ov)VyyY}@itlj&sao|>Sb5 zeY+#1EK(}iaYI~EaHQkh7Uh>DnzcfIKv8ygx1Dv`8N8a6m+AcTa-f;17RiEed>?RT zk=dAksmFYPMV1vIS(Qc6tUO+`1jRZ}tcDP? zt)=7B?yK2RcAd1+Y!$K5*ds=SD;EEqCMG6+OqPoj{&8Y5IqP(&@zq@=A7+X|JBRi4 zMv!czlMPz)gt-St2VZwDD=w_S>gRpc-g zUd*J3>bXeZ?Psjohe;z7k|d<*T21PA1i)AOi8iMRwTBSCd0ses{)Q`9o&p9rsKeLaiY zluBw{1r_IFKR76YCAfl&_S1*(yFW8HM^T()&p#6y%{(j7Qu56^ZJx1LnN`-RTwimdnuo*M8N1ISl+$C-%=HLG-s} zc99>IXRG#FEWqSV9@GFW$V8!{>=lSO%v@X*pz*7()xb>=yz{E$3VE;e)_Ok@A*~El zV$sYm=}uNlUxV~6e<6LtYli1!^X!Ii$L~j4e{sI$tq_A(OkGquC$+>Rw3NFObV2Z)3Rt~Jr{oYGnZaFZ^g5TDZlg;gaeIP} z!7;T{(9h7mv{s@piF{-35L=Ea%kOp;^j|b5ZC#xvD^^n#vPH=)lopYz1n?Kt;vZmJ z!FP>Gs7=W{sva+aO9S}jh0vBs+|(B6Jf7t4F^jO3su;M13I{2rd8PJjQe1JyBUJ5v zcT%>D?8^Kp-70bP8*rulxlm)SySQhG$Pz*bo@mb5bvpLAEp${?r^2!Wl*6d7+0Hs_ zGPaC~w0E!bf1qFLDM@}zso7i~(``)H)zRgcExT_2#!YOPtBVN5Hf5~Ll3f~rWZ(UsJtM?O*cA1_W0)&qz%{bDoA}{$S&-r;0iIkIjbY~ zaAqH45I&ALpP=9Vof4OapFB`+_PLDd-0hMqCQq08>6G+C;9R~}Ug_nm?hhdkK$xpI zgXl24{4jq(!gPr2bGtq+hyd3%Fg%nofK`psHMs}EFh@}sdWCd!5NMs)eZg`ZlS#O0 zru6b8#NClS(25tXqnl{|Ax@RvzEG!+esNW-VRxba(f`}hGoqci$U(g30i}2w9`&z= zb8XjQLGN!REzGx)mg~RSBaU{KCPvQx8)|TNf|Oi8KWgv{7^tu}pZq|BS&S<53fC2K4Fw6>M^s$R$}LD*sUxdy6Pf5YKDbVet;P!bw5Al-8I1Nr(`SAubX5^D9hk6$agWpF}T#Bdf{b9-F#2WVO*5N zp+5uGgADy7m!hAcFz{-sS0kM7O)qq*rC!>W@St~^OW@R1wr{ajyYZq5H!T?P0e+)a zaQ%IL@X_`hzp~vRH0yUblo`#g`LMC%9}P;TGt+I7qNcBSe&tLGL4zqZqB!Bfl%SUa z6-J_XLrnm*WA`34&mF+&e1sPCP9=deazrM=Pc4Bn(nV;X%HG^4%Afv4CI~&l!Sjzb z{rHZ3od0!Al{}oBO>F*mOFAJrz>gX-vs!7>+_G%BB(ljWh$252j1h;9p~xVA=9_`P z5KoFiz96_QsTK%B&>MSXEYh`|U5PjX1(+4b#1PufXRJ*uZ*KWdth1<0 zsAmgjT%bowLyNDv7bTUGy|g~N34I-?lqxOUtFpTLSV6?o?<7-UFy*`-BEUsrdANh} zBWkDt2SAcGHRiqz)x!iVoB~&t?$yn6b#T=SP6Ou8lW=B>=>@ik93LaBL56ub`>Uo!>0@O8?e)$t(sgy$I z6tk3nS@yFFBC#aFf?!d_3;%>wHR;A3f2SP?Na8~$r5C1N(>-ME@HOpv4B|Ty7%jAv zR}GJwsiJZ5@H+D$^Cwj#0XA_(m^COZl8y7Vv(k=iav1=%QgBOVzeAiw zaDzzdrxzj%sE^c9_uM5D;$A_7)Ln}BvBx^=)fO+${ou%B*u$(IzVr-gH3=zL6La;G zu0Kzy5CLyNGoKRtK=G0-w|tnwI)puPDOakRzG(}R9fl7#<|oQEX;E#yCWVg95 z;NzWbyF&wGg_k+_4x4=z1GUcn6JrdX4nOVGaAQ8#^Ga>aFvajQN{!+9rgO-dHP zIp@%&ebVg}IqnRWwZRTNxLds+gz2@~VU(HI=?Epw>?yiEdZ>MjajqlO>2KDxA>)cj z2|k%dhh%d8SijIo1~20*5YT1eZTDkN2rc^zWr!2`5}f<2f%M_$to*3?Ok>e9$X>AV z2jYmfAd)s|(h?|B(XYrIfl=Wa_lBvk9R1KaP{90-z{xKi+&8=dI$W0+qzX|ZovWGOotP+vvYR(o=jo?k1=oG?%;pSqxcU* zWVGVMw?z__XQ9mnP!hziHC`ChGD{k#SqEn*ph6l46PZVkm>JF^Q{p&0=MKy_6apts z`}%_y+Tl_dSP(;Ja&sih$>qBH;bG;4;75)jUoVqw^}ee=ciV;0#t09AOhB^Py7`NC z-m+ybq1>_OO+V*Z>dhk}QFKA8V?9Mc4WSpzj{6IWfFpF7l^au#r7&^BK2Ac7vCkCn{m0uuN93Ee&rXfl1NBY4NnO9lFUp zY++C1I;_{#OH#TeP2Dp?l4KOF8ub?m6zE@XOB5Aiu$E~QNBM@;r+A5mF2W1-c7>ex zHiB=WJ&|`6wDq*+xv8UNLVUy4uW1OT>ey~Xgj@MMpS@wQbHAh>ysYvdl-1YH@&+Q! z075(Qd4C!V`9Q9jI4 zSt{HJRvZec>vaL_brKhQQwbpQd4_Lmmr0@1GdUeU-QcC{{8o=@nwwf>+dIKFVzPriGNX4VjHCa zTbL9w{Y2V87c2ofX%`(48A+4~mYTiFFl!e{3K^C_k%{&QTsgOd0*95KmWN)P}m zTRr{`f7@=v#+z_&fKYkQT!mJn{*crj%ZJz#(+c?>cD&2Lo~FFAWy&UG*Op^pV`BR^I|g?T>4l5;b|5OQ@t*?_Slp`*~Y3`&RfKD^1uLezIW(cE-Dq2z%I zBi8bWsz0857`6e!ahet}1>`9cYyIa{pe53Kl?8|Qg2RGrx@AlvG3HAL-^9c^1GW;)vQt8IK+ zM>!IW*~682A~MDlyCukldMd;8P|JCZ&oNL(;HZgJ>ie1PlaInK7C@Jg{3kMKYui?e!b`(&?t6PTb5UPrW-6DVU%^@^E`*y-Fd(p|`+JH&MzfEq;kikdse ziFOiDWH(D< zyV7Rxt^D0_N{v?O53N$a2gu%1pxbeK;&ua`ZkgSic~$+zvt~|1Yb=UfKJW2F7wC^evlPf(*El+#}ZBy0d4kbVJsK- z05>;>?HZO(YBF&v5tNv_WcI@O@LKFl*VO?L(!BAd!KbkVzo;v@~3v`-816GG?P zY+H3ujC>5=Am3RIZDdT#0G5A6xe`vGCNq88ZC1aVXafJkUlcYmHE^+Z{*S->ol%-O znm9R0TYTr2w*N8Vs#s-5=^w*{Y}qp5GG)Yt1oLNsH7y~N@>Eghms|K*Sdt_u!&I}$ z+GSdFTpbz%KH+?B%Ncy;C`uW6oWI46(tk>r|5|-K6)?O0d_neghUUOa9BXHP*>vi; z={&jIGMn-92HvInCMJcyXwHTJ42FZp&Wxu+9Rx;1x(EcIQwPUQ@YEQQ`bbMy4q3hP zNFoq~Qd0=|xS-R}k1Im3;8s{BnS!iaHIMLx)aITl)+)?Yt#fov|Eh>}dv@o6R{tG>uHsy&jGmWN5+*wAik|78(b?jtysPHC#e+Bzz~V zS3eEXv7!Qn4uWi!FS3B?afdD*{fr9>B~&tc671fi--V}~E4un;Q|PzZRwk-azprM$4AesvUb5`S`(5x#5VJ~4%ET6&%GR$}muHV-5lTsCi_R|6KM(g2PCD@|yOpKluT zakH!1V7nKN)?6JmC-zJoA#ciFux8!)ajiY%K#RtEg$gm1#oKUKX_Ms^%hvKWi|B=~ zLbl-L)-=`bfhl`>m!^sRR{}cP`Oim-{7}oz4p@>Y(FF5FUEOfMwO!ft6YytF`iZRq zfFr{!&0Efqa{1k|bZ4KLox;&V@ZW$997;+Ld8Yle91he{BfjRhjFTFv&^YuBr^&Pe zswA|Bn$vtifycN8Lxr`D7!Kygd7CuQyWqf}Q_PM}cX~S1$-6xUD%-jrSi24sBTFNz(Fy{QL2AmNbaVggWOhP;UY4D>S zqKr!UggZ9Pl9Nh_H;qI`-WoH{ceXj?m8y==MGY`AOJ7l0Uu z)>M%?dtaz2rjn1SW3k+p`1vs&lwb%msw8R!5nLS;upDSxViY98IIbxnh{}mRfEp=9 zbrPl>HEJeN7J=KnB6?dwEA6YMs~chHNG?pJsEj#&iUubdf3JJwu=C(t?JpE6xMyhA3e}SRhunDC zn-~83*9=mADUsk^sCc%&&G1q5T^HR9$P#2DejaG`Ui*z1hI#h7dwpIXg)C{8s< z%^#@uQRAg-$z&fmnYc$Duw63_Zopx|n{Bv*9Xau{a)2%?H<6D>kYY7_)e>OFT<6TT z0A}MQLgXbC2uf`;67`mhlcUhtXd)Kbc$PMm=|V}h;*_%vCw4L6r>3Vi)lE5`8hkSg zNGmW-BAOO)(W((6*e_tW&I>Nt9B$xynx|sj^ux~?q?J@F$L4;rnm_xy8E*JYwO-02u9_@@W0_2@?B@1J{y~Q39N3NX^t7#`=34Wh)X~sU&uZWgS1Z09%_k|EjA4w_QqPdY`oIdv$dJZ;(!k)#U8L+|y~gCzn+6WmFt#d{OUuKHqh1-uX_p*Af8pFYkYvKPKBxyid4KHc}H` z*KcyY;=@wzXYR{`d{6RYPhapShXIV?0cg_?ahZ7do)Ot#mxgXYJYx}<%E1pX;zqHd zf!c(onm{~#!O$2`VIXezECAHVd|`vyP)Uyt^-075X@NZDBaQt<>trA3nY-Dayki4S zZ^j6CCmx1r46`4G9794j-WC0&R9(G7kskS>=y${j-2;(BuIZTLDmAyWTG~`0)Bxqk zd{NkDe9ug|ms@0A>JVmB-IDuse9h?z9nw!U6tr7t-Lri5H`?TjpV~8(gZWFq4Vru4 z!86bDB;3lpV%{rZ`3gtmcRH1hjj!loI9jN>6stN6A*ujt!~s!2Q+U1(EFQEQb(h4E z6VKuRouEH`G6+8Qv2C)K@^;ldIuMVXdDDu}-!7FS8~k^&+}e9EXgx~)4V4~o6P^52 z)a|`J-fOirL^oK}tqD@pqBZi_;7N43%{IQ{v&G9^Y^1?SesL`;Z(dt!nn9Oj5Odde%opv&t zxJ><~b#m+^KV&b?R#)fRi;eyqAJ_0(nL*61yPkJGt;gZxSHY#t>ATnEl-E%q$E16% zZdQfvhm5B((y4E3Hk6cBdwGdDy?i5CqBlCVHZr-rI$B#>Tbi4}Gcvyg_~2=6O9D-8 zY2|tKrNzbVR$h57R?Pe+gUU_il}ZaWu|Az#QO@};=|(L-RVf0AIW zq#pO+RfM7tdV`9lI6g;{qABNId`fG%U9Va^ravVT^)CklDcx)YJKeJdGpM{W1v8jg z@&N+mR?BPB=K1}kNwXk_pj44sd>&^;d!Z~P>O78emE@Qp@&8PyB^^4^2f7e)gekMv z2aZNvP@;%i{+_~>jK7*2wQc6nseT^n6St9KG#1~Y@$~zR_=AcO2hF5lCoH|M&c{vR zSp(GRVVl=T*m~dIA;HvYm8HOdCkW&&4M~UDd^H)`p__!4k+6b)yG0Zcek8OLw$C^K z3-BbLiG_%qX|ZYpXJ$(c@aa7b4-*IQkDF}=gZSV`*ljP|5mWuHSCcf$5qqhZTv&P?I$z^>}qP(q!Aku2yA5vu38d8x*q{6-1`%PrE_r0-9Qo?a#7Zbz#iGI7K<(@k^|i4QJ1H z4jx?{rZbgV!me2VT72@nBjucoT zUM9;Y%TCoDop?Q5fEQ35bCYk7!;gH*;t9t-QHLXGmUF;|vm365#X)6b2Njsyf1h9JW#x$;@x5Nx2$K$Z-O3txa%;OEbOn6xBzd4n4v)Va=sj5 z%rb#j7{_??Tjb8(Hac<^&s^V{yO-BL*uSUk2;X4xt%NC8SjO-3?;Lzld{gM5A=9AV z)DBu-Z8rRvXXwSVDH|dL-3FODWhfe1C_iF``F05e{dl(MmS|W%k-j)!7(ARkV?6r~ zF=o42y+VapxdZn;GnzZfGu<6oG-gQ7j7Zvgo7Am@jYxC2FpS@I;Jb%EyaJDBQC(q% zKlZ}TVu!>;i3t~OAgl@QYy1X|T~D{HOyaS*Bh}A}S#a9MYS{XV{R-|niEB*W%GPW! zP^NU(L<}>Uab<;)#H)rYbnqt|dOK(-DCnY==%d~y(1*{D{Eo1cqIV8*iMfx&J*%yh zx=+WHjt0q2m*pLx8=--UqfM6ZWjkev>W-*}_*$Y(bikH`#-Gn#!6_ zIA&kxn;XYI;eN9yvqztK-a113A%97in5CL5Z&#VsQ4=fyf&3MeKu70)(x^z_uw*RG zo2Pv&+81u*DjMO6>Mrr7vKE2CONqR6C0(*;@4FBM;jPIiuTuhQ-0&C)JIzo_k>TaS zN_hB;_G=JJJvGGpB?uGgSeKaix~AkNtYky4P7GDTW6{rW{}V9K)Cn^vBYKe*OmP!; zohJs=l-0sv5&pL6-bowk~(swtdRBZQHh8)m^r2+qTtZ zt4m$B?OQYNyfBA0E)g28a*{)a=%%f-?{F;++-Xs#5|7kSHTD*E9@$V ztE%7zX4A(L`n)FY8Y4pOnKC|Pf)j$iR#yP;V0+|Hki+D;t4I4BjkfdYliK9Gf6RYw z;3px$Ud5aTd`yq$N7*WOs!{X91hZZ;AJ9iQOH%p;v$R%OQum_h#rq9*{ve(++|24z zh2P;{-Z?u#rOqd0)D^_Ponv(Y9KMB9#?}nJdUX&r_rxF0%3__#8~ZwsyrSPmtWY27 z-54ZquV2t_W!*+%uwC=h-&_q~&nQer0(FL74to%&t^byl^C?wTaZ-IS9OssaQFP)1 zAov0o{?IRAcCf+PjMWSdmP42gysh|c9Ma&Q^?_+>>+-yrC8WR;*XmJ;>r9v*>=W}tgWG;WIt{~L8`gk8DP{dSdG z4SDM7g5ahMHYHHk*|mh9{AKh-qW7X+GEQybJt9A@RV{gaHUAva+=lSroK^NUJYEiL z?X6l9ABpd)9zzA^;FdZ$QQs#uD@hdcaN^;Q=AXlbHv511Meye`p>P4Y2nblEDEeZo}-$@g&L98Aih6tgLz--${eKTxymIipy0xSYgZZ zq^yyS4yNPTtPj-sM?R8@9Q1gtXPqv{$lb5i|C1yymwnGdfYV3nA-;5!Wl zD0fayn!B^grdE?q^}ba{-LIv*Z}+hZm_F9c$$cW!bx2DgJD&6|bBIcL@=}kQA1^Eh zXTEznqk)!!IcTl>ey?V;X8k<+C^DRA{F?T*j0wV`fflrLBQq!l7cbkAUE*6}WabyF zgpb+|tv=aWg0i}9kBL8ZCObYqHEycr5tpc-$|vdvaBsu#lXD@u_e1iL z{h>xMRS0a7KvW?VttrJFpX^5DC4Bv4cp6gNG6#8)7r7IxXfSNSp6)_6tZ4l>(D+0I zPhU)N!sKywaBusHdVE!yo5$20JAU8V_XcW{QmO!p*~ns8{2~bhjydnmA&=r zX9NSM9QYogYMDZ~kS#Qx`mt>AmeR3p@K$`fbJ%LQ1c5lEOz<%BS<}2DL+$>MFcE%e zlxC)heZ7#i80u?32eOJI9oQRz0z;JW@7Th4q}YmQ-`Z?@y3ia^_)7f37QMwDw~<-@ zT)B6fftmK_6YS!?{uaj5lLxyR++u*ZY2Mphm5cd7PA5=%rd)95hJ9+aGSNfjy>Ylc zoI0nGIT3sKmwX8h=6CbvhVO+ehFIR155h8iRuXZx^cW>rq5K4z_dvM#hRER=WR@THs%WELI9uYK9HN44Em2$#@k)hD zicqRPKV#yB;UlcsTL_}zCMK0T;eXHfu`y2(dfwm(v)IBbh|#R>`2cot{m7}8_X&oD zr@94PkMCl%d3FsC4pil=#{3uv^+)pvxfwmPUr)T)T|GcZVD$wVj$mjkjDs`5cm8N! zXVq2CvL;gWGpPI4;9j;2&hS*o+LNp&C5Ac=OXx*W5y6Z^az)^?G0)!_iAfjH5wiSE zD(F}hQZB#tF5iEx@0sS+dP70DbZ*<=5X^)Pxo^8aKzOzuyc2rq=<0-k;Y_ID1>9^v z+)nc36}?>jen*1%OX3R*KRASj${u$gZ$27Hpcj=95kK^aLzxhW6jj_$w6}%#1*$5D zG1H_vYFrCSwrRqYw*9<}OYAOQT)u%9lC`$IjZV<4`9Sc;j{Qv_6+uHrYifK&On4V_7yMil!0Yv55z@dFyD{U@Sy>|vTX=P_( zRm<2xj*Z}B30VAu@0e+}at*y?wXTz|rPalwo?4ZZc>hS0Ky6~mi@kv#?xP2a;yt?5=(-CqvP_3&$KdjB7Ku;# z`GLE*jW1QJB5d&E?IJO?1+!Q8HQMGvv^RuFoi=mM4+^tOqvX%X&viB%Ko2o-v4~~J z267ui;gsW?J=qS=D*@*xJvAy3IOop5bEvfR4MZC>9Y4Z$rGI|EHNNZ7KX;Ix{xSvm z-)Cau-xuTm|7`4kUdXvd_d^E=po(76ELfq5OgxIt3aqDy#zBfIy-5<3gpn{Ce`-ha z<;6y@{Bgqw?c~h*&j{FozQCh=`Lv-5Iw!KdSt;%GDOq%=(V!dJ-}|}|0o5G2kJj6{ z`jCSPs$9Fe8O(+qALZiJ$WtR=<@GvsdM)IJ`7XrBfW0iyYE#Vy^e@zbysg*B5Z_kSL6<)vqoaH zQ{!9!*{e9UZo^h+qZ`T@LfVwAEwc&+9{C8c%oj41q#hyn<&zA9IIur~V|{mmu`n5W z8)-Ou$YgjQ*PMIqHhZ_9E?(uoK0XM5aQkarcp}WT^7b^FC#^i>#8LGZ9puDuXUYas z7caX)V5U6uY-L5Wl%)j$qRkR;7@3T*N64YK_!`Fw=>CAwe~2loI1<>DZW&sb7Q)X;6E08&$h! z2=c1i4UOO{R4TmkTz+o9n`}+%d%blR6P;5{`qjtxlN$~I%tMMDCY`~e{+mRF!rj5( z3ywv)P_PUUqREu)TioPkg&5RKjY6z%pRxQPQ{#GNMTPag^S8(8l{!{WGNs2U1JA-O zq02VeYcArhTAS;v3);k(&6ayCH8SXN@r;1NQeJ*y^NHM+zOd;?t&c!Hq^SR_w6twGV8dl>j zjS+Zc&Yp7cYj&c1y3IxQ%*kWiYypvoh(k8g`HrY<_Bi-r%m-@SLfy-6mobxkWHxyS z>TtM2M4;Uqqy|+8Q++VcEq$PwomV1D4UzNA*Tgkg9#Gpz#~&iPf|Czx!J?qss?e|3 z4gTua75-P{2X7w9eeK3~GE0ip-D;%%gTi)8bR~Ez@)$gpuS~jZs`CrO5SR-Xy7bkA z89fr~mY}u4A$|r1$fe-;T{yJh#9Ime1iRu8eo?uY9@yqAU3P!rx~SsP;LTBL zeoMK(!;(Zt8313 z3)V)q_%eflKW?BnMZa}6E0c7t!$-mC$qt44OME5F(6B$E8w*TUN-h}0dOiXI+TH zYFrr&k1(yO(|J0vP|{22@Z}bxm@7BkjO)f)&^fv|?_JX+s)1*|7X7HH(W?b3QZ3!V|~m?8}uJsF>NvE4@fik zjyyh+U*tt`g6v>k9ub88a;ySvS1QawGn7}aaR**$rJA=a#eUT~ngUbJ%V=qsFIekLbv!YkqjTG{_$F;$w19$(ivIs*1>?2ka%uMOx@B9`LD zhm~)z@u4x*zcM1WhiX)!U{qOjJHt1xs{G1S?rYe)L)ntUu^-(o_dfqZu)}W(X%Uu| zN*qI@&R2fB#Jh|Mi+eMrZDtbNvYD3|v0Kx>E#Ss;Be*T$@DC!2A|mb%d}TTN3J+c= zu@1gTOXFYy972S+=C;#~)Z{Swr0VI5&}WYzH22un_Yg5o%f9fvV(`6!{C<(ZigQ2`wso)cj z9O12k)15^Wuv#rHpe*k5#4vb%c znP+Gjr<-p%01d<+^yrSoG?}F=eI8X;?=Fo2a~HUiJ>L!oE#9tXRp!adg-b9D;(6$E zeW0tH$US04zTX$OxM&X+2ip>KdFM?iG_fgOD-qB|uFng8*#Z5jgqGY=zLU?4!OlO#~YBTB9b9#~H@nqQ#5 z6bV));d?IJTVBC+79>rGuy1JgxPLy$dA7;_^^L)02m}XLjFR*qH`eI~+eJo(7D`LH z(W%lGnGK+Vk_3kyF*zpgO=1MxMg?hxe3}}YI>dVs8l}5eWjYu4=w6MWK09+05 zGdpa#$awd>Q|@aZa*z{5F3xy3n@E4YT9%TmMo0jxW59p0bI?&S}M+ z&^NG%rf7h*m9~p#b19|`wO5OMY-=^XT+=yrfGNpl<&~~FGsx_`IaFn+sEgF$hgOa~oAVAiu^a$jHcqkE=dj`ze z=axsfrzzh6VGD0x#6Ff=t%+VTiq!n6^gv*uIUD<9fOhvR;al5kcY${uunn}-!74<7 zmP^3cl-kyN(QY!!Z-^PY-OUkh=3ZWk6>le$_Q&xk4cgH{?i)C%2RM@pX5Q{jdSlo! zVau5v44cQX5|zQlQDt;dCg)oM0B<=P1CR!W%!^m$!{pKx;bn9DePJjWBX)q!`$;0K zqJIIyD#aK;#-3&Nf=&IhtbV|?ZGYHSphp~6th`p2rkw&((%kBV7<{siEOU7AxJj+FuRdDu$ zcmTW8usU_u!r)#jg|J=Gt{##7;uf4A5cdt6Y02}f(d2)z~ z)CH~gVAOwBLk$ZiIOn}NzDjvfw(w$u|BdCBI#)3xB-Ot?nz?iR38ayCm48M=_#9r7 zw8%pwQ<9mbEs5~_>pN3~#+Er~Q86J+2TDXM6umCbukd-X6pRIr5tF?VauT8jW> zY^#)log>jtJs2s3xoiPB7~8#1ZMv>Zx0}H58k-@H2huNyw~wsl0B8j)H5)H9c7y&i zp8^0;rKbxC1eEZ-#Qxvz)Xv$((8lK9I>BspPajluysw^f#t9P;OUis43mmEzX+lk* zc4T-Ms9_687GR+~QS#0~vxK#DSGN=a-m(@eZTqw2<+lN9>R~gK2)3;sT4%nI%Y|0m zX9SPR!>?~s=j5H4WMqeTW8QaLZ=1bWS5I3xZ&$(ypc=tHrv+hX@s)VG(tc!yvLM7n zshN=C#v={X1r;)xn0Pow_1eMhkn!{;x$BJ#PIz)m585&%cmzk;btQzZAN_^zis;n? z?6I~bN?s;7vg_dtoTc4A5Ow*Rb}No#UYl)sN|RmoYo}k^cKLXd8F`44?RrokkPvN5 ztUrx;U~B;jbE_qGd3n0j2i}A{enJvJ?gSF~NQj~EP5vM-w4@;QQ5n(Npic}XNW6B0 zq9F4T%6kp7qGhd0vpQcz+nMk8GOAmbz8Bt4@GtewGr6_>Xj>ge)SyfY}nu>Y!a@HoIx(StD zx`!>RT&}tpBL%nOF%7XIFW?n1AP*xthCMzhrU6G!U6?m4!CPWTvn#Yaoi_95CT2!L z|B=5zeRW30&ANGN>J9#GtCm&3SF6n4TqDz<-{@ZXkrkRDCpV$DwCtI^e&3i1A{Ar&JZtS^c+lyPa6 z%JJr42S_;eFC#M~bdtQePhOU32WDiZ4@H&af)z#$Y|hnQNb)8(3?1Ad>5uaZ1z zU~!jt3XUI@gpWb8tWTyH7DGvKvzYfqNIy3P{9vpwz_C-QL&`+8Io$F5PS-@YQJoEO z17D9P(+sXajWSH_8&C?fn>rTLX+(?KiwX#JNV)xE0!Q@>Tid$V2#r4y6fkph?YZ>^ z(o^q(0*P->3?I0cELXJn(N|#qTm6 zAPIL~n)m!50;*?5=MOOc4Wk;w(0c$(!e?vpV23S|n|Y7?nyc8)fD8t-KI&nTklH&BzqQ}D(1gH3P+5zGUzIjT~x`;e8JH=86&5&l-DP% z)F+Et(h|GJ?rMy-Zrf>Rv@<3^OrCJ1xv_N*_@-K5=)-jP(}h1Rts44H&ou8!G_C1E zhTfUDASJ2vu!4@j58{NN;78i?6__xR75QEDC4JN{>RmgcNrn-EOpEOcyR<8FS@RB@ zH!R7J=`KK^u06eeI|X@}KvQmdKE3AmAy8 zM4IIvde#e4O(iwag`UL5yQo>6&7^=D4yE-Eo9$9R2hR} zn;Z9i-d=R-xZl4@?s%8|m1M`$J6lW1r0Y)+8q$}Vn4qyR1jqTjGH;@Z!2KiGun2~x zaiEfzVT<|_b6t}~XPeflAm8hvCHP3Bp*tl{^y_e{Jsn@w+KP{7}bH_s=1S2E1sj=18a39*Ag~lbkT^_OQuYQey=b zW^{0xlQ@O$^cSxUZ8l(Mspg8z0cL*?yH4;X2}TdN)uN31A%$3$a=4;{S@h#Y(~i%) zc=K7Ggl=&2hYVic*W65gpSPE70pU;FN@3k?BYdNDKv6wlsBAF^);qiqI zhklsX4TaWiC%VbnZ|yqL+Pcc;(#&E*{+Rx&<&R{uTYCn^OD|mAk4%Q7gbbgMnZwE{ zy7QMK%jIjU@ye?0; z;0--&xVeD}m_hq9A8a}c9WkI2YKj8t!Mkk!o%AQ?|CCBL9}n570}OmZ(w)YI6#QS&p<={tcek*D{CPR%eVA1WBGUXf z%gO2vL7iVDr1$!LAW)1@H>GoIl=&yyZ7=*9;wrOYQ}O}u>h}4FWL?N2ivURlUi11- zl{G0fo`9?$iAEN<4kxa#9e0SZPqa{pw?K=tdN5tRc7HDX-~Ta6_+#s9W&d`6PB7dF*G@|!Mc}i zc=9&T+edI(@la}QU2An#wlkJ&7RmTEMhyC_A8hWM54?s1WldCFuBmT5*I3K9=1aj= z6V@93P-lUou`xmB!ATp0(We$?)p*oQs;(Kku15~q9`-LSl{(Efm&@%(zj?aK2;5}P z{6<@-3^k^5FCDT@Z%XABEcuPoumYkiD&)-8z2Q}HO9OVEU3WM;V^$5r4q>h^m73XF z5!hZ7SCjfxDcXyj(({vg8FU(m2_}36L_yR>fnW)u=`1t@mPa76`2@%8v@2@$N@TE` z)kYhGY1jD;B9V=Dv1>BZhR9IJmB?X9Wj99f@MvJ2Fim*R`rsRilvz_3n!nPFLmj({EP!@CGkY5R*Y_dSO{qto~WerlG}DMw9k+n}pk z*nL~7R2gB{_9=zpqX|*vkU-dx)(j+83uvYGP?K{hr*j2pQsfXn<_As6z%-z+wFLqI zMhTkG>2M}#BLIOZ(ya1y8#W<+uUo@(43=^4@?CX{-hAuaJki(_A(uXD(>`lzuM~M;3XA48ZEN@HRV{1nvt?CV)t;|*dow0Ue2`B*iA&!rI`fZQ=b28= z_dxF}iUQ8}nq0SA4NK@^EQ%=)OY;3fC<$goJ&Kp|APQ@qVbS-MtJQBc)^aO8mYFsbhafeRKdHPW&s^&;%>v zlTz`YE}CuQ@_X&mqm{+{!h2r)fPGeM_Ge4RRYQkrma`&G<>RW<>S(?#LJ}O-t)d$< zf}b0svP^Zu@)MqwEV^Fb_j zPYYs~vmEC~cOIE6Nc^@b@nyL!w5o?nQ!$mGq(Pa|1-MD}K0si<&}eag=}WLSDO zE4+eA~!J(K}605x&4 zT72P7J^)Y)b(3g2MZ@1bv%o1ggwU4Yb!DhQ=uu-;vX+Ix8>#y6wgNKuobvrPNx?$3 zI{BbX<=Y-cBtvY&#MpGTgOLYU4W+csqWZx!=AVMb)Z;8%#1*x_(-)teF>45TCRwi1 z)Nn>hy3_lo44n-4A@=L2gI$yXCK0lPmMuldhLxR8aI;VrHIS{Dk}yp= zwjhB6v@0DN=Hnm~3t>`CtnPzvA*Kumfn5OLg&-m&fObRD};c}Hf?n&mS< z%$wztc%kjWjCf-?+q(bZh9k~(gs?i4`XVfqMXvPVkUWfm4+EBF(nOkg!}4u)6I)JT zU6IXqQk?p1a2(bz^S;6ZH3Wy9!JvbiSr7%c$#G1eK2^=~z1WX+VW)CPD#G~)13~pX zErO(>x$J_4qu-)lNlZkLj2}y$OiKn0ad5Imu5p-2dnt)(YI|b7rJ3TBUQ8FB8=&ym50*ibd2NAbj z;JA&hJ$AJlldM+tO;Yl3rBOFiP8fDdF?t(`gkRpmT9inR@uX{bThYNmxx-LN5K8h0 ztS%w*;V%b`%;-NARbNXn9he&AO4$rvmkB#;aaOx?Wk|yBCmN{oMTK&E)`s&APR<-5 z#;_e75z;LJ)gBG~h<^`SGmw<$Z3p`KG|I@7Pd)sTJnouZ1hRvm3}V+#lPGk4b&A#Y z4VSNi8(R1z7-t=L^%;*;iMTIAjrXl;h106hFrR{n9o8vlz?+*a1P{rEZ2ie{luQs} zr6t746>eoqiO5)^y;4H%2~&FT*Qc*9_oC2$+&syHWsA=rn3B~4#QEW zf4GT3i_@)f(Fj}gAZj`7205M8!B&HhmbgyZB& z+COyAVNxql#DwfP;H48Yc+Y~ChV6b9auLnfXXvpjr<~lQ@>VbCpQvWz=lyVf1??_c zAo3C^otZD@(v?X)UX*@w?TF|F8KF>l7%!Dzu+hksSA^akEkx8QD(V(lK+HBCw6C}2onVExW)f$ zncm*HI(_H;jF@)6eu}Tln!t?ynRkcqBA5MitIM@L^(4_Ke}vy7c%$w{(`&7Rn=u>oDM+Z^RUYcbSOPwT(ONyq76R>$V6_M_UP4vs=__I#io{{((| zy5=k=oVr-Qt$FImP~+&sN8rf2UH*vRMpwohPc@9?id17La4weIfBNa>1Djy+1=ugn z@}Zs;eFY1OC}WBDxDF=i=On_33(jWE-QYV)HbQ^VM!n>Ci9_W0Zofz7!m>do@KH;S z4k}FqEAU2)b%B_B-QcPnM5Zh=dQ+4|DJoJwo?)f2nWBuZE@^>a(gP~ObzMuyNJTgJFUPcH`%9UFA(P23iaKgo0)CI!SZ>35LpFaD7 z)C2sW$ltSEYNW%%j8F;yK{iHI2Q^}coF@LX`=EvxZb*_O;2Z0Z5 z7 zlccxmCfCI;_^awp|G748%Wx%?t9Sh8!V9Y(9$B?9R`G)Nd&snX1j+VpuQ@GGk=y(W zK|<$O`Cad`Y4#W3GKXgs%lZduAd1t1<7LwG4*zaStE*S)XXPFDyKdgiaVXG2)LvDn zf}eQ_S(&2!H0Mq1Yt&WpM1!7b#yt_ie7naOfX129_E=)beKj|p1VW9q>>+e$3@G$K zrB%i_TT1DHjOf7IQ8)Wu4#K%ZSCDGMP7Ab|Kvjq7*~@ewPm~h_-8d4jmNH<&mNZC@CI zKxG5O08|@<4(6IEC@L-lcrrvix&_Dj4tBvl=8A}2UX|)~v#V$L22U}UHk`B-1MF(t zU6aVJWR!>Y0@4m0UA%Sq9B5;4hZvsOu=>L`IU4#3r_t}os|vSDVMA??h>QJ1FD1vR z*@rclvfD!Iqoxh>VP+?b9TVH8g@KjYR@rRWQy44A`f6doIi+8VTP~pa%`(Oa@5?=h z8>YxNvA##a3D0)^P|2|+0~f|UsAJV=q(S>eq-dehQ+T>*Q@qN zU8@kdpU5gGk%ozt?%c8oM6neA?GuSsOfU_b1U)uiEP8eRn~>M$p*R z43nSZs@^ahO78s zulbK@@{3=2=@^yZ)DuIC$ki;`2WNbD_#`LOHN9iMsrgzt-T<8aeh z(oXrqI$Kgt6)Icu=?11NWs>{)_ed1wh>)wv6RYNUA-C&bejw{cBE_5Wzeo!AHdTd+ z)d(_IKN7z^n|As~3XS=cCB_TgM7rK;X586re`{~Foml$aKs zb!4Pe7hEP|370EWwn$HKPM!kL94UPZ1%8B^e5fB+=Iw^6=?5n3tZGYjov83CLB&OQ++p)WCMeshCv_9-~G9C_2x`LxTDjUcW$l6e!6-&a^fM3oP9*g(H zmCk0nGt1UMdU#pfg1G0um5|sc|KO<+qU1E4iBF~RvN*+`7uNHH^gu{?nw2DSCjig% zI@ymKZSK=PhHJa(jW&xeApv&JcfSmNJ4uQ|pY=Lcc>=J|{>5Ug3@x#R_b@55xFgfs za^ANzWdD$ZYtFs$d7+oiw0ZmPk2&l|< zc8()wfiJx@EGpQT zG$8iLkQZ-086doF1R zh<#9cz_vRsJdoXbD=QgOtpm}cFAJX8c}>Jew;PQJSXSb^;wlC zxXLHTS|!GZ-VK_4wV<9bk4RUmlsByzW_^b>)$6R+jQ}^wco1nMA`9Lncs;&QGp!`5Tx#aXXU?}5_RrtUY zx(EMzDhl-a^y^f5yfFLMnOO#u)l69&4M?|ne|2EV>zQ}4JQCBel?~2I4?D|>L$%H(peOOII!U}i z-j)*h1rODe9{0`xmhG;`AKqw1p0_KhEIU8)DoGnEn9wAhXPaxO_(jNSij~J5m$P*$ z9Mt(t;eV}2+i|kjQpBFcNb7_(VbuF<;RQB~R~p>2*Lg>a&7DEEuq*I%Ls4{zHeUDq z+M0&YhEn^C*9-B4Q7HJ$xj)dORCXPK+)ZtLOa0o&)Sl+f(Y{p*68$-#yagW5^HQnQ z0pWpoQpxg8<&gx9im(>=x6v#&RbQ7^AsjxeSDA? zi4MEJUC~ByG!PiBjq7$pK&FA^5 z=Y@dtQnuy%IfsaR`TVP0q^3mixl&J-3!$H!ua#{A>0Z1JdLq#d4UV9nlYm641ZHl zH6mK~iI6lR3OUEVL}Z5{ONZ_6{Nk%Bv03ag<1HVN?R%w2^aR5@E>6(r>}IoMl$wRF zWr-DItN*k7T$NTT8B)+23c?171sADhjInb2Xb>GhFYGC&3{b>huvLlaS4O z^{j5q+b5H?Z)yuy%AByaVl2yj9cnalY1sMQ zXI#e%*CLajxGxP!K6xf9RD2pMHOfAa1d^Lr6kE`IBpxOiGXfNcoQ*FI6wsNtLD!T+ zC4r2q>5qz0f}UY^RY#1^0*FPO*Zp-U1h9U|qWjwqJaDB(pZ`<`U-xo7+JB$zvwV}^ z2>$0&Q5k#l|Er7*PPG1ycj4BGz zg&`d*?nUi1Q!OB>{V@T$A;)8@h;*Rb1{xk_8X<34L`s}xkH-rQZvjM`jI=jaJRGRg zeEcjYChf-78|RLrao%4HyZBfnAx5KaE~@Sx+o-2MLJ>j-6uDb!U`odj*=)0k)K75l zo^)8-iz{_k7-_qy{Ko~N#B`n@o#A22YbKiA>0f3k=p-B~XX=`Ug>jl$e7>I=hph0&AK z?ya;(NaKY_!od=tFUcGU5Kwt!c9EPUQLi;JDCT*{90O@Wc>b| zI;&GIY$JlQW^9?R$-OEUG|3sp+hn+TL(YK?S@ZW<4PQa}=IcUAn_wW3d!r#$B}n08 z*&lf(YN21NDJ74DqwV`l`RX(4zJ<(E4D}N0@QaE-hnfdPDku~@yhb^AeZL73RgovX z6=e>!`&e^l@1WA5h!}}PwwL*Gjg!LbC5g0|qb8H$^S{eGs%cc?4vTyVFW=s6KtfW? z@&Xm+E(uz(qDbwDvRQI9DdB<2sW}FYK9sg*f%-i*>*n{t-_wXvg~N7gM|a91B!x|K zyLbJ~6!!JZpZ`#HpCB8g#Q*~VU47Rp$NyZb3WhEgg3ivSwnjGJgi0BEV?!H}Z@QF| zrO`Kx*52;FR#J-V-;`oR-pr!t>bYf)UYcixN=(FUR6$fhN@~i09^3WeP3*)D*`*mJ z1u%klAbzQ=P4s%|FnVTZv%|@(HDB+ap5S#cFSJUSGkyI*Y>9Lwx|0lTs%uhoCW(f1 zi+|a9;vDPfh3nS<7m~wqTM6+pEm(&z-Ll;lFH!w#(Uk#2>Iv~2Hu}lITn7hnOny`~ z*Vj=r<&Nwpq^@g5m`u&QTBRoK*}plAuHg$L$~NO#wF0!*r0OfcS%)k0A??uY*@B^C zJe9WdU(w){rTIf<;rwJt^_35^d<A@$FqEZW6kwyfAo2x0T$Ye2MZox6Z7<%Qbu$}}u{rtE+h2M+Z}T4I zxF1cwJ(Uvp!T#mogWkhb(?SxD4_#tV(Sc8N4Gu*{Fh#})Pvb^ef%jrlnG*&Ie+J5 zsly5oo?1((um&lLDxn(DkYtk`My>lgKTp3Y4?hTQ4_`YNOFtjF-FUY#d#(EQd(rfz zB8z%Vi;?x)ZM$3c>yc5H8KBvSevnWNdCbAj?QCac)6-K~Xz@EZp}~N9q)5*Ufjz3C z6kkOeI{3H(^VO8hKDrVjy2DXd;5wr4nb`19yJi0DO@607MSx+7F$ zz3F7sl8JV@@sM$6`#JmSilqI%Bs)}Py2eFT;TjcG5?8$zwV60b(_5A>b#uk~7U^bO z>y|6SCrP2IGST(8HFuX|XQUXPLt2gL_hm|uj1Ws`O2VW>SyL^uXkl>Zvkcpi?@!F7 z%svLoT@{R#XrIh^*dE~$YhMwC+b7JE09NAS47kT%Ew zD!XjxA@1+KOAyu`H2z#h+pGm!lG>WI0v745l+Fd><3dh{ATq%h?JSdEt zu%J*zfFUx%Tx&0DS5WSbE)vwZSoAGT=;W#(DoiL($BcK;U*w`xA&kheyMLI673HCb7fGkp{_vdV2uo;vSoAH z9BuLM#Vzwt#rJH>58=KXa#O;*)_N{$>l7`umacQ0g$pI3iW4=L--O;Wiq0zy7OKp`j2r^y3`7X!?sq9rr5B{41BkBr1fEd1#Q3 z-dXc2RSb4U>FvpVhlQCIzQ-hs=8420z=7F2F(^xD;^RXgpjlh8S6*xCP#Gj2+Q0bAg?XARw3dnlQ*Lz3vk}m`HXmCgN=?bIL{T zi}Ds-xn|P)dxhraT@XY$ZQ&^%x8y!o+?n#+>+dZ1c{hYwNTNRke@3enT(a@}V*X{! z81+{Jc2UR;+Zcbc6cUlafh4DFKwp>;M}8SGD+YnW3Q_)*9Z_pny_z+MeYQmz?r%EVaN0d!NE*FVPq&U@vo{ef6wkMIDEWLbDs zz91$($XbGnQ?4WHjB~4xgPgKZts{p|g1B{-4##}#c5aL5C6_RJ_(*5>85B1}U!_<``}q-97Q7~u)(&lsb(WT^(*n7H%33%@_b zO5(?-v??s??33b19xiB7t_YT!q8!qAzN1#RD@3;kYAli%kazt#YN7}MhVu=ljuz27 z1`<+g8oVwy57&$`CiHeaM)tz(OSt4E# zJ@P6E*e504oUw~RD(=9WP8QdW^6wRdFbKII!GAWecJ(?{`EzTR@?j!3g?$@LLCt;U={>!9z7DU!(1Jq zqEwdx5q?W1Ncm7mXP8MFwAr?nw5$H%cb>Q><9j{Tk2RY9ngGvaJgWXx^r!ywk{ph- zs2PFto4@IIwBh{oXe;yMZJYlS?3%a-CJ#js90hoh5W5d^OMwCFmpryHFr|mG+*ZP$ zqyS5BW@s}|3xUO0PR<^{a2M(gkP5BDGxvkWkPudSV*TMRK5Qm4?~VuqVAOerffRt$HGAvp;M++Iq$E6alB z;ykBr-eZ6v_H^1Wip56Czj&=`mb^TsX|FPN#-gnlP03AkiJDM=?y|LzER1M93R4sC z*HT(;EV=*F*>!+Z{r!KG?6ODMGvkt3viG=@kQJHNMYd}bS4KrrHf4`&*(0m0R5Hqz zEk)r=sFeS?MZRvn<@Z0&bDw)XkMnw+_xqgp=W{;ioX`6;G-P9N%wfoYJ$-m$L#MC% z^sH?tSzA|WWP(cN3({~_*X$l{M*;1V{l$;T6b){#l4pswDTid26HaXgKed}13YIP= zJRvA3nmx{}R$Lr&S4!kWU3`~dxM}>VXWu6Xd(VP}z1->h&f%82eXD_TuTs@=c;l0T z|LHmWKJ+?7hkY=YM>t}zvb4|lV;!ARMtWFp!E^J=Asu9w&kVF*i{T#}sY++-qnVh! z5TQ|=>)+vutf{&qB+LO9^jm#rD7E5+tcorr^Fn5Xb0B;)f^$7Ev#}G_`r==ea294V z--v4LwjswWlSq9ba6i?IXr8M_VEGQ$H%hCqJTFQ3+1B9tmxDUhnNU%dy4+zbqYJ|o z3!N{b?A@{;cG2~nb-`|z;gEDL5ffF@oc3`R{fGi)0wtMqEkw4tRX3t;LVS3-zAmg^ zgL7Z{hmdPSz9oA@t>tZ1<|Khn&Lp=_!Q=@a?k+t~H&3jN?dr(}7s;{L+jiKY57?WsFBfW^mu6a03_^VKrdK=9egXw@!nzZ3TbYc*osyQNoCXPYoFS<&Nr97MrQCOK(gO8 z;0@iqRTJy4-RH)PJld5`AJN}n?5r^-enKrHQOR;z>UMfm+e8~4ZL5k>oXMiYq12Bx4eVQv0jFgp_zC#``sjZpywYqISMP}VZ@!~1Mf$!x|opj%mQ98JnSk@`~ zPmmyuPZKtZOnEC!1y!?`TYRsZ!II;d!iln}%e}bk5qIiUADERr*K$3dekgHV9TtBX zi5q!J!6Zgd#cLxRmZN^J`o@Zv{+p+<_#8^nvY)44Hw_2i@?R&5n^q33fpOnDg1nPQ z_r<$hURl~OketX|Tdbvf_7=3x^rSFJtEp@tuDpVB&uq)qW;xUQ7mmkr-@eZwa$l+? zoKk``Vz@TH#>jMce*8>@FZ+@BEUdYa_K0i|{*;j9MW3K%pnM*T;@>|o@lMhgLrpZP5aol(z>g;b4}|e$U~Fn zGL%(}p%Jsl4LxE!VW_Y4T>e}W4e#~F03H_^R!Q)kpJG{lO!@I4{mFo^V#ayHh_5~o zB$O71gcE(G@6xv);#Ky?e(Ed}^O+Ho(t=93T9T3TnEY(OVf_dR-gY@jj+iJSY?q|6prBv(S9A4k=2fNZz!W@S=B@~b?TJRTuBQq448@juN#Y=3q=^VCF>Z}n6wICJ<^^Kn8C;mK zZYiFSN#Z$?NDGV7(#}q2tAZAtE63icK-MY>UQu4MWlGIbJ$AF8Zt-jV;@7P5MPI>% zPWvO!t%1+s>-A%`;0^o8Ezeaa4DMwI8ooQrJ;ax@Qt*6XONWw)dPwOPI9@u*EG&844*1~EoZ2qsAe~M>d`;Bc_CWY zMoDKEmDh-}k9d6*<0g@aQmsnrM1H9IcKYZs)><)d92{|0Hh8?~XbF)7U+UmP@Pw_6geVB?7N$4J4*E0z3EO&5kRS(EE zv92(+e5WxLXMN{h;-|8@!Q#0q247hb^3R%*k3MuMO5*L}$0D#5P*N$aHd54C+=_RToYXTyewugOaDmGsCvb4H1s=@gkfVnzTCWKMa-Mm1v4Wq!t-JIrbV&EWwKDe ze#kJpOq#iRlFz%5#6Fio9IUlKnQ#X&DY8Ux#<-WqxAac-y%U_L+EZZ4Rg5*yNg`f< zSZn&uio@zanUCPqX1l4W&B!;UWs#P7B^|4WwoCxQXl|44n^cBNqu=3Vl*ltAqsUQO z9q_@nD0zq0O8r`coEm>9+|rA3HL#l}X;0##>SJS$cVavOZVCpSGf4mUU1( zWaRCUYc^9QbG9=vpWo%xP}CMFnMb{reA`K7tT(t5DM)d9l}jVPY>qoRzT zE3m-p#=i=$9x*CB`AL>SY}u3agYFl#uULNen#&44H;!L@I{RI=PlWxG8J((f)ma7A z@jLvQ>?Nx`n?3ChRG#HqE3MXP8*o3!Qq`+t8EMt_p)oeKHqPusBxPn!#?R??-=e3e zo73WNs_IZF`WLigre=|`aS2^> zN1zn!7k&Dh28t%VpJ%**&E!eAcB5oLjQFFcJQj*URMia%Ya3@q1UQ18=oWMM6`I}iT_&L1gl?*~6nU4q4Z0`H<5yDp(HeZ+RGf9`mM&= zn-qRp%i!g$R;i1d1aMZ{IewNjE@p2+Z{`x{*xL*x$?WV~{BjJpsP&C&JK0HLoyf z`0z^v&fBQSa!I7FU~9MaQ%e|?RP>sM^2PL!mE^Q1Ig_4M$5BRfi72oMYu6Ke?wmDX z@0a%-V|z}b23K=ye(W+fG#w|jJUnT{=KR5jfuq!RX}<1irTDw(${<&}dWQu4;EuE< z@3u4dBkQaCHHM&;cE0z50_V!(vJ1_V)A8?C#eJuLkt!98Z%|Bgzidc0j|z(&o)TCzYlrgZA zC3@i>L!&Gw_~7`>puB97I2lK)lESZQqVXc_8T^G2O#VHhO?IC$g zOYhXJ7)~C<8l|Xrftka@QuowScM{K&0zskoU$Aw~vIRVRF9TEQ4*3=_5)98B`=t8(N%ZuWqmwlW zllAzq=E5_5!sKDXam@w`ZD(nl%LAPxQuEtDcKPqu9LPJvNIITawU#c^PQ2HmZgs)r zH^+gRwZ?0)8IFQgU)+p@0Iqb^tcEoqcB@zhfz_FaOM&_d<|jnU>q5nSKa<@%9|dje zIupcg1!tRiMP4X=oG<7s4|AW&^-Cw4FL9OuI$t zxjc*y;Uw!G7a|jz>E*2+PlR(CemWebS7m-&*CDwnmxbiRqJvQ&os-sC&4OWt^(2@vG4|jui#Df@-D= zh3D%8Y3R6+jRBStSvH9pt&tCI`NK08J1*pC(?OM0h!bS-JK3I}`pDY-fDIaB_*W6KS+TO0Q*%kkeuN6uWITt=TsCGw6uBE710q; zRluI%j{?@jwhM|l5&TB!-TkQs!A=DXRE>u18t@;zndD0M$U@Igrt?UW2; z7%=dsHIVH_LCkGUU0fW&UMjDnvjcc0Mp(mK&;d~ZJ5EJ)#7@aTZvGDFXzFZg2Lq~s z5PR_LazNN)JD5K_uK*Hy{mXuHTkGGv|9V8KP#iQ$3!G*^>7UiE{|1G1A-qg(xH;Xa>&%f|BZkH zG=J^0pHzSAqv5*5ysQ{Puy^-_|IPrii zKS$mE10Zngf>Sgg@BjpRyJbrHeo zD8Ro0LI*W#+9?^xlOS^c>Z^^n^0I|FH^@^`ZR`{H=$ zjO0_$cnpBM7Zcm?H_RXIu-Lu~qweDSV|tEZBZh!e6hQy->}e;d#osZ1hQj{HhHkC0 zJ|F-HKmeTGgDe979ogBz24;@<|I7;TU!IXb@oWMsMECIETmQy`zPtM`|NP}PjzR_u zKMG1Z{%1kWeMfEf(10U#w!clmQ2)JC8zm(Fv!H4dUHQHCFLikID?hrd{0>kCQt?kP zdqn2ZG0}ytcQJ7t_B3s0ZvH3PYjkjQ`Q%;jV@?MK-+z3etBCGGo4f4`y^|AdCs!DH zThTQ;cL5dM{|tB_1y6K3bVa^hx_<9J(}5`2SDz1^0bT!Vm*JV;9~t&{IC{$DUAVV* z{|E=#yN{wNdTY@$6z{_KNA3&%w|vFu1n9XRcM0Ak>`UW!lQ`ah3D4r%}Z literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..bdc9a83 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..79a61d4 --- /dev/null +++ b/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# 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*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + 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 \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# 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..93e3f59 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@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=. +@rem This is normally unused +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% equ 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% equ 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! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..9eb9fb1 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,3 @@ +rootProject.name = "trees-6" +include("app") +include("BSTrees") From be022f79cb26d643f6da6bc6659179822f582507 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 26 Mar 2023 22:03:47 +0300 Subject: [PATCH 004/135] feat: Added trees architecture --- BSTrees/src/main/kotlin/BTree.kt | 44 +++++++++++++++++++ BSTrees/src/main/kotlin/Node.kt | 17 +++++++ BSTrees/src/main/kotlin/avlTree/AvlNode.kt | 5 +++ BSTrees/src/main/kotlin/avlTree/AvlTree.kt | 17 +++++++ .../src/main/kotlin/balancers/AvlBalancer.kt | 8 ++++ BSTrees/src/main/kotlin/balancers/Balancer.kt | 17 +++++++ .../src/main/kotlin/balancers/RBBalancer.kt | 8 ++++ .../main/kotlin/binarySearchTree/BSNode.kt | 5 +++ .../main/kotlin/binarySearchTree/BSTree.kt | 15 +++++++ .../src/main/kotlin/redBlackTree/RBNode.kt | 17 +++++++ .../src/main/kotlin/redBlackTree/RBTree.kt | 18 ++++++++ 11 files changed, 171 insertions(+) create mode 100644 BSTrees/src/main/kotlin/BTree.kt create mode 100644 BSTrees/src/main/kotlin/Node.kt create mode 100644 BSTrees/src/main/kotlin/avlTree/AvlNode.kt create mode 100644 BSTrees/src/main/kotlin/avlTree/AvlTree.kt create mode 100644 BSTrees/src/main/kotlin/balancers/AvlBalancer.kt create mode 100644 BSTrees/src/main/kotlin/balancers/Balancer.kt create mode 100644 BSTrees/src/main/kotlin/balancers/RBBalancer.kt create mode 100644 BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt create mode 100644 BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt create mode 100644 BSTrees/src/main/kotlin/redBlackTree/RBNode.kt create mode 100644 BSTrees/src/main/kotlin/redBlackTree/RBTree.kt diff --git a/BSTrees/src/main/kotlin/BTree.kt b/BSTrees/src/main/kotlin/BTree.kt new file mode 100644 index 0000000..5ebddc6 --- /dev/null +++ b/BSTrees/src/main/kotlin/BTree.kt @@ -0,0 +1,44 @@ + +abstract class BTree, V, NODE_TYPE : Node>(private var root: NODE_TYPE?) { + + private var leftBTree: BTree? = null + private var rightBTree: BTree? = null + + fun getRoot() = this.root + + fun setRoot(newRoot: NODE_TYPE?) { + this.root = newRoot + } + + fun getLeftTree() = this.leftBTree + + fun setLeftTree(newValue: BTree?) { + this.leftBTree = newValue + } + + fun getRightTree() = this.rightBTree + + fun setRightTree(newValue: BTree?) { + this.rightBTree = newValue + } + + fun getHeight(): Int { + return this.root?.getHeight() ?: 0 + } + + fun setHeight(newValue: Int) { + this.root?.setHeight(newValue) + } + + fun updateHeight() { + TODO("Not yet implemented") + } + + abstract fun add(node: NODE_TYPE) + + fun find(key: K): V? { + TODO("Not yet implemented") + } + + abstract fun delete(key: K) +} diff --git a/BSTrees/src/main/kotlin/Node.kt b/BSTrees/src/main/kotlin/Node.kt new file mode 100644 index 0000000..2152d93 --- /dev/null +++ b/BSTrees/src/main/kotlin/Node.kt @@ -0,0 +1,17 @@ +abstract class Node, V, NODE_TYPE: Node>(private val key: K, private var value: V){ + private var height = 1 + + fun getKey() = this.key + + fun getValue() = this.value + + fun setValue(newValue: V){ + this.value = newValue + } + + fun getHeight() = this.height + + fun setHeight(newValue: Int){ + this.height = newValue + } +} diff --git a/BSTrees/src/main/kotlin/avlTree/AvlNode.kt b/BSTrees/src/main/kotlin/avlTree/AvlNode.kt new file mode 100644 index 0000000..466e0aa --- /dev/null +++ b/BSTrees/src/main/kotlin/avlTree/AvlNode.kt @@ -0,0 +1,5 @@ +package avlTree + +import Node + +class AvlNode, V>(key: K, value: V): Node>(key, value) diff --git a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt new file mode 100644 index 0000000..a1d6773 --- /dev/null +++ b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt @@ -0,0 +1,17 @@ +package avlTree + +import balancers.AvlBalancer +import BTree + +class AvlTree, V>(root: AvlNode): BTree>(root){ + + private val balancer = AvlBalancer() + + override fun add(node: AvlNode) { + TODO("Not yet implemented") + } + + override fun delete(key: K) { + TODO("Not yet implemented") + } +} diff --git a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt b/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt new file mode 100644 index 0000000..397d067 --- /dev/null +++ b/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt @@ -0,0 +1,8 @@ +package balancers + +open class AvlBalancer: Balancer() { + + override fun balance() { + TODO("Not yet implemented") + } +} diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt new file mode 100644 index 0000000..5bb2e84 --- /dev/null +++ b/BSTrees/src/main/kotlin/balancers/Balancer.kt @@ -0,0 +1,17 @@ +package balancers + +abstract class Balancer { + protected fun leftRotate(){ + TODO("Not yet implemented") + } + + protected fun rightRotate(){ + TODO("Not yet implemented") + } + + protected fun balanceFactory(){ + TODO("Not yet implemented") + } + + abstract fun balance() +} diff --git a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt new file mode 100644 index 0000000..673aabf --- /dev/null +++ b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt @@ -0,0 +1,8 @@ +package balancers + +open class RBBalancer: Balancer() { + + override fun balance() { + TODO("Not yet implemented") + } +} diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt new file mode 100644 index 0000000..9c30a62 --- /dev/null +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt @@ -0,0 +1,5 @@ +package binarySearchTree + +import Node + +class BSNode, V>(key: K, value: V): Node>(key, value) diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt new file mode 100644 index 0000000..221ae08 --- /dev/null +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt @@ -0,0 +1,15 @@ +package binarySearchTree + +import BTree + +class BSTree, V>(root: BSNode): BTree>(root) { + + override fun add(node: BSNode) { + TODO("Not yet implemented") + } + + override fun delete(key: K) { + TODO("Not yet implemented") + } + +} diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt b/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt new file mode 100644 index 0000000..0cf7893 --- /dev/null +++ b/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt @@ -0,0 +1,17 @@ +package redBlackTree + +import Node + +class RBNode, V>(key: K, value: V): Node>(key, value){ + + enum class Color{ + BLACK, + RED + } + + var color = Color.RED + + fun changeColor(){ + TODO("Not yet implemented") + } +} diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt new file mode 100644 index 0000000..b882d75 --- /dev/null +++ b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt @@ -0,0 +1,18 @@ +package redBlackTree + +import BTree +import balancers.RBBalancer + +class RBTree, V>(root: RBNode): BTree>(root) { + + private val balancer = RBBalancer() + + override fun add(node: RBNode) { + TODO("Not yet implemented") + } + + override fun delete(key: K) { + TODO("Not yet implemented") + } + +} From 422d4e00dd6b5dd91ad8c6572a75ea5b567e4668 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Sun, 26 Mar 2023 22:26:23 +0300 Subject: [PATCH 005/135] feat: updateHeight function is implemented --- BSTrees/src/main/kotlin/BTree.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/BSTrees/src/main/kotlin/BTree.kt b/BSTrees/src/main/kotlin/BTree.kt index 5ebddc6..65f2a2b 100644 --- a/BSTrees/src/main/kotlin/BTree.kt +++ b/BSTrees/src/main/kotlin/BTree.kt @@ -31,7 +31,9 @@ abstract class BTree, V, NODE_TYPE : Node>(pr } fun updateHeight() { - TODO("Not yet implemented") + val leftHeight = this.getLeftTree()?.getHeight() ?: 0 + val rightHeight = this.getRightTree()?.getHeight() ?: 0 + setHeight(leftHeight + rightHeight + 1) } abstract fun add(node: NODE_TYPE) From c54a2e6846a91ca8dddb2700804890e2ec8a99bd Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Sun, 26 Mar 2023 22:31:40 +0300 Subject: [PATCH 006/135] feat: find function is implemented --- BSTrees/src/main/kotlin/BTree.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/BSTrees/src/main/kotlin/BTree.kt b/BSTrees/src/main/kotlin/BTree.kt index 65f2a2b..584ac8c 100644 --- a/BSTrees/src/main/kotlin/BTree.kt +++ b/BSTrees/src/main/kotlin/BTree.kt @@ -1,4 +1,3 @@ - abstract class BTree, V, NODE_TYPE : Node>(private var root: NODE_TYPE?) { private var leftBTree: BTree? = null @@ -39,7 +38,13 @@ abstract class BTree, V, NODE_TYPE : Node>(pr abstract fun add(node: NODE_TYPE) fun find(key: K): V? { - TODO("Not yet implemented") + if (this.root == null) return null + if (this.root?.getKey() == key) return this.root?.getValue() + return if (this.root!!.getKey() > key) { + this.getLeftTree()?.find(key) + } else { + this.getRightTree()?.find(key) + } } abstract fun delete(key: K) From 7651f791e6a052f8965838cd7cdbb2faff23cf08 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Sun, 26 Mar 2023 22:51:00 +0300 Subject: [PATCH 007/135] fix: codestyle in the Node class --- BSTrees/src/main/kotlin/Node.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/BSTrees/src/main/kotlin/Node.kt b/BSTrees/src/main/kotlin/Node.kt index 2152d93..84f185c 100644 --- a/BSTrees/src/main/kotlin/Node.kt +++ b/BSTrees/src/main/kotlin/Node.kt @@ -1,17 +1,19 @@ -abstract class Node, V, NODE_TYPE: Node>(private val key: K, private var value: V){ +abstract class Node, V, NODE_TYPE : Node>(private val key: K, private var value: V) { + private var height = 1 fun getKey() = this.key fun getValue() = this.value - fun setValue(newValue: V){ + fun setValue(newValue: V) { this.value = newValue } fun getHeight() = this.height - fun setHeight(newValue: Int){ + fun setHeight(newValue: Int) { this.height = newValue } + } From 5854acaf80e66125d205054ae1bcde54ef9efa6b Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 27 Mar 2023 00:47:44 +0300 Subject: [PATCH 008/135] fix: Changed type of node. It can't be null now --- BSTrees/src/main/kotlin/BTree.kt | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/BSTrees/src/main/kotlin/BTree.kt b/BSTrees/src/main/kotlin/BTree.kt index 584ac8c..92b8204 100644 --- a/BSTrees/src/main/kotlin/BTree.kt +++ b/BSTrees/src/main/kotlin/BTree.kt @@ -1,11 +1,11 @@ -abstract class BTree, V, NODE_TYPE : Node>(private var root: NODE_TYPE?) { +abstract class BTree, V, NODE_TYPE : Node>(private var root: NODE_TYPE) { private var leftBTree: BTree? = null private var rightBTree: BTree? = null fun getRoot() = this.root - fun setRoot(newRoot: NODE_TYPE?) { + fun setRoot(newRoot: NODE_TYPE) { this.root = newRoot } @@ -22,11 +22,11 @@ abstract class BTree, V, NODE_TYPE : Node>(pr } fun getHeight(): Int { - return this.root?.getHeight() ?: 0 + return this.root.getHeight() } fun setHeight(newValue: Int) { - this.root?.setHeight(newValue) + this.root.setHeight(newValue) } fun updateHeight() { @@ -38,9 +38,8 @@ abstract class BTree, V, NODE_TYPE : Node>(pr abstract fun add(node: NODE_TYPE) fun find(key: K): V? { - if (this.root == null) return null - if (this.root?.getKey() == key) return this.root?.getValue() - return if (this.root!!.getKey() > key) { + if (this.root.getKey() == key) return this.root.getValue() + return if (this.root.getKey() > key) { this.getLeftTree()?.find(key) } else { this.getRightTree()?.find(key) From 7caf5ee6be6f0d200bf63986ddcdb74b70a64891 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 27 Mar 2023 01:51:15 +0300 Subject: [PATCH 009/135] feat: Added left rotate --- BSTrees/src/main/kotlin/balancers/Balancer.kt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt index 5bb2e84..72fb887 100644 --- a/BSTrees/src/main/kotlin/balancers/Balancer.kt +++ b/BSTrees/src/main/kotlin/balancers/Balancer.kt @@ -1,15 +1,24 @@ package balancers -abstract class Balancer { - protected fun leftRotate(){ - TODO("Not yet implemented") +import BTree +import Node + +abstract class Balancer, V, NODE_TYPE : Node, TREE_TYPE : BTree>( + val tree: TREE_TYPE +) { + protected fun leftRotate() { + val temp = tree.getLeftTree() + tree.setLeftTree(temp?.getRightTree()) + temp?.setRightTree(tree) + tree.updateHeight() + temp?.updateHeight() } - protected fun rightRotate(){ + protected fun rightRotate() { TODO("Not yet implemented") } - protected fun balanceFactory(){ + protected fun balanceFactory() { TODO("Not yet implemented") } From 0a9523cc76acde3f90f134b81cceb22490a80471 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 27 Mar 2023 01:55:34 +0300 Subject: [PATCH 010/135] feat: Added right rotate --- BSTrees/src/main/kotlin/balancers/Balancer.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt index 72fb887..c9df5e1 100644 --- a/BSTrees/src/main/kotlin/balancers/Balancer.kt +++ b/BSTrees/src/main/kotlin/balancers/Balancer.kt @@ -15,7 +15,11 @@ abstract class Balancer, V, NODE_TYPE : Node, } protected fun rightRotate() { - TODO("Not yet implemented") + val temp = tree.getRightTree() + temp?.setRightTree(tree.getLeftTree()) + tree.setLeftTree(temp) + temp?.updateHeight() + tree.updateHeight() } protected fun balanceFactory() { From 5dca01101ab7b4e614111b25a98dc14e930bf079 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 27 Mar 2023 02:02:13 +0300 Subject: [PATCH 011/135] feat: Added auxiliary function balance factor --- BSTrees/src/main/kotlin/balancers/Balancer.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt index c9df5e1..29b2dda 100644 --- a/BSTrees/src/main/kotlin/balancers/Balancer.kt +++ b/BSTrees/src/main/kotlin/balancers/Balancer.kt @@ -22,8 +22,8 @@ abstract class Balancer, V, NODE_TYPE : Node, tree.updateHeight() } - protected fun balanceFactory() { - TODO("Not yet implemented") + protected fun balanceFactory(): Int { + return (tree.getRightTree()?.getRoot()?.getHeight() ?: 0) - (tree.getLeftTree()?.getRoot()?.getHeight() ?: 0) } abstract fun balance() From 6cc17bf4d2fffb01b520712c7ad0384d457c9cbf Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 27 Mar 2023 02:37:19 +0300 Subject: [PATCH 012/135] feat: Added TREE_TYPE in BTree abstract class --- BSTrees/src/main/kotlin/BTree.kt | 12 +++++++----- BSTrees/src/main/kotlin/avlTree/AvlTree.kt | 2 +- BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt | 2 +- BSTrees/src/main/kotlin/redBlackTree/RBTree.kt | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/BSTrees/src/main/kotlin/BTree.kt b/BSTrees/src/main/kotlin/BTree.kt index 92b8204..23c3305 100644 --- a/BSTrees/src/main/kotlin/BTree.kt +++ b/BSTrees/src/main/kotlin/BTree.kt @@ -1,7 +1,9 @@ -abstract class BTree, V, NODE_TYPE : Node>(private var root: NODE_TYPE) { +abstract class BTree, V, NODE_TYPE : Node, TREE_TYPE : BTree>( + private var root: NODE_TYPE +) { - private var leftBTree: BTree? = null - private var rightBTree: BTree? = null + private var leftBTree: TREE_TYPE? = null + private var rightBTree: TREE_TYPE? = null fun getRoot() = this.root @@ -11,13 +13,13 @@ abstract class BTree, V, NODE_TYPE : Node>(pr fun getLeftTree() = this.leftBTree - fun setLeftTree(newValue: BTree?) { + fun setLeftTree(newValue: TREE_TYPE?) { this.leftBTree = newValue } fun getRightTree() = this.rightBTree - fun setRightTree(newValue: BTree?) { + fun setRightTree(newValue: TREE_TYPE?) { this.rightBTree = newValue } diff --git a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt index a1d6773..f0d3814 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt +++ b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt @@ -3,7 +3,7 @@ package avlTree import balancers.AvlBalancer import BTree -class AvlTree, V>(root: AvlNode): BTree>(root){ +class AvlTree, V>(root: AvlNode): BTree, AvlTree>(root){ private val balancer = AvlBalancer() diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt index 221ae08..4396959 100644 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt @@ -2,7 +2,7 @@ package binarySearchTree import BTree -class BSTree, V>(root: BSNode): BTree>(root) { +class BSTree, V>(root: BSNode): BTree, BSTree>(root) { override fun add(node: BSNode) { TODO("Not yet implemented") diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt index b882d75..a716a63 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt @@ -3,7 +3,7 @@ package redBlackTree import BTree import balancers.RBBalancer -class RBTree, V>(root: RBNode): BTree>(root) { +class RBTree, V>(root: RBNode): BTree, RBTree>(root) { private val balancer = RBBalancer() From 9873b12aa3c2dc68cb2261c7a3de0744c9be94ca Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 27 Mar 2023 02:57:14 +0300 Subject: [PATCH 013/135] fix: Added generics to balancer due to changes in BTree --- BSTrees/src/main/kotlin/balancers/Balancer.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt index 29b2dda..e4b1917 100644 --- a/BSTrees/src/main/kotlin/balancers/Balancer.kt +++ b/BSTrees/src/main/kotlin/balancers/Balancer.kt @@ -3,8 +3,8 @@ package balancers import BTree import Node -abstract class Balancer, V, NODE_TYPE : Node, TREE_TYPE : BTree>( - val tree: TREE_TYPE +abstract class Balancer, V, NODE_TYPE : Node, TREE_TYPE : BTree>( + private val tree: TREE_TYPE ) { protected fun leftRotate() { val temp = tree.getLeftTree() From 299070e2f1b0227f23a29bc77c1e6252c0bd171e Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 27 Mar 2023 03:07:16 +0300 Subject: [PATCH 014/135] fix: Changed tree access modifier from private to protected --- BSTrees/src/main/kotlin/balancers/Balancer.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt index e4b1917..e358e7f 100644 --- a/BSTrees/src/main/kotlin/balancers/Balancer.kt +++ b/BSTrees/src/main/kotlin/balancers/Balancer.kt @@ -4,7 +4,7 @@ import BTree import Node abstract class Balancer, V, NODE_TYPE : Node, TREE_TYPE : BTree>( - private val tree: TREE_TYPE + protected val tree: TREE_TYPE ) { protected fun leftRotate() { val temp = tree.getLeftTree() From b6f26d1a1fce3ebe192febb7ff31372e80af16af Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 27 Mar 2023 03:15:11 +0300 Subject: [PATCH 015/135] feat: BSBalancer is implemented --- BSTrees/src/main/kotlin/balancers/BSBalancer.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 BSTrees/src/main/kotlin/balancers/BSBalancer.kt diff --git a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt new file mode 100644 index 0000000..ec3f14d --- /dev/null +++ b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt @@ -0,0 +1,10 @@ +package balancers + +import binarySearchTree.BSNode +import binarySearchTree.BSTree + +class BSBalancer, V>(tree: BSTree):Balancer, BSTree>(tree){ + + override fun balance() {} + +} \ No newline at end of file From a4d3e20b718ce12dec1032534414217968e1a969 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 27 Mar 2023 03:17:49 +0300 Subject: [PATCH 016/135] fix: Codestyle --- BSTrees/src/main/kotlin/balancers/BSBalancer.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt index ec3f14d..3751806 100644 --- a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt @@ -3,7 +3,7 @@ package balancers import binarySearchTree.BSNode import binarySearchTree.BSTree -class BSBalancer, V>(tree: BSTree):Balancer, BSTree>(tree){ +class BSBalancer, V>(tree: BSTree) : Balancer, BSTree>(tree) { override fun balance() {} From 3a616f4ab940da0be79c09b8af8e2144264a1396 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 27 Mar 2023 03:19:09 +0300 Subject: [PATCH 017/135] fix: Added last line --- BSTrees/src/main/kotlin/balancers/BSBalancer.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt index 3751806..94db43f 100644 --- a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt @@ -7,4 +7,4 @@ class BSBalancer, V>(tree: BSTree) : Balancer Date: Mon, 27 Mar 2023 13:49:00 +0300 Subject: [PATCH 018/135] fix: Fixed a bug in rightRotate --- BSTrees/src/main/kotlin/balancers/Balancer.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt index e358e7f..fe10457 100644 --- a/BSTrees/src/main/kotlin/balancers/Balancer.kt +++ b/BSTrees/src/main/kotlin/balancers/Balancer.kt @@ -16,10 +16,10 @@ abstract class Balancer, V, NODE_TYPE : Node, protected fun rightRotate() { val temp = tree.getRightTree() - temp?.setRightTree(tree.getLeftTree()) - tree.setLeftTree(temp) - temp?.updateHeight() + tree.setRightTree(temp?.getLeftTree()) + temp?.setLeftTree(tree) tree.updateHeight() + temp?.updateHeight() } protected fun balanceFactory(): Int { From 3254920182664b9b21b1581b607232783c1d71f4 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 3 Apr 2023 23:27:26 +0300 Subject: [PATCH 019/135] fix: Changed NODE_TYPE to nullable type --- BSTrees/src/main/kotlin/BTree.kt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/BSTrees/src/main/kotlin/BTree.kt b/BSTrees/src/main/kotlin/BTree.kt index 23c3305..a243d6c 100644 --- a/BSTrees/src/main/kotlin/BTree.kt +++ b/BSTrees/src/main/kotlin/BTree.kt @@ -1,5 +1,7 @@ +import kotlin.math.max + abstract class BTree, V, NODE_TYPE : Node, TREE_TYPE : BTree>( - private var root: NODE_TYPE + private var root: NODE_TYPE? ) { private var leftBTree: TREE_TYPE? = null @@ -7,7 +9,7 @@ abstract class BTree, V, NODE_TYPE : Node, TR fun getRoot() = this.root - fun setRoot(newRoot: NODE_TYPE) { + fun setRoot(newRoot: NODE_TYPE?) { this.root = newRoot } @@ -24,24 +26,25 @@ abstract class BTree, V, NODE_TYPE : Node, TR } fun getHeight(): Int { - return this.root.getHeight() + return this.root?.getHeight() ?: 0 } fun setHeight(newValue: Int) { - this.root.setHeight(newValue) + this.root?.setHeight(newValue) } fun updateHeight() { val leftHeight = this.getLeftTree()?.getHeight() ?: 0 val rightHeight = this.getRightTree()?.getHeight() ?: 0 - setHeight(leftHeight + rightHeight + 1) + setHeight(max(leftHeight, rightHeight) + 1) } abstract fun add(node: NODE_TYPE) fun find(key: K): V? { - if (this.root.getKey() == key) return this.root.getValue() - return if (this.root.getKey() > key) { + val temp = this.root ?: return null + if (temp.getKey() == key) return temp.getValue() + return if (temp.getKey() > key) { this.getLeftTree()?.find(key) } else { this.getRightTree()?.find(key) From 3daf43cdf01953c650b6ac6eaa4201cf0ca31321 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Thu, 6 Apr 2023 11:45:15 +0300 Subject: [PATCH 020/135] fix: Changing Balancers constructors and a small fix in leftRotate, rightRotate methods --- BSTrees/build.gradle.kts | 6 ++---- BSTrees/src/main/kotlin/avlTree/AvlTree.kt | 2 +- .../src/main/kotlin/balancers/AvlBalancer.kt | 6 +++++- .../src/main/kotlin/balancers/BSBalancer.kt | 6 ++++-- BSTrees/src/main/kotlin/balancers/Balancer.kt | 18 ++++++++++-------- .../src/main/kotlin/balancers/RBBalancer.kt | 6 +++++- BSTrees/src/main/kotlin/redBlackTree/RBTree.kt | 2 +- 7 files changed, 28 insertions(+), 18 deletions(-) diff --git a/BSTrees/build.gradle.kts b/BSTrees/build.gradle.kts index 2cf5edd..ab68414 100644 --- a/BSTrees/build.gradle.kts +++ b/BSTrees/build.gradle.kts @@ -7,11 +7,9 @@ repositories { } dependencies { - // Use the Kotlin test library. - testImplementation("org.jetbrains.kotlin:kotlin-test") + testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.1") - // Use the Kotlin JUnit integration. - testImplementation("org.jetbrains.kotlin:kotlin-test-junit") + testImplementation("org.mockito:mockito-core:3.9.0") } tasks.getByName("test") { diff --git a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt index f0d3814..1100f2f 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt +++ b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt @@ -5,7 +5,7 @@ import BTree class AvlTree, V>(root: AvlNode): BTree, AvlTree>(root){ - private val balancer = AvlBalancer() + private val balancer = AvlBalancer(this) override fun add(node: AvlNode) { TODO("Not yet implemented") diff --git a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt b/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt index 397d067..14f3852 100644 --- a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt @@ -1,6 +1,10 @@ package balancers -open class AvlBalancer: Balancer() { +import avlTree.AvlNode +import avlTree.AvlTree + + +open class AvlBalancer, V>(tree: AvlTree?) : Balancer, AvlTree>(tree) { override fun balance() { TODO("Not yet implemented") diff --git a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt index 94db43f..528fe97 100644 --- a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt @@ -3,8 +3,10 @@ package balancers import binarySearchTree.BSNode import binarySearchTree.BSTree -class BSBalancer, V>(tree: BSTree) : Balancer, BSTree>(tree) { +open class BSBalancer, V>(tree: BSTree?) : Balancer, BSTree>(tree) { - override fun balance() {} + override fun balance() { + TODO("Not yet implemented") + } } diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt index fe10457..2b3f337 100644 --- a/BSTrees/src/main/kotlin/balancers/Balancer.kt +++ b/BSTrees/src/main/kotlin/balancers/Balancer.kt @@ -4,26 +4,28 @@ import BTree import Node abstract class Balancer, V, NODE_TYPE : Node, TREE_TYPE : BTree>( - protected val tree: TREE_TYPE + protected var tree: TREE_TYPE? ) { protected fun leftRotate() { - val temp = tree.getLeftTree() - tree.setLeftTree(temp?.getRightTree()) + val temp = tree?.getLeftTree() + tree?.setLeftTree(temp?.getRightTree()) temp?.setRightTree(tree) - tree.updateHeight() + tree?.updateHeight() temp?.updateHeight() + tree = temp } protected fun rightRotate() { - val temp = tree.getRightTree() - tree.setRightTree(temp?.getLeftTree()) + val temp = tree?.getRightTree() + tree?.setRightTree(temp?.getLeftTree()) temp?.setLeftTree(tree) - tree.updateHeight() + tree?.updateHeight() temp?.updateHeight() + tree = temp } protected fun balanceFactory(): Int { - return (tree.getRightTree()?.getRoot()?.getHeight() ?: 0) - (tree.getLeftTree()?.getRoot()?.getHeight() ?: 0) + return (tree?.getRightTree()?.getRoot()?.getHeight() ?: 0) - (tree?.getLeftTree()?.getRoot()?.getHeight() ?: 0) } abstract fun balance() diff --git a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt index 673aabf..f4d9d77 100644 --- a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt @@ -1,7 +1,11 @@ package balancers -open class RBBalancer: Balancer() { +import redBlackTree.RBNode +import redBlackTree.RBTree +open class RBBalancer, V>(tree: RBTree?) : Balancer, RBTree>(tree) { + + //update parent override fun balance() { TODO("Not yet implemented") } diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt index a716a63..44ec4d9 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt @@ -5,7 +5,7 @@ import balancers.RBBalancer class RBTree, V>(root: RBNode): BTree, RBTree>(root) { - private val balancer = RBBalancer() + private val balancer = RBBalancer(this) override fun add(node: RBNode) { TODO("Not yet implemented") From ca5a9da9feb9defe25491831966f3ad3cadece1f Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Thu, 6 Apr 2023 16:47:54 +0300 Subject: [PATCH 021/135] feat: Added tests for Balancer class --- BSTrees/build.gradle.kts | 1 + .../src/test/kotlin/balancers/BalancerTest.kt | 39 ++++++++++ BSTrees/src/test/kotlin/utils/BSTreeUtil.kt | 76 +++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 BSTrees/src/test/kotlin/balancers/BalancerTest.kt create mode 100644 BSTrees/src/test/kotlin/utils/BSTreeUtil.kt diff --git a/BSTrees/build.gradle.kts b/BSTrees/build.gradle.kts index ab68414..3f46689 100644 --- a/BSTrees/build.gradle.kts +++ b/BSTrees/build.gradle.kts @@ -8,6 +8,7 @@ repositories { dependencies { testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.1") + testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.1") testImplementation("org.mockito:mockito-core:3.9.0") } diff --git a/BSTrees/src/test/kotlin/balancers/BalancerTest.kt b/BSTrees/src/test/kotlin/balancers/BalancerTest.kt new file mode 100644 index 0000000..99558ef --- /dev/null +++ b/BSTrees/src/test/kotlin/balancers/BalancerTest.kt @@ -0,0 +1,39 @@ +package balancers + +import binarySearchTree.BSTree +import utils.BSTreeUtil + +import org.junit.jupiter.api.Test + +class BalancerTest { + + @Test + fun testLeftRotate() { + val balancer = BSBalancer(BSTreeUtil.createBSTree()) + + val privateLeftRotateField = Balancer::class.java.getDeclaredMethod("leftRotate") + privateLeftRotateField.isAccessible = true + privateLeftRotateField.invoke(balancer) + + val protectedTreeField = Balancer::class.java.getDeclaredField("tree") + protectedTreeField.isAccessible = true + val newTree = protectedTreeField.get(balancer) as BSTree + + assert(BSTreeUtil.checkTreeEquals(newTree, BSTreeUtil.createLeftRotatedBSTree())) + } + + @Test + fun testRightRotate() { + val balancer = BSBalancer(BSTreeUtil.createBSTree()) + + val privateRightRotateField = Balancer::class.java.getDeclaredMethod("rightRotate") + privateRightRotateField.isAccessible = true + privateRightRotateField.invoke(balancer) + + val protectedTreeField = Balancer::class.java.getDeclaredField("tree") + protectedTreeField.isAccessible = true + val newTree = protectedTreeField.get(balancer) as BSTree + + assert(BSTreeUtil.checkTreeEquals(newTree, BSTreeUtil.createRightRotatedBSTree())) + } +} \ No newline at end of file diff --git a/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt b/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt new file mode 100644 index 0000000..dd920ae --- /dev/null +++ b/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt @@ -0,0 +1,76 @@ +package utils + +import binarySearchTree.BSNode +import binarySearchTree.BSTree + + +/** + * BSTreeUtil performs the BSTree handler function for test classes + */ +object BSTreeUtil { + + fun checkTreeEquals(tree1: BSTree<*, *>?, tree2: BSTree<*, *>?): Boolean { + if (tree1 == null || tree2 == null) { + return tree1 == null && tree2 == null + } + return checkRootEquals(tree1.getRoot(), tree2.getRoot()) && + checkTreeEquals(tree1.getLeftTree(), tree2.getLeftTree()) && + checkTreeEquals(tree1.getRightTree(), tree2.getRightTree()) + } + + fun checkRootEquals(root1: BSNode<*, *>?, root2: BSNode<*, *>?): Boolean { + if (root1 == null || root2 == null) { + return root1 == null && root2 == null + } + return root1.getKey() == root2.getKey() && root1.getValue() == root1.getValue() + } + + fun createBSTree(): BSTree { + val testBSTree: BSTree = BSTree(BSNode(0, 0)) + + val leftSubTestBSTree = BSTree(BSNode(-2, 2)) + leftSubTestBSTree.setLeftTree(BSTree(BSNode(-3, 5))) + leftSubTestBSTree.setRightTree(BSTree(BSNode(-1, 6))) + + val rightSubTestBSTree = BSTree(BSNode(2, 3)) + rightSubTestBSTree.setLeftTree(BSTree(BSNode(1, 7))) + rightSubTestBSTree.setRightTree(BSTree(BSNode(3, 8))) + + testBSTree.setLeftTree(leftSubTestBSTree) + testBSTree.setRightTree(rightSubTestBSTree) + + return testBSTree + } + + fun createLeftRotatedBSTree(): BSTree { + val leftRotatedTestBSTree: BSTree = BSTree(BSNode(-2, 2)) + + leftRotatedTestBSTree.setLeftTree(BSTree(BSNode(-3, 5))) + leftRotatedTestBSTree.setRightTree(BSTree(BSNode(0, 0))) + + val rightRotatedSubTestBSTree = BSTree(BSNode(2, 3)) + rightRotatedSubTestBSTree.setLeftTree(BSTree(BSNode(1, 7))) + rightRotatedSubTestBSTree.setRightTree(BSTree(BSNode(3, 8))) + + leftRotatedTestBSTree.getRightTree()?.setLeftTree(BSTree(BSNode(-1, 6))) + leftRotatedTestBSTree.getRightTree()?.setRightTree(rightRotatedSubTestBSTree) + + return leftRotatedTestBSTree + } + + fun createRightRotatedBSTree(): BSTree { + val rightRotatedTestBSTree: BSTree = BSTree(BSNode(2, 3)) + + rightRotatedTestBSTree.setRightTree(BSTree(BSNode(3, 8))) + rightRotatedTestBSTree.setLeftTree(BSTree(BSNode(0, 0))) + + val leftRotatedSubTestBSTree = BSTree(BSNode(-2, 2)) + leftRotatedSubTestBSTree.setLeftTree(BSTree(BSNode(-3, 5))) + leftRotatedSubTestBSTree.setRightTree(BSTree(BSNode(-1, 6))) + + rightRotatedTestBSTree.getLeftTree()?.setRightTree(BSTree(BSNode(1, 7))) + rightRotatedTestBSTree.getLeftTree()?.setLeftTree(leftRotatedSubTestBSTree) + + return rightRotatedTestBSTree + } +} \ No newline at end of file From d6b41caf598532bdfa01563074546a06ce2ec04a Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Fri, 7 Apr 2023 00:29:52 +0300 Subject: [PATCH 022/135] feat: Changing the architecture. Now Node stores information about its sons and parent --- BSTrees/src/main/kotlin/BTree.kt | 48 ++++------- BSTrees/src/main/kotlin/Node.kt | 29 +++++++ BSTrees/src/main/kotlin/avlTree/AvlTree.kt | 7 +- .../src/main/kotlin/balancers/AvlBalancer.kt | 5 +- .../src/main/kotlin/balancers/BSBalancer.kt | 5 +- BSTrees/src/main/kotlin/balancers/Balancer.kt | 35 ++++---- .../src/main/kotlin/balancers/RBBalancer.kt | 5 +- .../main/kotlin/binarySearchTree/BSTree.kt | 6 +- .../src/main/kotlin/redBlackTree/RBNode.kt | 4 +- .../src/main/kotlin/redBlackTree/RBTree.kt | 8 +- .../src/test/kotlin/balancers/BalancerTest.kt | 29 +++---- BSTrees/src/test/kotlin/utils/BSTreeUtil.kt | 82 +++++++++++-------- 12 files changed, 140 insertions(+), 123 deletions(-) diff --git a/BSTrees/src/main/kotlin/BTree.kt b/BSTrees/src/main/kotlin/BTree.kt index a243d6c..fd8e1a0 100644 --- a/BSTrees/src/main/kotlin/BTree.kt +++ b/BSTrees/src/main/kotlin/BTree.kt @@ -1,54 +1,36 @@ -import kotlin.math.max +abstract class BTree, V, NODE_TYPE : Node>{ -abstract class BTree, V, NODE_TYPE : Node, TREE_TYPE : BTree>( - private var root: NODE_TYPE? -) { + private var root: NODE_TYPE? = null - private var leftBTree: TREE_TYPE? = null - private var rightBTree: TREE_TYPE? = null - - fun getRoot() = this.root + fun getRoot() = root fun setRoot(newRoot: NODE_TYPE?) { - this.root = newRoot - } - - fun getLeftTree() = this.leftBTree - - fun setLeftTree(newValue: TREE_TYPE?) { - this.leftBTree = newValue - } - - fun getRightTree() = this.rightBTree - - fun setRightTree(newValue: TREE_TYPE?) { - this.rightBTree = newValue + root = newRoot } fun getHeight(): Int { - return this.root?.getHeight() ?: 0 + return root?.getHeight() ?: 0 } fun setHeight(newValue: Int) { this.root?.setHeight(newValue) } - fun updateHeight() { - val leftHeight = this.getLeftTree()?.getHeight() ?: 0 - val rightHeight = this.getRightTree()?.getHeight() ?: 0 - setHeight(max(leftHeight, rightHeight) + 1) - } + abstract fun insert(key: K, value: V) abstract fun add(node: NODE_TYPE) fun find(key: K): V? { - val temp = this.root ?: return null - if (temp.getKey() == key) return temp.getValue() - return if (temp.getKey() > key) { - this.getLeftTree()?.find(key) - } else { - this.getRightTree()?.find(key) + var temp: NODE_TYPE? = root ?: return null + while(temp != null){ + if(temp.getKey() == key)return temp.getValue() + temp = if(temp.getKey() > key){ + temp.getLeftNode() + } else{ + temp.getRightNode() + } } + return null } abstract fun delete(key: K) diff --git a/BSTrees/src/main/kotlin/Node.kt b/BSTrees/src/main/kotlin/Node.kt index 84f185c..8174900 100644 --- a/BSTrees/src/main/kotlin/Node.kt +++ b/BSTrees/src/main/kotlin/Node.kt @@ -1,5 +1,10 @@ +import kotlin.math.max + abstract class Node, V, NODE_TYPE : Node>(private val key: K, private var value: V) { + private var parent: NODE_TYPE? = null + private var leftNode: NODE_TYPE? = null + private var rightNode: NODE_TYPE? = null private var height = 1 fun getKey() = this.key @@ -10,10 +15,34 @@ abstract class Node, V, NODE_TYPE : Node>(pri this.value = newValue } + fun getParent() = parent + + fun setParent(newNode: NODE_TYPE?){ + parent = newNode + } + + fun getLeftNode() = leftNode + + fun setLeftNode(newNode: NODE_TYPE?){ + leftNode = newNode + } + + fun getRightNode() = rightNode + + fun setRightNode(newNode: NODE_TYPE?){ + rightNode = newNode + } + fun getHeight() = this.height fun setHeight(newValue: Int) { this.height = newValue } + fun updateHeight() { + val leftHeight = leftNode?.getHeight() ?: 0 + val rightHeight = rightNode?.getHeight() ?: 0 + setHeight(max(leftHeight, rightHeight) + 1) + } + } diff --git a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt index 1100f2f..e84f7d2 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt +++ b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt @@ -3,10 +3,13 @@ package avlTree import balancers.AvlBalancer import BTree -class AvlTree, V>(root: AvlNode): BTree, AvlTree>(root){ +class AvlTree, V>: BTree>() { - private val balancer = AvlBalancer(this) + private val balancer = AvlBalancer() + override fun insert(key: K, value: V) { + TODO("Not yet implemented") + } override fun add(node: AvlNode) { TODO("Not yet implemented") } diff --git a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt b/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt index 14f3852..65120e3 100644 --- a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt @@ -1,12 +1,11 @@ package balancers import avlTree.AvlNode -import avlTree.AvlTree -open class AvlBalancer, V>(tree: AvlTree?) : Balancer, AvlTree>(tree) { +open class AvlBalancer, V> : Balancer>() { - override fun balance() { + override fun balance(node: AvlNode?) { TODO("Not yet implemented") } } diff --git a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt index 528fe97..bde91df 100644 --- a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt @@ -1,11 +1,10 @@ package balancers import binarySearchTree.BSNode -import binarySearchTree.BSTree -open class BSBalancer, V>(tree: BSTree?) : Balancer, BSTree>(tree) { +open class BSBalancer, V>: Balancer>() { - override fun balance() { + override fun balance(node: BSNode?) { TODO("Not yet implemented") } diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt index 2b3f337..c37975e 100644 --- a/BSTrees/src/main/kotlin/balancers/Balancer.kt +++ b/BSTrees/src/main/kotlin/balancers/Balancer.kt @@ -1,32 +1,29 @@ package balancers -import BTree import Node -abstract class Balancer, V, NODE_TYPE : Node, TREE_TYPE : BTree>( - protected var tree: TREE_TYPE? -) { - protected fun leftRotate() { - val temp = tree?.getLeftTree() - tree?.setLeftTree(temp?.getRightTree()) - temp?.setRightTree(tree) - tree?.updateHeight() +abstract class Balancer, V, NODE_TYPE : Node>{ + protected fun leftRotate(node: NODE_TYPE?): NODE_TYPE? { + val temp = node?.getLeftNode() + node?.setLeftNode(temp?.getRightNode()) + temp?.setRightNode(node) + node?.updateHeight() temp?.updateHeight() - tree = temp + return temp } - protected fun rightRotate() { - val temp = tree?.getRightTree() - tree?.setRightTree(temp?.getLeftTree()) - temp?.setLeftTree(tree) - tree?.updateHeight() + protected fun rightRotate(node: NODE_TYPE?): NODE_TYPE? { + val temp = node?.getRightNode() + node?.setRightNode(temp?.getLeftNode()) + temp?.setLeftNode(node) + node?.updateHeight() temp?.updateHeight() - tree = temp + return temp } - protected fun balanceFactory(): Int { - return (tree?.getRightTree()?.getRoot()?.getHeight() ?: 0) - (tree?.getLeftTree()?.getRoot()?.getHeight() ?: 0) + protected fun balanceFactory(node: NODE_TYPE?): Int { + return (node?.getRightNode()?.getHeight() ?: 0) - (node?.getLeftNode()?.getHeight() ?: 0) } - abstract fun balance() + abstract fun balance(node: NODE_TYPE?) } diff --git a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt index f4d9d77..a077855 100644 --- a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt @@ -1,12 +1,11 @@ package balancers import redBlackTree.RBNode -import redBlackTree.RBTree -open class RBBalancer, V>(tree: RBTree?) : Balancer, RBTree>(tree) { +open class RBBalancer, V>: Balancer>() { //update parent - override fun balance() { + override fun balance(node: RBNode?) { TODO("Not yet implemented") } } diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt index 4396959..dd535b7 100644 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt @@ -2,8 +2,11 @@ package binarySearchTree import BTree -class BSTree, V>(root: BSNode): BTree, BSTree>(root) { +class BSTree, V>: BTree>() { + override fun insert(key: K, value: V) { + TODO("Not yet implemented") + } override fun add(node: BSNode) { TODO("Not yet implemented") } @@ -11,5 +14,4 @@ class BSTree, V>(root: BSNode): BTree, override fun delete(key: K) { TODO("Not yet implemented") } - } diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt b/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt index 0cf7893..a04ff4c 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt @@ -11,7 +11,7 @@ class RBNode, V>(key: K, value: V): Node>(ke var color = Color.RED - fun changeColor(){ - TODO("Not yet implemented") + fun setNodeColor(newColor: Color){ + color = newColor } } diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt index 44ec4d9..77da0ce 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt @@ -3,9 +3,13 @@ package redBlackTree import BTree import balancers.RBBalancer -class RBTree, V>(root: RBNode): BTree, RBTree>(root) { +class RBTree, V> : BTree>() { - private val balancer = RBBalancer(this) + private val balancer = RBBalancer() + + override fun insert(key: K, value: V) { + add(RBNode(key, value)) + } override fun add(node: RBNode) { TODO("Not yet implemented") diff --git a/BSTrees/src/test/kotlin/balancers/BalancerTest.kt b/BSTrees/src/test/kotlin/balancers/BalancerTest.kt index 99558ef..667484f 100644 --- a/BSTrees/src/test/kotlin/balancers/BalancerTest.kt +++ b/BSTrees/src/test/kotlin/balancers/BalancerTest.kt @@ -1,39 +1,32 @@ package balancers -import binarySearchTree.BSTree -import utils.BSTreeUtil +import Node +import binarySearchTree.BSNode import org.junit.jupiter.api.Test +import utils.BSTreeUtil class BalancerTest { @Test fun testLeftRotate() { - val balancer = BSBalancer(BSTreeUtil.createBSTree()) + val balancer = BSBalancer() - val privateLeftRotateField = Balancer::class.java.getDeclaredMethod("leftRotate") + val privateLeftRotateField = Balancer::class.java.getDeclaredMethod("leftRotate", Node::class.java) privateLeftRotateField.isAccessible = true - privateLeftRotateField.invoke(balancer) + val newNode = privateLeftRotateField.invoke(balancer, BSTreeUtil.createBSTree().getRoot()) as BSNode - val protectedTreeField = Balancer::class.java.getDeclaredField("tree") - protectedTreeField.isAccessible = true - val newTree = protectedTreeField.get(balancer) as BSTree - - assert(BSTreeUtil.checkTreeEquals(newTree, BSTreeUtil.createLeftRotatedBSTree())) + assert(BSTreeUtil.checkNodeEquals(newNode, BSTreeUtil.createLeftRotatedBSTree().getRoot())) } @Test fun testRightRotate() { - val balancer = BSBalancer(BSTreeUtil.createBSTree()) + val balancer = BSBalancer() - val privateRightRotateField = Balancer::class.java.getDeclaredMethod("rightRotate") + val privateRightRotateField = Balancer::class.java.getDeclaredMethod("rightRotate", Node::class.java) privateRightRotateField.isAccessible = true - privateRightRotateField.invoke(balancer) - - val protectedTreeField = Balancer::class.java.getDeclaredField("tree") - protectedTreeField.isAccessible = true - val newTree = protectedTreeField.get(balancer) as BSTree + val newNode = privateRightRotateField.invoke(balancer, BSTreeUtil.createBSTree().getRoot()) as BSNode - assert(BSTreeUtil.checkTreeEquals(newTree, BSTreeUtil.createRightRotatedBSTree())) + assert(BSTreeUtil.checkNodeEquals(newNode, BSTreeUtil.createRightRotatedBSTree().getRoot())) } } \ No newline at end of file diff --git a/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt b/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt index dd920ae..2c4aa99 100644 --- a/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt +++ b/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt @@ -9,67 +9,77 @@ import binarySearchTree.BSTree */ object BSTreeUtil { - fun checkTreeEquals(tree1: BSTree<*, *>?, tree2: BSTree<*, *>?): Boolean { - if (tree1 == null || tree2 == null) { - return tree1 == null && tree2 == null - } - return checkRootEquals(tree1.getRoot(), tree2.getRoot()) && - checkTreeEquals(tree1.getLeftTree(), tree2.getLeftTree()) && - checkTreeEquals(tree1.getRightTree(), tree2.getRightTree()) - } - - fun checkRootEquals(root1: BSNode<*, *>?, root2: BSNode<*, *>?): Boolean { + fun checkNodeEquals(root1: BSNode<*, *>?, root2: BSNode<*, *>?): Boolean { if (root1 == null || root2 == null) { return root1 == null && root2 == null } - return root1.getKey() == root2.getKey() && root1.getValue() == root1.getValue() + return root1.getKey() == root2.getKey() && root1.getValue() == root1.getValue() && + checkNodeEquals(root1.getLeftNode(), root2.getLeftNode()) && + checkNodeEquals(root1.getRightNode(), root2.getRightNode()) } + + // This will be rewritten when the BSTree implementation is added fun createBSTree(): BSTree { - val testBSTree: BSTree = BSTree(BSNode(0, 0)) + val testBSTree: BSTree = BSTree() + testBSTree.setRoot(BSNode(0, 0)) + val testBSTreeRoot = testBSTree.getRoot()!! + + val leftSubTestBSTree: BSTree = BSTree() + leftSubTestBSTree.setRoot(BSNode(-2, 2)) + val leftSubTestBSTreeRoot = leftSubTestBSTree.getRoot()!! + leftSubTestBSTreeRoot.setLeftNode(BSNode(-3, 5)) + leftSubTestBSTreeRoot.setRightNode(BSNode(-1, 6)) - val leftSubTestBSTree = BSTree(BSNode(-2, 2)) - leftSubTestBSTree.setLeftTree(BSTree(BSNode(-3, 5))) - leftSubTestBSTree.setRightTree(BSTree(BSNode(-1, 6))) + val rightSubTestBSTree: BSTree = BSTree() + rightSubTestBSTree.setRoot(BSNode(2, 3)) + val rightSubTestBSTreeRoot = rightSubTestBSTree.getRoot()!! + rightSubTestBSTreeRoot.setLeftNode(BSNode(1, 7)) + rightSubTestBSTreeRoot.setRightNode(BSNode(3, 8)) - val rightSubTestBSTree = BSTree(BSNode(2, 3)) - rightSubTestBSTree.setLeftTree(BSTree(BSNode(1, 7))) - rightSubTestBSTree.setRightTree(BSTree(BSNode(3, 8))) - testBSTree.setLeftTree(leftSubTestBSTree) - testBSTree.setRightTree(rightSubTestBSTree) + testBSTreeRoot.setLeftNode(leftSubTestBSTreeRoot) + testBSTreeRoot.setRightNode(rightSubTestBSTreeRoot) return testBSTree } fun createLeftRotatedBSTree(): BSTree { - val leftRotatedTestBSTree: BSTree = BSTree(BSNode(-2, 2)) + val leftRotatedTestBSTree: BSTree = BSTree() + leftRotatedTestBSTree.setRoot(BSNode(-2, 2)) + val leftRotatedTestBSTreeRoot = leftRotatedTestBSTree.getRoot()!! - leftRotatedTestBSTree.setLeftTree(BSTree(BSNode(-3, 5))) - leftRotatedTestBSTree.setRightTree(BSTree(BSNode(0, 0))) + leftRotatedTestBSTreeRoot.setLeftNode(BSNode(-3, 5)) + leftRotatedTestBSTreeRoot.setRightNode(BSNode(0, 0)) - val rightRotatedSubTestBSTree = BSTree(BSNode(2, 3)) - rightRotatedSubTestBSTree.setLeftTree(BSTree(BSNode(1, 7))) - rightRotatedSubTestBSTree.setRightTree(BSTree(BSNode(3, 8))) + val rightRotatedSubTestBSTree: BSTree = BSTree() + rightRotatedSubTestBSTree.setRoot(BSNode(2, 3)) + val rightRotatedSubTestBSTreeRoot = rightRotatedSubTestBSTree.getRoot()!! + rightRotatedSubTestBSTreeRoot.setLeftNode(BSNode(1, 7)) + rightRotatedSubTestBSTreeRoot.setRightNode(BSNode(3, 8)) - leftRotatedTestBSTree.getRightTree()?.setLeftTree(BSTree(BSNode(-1, 6))) - leftRotatedTestBSTree.getRightTree()?.setRightTree(rightRotatedSubTestBSTree) + leftRotatedTestBSTreeRoot.getRightNode()?.setLeftNode(BSNode(-1, 6)) + leftRotatedTestBSTreeRoot.getRightNode()?.setRightNode(rightRotatedSubTestBSTreeRoot) return leftRotatedTestBSTree } fun createRightRotatedBSTree(): BSTree { - val rightRotatedTestBSTree: BSTree = BSTree(BSNode(2, 3)) + val rightRotatedTestBSTree: BSTree = BSTree() + rightRotatedTestBSTree.setRoot(BSNode(2, 3)) + val rightRotatedTestBSTreeRoot = rightRotatedTestBSTree.getRoot()!! - rightRotatedTestBSTree.setRightTree(BSTree(BSNode(3, 8))) - rightRotatedTestBSTree.setLeftTree(BSTree(BSNode(0, 0))) + rightRotatedTestBSTreeRoot.setRightNode(BSNode(3, 8)) + rightRotatedTestBSTreeRoot.setLeftNode(BSNode(0, 0)) - val leftRotatedSubTestBSTree = BSTree(BSNode(-2, 2)) - leftRotatedSubTestBSTree.setLeftTree(BSTree(BSNode(-3, 5))) - leftRotatedSubTestBSTree.setRightTree(BSTree(BSNode(-1, 6))) + val leftRotatedSubTestBSTree: BSTree = BSTree() + leftRotatedSubTestBSTree.setRoot(BSNode(-2, 2)) + val leftRotatedSubTestBSTreeRoot = leftRotatedSubTestBSTree.getRoot()!! + leftRotatedSubTestBSTreeRoot.setLeftNode(BSNode(-3, 5)) + leftRotatedSubTestBSTreeRoot.setRightNode(BSNode(-1, 6)) - rightRotatedTestBSTree.getLeftTree()?.setRightTree(BSTree(BSNode(1, 7))) - rightRotatedTestBSTree.getLeftTree()?.setLeftTree(leftRotatedSubTestBSTree) + rightRotatedTestBSTreeRoot.getLeftNode()?.setRightNode(BSNode(1, 7)) + rightRotatedTestBSTreeRoot.getLeftNode()?.setLeftNode(leftRotatedSubTestBSTreeRoot) return rightRotatedTestBSTree } From cad65296cc8b2cb14b5150a93f1ca8f358459247 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Fri, 7 Apr 2023 00:30:38 +0300 Subject: [PATCH 023/135] feat: Added implementation of the 'add' method in RBTree --- .../src/main/kotlin/redBlackTree/RBTree.kt | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt index 77da0ce..a18a110 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt @@ -12,11 +12,42 @@ class RBTree, V> : BTree>() { } override fun add(node: RBNode) { - TODO("Not yet implemented") + var root = this.getRoot() + if (root == null) { + this.setRoot(node) + return + } + while (true) { + root ?: error("IT IS IMPOSSIBLE!!!") + if (root.getKey() > node.getKey()) { + val leftNode = root.getLeftNode() + if (leftNode == null) { + node.setNodeColor(RBNode.Color.RED) + root.setLeftNode(node) + root.getLeftNode()?.setParent(root) + balancer.balance(root) + break + } else { + root = leftNode + val newTree = RBTree() + newTree.setRoot(root) + + } + } else { + val rightNode = root.getRightNode() + if (rightNode == null) { + node.setNodeColor(RBNode.Color.RED) + root.setRightNode(node) + root.getRightNode()?.setParent(root) + break + } else { + root = rightNode + } + } + } } override fun delete(key: K) { TODO("Not yet implemented") } - } From 5aebc83475c6cfacaf713674277d349ffec50307 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 9 Apr 2023 20:38:03 +0300 Subject: [PATCH 024/135] fix: leftRotate and rightRotate methods have been rewritten --- BSTrees/src/main/kotlin/BTree.kt | 11 ++-- BSTrees/src/main/kotlin/avlTree/AvlTree.kt | 3 - .../src/main/kotlin/balancers/AvlBalancer.kt | 4 +- .../src/main/kotlin/balancers/BSBalancer.kt | 2 +- BSTrees/src/main/kotlin/balancers/Balancer.kt | 48 +++++++++++----- .../src/main/kotlin/balancers/RBBalancer.kt | 5 +- .../src/main/kotlin/redBlackTree/RBNode.kt | 6 +- .../src/main/kotlin/redBlackTree/RBTree.kt | 10 ++-- .../src/test/kotlin/balancers/BalancerTest.kt | 9 +-- BSTrees/src/test/kotlin/utils/BSTreeUtil.kt | 56 +++++++++---------- 10 files changed, 82 insertions(+), 72 deletions(-) diff --git a/BSTrees/src/main/kotlin/BTree.kt b/BSTrees/src/main/kotlin/BTree.kt index fd8e1a0..f0cc63d 100644 --- a/BSTrees/src/main/kotlin/BTree.kt +++ b/BSTrees/src/main/kotlin/BTree.kt @@ -1,12 +1,11 @@ abstract class BTree, V, NODE_TYPE : Node>{ - private var root: NODE_TYPE? = null - - fun getRoot() = root + var root: NODE_TYPE? = null + get() = field + set(value){ + field = value + } - fun setRoot(newRoot: NODE_TYPE?) { - root = newRoot - } fun getHeight(): Int { return root?.getHeight() ?: 0 diff --git a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt index e84f7d2..cdda2bb 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt +++ b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt @@ -1,12 +1,9 @@ package avlTree -import balancers.AvlBalancer import BTree class AvlTree, V>: BTree>() { - private val balancer = AvlBalancer() - override fun insert(key: K, value: V) { TODO("Not yet implemented") } diff --git a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt b/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt index 65120e3..e6304cd 100644 --- a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt @@ -3,9 +3,9 @@ package balancers import avlTree.AvlNode -open class AvlBalancer, V> : Balancer>() { +open class AvlBalancer, V>: Balancer>() { - override fun balance(node: AvlNode?) { + override fun balance(node: AvlNode): AvlNode { TODO("Not yet implemented") } } diff --git a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt index bde91df..6f63f44 100644 --- a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt @@ -4,7 +4,7 @@ import binarySearchTree.BSNode open class BSBalancer, V>: Balancer>() { - override fun balance(node: BSNode?) { + override fun balance(node: BSNode): BSNode { TODO("Not yet implemented") } diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt index c37975e..5046521 100644 --- a/BSTrees/src/main/kotlin/balancers/Balancer.kt +++ b/BSTrees/src/main/kotlin/balancers/Balancer.kt @@ -3,27 +3,45 @@ package balancers import Node abstract class Balancer, V, NODE_TYPE : Node>{ - protected fun leftRotate(node: NODE_TYPE?): NODE_TYPE? { - val temp = node?.getLeftNode() - node?.setLeftNode(temp?.getRightNode()) - temp?.setRightNode(node) - node?.updateHeight() + protected fun leftRotate(node: NODE_TYPE): NODE_TYPE { + val nodeParent = node.getParent() + val temp = node.getRightNode() + temp?.setParent(nodeParent) + if(nodeParent?.getLeftNode() == node)nodeParent.setLeftNode(temp) else nodeParent?.setRightNode(temp) + + node.setRightNode(temp?.getLeftNode()) + node.getRightNode()?.setParent(node) + + temp?.setLeftNode(node) + node.setParent(temp) + + node.updateHeight() temp?.updateHeight() - return temp + + return temp ?: node } - protected fun rightRotate(node: NODE_TYPE?): NODE_TYPE? { - val temp = node?.getRightNode() - node?.setRightNode(temp?.getLeftNode()) - temp?.setLeftNode(node) - node?.updateHeight() + protected fun rightRotate(node: NODE_TYPE): NODE_TYPE{ + val nodeParent = node.getParent() + val temp = node.getLeftNode() + temp?.setParent(nodeParent) + if(nodeParent?.getLeftNode() == node)nodeParent.setLeftNode(temp) else nodeParent?.setRightNode(temp) + + node.setLeftNode(temp?.getRightNode()) + node.getLeftNode()?.setParent(node) + + temp?.setRightNode(node) + node.setParent(temp) + + node.updateHeight() temp?.updateHeight() - return temp + + return temp ?: node } - protected fun balanceFactory(node: NODE_TYPE?): Int { - return (node?.getRightNode()?.getHeight() ?: 0) - (node?.getLeftNode()?.getHeight() ?: 0) + protected fun balanceFactory(node: NODE_TYPE): Int { + return (node.getRightNode()?.getHeight() ?: 0) - (node.getLeftNode()?.getHeight() ?: 0) } - abstract fun balance(node: NODE_TYPE?) + abstract fun balance(node: NODE_TYPE): NODE_TYPE } diff --git a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt index a077855..531111f 100644 --- a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt @@ -2,10 +2,9 @@ package balancers import redBlackTree.RBNode -open class RBBalancer, V>: Balancer>() { +open class RBBalancer, V>: Balancer>(){ - //update parent - override fun balance(node: RBNode?) { + override fun balance(node: RBNode): RBNode { TODO("Not yet implemented") } } diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt b/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt index a04ff4c..7d678bd 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt @@ -9,9 +9,5 @@ class RBNode, V>(key: K, value: V): Node>(ke RED } - var color = Color.RED - - fun setNodeColor(newColor: Color){ - color = newColor - } + var color = Color.BLACK } diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt index a18a110..7ca5f9b 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt @@ -12,9 +12,9 @@ class RBTree, V> : BTree>() { } override fun add(node: RBNode) { - var root = this.getRoot() + var root = this.root if (root == null) { - this.setRoot(node) + this.root = node return } while (true) { @@ -22,7 +22,7 @@ class RBTree, V> : BTree>() { if (root.getKey() > node.getKey()) { val leftNode = root.getLeftNode() if (leftNode == null) { - node.setNodeColor(RBNode.Color.RED) + node.color = RBNode.Color.RED root.setLeftNode(node) root.getLeftNode()?.setParent(root) balancer.balance(root) @@ -30,13 +30,13 @@ class RBTree, V> : BTree>() { } else { root = leftNode val newTree = RBTree() - newTree.setRoot(root) + newTree.root = root } } else { val rightNode = root.getRightNode() if (rightNode == null) { - node.setNodeColor(RBNode.Color.RED) + node.color = RBNode.Color.RED root.setRightNode(node) root.getRightNode()?.setParent(root) break diff --git a/BSTrees/src/test/kotlin/balancers/BalancerTest.kt b/BSTrees/src/test/kotlin/balancers/BalancerTest.kt index 667484f..8880c4f 100644 --- a/BSTrees/src/test/kotlin/balancers/BalancerTest.kt +++ b/BSTrees/src/test/kotlin/balancers/BalancerTest.kt @@ -6,6 +6,7 @@ import binarySearchTree.BSNode import org.junit.jupiter.api.Test import utils.BSTreeUtil +@Suppress("UNCHECKED_CAST") class BalancerTest { @Test @@ -14,9 +15,9 @@ class BalancerTest { val privateLeftRotateField = Balancer::class.java.getDeclaredMethod("leftRotate", Node::class.java) privateLeftRotateField.isAccessible = true - val newNode = privateLeftRotateField.invoke(balancer, BSTreeUtil.createBSTree().getRoot()) as BSNode + val newNode = privateLeftRotateField.invoke(balancer, BSTreeUtil.createBSTree().root) as BSNode - assert(BSTreeUtil.checkNodeEquals(newNode, BSTreeUtil.createLeftRotatedBSTree().getRoot())) + assert(BSTreeUtil.checkNodeEquals(newNode, BSTreeUtil.createLeftRotatedBSTree().root)) } @Test @@ -25,8 +26,8 @@ class BalancerTest { val privateRightRotateField = Balancer::class.java.getDeclaredMethod("rightRotate", Node::class.java) privateRightRotateField.isAccessible = true - val newNode = privateRightRotateField.invoke(balancer, BSTreeUtil.createBSTree().getRoot()) as BSNode + val newNode = privateRightRotateField.invoke(balancer, BSTreeUtil.createBSTree().root) as BSNode - assert(BSTreeUtil.checkNodeEquals(newNode, BSTreeUtil.createRightRotatedBSTree().getRoot())) + assert(BSTreeUtil.checkNodeEquals(newNode, BSTreeUtil.createRightRotatedBSTree().root)) } } \ No newline at end of file diff --git a/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt b/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt index 2c4aa99..2b82113 100644 --- a/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt +++ b/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt @@ -22,18 +22,18 @@ object BSTreeUtil { // This will be rewritten when the BSTree implementation is added fun createBSTree(): BSTree { val testBSTree: BSTree = BSTree() - testBSTree.setRoot(BSNode(0, 0)) - val testBSTreeRoot = testBSTree.getRoot()!! + testBSTree.root = BSNode(0, 0) + val testBSTreeRoot = testBSTree.root!! val leftSubTestBSTree: BSTree = BSTree() - leftSubTestBSTree.setRoot(BSNode(-2, 2)) - val leftSubTestBSTreeRoot = leftSubTestBSTree.getRoot()!! + leftSubTestBSTree.root = BSNode(-2, 2) + val leftSubTestBSTreeRoot = leftSubTestBSTree.root!! leftSubTestBSTreeRoot.setLeftNode(BSNode(-3, 5)) leftSubTestBSTreeRoot.setRightNode(BSNode(-1, 6)) val rightSubTestBSTree: BSTree = BSTree() - rightSubTestBSTree.setRoot(BSNode(2, 3)) - val rightSubTestBSTreeRoot = rightSubTestBSTree.getRoot()!! + rightSubTestBSTree.root = BSNode(2, 3) + val rightSubTestBSTreeRoot = rightSubTestBSTree.root!! rightSubTestBSTreeRoot.setLeftNode(BSNode(1, 7)) rightSubTestBSTreeRoot.setRightNode(BSNode(3, 8)) @@ -46,40 +46,40 @@ object BSTreeUtil { fun createLeftRotatedBSTree(): BSTree { val leftRotatedTestBSTree: BSTree = BSTree() - leftRotatedTestBSTree.setRoot(BSNode(-2, 2)) - val leftRotatedTestBSTreeRoot = leftRotatedTestBSTree.getRoot()!! + leftRotatedTestBSTree.root = BSNode(2, 3) + val leftRotatedTestBSTreeRoot = leftRotatedTestBSTree.root!! - leftRotatedTestBSTreeRoot.setLeftNode(BSNode(-3, 5)) - leftRotatedTestBSTreeRoot.setRightNode(BSNode(0, 0)) + leftRotatedTestBSTreeRoot.setRightNode(BSNode(3, 8)) + leftRotatedTestBSTreeRoot.setLeftNode(BSNode(0, 0)) - val rightRotatedSubTestBSTree: BSTree = BSTree() - rightRotatedSubTestBSTree.setRoot(BSNode(2, 3)) - val rightRotatedSubTestBSTreeRoot = rightRotatedSubTestBSTree.getRoot()!! - rightRotatedSubTestBSTreeRoot.setLeftNode(BSNode(1, 7)) - rightRotatedSubTestBSTreeRoot.setRightNode(BSNode(3, 8)) + val leftRotatedSubTestBSTree: BSTree = BSTree() + leftRotatedSubTestBSTree.root = BSNode(-2, 2) + val leftRotatedSubTestBSTreeRoot = leftRotatedSubTestBSTree.root!! + leftRotatedSubTestBSTreeRoot.setLeftNode(BSNode(-3, 5)) + leftRotatedSubTestBSTreeRoot.setRightNode(BSNode(-1, 6)) - leftRotatedTestBSTreeRoot.getRightNode()?.setLeftNode(BSNode(-1, 6)) - leftRotatedTestBSTreeRoot.getRightNode()?.setRightNode(rightRotatedSubTestBSTreeRoot) + leftRotatedTestBSTreeRoot.getLeftNode()?.setRightNode(BSNode(1, 7)) + leftRotatedTestBSTreeRoot.getLeftNode()?.setLeftNode(leftRotatedSubTestBSTreeRoot) return leftRotatedTestBSTree } fun createRightRotatedBSTree(): BSTree { val rightRotatedTestBSTree: BSTree = BSTree() - rightRotatedTestBSTree.setRoot(BSNode(2, 3)) - val rightRotatedTestBSTreeRoot = rightRotatedTestBSTree.getRoot()!! + rightRotatedTestBSTree.root = BSNode(-2, 2) + val rightRotatedTestBSTreeRoot = rightRotatedTestBSTree.root!! - rightRotatedTestBSTreeRoot.setRightNode(BSNode(3, 8)) - rightRotatedTestBSTreeRoot.setLeftNode(BSNode(0, 0)) + rightRotatedTestBSTreeRoot.setLeftNode(BSNode(-3, 5)) + rightRotatedTestBSTreeRoot.setRightNode(BSNode(0, 0)) - val leftRotatedSubTestBSTree: BSTree = BSTree() - leftRotatedSubTestBSTree.setRoot(BSNode(-2, 2)) - val leftRotatedSubTestBSTreeRoot = leftRotatedSubTestBSTree.getRoot()!! - leftRotatedSubTestBSTreeRoot.setLeftNode(BSNode(-3, 5)) - leftRotatedSubTestBSTreeRoot.setRightNode(BSNode(-1, 6)) + val rightRotatedSubTestBSTree: BSTree = BSTree() + rightRotatedSubTestBSTree.root = BSNode(2, 3) + val rightRotatedSubTestBSTreeRoot = rightRotatedSubTestBSTree.root!! + rightRotatedSubTestBSTreeRoot.setLeftNode(BSNode(1, 7)) + rightRotatedSubTestBSTreeRoot.setRightNode(BSNode(3, 8)) - rightRotatedTestBSTreeRoot.getLeftNode()?.setRightNode(BSNode(1, 7)) - rightRotatedTestBSTreeRoot.getLeftNode()?.setLeftNode(leftRotatedSubTestBSTreeRoot) + rightRotatedTestBSTreeRoot.getRightNode()?.setLeftNode(BSNode(-1, 6)) + rightRotatedTestBSTreeRoot.getRightNode()?.setRightNode(rightRotatedSubTestBSTreeRoot) return rightRotatedTestBSTree } From 156e902a887e70521ce0ac1daec9a71375157bc1 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 9 Apr 2023 21:13:12 +0300 Subject: [PATCH 025/135] feat: added balance implementation for RBTree --- .../src/main/kotlin/balancers/RBBalancer.kt | 59 ++++++++++++++++++- .../src/main/kotlin/redBlackTree/RBTree.kt | 19 +++--- 2 files changed, 66 insertions(+), 12 deletions(-) diff --git a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt index 531111f..9a0bc44 100644 --- a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt @@ -1,10 +1,65 @@ package balancers import redBlackTree.RBNode +import redBlackTree.RBNode.Color open class RBBalancer, V>: Balancer>(){ override fun balance(node: RBNode): RBNode { - TODO("Not yet implemented") + var nodeParent = node.getParent() + var curNode = node + while (nodeParent != null && nodeParent.color == Color.RED){ + // It must exist, since the root of the tree cannot be red + val nodeGrandParent = nodeParent.getParent() ?: error("RTTree structure error") + + if(nodeParent == nodeGrandParent.getLeftNode()){ + val nodeUncle = nodeGrandParent.getRightNode() + + if(nodeUncle == null || nodeUncle.color == Color.BLACK){ + if(curNode == nodeParent.getRightNode()) { + nodeParent = leftRotate(nodeParent) + curNode = nodeParent.getLeftNode()!! + } + nodeParent.color = Color.BLACK + nodeGrandParent.color = Color.RED + rightRotate(nodeGrandParent) + } + else{ + nodeParent.color = Color.BLACK + nodeUncle.color = Color.BLACK + nodeGrandParent.color = Color.RED + + curNode = nodeGrandParent + nodeParent = curNode.getParent() + } + } + else{ + val nodeUncle = nodeGrandParent.getLeftNode() + + if(nodeUncle == null || nodeUncle.color == Color.BLACK){ + if(curNode == nodeParent.getLeftNode()) { + nodeParent = rightRotate(nodeParent) + curNode = nodeParent.getRightNode()!! + } + nodeParent.color = Color.BLACK + nodeGrandParent.color = Color.RED + leftRotate(nodeGrandParent) + } + else{ + nodeParent.color = Color.BLACK + nodeUncle.color = Color.BLACK + nodeGrandParent.color = Color.RED + + curNode = nodeGrandParent + nodeParent = curNode.getParent() + } + } + } + while(curNode.getParent() != null){ + curNode = curNode.getParent()!! + } + + curNode.color = Color.BLACK + return curNode } -} +} \ No newline at end of file diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt index 7ca5f9b..cf93523 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt @@ -2,6 +2,7 @@ package redBlackTree import BTree import balancers.RBBalancer +import redBlackTree.RBNode.Color class RBTree, V> : BTree>() { @@ -18,27 +19,25 @@ class RBTree, V> : BTree>() { return } while (true) { - root ?: error("IT IS IMPOSSIBLE!!!") + root ?: error("adding error") if (root.getKey() > node.getKey()) { val leftNode = root.getLeftNode() if (leftNode == null) { - node.color = RBNode.Color.RED + node.color = Color.RED root.setLeftNode(node) - root.getLeftNode()?.setParent(root) - balancer.balance(root) + node.setParent(root) + this.root = balancer.balance(node) break } else { root = leftNode - val newTree = RBTree() - newTree.root = root - } } else { val rightNode = root.getRightNode() if (rightNode == null) { - node.color = RBNode.Color.RED + node.color = Color.RED root.setRightNode(node) - root.getRightNode()?.setParent(root) + node.setParent(root) + this.root = balancer.balance(node) break } else { root = rightNode @@ -50,4 +49,4 @@ class RBTree, V> : BTree>() { override fun delete(key: K) { TODO("Not yet implemented") } -} +} \ No newline at end of file From 2e975684090395ded2bc1bd8dd7d4c26303eb8fc Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 9 Apr 2023 21:15:49 +0300 Subject: [PATCH 026/135] feat: Implemented the TreesInvariants class to check all types of trees and added a test for adding nodes to RBTree --- .../test/kotlin/redBlackTree/RBTreeTest.kt | 30 ++++++++++++ .../kotlin/treeInvariants/TreesInvariants.kt | 49 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt create mode 100644 BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt diff --git a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt new file mode 100644 index 0000000..2c0c5bd --- /dev/null +++ b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt @@ -0,0 +1,30 @@ +package redBlackTree + +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import treeInvariants.TreesInvariants +import kotlin.random.Random + +const val seed = 10 + +class RBTreeTest { + + private val randomizer = Random(seed) + + private val treeChecker = TreesInvariants>() + private lateinit var keyValue: Array> + + @BeforeEach + fun beforeEach() { + keyValue = Array(10000) { Pair(randomizer.nextInt(), randomizer.nextInt()) } + } + + @Test + fun addNodeTest() { + val tree = RBTree() + for (i in 0 until 10000) { + tree.insert(keyValue[i].first, keyValue[i].second) + assert(treeChecker.checkRBTreeInvariants(tree.root!!)) { "Adding test error on $i iteration with params ${keyValue[i].first} ${keyValue[i].second}" } + } + } +} \ No newline at end of file diff --git a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt new file mode 100644 index 0000000..32dec29 --- /dev/null +++ b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt @@ -0,0 +1,49 @@ +package treeInvariants + +import Node +import redBlackTree.RBNode +import redBlackTree.RBNode.Color + +@Suppress("UNCHECKED_CAST") +class TreesInvariants, V, NODE_TYPE : Node> { + + fun checkRBTreeInvariants(root: RBNode): Boolean { + return checkNodeInvariants(root as NODE_TYPE) && root.color == Color.BLACK && + checkRBNodeBlackHeightInvariant(root, 0, getSomeBlackHeight(root)) && + checkRBNodeBlackParentForRedInvariant(root) + } + + private fun checkRBNodeBlackParentForRedInvariant(node: RBNode): Boolean { + return (node.color == Color.BLACK || node.getParent()!!.color == Color.BLACK) && + (node.getLeftNode() == null || checkRBNodeBlackParentForRedInvariant(node.getLeftNode()!!)) && + (node.getRightNode() == null || checkRBNodeBlackParentForRedInvariant(node.getRightNode()!!)) + } + + private fun checkRBNodeBlackHeightInvariant(node: RBNode, curHeight: Int, rightHeight: Int): Boolean{ + val newCurHeight = curHeight + if(node.color == Color.BLACK) 1 else 0 + if(node.getLeftNode() == null && node.getRightNode() == null){ + return newCurHeight == rightHeight + } + return (node.getLeftNode() == null || checkRBNodeBlackHeightInvariant(node.getLeftNode()!!, newCurHeight, rightHeight) && + node.getRightNode() == null || checkRBNodeBlackHeightInvariant(node.getRightNode()!!, newCurHeight, rightHeight)) + } + + private fun getSomeBlackHeight(root: RBNode): Int{ + var curNode: RBNode? = root + var blackHeight = 0 + while(curNode != null){ + if(curNode.color == Color.BLACK){ + ++blackHeight + } + curNode = curNode.getLeftNode() + } + return blackHeight + } + + private fun checkNodeInvariants(node: NODE_TYPE): Boolean { + return (node.getLeftNode() == null || node.getLeftNode()!!.getParent() == node && + node.getLeftNode()!!.getKey() < node.getKey() && checkNodeInvariants(node.getLeftNode()!!)) && + (node.getRightNode() == null || node.getRightNode()!!.getParent() == node && + node.getRightNode()!!.getKey() > node.getKey() && checkNodeInvariants(node.getRightNode()!!)) + } +} \ No newline at end of file From 297a5cd365149a86f22c418649b8517c12038dc8 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 10 Apr 2023 03:20:47 +0300 Subject: [PATCH 027/135] feat: Added the "insert" function fix: The "Add" function now protected. Rotates in Balancer now public --- BSTrees/src/main/kotlin/BTree.kt | 2 +- .../src/main/kotlin/balancers/BSBalancer.kt | 5 +- BSTrees/src/main/kotlin/balancers/Balancer.kt | 6 +- .../main/kotlin/binarySearchTree/BSTree.kt | 55 ++++++++++++++++++- 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/BSTrees/src/main/kotlin/BTree.kt b/BSTrees/src/main/kotlin/BTree.kt index f0cc63d..47286c8 100644 --- a/BSTrees/src/main/kotlin/BTree.kt +++ b/BSTrees/src/main/kotlin/BTree.kt @@ -17,7 +17,7 @@ abstract class BTree, V, NODE_TYPE : Node>{ abstract fun insert(key: K, value: V) - abstract fun add(node: NODE_TYPE) + protected abstract fun add(node: NODE_TYPE) fun find(key: K): V? { var temp: NODE_TYPE? = root ?: return null diff --git a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt index 6f63f44..35b1e5d 100644 --- a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt @@ -2,10 +2,11 @@ package balancers import binarySearchTree.BSNode -open class BSBalancer, V>: Balancer>() { +class BSBalancer, V>: Balancer>() { override fun balance(node: BSNode): BSNode { - TODO("Not yet implemented") + //We don't need balance function in BSTree, but we need rotates + TODO("Nothing") } } diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt index 5046521..6ff5207 100644 --- a/BSTrees/src/main/kotlin/balancers/Balancer.kt +++ b/BSTrees/src/main/kotlin/balancers/Balancer.kt @@ -3,7 +3,7 @@ package balancers import Node abstract class Balancer, V, NODE_TYPE : Node>{ - protected fun leftRotate(node: NODE_TYPE): NODE_TYPE { + fun leftRotate(node: NODE_TYPE): NODE_TYPE { val nodeParent = node.getParent() val temp = node.getRightNode() temp?.setParent(nodeParent) @@ -21,7 +21,7 @@ abstract class Balancer, V, NODE_TYPE : Node> return temp ?: node } - protected fun rightRotate(node: NODE_TYPE): NODE_TYPE{ + fun rightRotate(node: NODE_TYPE): NODE_TYPE{ val nodeParent = node.getParent() val temp = node.getLeftNode() temp?.setParent(nodeParent) @@ -39,7 +39,7 @@ abstract class Balancer, V, NODE_TYPE : Node> return temp ?: node } - protected fun balanceFactory(node: NODE_TYPE): Int { + fun balanceFactory(node: NODE_TYPE): Int { return (node.getRightNode()?.getHeight() ?: 0) - (node.getLeftNode()?.getHeight() ?: 0) } diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt index dd535b7..40bf6f7 100644 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt @@ -1,14 +1,63 @@ package binarySearchTree import BTree +import balancers.BSBalancer +import kotlin.random.Random -class BSTree, V>: BTree>() { +class BSTree, V> : BTree>() { + + val balancer = BSBalancer() override fun insert(key: K, value: V) { - TODO("Not yet implemented") + add(BSNode(key, value)) + } + + private fun addRoot(root: BSNode): BSNode { + + val temp = this.root + if (temp == null) return root + else { + val subTree = BSTree() + if (root.getKey() < temp.getKey()) { + subTree.root = temp.getLeftNode() + this.root?.setLeftNode(subTree.addRoot(root)) + return balancer.rightRotate(temp) + } else { + subTree.root = temp.getRightNode() + this.root?.setRightNode(subTree.addRoot(root)) + return balancer.leftRotate(temp) + } + } + } + override fun add(node: BSNode) { - TODO("Not yet implemented") + + val temp = this.root + if (temp == null || temp.getKey() == node.getKey()) this.root = root + + else { + + if (Random.nextInt() % (node.getHeight() + 1) == 0) this.root = this.addRoot(node) + /* + Randomized insertion into the root of the tree allows you + to artificially balance it with a fairly small height. + Otherwise, we perform the usual insertion + */ + else { + val subTree = BSTree() + if (temp.getKey() > node.getKey()) { + subTree.root = temp.getLeftNode() + subTree.add(node) + this.root?.setLeftNode(subTree.root) + } else { + subTree.root = temp.getRightNode() + subTree.add(node) + this.root?.setRightNode(subTree.root) + } + } + + } } override fun delete(key: K) { From a75f9b7798a1023cbbd16f37d5119e0f9509676a Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 10 Apr 2023 04:16:02 +0300 Subject: [PATCH 028/135] feat: Added the "delete" function. Added the "size" field to Node to realize correct randomization fix: Fixed "balancer" due to adding the "size" field --- BSTrees/src/main/kotlin/Node.kt | 13 +++++ BSTrees/src/main/kotlin/balancers/Balancer.kt | 4 ++ .../main/kotlin/binarySearchTree/BSTree.kt | 51 ++++++++++++++++--- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/BSTrees/src/main/kotlin/Node.kt b/BSTrees/src/main/kotlin/Node.kt index 8174900..7286a24 100644 --- a/BSTrees/src/main/kotlin/Node.kt +++ b/BSTrees/src/main/kotlin/Node.kt @@ -6,6 +6,13 @@ abstract class Node, V, NODE_TYPE : Node>(pri private var leftNode: NODE_TYPE? = null private var rightNode: NODE_TYPE? = null private var height = 1 + private var size = 1 + + fun getSize() = size + + fun setSize(newSize: Int){ + this.size = newSize + } fun getKey() = this.key @@ -45,4 +52,10 @@ abstract class Node, V, NODE_TYPE : Node>(pri setHeight(max(leftHeight, rightHeight) + 1) } + fun updateSize(){ + val leftSize = getLeftNode()?.getHeight() ?: 0 + val rightSize = getRightNode()?.getHeight() ?: 0 + setHeight(leftSize + rightSize + 1) + } + } diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt index 6ff5207..138c69f 100644 --- a/BSTrees/src/main/kotlin/balancers/Balancer.kt +++ b/BSTrees/src/main/kotlin/balancers/Balancer.kt @@ -16,7 +16,9 @@ abstract class Balancer, V, NODE_TYPE : Node> node.setParent(temp) node.updateHeight() + node.updateSize() temp?.updateHeight() + temp?.updateSize() return temp ?: node } @@ -34,7 +36,9 @@ abstract class Balancer, V, NODE_TYPE : Node> node.setParent(temp) node.updateHeight() + node.updateSize() temp?.updateHeight() + temp?.updateSize() return temp ?: node } diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt index 40bf6f7..dbae400 100644 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt @@ -6,7 +6,7 @@ import kotlin.random.Random class BSTree, V> : BTree>() { - val balancer = BSBalancer() + private val balancer = BSBalancer() override fun insert(key: K, value: V) { add(BSNode(key, value)) @@ -15,17 +15,17 @@ class BSTree, V> : BTree>() { private fun addRoot(root: BSNode): BSNode { val temp = this.root - if (temp == null) return root + return if (temp == null) root else { val subTree = BSTree() if (root.getKey() < temp.getKey()) { subTree.root = temp.getLeftNode() this.root?.setLeftNode(subTree.addRoot(root)) - return balancer.rightRotate(temp) + balancer.rightRotate(temp) } else { subTree.root = temp.getRightNode() this.root?.setRightNode(subTree.addRoot(root)) - return balancer.leftRotate(temp) + balancer.leftRotate(temp) } } @@ -35,10 +35,9 @@ class BSTree, V> : BTree>() { val temp = this.root if (temp == null || temp.getKey() == node.getKey()) this.root = root - else { - if (Random.nextInt() % (node.getHeight() + 1) == 0) this.root = this.addRoot(node) + if (Random.nextInt() % (node.getSize() + 1) == 0) this.root = this.addRoot(node) /* Randomized insertion into the root of the tree allows you to artificially balance it with a fairly small height. @@ -57,10 +56,48 @@ class BSTree, V> : BTree>() { } } + this.root?.updateSize() + } } + private fun join(left: BSNode?, right: BSNode?): BSNode? { + + if (left == null) return right + if (right == null) return left + + return if (Random.nextInt() % (left.getSize() + right.getSize()) < left.getSize()) { + left.setRightNode(join(left.getRightNode(), right)) + left.updateSize() + left + } else { + right.setLeftNode(join(right.getLeftNode(), left)) + right.updateSize() + right + } + + } + override fun delete(key: K) { - TODO("Not yet implemented") + + val temp = this.root + + if (temp != null) { + + if (temp.getKey() == key) this.root = join(temp.getLeftNode(), temp.getRightNode()) + else if (key < temp.getKey()) { + val subTree = BSTree() + subTree.root = temp.getLeftNode() + subTree.delete(key) + this.root?.setLeftNode(subTree.root) + } else { + val subTree = BSTree() + subTree.root = temp.getRightNode() + subTree.delete(key) + this.root?.setRightNode(subTree.root) + } + + } + } } From 78eca0396e0a87f9ccdcceca2b593a483334ec33 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 11 Apr 2023 16:06:13 +0300 Subject: [PATCH 029/135] feat: added implementation of the "delete" method --- .../src/main/kotlin/balancers/RBBalancer.kt | 124 +++++++++++++++ .../src/main/kotlin/redBlackTree/RBTree.kt | 150 +++++++++++++++++- .../test/kotlin/redBlackTree/RBTreeTest.kt | 28 +++- .../kotlin/treeInvariants/TreesInvariants.kt | 4 +- 4 files changed, 295 insertions(+), 11 deletions(-) diff --git a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt index 9a0bc44..d3f478b 100644 --- a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt @@ -2,9 +2,133 @@ package balancers import redBlackTree.RBNode import redBlackTree.RBNode.Color +import redBlackTree.RBTree open class RBBalancer, V>: Balancer>(){ + fun balanceForDelete(tree: RBTree, node: RBNode){ + var curNode = node + var nodeParent = node.getParent() + while(nodeParent != null && curNode.color != Color.RED){ + if(nodeParent.getLeftNode() == curNode){ + + if(nodeParent.getLeftNode() == null){ + curNode = nodeParent + nodeParent = curNode.getParent() + continue + } + + // brother MUST exist, because we have a 2xBLACK curNode in leftTree + var nodeBrother = nodeParent.getRightNode()!! + if(nodeBrother.color == Color.RED){ + nodeBrother.color = Color.BLACK + nodeParent.color = Color.RED + if(nodeParent.getParent() == null){ + nodeParent = leftRotate(nodeParent) + tree.root = nodeParent + } + else{ + nodeParent = leftRotate(nodeParent) + } + + + + // these nodes MUST exist because we did leftRotate with theirs nodes + nodeParent = nodeParent.getLeftNode()!! + curNode = nodeParent.getLeftNode()!! + nodeBrother = nodeParent.getRightNode()!! + } + + // left and right sons of nodeBrother MUST exist, because of comment, which is located a little higher + if((nodeBrother.getLeftNode() == null || nodeBrother.getLeftNode()!!.color == Color.BLACK) && + (nodeBrother.getRightNode() == null || nodeBrother.getRightNode()!!.color == Color.BLACK) + ){ + nodeBrother.color = Color.RED + val flag = nodeParent.color == Color.RED + nodeParent.color = Color.BLACK + curNode = nodeParent + nodeParent = curNode.getParent() + if(flag)break + } + else{ + if(nodeBrother.getLeftNode() != null && nodeBrother.getLeftNode()!!.color == Color.RED && (nodeBrother.getRightNode() == null || nodeBrother.getRightNode()!!.color == Color.BLACK)){ + nodeBrother.color = Color.RED + nodeBrother.getLeftNode()!!.color = Color.BLACK + nodeBrother = rightRotate(nodeBrother) + + } + nodeBrother.color = nodeParent.color + nodeParent.color = Color.BLACK + nodeBrother.getRightNode()!!.color = Color.BLACK + if(nodeParent.getParent() == null){ + tree.root = leftRotate(nodeParent) + } + else { + leftRotate(nodeParent) + } + break + } + } + else{ + + if(nodeParent.getLeftNode() == null){ + curNode = nodeParent + nodeParent = curNode.getParent() + continue + } + + // brother MUST exist, because we have a 2xBLACK curNode in rightTree + var nodeBrother = nodeParent.getLeftNode()!! + if(nodeBrother.color == Color.RED){ + nodeBrother.color = Color.BLACK + nodeParent.color = Color.RED + + if(nodeParent.getParent() == null){ + nodeParent = rightRotate(nodeParent) + tree.root = nodeParent + } + else{ + nodeParent = rightRotate(nodeParent) + } + + // these nodes MUST exist because we did rightRotate with theirs nodes + nodeParent = nodeParent.getRightNode()!! + curNode = nodeParent.getRightNode()!! + nodeBrother = nodeParent.getLeftNode()!! + } + + // left and right sons of nodeBrother MUST exist, because of comment, which is located a little higher + if((nodeBrother.getLeftNode() == null || nodeBrother.getLeftNode()!!.color == Color.BLACK) && + (nodeBrother.getRightNode() == null || nodeBrother.getRightNode()!!.color == Color.BLACK) + ){ + nodeBrother.color = Color.RED + val flag = nodeParent.color == Color.RED + nodeParent.color = Color.BLACK + curNode = nodeParent + nodeParent = curNode.getParent() + if(flag)break + } + else{ + if((nodeBrother.getLeftNode() == null || nodeBrother.getLeftNode()!!.color == Color.BLACK) && nodeBrother.getRightNode() != null && nodeBrother.getRightNode()!!.color == Color.RED){ + nodeBrother.color = Color.RED + nodeBrother.getRightNode()!!.color = Color.BLACK + nodeBrother = leftRotate(nodeBrother) + } + nodeBrother.color = nodeParent.color + nodeParent.color = Color.BLACK + nodeBrother.getLeftNode()!!.color = Color.BLACK + if(nodeParent.getParent() == null) { + tree.root = rightRotate(nodeParent) + } + else{ + rightRotate(nodeParent) + } + break + } + } + } + curNode.color = Color.BLACK + } override fun balance(node: RBNode): RBNode { var nodeParent = node.getParent() var curNode = node diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt index cf93523..193c980 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt @@ -8,11 +8,28 @@ class RBTree, V> : BTree>() { private val balancer = RBBalancer() + private fun findNodeByKey(key: K): RBNode?{ + var temp: RBNode? = root ?: return null + while(temp != null){ + if(temp.getKey() == key)return temp + temp = if(temp.getKey() > key){ + temp.getLeftNode() + } else{ + temp.getRightNode() + } + } + return null + } + override fun insert(key: K, value: V) { add(RBNode(key, value)) } override fun add(node: RBNode) { + + // if a node with such a key already exists, then we do nothing + if(findNodeByKey(node.getKey()) != null)return + var root = this.root if (root == null) { this.root = node @@ -46,7 +63,136 @@ class RBTree, V> : BTree>() { } } - override fun delete(key: K) { - TODO("Not yet implemented") + private fun treeMinimum(node: RBNode): RBNode{ + var curNode = node + while(curNode.getLeftNode() != null){ + curNode = curNode.getLeftNode()!! + } + return curNode + } + + override fun delete(key: K){ + val curNode = findNodeByKey(key) ?: return + + val nodeForSwapping = if(curNode.getLeftNode() == null || curNode.getRightNode() == null){ + curNode + } + else{ + // If we got here, then curNode has both a left and a right son + treeMinimum(curNode.getRightNode()!!) + } + + if(nodeForSwapping == curNode.getRightNode() && nodeForSwapping.getRightNode() == null){ + val virtualSonNodeOfSwapping = RBNode(curNode.getKey(), curNode.getValue()) + virtualSonNodeOfSwapping.color = Color.BLACK + + nodeForSwapping.setLeftNode(curNode.getLeftNode()) + curNode.getLeftNode()?.setParent(nodeForSwapping) + nodeForSwapping.setRightNode(virtualSonNodeOfSwapping) + virtualSonNodeOfSwapping.setParent(nodeForSwapping) + + val nodeForSwappingOldColor = nodeForSwapping.color + + nodeForSwapping.color = curNode.color + + val curNodeParent = curNode.getParent() + if(curNodeParent == null){ + nodeForSwapping.setParent(null) + this.root = nodeForSwapping + } + else{ + nodeForSwapping.setParent(curNode.getParent()) + + if(curNodeParent.getLeftNode() == curNode){ + curNodeParent.setLeftNode(nodeForSwapping) + } + else{ + curNodeParent.setRightNode(nodeForSwapping) + } + } + + if(nodeForSwappingOldColor == Color.BLACK) { + balancer.balanceForDelete(this, virtualSonNodeOfSwapping) + } + + if(virtualSonNodeOfSwapping.getParent()?.getLeftNode() == virtualSonNodeOfSwapping){ + virtualSonNodeOfSwapping.getParent()?.setLeftNode(null) + } + else{ + virtualSonNodeOfSwapping.getParent()?.setRightNode(null) + } + } + else { + var isVirtualNode = false + + val sonOfNodeForSwapping = if(nodeForSwapping.getLeftNode() == null && nodeForSwapping.getRightNode() == null){ + isVirtualNode = true + + val virtualSonNodeOfSwapping = RBNode(curNode.getKey(), curNode.getValue()) + virtualSonNodeOfSwapping.color = Color.BLACK + + virtualSonNodeOfSwapping + } + else { + if (nodeForSwapping.getLeftNode() != null) { + nodeForSwapping.getLeftNode() + } else { + nodeForSwapping.getRightNode() + } + } + + // adding the old links to the new sonOfNodeForSwapping + sonOfNodeForSwapping?.setParent(nodeForSwapping.getParent()) + + val parentNodeForSwapping = nodeForSwapping.getParent() + if (parentNodeForSwapping == null) { + sonOfNodeForSwapping?.setParent(null) + this.root = if(!isVirtualNode)sonOfNodeForSwapping else null + } else { + if (nodeForSwapping == parentNodeForSwapping.getLeftNode()) { + parentNodeForSwapping.setLeftNode(sonOfNodeForSwapping) + } else { + parentNodeForSwapping.setRightNode(sonOfNodeForSwapping) + } + } + + val nodeForSwappingOldColor = nodeForSwapping.color + + // we replace nodeForSwapping with the one that we delete and transfer all links + if (curNode != nodeForSwapping) { + nodeForSwapping.setLeftNode(curNode.getLeftNode()) + nodeForSwapping.getLeftNode()?.setParent(nodeForSwapping) + nodeForSwapping.setRightNode(curNode.getRightNode()) + nodeForSwapping.getRightNode()?.setParent(nodeForSwapping) + + val parentCurNode = curNode.getParent() + if (parentCurNode == null) { + nodeForSwapping.setParent(null) + this.root = nodeForSwapping + } else { + nodeForSwapping.setParent(parentCurNode) + if (curNode == parentCurNode.getLeftNode()) { + parentCurNode.setLeftNode(nodeForSwapping) + } else { + parentCurNode.setRightNode(nodeForSwapping) + } + } + + nodeForSwapping.color = curNode.color + } + + if (nodeForSwappingOldColor == Color.BLACK) { + balancer.balanceForDelete(this, sonOfNodeForSwapping!!) + } + + if(isVirtualNode){ + if(sonOfNodeForSwapping?.getParent()?.getLeftNode() == sonOfNodeForSwapping){ + sonOfNodeForSwapping?.getParent()?.setLeftNode(null) + } + else{ + sonOfNodeForSwapping?.getParent()?.setRightNode(null) + } + } + } } } \ No newline at end of file diff --git a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt index 2c0c5bd..98c286a 100644 --- a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt +++ b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt @@ -1,22 +1,24 @@ package redBlackTree -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test +import org.junit.jupiter.api.* import treeInvariants.TreesInvariants import kotlin.random.Random const val seed = 10 +@TestInstance(TestInstance.Lifecycle.PER_CLASS) class RBTreeTest { private val randomizer = Random(seed) - private val treeChecker = TreesInvariants>() private lateinit var keyValue: Array> + private val tree = RBTree() + private val treeChecker = TreesInvariants>() - @BeforeEach - fun beforeEach() { - keyValue = Array(10000) { Pair(randomizer.nextInt(), randomizer.nextInt()) } + + @BeforeAll + fun beforeAll() { + keyValue = Array(10000) { Pair(randomizer.nextInt(10000), randomizer.nextInt(10000)) } } @Test @@ -24,7 +26,19 @@ class RBTreeTest { val tree = RBTree() for (i in 0 until 10000) { tree.insert(keyValue[i].first, keyValue[i].second) - assert(treeChecker.checkRBTreeInvariants(tree.root!!)) { "Adding test error on $i iteration with params ${keyValue[i].first} ${keyValue[i].second}" } + assert(treeChecker.checkRBTreeInvariants(tree.root)) { "Adding test error on $i iteration with params ${keyValue[i].first} ${keyValue[i].second}" } + } + } + + @Test + fun deleteNodeTest(){ + keyValue.forEach { tree.insert(it.first, it.second) } + keyValue.shuffle() + for(i in 0 until 10000){ + tree.delete(keyValue[i].first) + assert(treeChecker.checkRBTreeInvariants(tree.root)) { "Adding test error on $i iteration with params ${keyValue[i].first} ${keyValue[i].second}" } + } + assert(tree.root == null) { "tree is not null" } } } \ No newline at end of file diff --git a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt index 32dec29..c79868d 100644 --- a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt +++ b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt @@ -7,8 +7,8 @@ import redBlackTree.RBNode.Color @Suppress("UNCHECKED_CAST") class TreesInvariants, V, NODE_TYPE : Node> { - fun checkRBTreeInvariants(root: RBNode): Boolean { - return checkNodeInvariants(root as NODE_TYPE) && root.color == Color.BLACK && + fun checkRBTreeInvariants(root: RBNode?): Boolean { + return root == null || root.getParent() == null && checkNodeInvariants(root as NODE_TYPE) && root.color == Color.BLACK && checkRBNodeBlackHeightInvariant(root, 0, getSomeBlackHeight(root)) && checkRBNodeBlackParentForRedInvariant(root) } From 9cd57c1a3f8fad40a3ca534e24db90c941cdcdde Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Tue, 11 Apr 2023 01:58:08 +0300 Subject: [PATCH 030/135] feat: AvlBalancer is implemented --- .../src/main/kotlin/balancers/AvlBalancer.kt | 33 +++++++++++++++++-- BSTrees/src/main/kotlin/balancers/Balancer.kt | 2 +- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt b/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt index e6304cd..5bb8c54 100644 --- a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt @@ -3,9 +3,38 @@ package balancers import avlTree.AvlNode -open class AvlBalancer, V>: Balancer>() { +class AvlBalancer, V> : Balancer>() { override fun balance(node: AvlNode): AvlNode { - TODO("Not yet implemented") + + node.updateHeight() + val bf = balanceFactor(node) + + if (bf == 2) { + + val temp = node.getRightNode() + if (temp != null) { + if (balanceFactor(temp) < 0) { + node.setRightNode(rightRotate(temp)) + } + } + + return leftRotate(node) + } + + if (bf == -2) { + + val temp = node.getLeftNode() + if (temp != null) { + if (balanceFactor(temp) > 0) { + node.setLeftNode(leftRotate(temp)) + } + } + + return leftRotate(node) + } + + return node } + } diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt index 138c69f..36e680d 100644 --- a/BSTrees/src/main/kotlin/balancers/Balancer.kt +++ b/BSTrees/src/main/kotlin/balancers/Balancer.kt @@ -43,7 +43,7 @@ abstract class Balancer, V, NODE_TYPE : Node> return temp ?: node } - fun balanceFactory(node: NODE_TYPE): Int { + fun balanceFactor(node: NODE_TYPE): Int { return (node.getRightNode()?.getHeight() ?: 0) - (node.getLeftNode()?.getHeight() ?: 0) } From 369703f6ee196357f7d5dbf44f24a7426694c9ef Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Tue, 11 Apr 2023 02:23:43 +0300 Subject: [PATCH 031/135] feat: insert function is implemented --- BSTrees/src/main/kotlin/avlTree/AvlTree.kt | 23 ++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt index cdda2bb..ea96dfb 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt +++ b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt @@ -1,14 +1,33 @@ package avlTree import BTree +import balancers.AvlBalancer class AvlTree, V>: BTree>() { + private val balancer = AvlBalancer() + override fun insert(key: K, value: V) { - TODO("Not yet implemented") + add(AvlNode(key, value)) } override fun add(node: AvlNode) { - TODO("Not yet implemented") + val temp = this.root + if (temp?.getKey() == node.getKey() || temp == null) this.root = node + else { + val subTree = AvlTree() + if (node.getKey() < temp.getKey()) { + subTree.root = temp.getLeftNode() + subTree.add(node) + this.root?.setLeftNode(subTree.root) + } + if (node.getKey() > temp.getKey()) { + subTree.root = temp.getRightNode() + subTree.add(node) + this.root?.setRightNode(subTree.root) + } + } + + this.root = this.root?.let { balancer.balance(it) } } override fun delete(key: K) { From fec8091c5af31a8cd88bb917dc091cae0c228f7a Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Tue, 11 Apr 2023 03:06:58 +0300 Subject: [PATCH 032/135] feat: delete function is implemented --- BSTrees/src/main/kotlin/avlTree/AvlTree.kt | 61 ++++++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt index ea96dfb..36d8b21 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt +++ b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt @@ -3,34 +3,87 @@ package avlTree import BTree import balancers.AvlBalancer -class AvlTree, V>: BTree>() { +class AvlTree, V> : BTree>() { private val balancer = AvlBalancer() override fun insert(key: K, value: V) { add(AvlNode(key, value)) } + override fun add(node: AvlNode) { val temp = this.root if (temp?.getKey() == node.getKey() || temp == null) this.root = node else { + val subTree = AvlTree() + if (node.getKey() < temp.getKey()) { subTree.root = temp.getLeftNode() subTree.add(node) this.root?.setLeftNode(subTree.root) - } - if (node.getKey() > temp.getKey()) { + } else if (node.getKey() > temp.getKey()) { subTree.root = temp.getRightNode() subTree.add(node) this.root?.setRightNode(subTree.root) } + } this.root = this.root?.let { balancer.balance(it) } } + private fun findMin(node: AvlNode): AvlNode { + val temp = node.getLeftNode() + return if (temp != null) findMin(temp) else node + } + + private fun removeMin(node: AvlNode): AvlNode? { + val temp = node.getLeftNode() + if (temp == null) return node.getRightNode() + node.setLeftNode(removeMin(temp)) + return balancer.balance(node) + } + override fun delete(key: K) { - TODO("Not yet implemented") + + val temp = this.root + + if (temp != null) { + + val subTree = AvlTree() + + if (key < temp.getKey()) { + + subTree.root = temp.getLeftNode() + subTree.delete(key) + this.root?.setLeftNode(subTree.root) + + } else if (key > temp.getKey()) { + + subTree.root = temp.getRightNode() + subTree.delete(key) + this.root?.setRightNode(subTree.root) + + } else { + + val leftNode = this.root?.getLeftNode() + val rightNode = this.root?.getRightNode() + + if (rightNode == null) this.root = leftNode + + else { + val tempMin: AvlNode = findMin(rightNode) + tempMin.setRightNode(removeMin(rightNode)) + tempMin.setLeftNode(leftNode) + this.root = balancer.balance(tempMin) + } + + } + + val nullCheck = this.root + if (nullCheck != null) this.root = balancer.balance(nullCheck) + + } } } From f360d79a2e3b2a9312c4a0258f0dd17bb4ded8ab Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 11 Apr 2023 18:16:07 +0300 Subject: [PATCH 033/135] feat: Code comments were added and code refactoring was performed --- .../src/main/kotlin/balancers/RBBalancer.kt | 123 +++++----- .../src/main/kotlin/redBlackTree/RBTree.kt | 231 +++++++++--------- .../src/test/kotlin/balancers/BalancerTest.kt | 4 +- .../test/kotlin/redBlackTree/RBTreeTest.kt | 4 +- 4 files changed, 179 insertions(+), 183 deletions(-) diff --git a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt index d3f478b..82aed38 100644 --- a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt @@ -4,15 +4,16 @@ import redBlackTree.RBNode import redBlackTree.RBNode.Color import redBlackTree.RBTree -open class RBBalancer, V>: Balancer>(){ +open class RBBalancer, V> : Balancer>() { - fun balanceForDelete(tree: RBTree, node: RBNode){ + fun balanceAfterDeletion(tree: RBTree, node: RBNode) { var curNode = node var nodeParent = node.getParent() - while(nodeParent != null && curNode.color != Color.RED){ - if(nodeParent.getLeftNode() == curNode){ + while (nodeParent != null && curNode.color != Color.RED) { - if(nodeParent.getLeftNode() == null){ + if (nodeParent.getLeftNode() == curNode) { + + if (nodeParent.getLeftNode() == null) { curNode = nodeParent nodeParent = curNode.getParent() continue @@ -20,58 +21,59 @@ open class RBBalancer, V>: Balancer>(){ // brother MUST exist, because we have a 2xBLACK curNode in leftTree var nodeBrother = nodeParent.getRightNode()!! - if(nodeBrother.color == Color.RED){ + + // Consideration of the case 1. + // nodeBrother is red + if (nodeBrother.color == Color.RED) { nodeBrother.color = Color.BLACK nodeParent.color = Color.RED - if(nodeParent.getParent() == null){ + if (nodeParent.getParent() == null) { nodeParent = leftRotate(nodeParent) tree.root = nodeParent - } - else{ + } else { nodeParent = leftRotate(nodeParent) } - // these nodes MUST exist because we did leftRotate with theirs nodes nodeParent = nodeParent.getLeftNode()!! curNode = nodeParent.getLeftNode()!! nodeBrother = nodeParent.getRightNode()!! } - // left and right sons of nodeBrother MUST exist, because of comment, which is located a little higher - if((nodeBrother.getLeftNode() == null || nodeBrother.getLeftNode()!!.color == Color.BLACK) && + // Consideration of the case 2. + // nodeBrother's sons are black + if ((nodeBrother.getLeftNode() == null || nodeBrother.getLeftNode()!!.color == Color.BLACK) && (nodeBrother.getRightNode() == null || nodeBrother.getRightNode()!!.color == Color.BLACK) - ){ + ) { nodeBrother.color = Color.RED - val flag = nodeParent.color == Color.RED - nodeParent.color = Color.BLACK curNode = nodeParent nodeParent = curNode.getParent() - if(flag)break - } - else{ - if(nodeBrother.getLeftNode() != null && nodeBrother.getLeftNode()!!.color == Color.RED && (nodeBrother.getRightNode() == null || nodeBrother.getRightNode()!!.color == Color.BLACK)){ + } else { + + // Consideration of the case 3. + // nodeBrother's left son is red, right son is black + if (nodeBrother.getLeftNode() != null && nodeBrother.getLeftNode()!!.color == Color.RED && (nodeBrother.getRightNode() == null || nodeBrother.getRightNode()!!.color == Color.BLACK)) { nodeBrother.color = Color.RED nodeBrother.getLeftNode()!!.color = Color.BLACK nodeBrother = rightRotate(nodeBrother) - } + + // Consideration of the case 4. + // nodeBrother's right son is red nodeBrother.color = nodeParent.color nodeParent.color = Color.BLACK nodeBrother.getRightNode()!!.color = Color.BLACK - if(nodeParent.getParent() == null){ + if (nodeParent.getParent() == null) { tree.root = leftRotate(nodeParent) - } - else { + } else { leftRotate(nodeParent) } break } - } - else{ + } else { - if(nodeParent.getLeftNode() == null){ + if (nodeParent.getLeftNode() == null) { curNode = nodeParent nodeParent = curNode.getParent() continue @@ -79,15 +81,17 @@ open class RBBalancer, V>: Balancer>(){ // brother MUST exist, because we have a 2xBLACK curNode in rightTree var nodeBrother = nodeParent.getLeftNode()!! - if(nodeBrother.color == Color.RED){ + + // Consideration of the case 1. + // nodeBrother is red + if (nodeBrother.color == Color.RED) { nodeBrother.color = Color.BLACK nodeParent.color = Color.RED - if(nodeParent.getParent() == null){ + if (nodeParent.getParent() == null) { nodeParent = rightRotate(nodeParent) tree.root = nodeParent - } - else{ + } else { nodeParent = rightRotate(nodeParent) } @@ -97,30 +101,32 @@ open class RBBalancer, V>: Balancer>(){ nodeBrother = nodeParent.getLeftNode()!! } - // left and right sons of nodeBrother MUST exist, because of comment, which is located a little higher - if((nodeBrother.getLeftNode() == null || nodeBrother.getLeftNode()!!.color == Color.BLACK) && - (nodeBrother.getRightNode() == null || nodeBrother.getRightNode()!!.color == Color.BLACK) - ){ + // Consideration of the case 2. + // nodeBrother's sons are black + if ((nodeBrother.getLeftNode() == null || nodeBrother.getLeftNode()!!.color == Color.BLACK) && + (nodeBrother.getRightNode() == null || nodeBrother.getRightNode()!!.color == Color.BLACK) + ) { nodeBrother.color = Color.RED - val flag = nodeParent.color == Color.RED - nodeParent.color = Color.BLACK curNode = nodeParent nodeParent = curNode.getParent() - if(flag)break - } - else{ - if((nodeBrother.getLeftNode() == null || nodeBrother.getLeftNode()!!.color == Color.BLACK) && nodeBrother.getRightNode() != null && nodeBrother.getRightNode()!!.color == Color.RED){ + } else { + + // Consideration of the case 3. + // nodeBrother's left son is black, right son is red + if ((nodeBrother.getLeftNode() == null || nodeBrother.getLeftNode()!!.color == Color.BLACK) && nodeBrother.getRightNode() != null && nodeBrother.getRightNode()!!.color == Color.RED) { nodeBrother.color = Color.RED nodeBrother.getRightNode()!!.color = Color.BLACK nodeBrother = leftRotate(nodeBrother) } + + // Consideration of the case 4. + // nodeBrother's right son is red nodeBrother.color = nodeParent.color nodeParent.color = Color.BLACK nodeBrother.getLeftNode()!!.color = Color.BLACK - if(nodeParent.getParent() == null) { + if (nodeParent.getParent() == null) { tree.root = rightRotate(nodeParent) - } - else{ + } else { rightRotate(nodeParent) } break @@ -129,26 +135,27 @@ open class RBBalancer, V>: Balancer>(){ } curNode.color = Color.BLACK } - override fun balance(node: RBNode): RBNode { + + + fun balanceAfterAdding(node: RBNode): RBNode { var nodeParent = node.getParent() var curNode = node - while (nodeParent != null && nodeParent.color == Color.RED){ + while (nodeParent != null && nodeParent.color == Color.RED) { // It must exist, since the root of the tree cannot be red val nodeGrandParent = nodeParent.getParent() ?: error("RTTree structure error") - if(nodeParent == nodeGrandParent.getLeftNode()){ + if (nodeParent == nodeGrandParent.getLeftNode()) { val nodeUncle = nodeGrandParent.getRightNode() - if(nodeUncle == null || nodeUncle.color == Color.BLACK){ - if(curNode == nodeParent.getRightNode()) { + if (nodeUncle == null || nodeUncle.color == Color.BLACK) { + if (curNode == nodeParent.getRightNode()) { nodeParent = leftRotate(nodeParent) curNode = nodeParent.getLeftNode()!! } nodeParent.color = Color.BLACK nodeGrandParent.color = Color.RED rightRotate(nodeGrandParent) - } - else{ + } else { nodeParent.color = Color.BLACK nodeUncle.color = Color.BLACK nodeGrandParent.color = Color.RED @@ -156,20 +163,18 @@ open class RBBalancer, V>: Balancer>(){ curNode = nodeGrandParent nodeParent = curNode.getParent() } - } - else{ + } else { val nodeUncle = nodeGrandParent.getLeftNode() - if(nodeUncle == null || nodeUncle.color == Color.BLACK){ - if(curNode == nodeParent.getLeftNode()) { + if (nodeUncle == null || nodeUncle.color == Color.BLACK) { + if (curNode == nodeParent.getLeftNode()) { nodeParent = rightRotate(nodeParent) curNode = nodeParent.getRightNode()!! } nodeParent.color = Color.BLACK nodeGrandParent.color = Color.RED leftRotate(nodeGrandParent) - } - else{ + } else { nodeParent.color = Color.BLACK nodeUncle.color = Color.BLACK nodeGrandParent.color = Color.RED @@ -179,11 +184,15 @@ open class RBBalancer, V>: Balancer>(){ } } } - while(curNode.getParent() != null){ + while (curNode.getParent() != null) { curNode = curNode.getParent()!! } curNode.color = Color.BLACK return curNode } + + override fun balance(node: RBNode): RBNode { + TODO("Not yet implemented") + } } \ No newline at end of file diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt index 193c980..a477d3c 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt @@ -8,19 +8,6 @@ class RBTree, V> : BTree>() { private val balancer = RBBalancer() - private fun findNodeByKey(key: K): RBNode?{ - var temp: RBNode? = root ?: return null - while(temp != null){ - if(temp.getKey() == key)return temp - temp = if(temp.getKey() > key){ - temp.getLeftNode() - } else{ - temp.getRightNode() - } - } - return null - } - override fun insert(key: K, value: V) { add(RBNode(key, value)) } @@ -28,7 +15,7 @@ class RBTree, V> : BTree>() { override fun add(node: RBNode) { // if a node with such a key already exists, then we do nothing - if(findNodeByKey(node.getKey()) != null)return + if (findNodeByKey(node.getKey()) != null) return var root = this.root if (root == null) { @@ -43,7 +30,7 @@ class RBTree, V> : BTree>() { node.color = Color.RED root.setLeftNode(node) node.setParent(root) - this.root = balancer.balance(node) + this.root = balancer.balanceAfterAdding(node) break } else { root = leftNode @@ -54,7 +41,7 @@ class RBTree, V> : BTree>() { node.color = Color.RED root.setRightNode(node) node.setParent(root) - this.root = balancer.balance(node) + this.root = balancer.balanceAfterAdding(node) break } else { root = rightNode @@ -63,136 +50,136 @@ class RBTree, V> : BTree>() { } } - private fun treeMinimum(node: RBNode): RBNode{ - var curNode = node - while(curNode.getLeftNode() != null){ - curNode = curNode.getLeftNode()!! + private fun findNodeByKey(key: K): RBNode? { + var temp: RBNode? = root ?: return null + while (temp != null) { + if (temp.getKey() == key) return temp + temp = if (temp.getKey() > key) { + temp.getLeftNode() + } else { + temp.getRightNode() + } } - return curNode + return null } - override fun delete(key: K){ + override fun delete(key: K) { + // This is the node that needs to be deleted val curNode = findNodeByKey(key) ?: return - val nodeForSwapping = if(curNode.getLeftNode() == null || curNode.getRightNode() == null){ - curNode - } - else{ - // If we got here, then curNode has both a left and a right son - treeMinimum(curNode.getRightNode()!!) - } - - if(nodeForSwapping == curNode.getRightNode() && nodeForSwapping.getRightNode() == null){ - val virtualSonNodeOfSwapping = RBNode(curNode.getKey(), curNode.getValue()) - virtualSonNodeOfSwapping.color = Color.BLACK + // This is the node that we will put in place of curNode + val nodeForSwapping = getNodeForSwapping(curNode) - nodeForSwapping.setLeftNode(curNode.getLeftNode()) - curNode.getLeftNode()?.setParent(nodeForSwapping) - nodeForSwapping.setRightNode(virtualSonNodeOfSwapping) - virtualSonNodeOfSwapping.setParent(nodeForSwapping) + var sonIsNillNode = false - val nodeForSwappingOldColor = nodeForSwapping.color - - nodeForSwapping.color = curNode.color - - val curNodeParent = curNode.getParent() - if(curNodeParent == null){ - nodeForSwapping.setParent(null) - this.root = nodeForSwapping + // This is the node that will take the place of nodeForSwapping + // If nodeForSwapping has no sons, then we create an imaginary(NILL) sonNode + val sonNodeForSwapping = + if (nodeForSwapping.getLeftNode() == null && nodeForSwapping.getRightNode() == null) { + sonIsNillNode = true + getNillNode(curNode) + } else { + getSonNodeForSwapping(nodeForSwapping) } - else{ - nodeForSwapping.setParent(curNode.getParent()) - if(curNodeParent.getLeftNode() == curNode){ - curNodeParent.setLeftNode(nodeForSwapping) - } - else{ - curNodeParent.setRightNode(nodeForSwapping) - } - } + // We put the sonOfNodeForSwapping in the place of nodeForSwapping and establish the necessary links + setLinksWithSonOfNodeForSwapping(nodeForSwapping, sonNodeForSwapping, sonIsNillNode) - if(nodeForSwappingOldColor == Color.BLACK) { - balancer.balanceForDelete(this, virtualSonNodeOfSwapping) - } + val colorOfNodeForSwapping = nodeForSwapping.color - if(virtualSonNodeOfSwapping.getParent()?.getLeftNode() == virtualSonNodeOfSwapping){ - virtualSonNodeOfSwapping.getParent()?.setLeftNode(null) - } - else{ - virtualSonNodeOfSwapping.getParent()?.setRightNode(null) - } + // If nodeForSwapping != curNode, then we need to add the necessary links to nodeForSwapping to replace it. + if (curNode != nodeForSwapping) { + setLinksWithNodeForSwapping(curNode, nodeForSwapping) + nodeForSwapping.color = curNode.color } - else { - var isVirtualNode = false - - val sonOfNodeForSwapping = if(nodeForSwapping.getLeftNode() == null && nodeForSwapping.getRightNode() == null){ - isVirtualNode = true - val virtualSonNodeOfSwapping = RBNode(curNode.getKey(), curNode.getValue()) - virtualSonNodeOfSwapping.color = Color.BLACK + // If the color of the deleted node is black, then we have to balance the tree + if (colorOfNodeForSwapping == Color.BLACK) { + balancer.balanceAfterDeletion(this, sonNodeForSwapping!!) + } - virtualSonNodeOfSwapping - } - else { - if (nodeForSwapping.getLeftNode() != null) { - nodeForSwapping.getLeftNode() - } else { - nodeForSwapping.getRightNode() - } + // If we used an imaginary(NILL) node, we have to remove unnecessary links + if (sonIsNillNode) { + if (sonNodeForSwapping?.getParent()?.getLeftNode() == sonNodeForSwapping) { + sonNodeForSwapping?.getParent()?.setLeftNode(null) + } else { + sonNodeForSwapping?.getParent()?.setRightNode(null) } + } + } - // adding the old links to the new sonOfNodeForSwapping - sonOfNodeForSwapping?.setParent(nodeForSwapping.getParent()) - - val parentNodeForSwapping = nodeForSwapping.getParent() - if (parentNodeForSwapping == null) { - sonOfNodeForSwapping?.setParent(null) - this.root = if(!isVirtualNode)sonOfNodeForSwapping else null + private fun setLinksWithNodeForSwapping(curNode: RBNode, nodeForSwapping: RBNode) { + nodeForSwapping.setLeftNode(curNode.getLeftNode()) + nodeForSwapping.getLeftNode()?.setParent(nodeForSwapping) + nodeForSwapping.setRightNode(curNode.getRightNode()) + nodeForSwapping.getRightNode()?.setParent(nodeForSwapping) + + val parentCurNode = curNode.getParent() + if (parentCurNode == null) { + nodeForSwapping.setParent(null) + this.root = nodeForSwapping + } else { + nodeForSwapping.setParent(parentCurNode) + if (curNode == parentCurNode.getLeftNode()) { + parentCurNode.setLeftNode(nodeForSwapping) } else { - if (nodeForSwapping == parentNodeForSwapping.getLeftNode()) { - parentNodeForSwapping.setLeftNode(sonOfNodeForSwapping) - } else { - parentNodeForSwapping.setRightNode(sonOfNodeForSwapping) - } + parentCurNode.setRightNode(nodeForSwapping) } + } + } - val nodeForSwappingOldColor = nodeForSwapping.color + private fun setLinksWithSonOfNodeForSwapping( + nodeForSwapping: RBNode, + sonOfNodeForSwapping: RBNode?, + sonIsNillNode: Boolean + ) { + sonOfNodeForSwapping?.setParent(nodeForSwapping.getParent()) + + val parentNodeForSwapping = nodeForSwapping.getParent() + if (parentNodeForSwapping == null) { + sonOfNodeForSwapping?.setParent(null) + this.root = if (!sonIsNillNode) sonOfNodeForSwapping else null + } else { + if (nodeForSwapping == parentNodeForSwapping.getLeftNode()) { + parentNodeForSwapping.setLeftNode(sonOfNodeForSwapping) + } else { + parentNodeForSwapping.setRightNode(sonOfNodeForSwapping) + } + } + } - // we replace nodeForSwapping with the one that we delete and transfer all links - if (curNode != nodeForSwapping) { - nodeForSwapping.setLeftNode(curNode.getLeftNode()) - nodeForSwapping.getLeftNode()?.setParent(nodeForSwapping) - nodeForSwapping.setRightNode(curNode.getRightNode()) - nodeForSwapping.getRightNode()?.setParent(nodeForSwapping) + // nodeForSwapping is the node with the next largest key or the node itself if it has a NILL son + private fun , V> getNodeForSwapping(curNode: RBNode): RBNode { + return if (curNode.getLeftNode() == null || curNode.getRightNode() == null) { + curNode + } else { + // If we got here, then curNode has both a left and a right son + nodeWithMinKey(curNode.getRightNode()!!) + } + } - val parentCurNode = curNode.getParent() - if (parentCurNode == null) { - nodeForSwapping.setParent(null) - this.root = nodeForSwapping - } else { - nodeForSwapping.setParent(parentCurNode) - if (curNode == parentCurNode.getLeftNode()) { - parentCurNode.setLeftNode(nodeForSwapping) - } else { - parentCurNode.setRightNode(nodeForSwapping) - } - } + private fun , V> getSonNodeForSwapping(nodeForSwapping: RBNode): RBNode? { + return if (nodeForSwapping.getLeftNode() != null) { + nodeForSwapping.getLeftNode() + } else { + nodeForSwapping.getRightNode() + } + } - nodeForSwapping.color = curNode.color - } + // We get an imaginary(NILL) node filled with some unnecessary data + private fun , V> getNillNode(nodeExample: RBNode): RBNode { + val nillSonNodeOfSwapping = RBNode(nodeExample.getKey(), nodeExample.getValue()) + nillSonNodeOfSwapping.color = Color.BLACK - if (nodeForSwappingOldColor == Color.BLACK) { - balancer.balanceForDelete(this, sonOfNodeForSwapping!!) - } + return nillSonNodeOfSwapping + } - if(isVirtualNode){ - if(sonOfNodeForSwapping?.getParent()?.getLeftNode() == sonOfNodeForSwapping){ - sonOfNodeForSwapping?.getParent()?.setLeftNode(null) - } - else{ - sonOfNodeForSwapping?.getParent()?.setRightNode(null) - } - } + // We are looking for a node with the minimum key available from this node + private fun , V> nodeWithMinKey(node: RBNode): RBNode { + var curNode = node + while (curNode.getLeftNode() != null) { + curNode = curNode.getLeftNode()!! } + return curNode } } \ No newline at end of file diff --git a/BSTrees/src/test/kotlin/balancers/BalancerTest.kt b/BSTrees/src/test/kotlin/balancers/BalancerTest.kt index 8880c4f..e9e3d9b 100644 --- a/BSTrees/src/test/kotlin/balancers/BalancerTest.kt +++ b/BSTrees/src/test/kotlin/balancers/BalancerTest.kt @@ -10,7 +10,7 @@ import utils.BSTreeUtil class BalancerTest { @Test - fun testLeftRotate() { + fun `left rotate`() { val balancer = BSBalancer() val privateLeftRotateField = Balancer::class.java.getDeclaredMethod("leftRotate", Node::class.java) @@ -21,7 +21,7 @@ class BalancerTest { } @Test - fun testRightRotate() { + fun `right rotate`() { val balancer = BSBalancer() val privateRightRotateField = Balancer::class.java.getDeclaredMethod("rightRotate", Node::class.java) diff --git a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt index 98c286a..88b02ab 100644 --- a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt +++ b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt @@ -22,7 +22,7 @@ class RBTreeTest { } @Test - fun addNodeTest() { + fun `invariants after addition`() { val tree = RBTree() for (i in 0 until 10000) { tree.insert(keyValue[i].first, keyValue[i].second) @@ -31,7 +31,7 @@ class RBTreeTest { } @Test - fun deleteNodeTest(){ + fun `invariants after deletion`(){ keyValue.forEach { tree.insert(it.first, it.second) } keyValue.shuffle() for(i in 0 until 10000){ From e851984c92df1f105456f90bdc26b360174b5c78 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sat, 15 Apr 2023 22:06:07 +0300 Subject: [PATCH 034/135] feat: Added mergeable file --- .github/mergeable.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/mergeable.yml diff --git a/.github/mergeable.yml b/.github/mergeable.yml new file mode 100644 index 0000000..60d24c8 --- /dev/null +++ b/.github/mergeable.yml @@ -0,0 +1,14 @@ +version: 2 +mergeable: + - when: pull_request.*, pull_request_review.* + validate: + - do: description + no_empty: + enabled: true + message: "Description should not be empty." + + - do: approvals + min: + count: 1 + required: + assignees: true From 7ade6dadb5091baf944c21c9193f30788b1d3c03 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 16 Apr 2023 00:37:19 +0300 Subject: [PATCH 035/135] feat: Added CI file --- .github/workflow/CI.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflow/CI.yml diff --git a/.github/workflow/CI.yml b/.github/workflow/CI.yml new file mode 100644 index 0000000..7c98c76 --- /dev/null +++ b/.github/workflow/CI.yml @@ -0,0 +1,23 @@ +name: Run build project + +on: + push: +jobs: + build-gradle-project: + runs-on: ubuntu-latest + steps: + - name: Checkout project sources + uses: actions/checkout@v3 + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + + - name: Run build with Gradle Wrapper + run: ./gradlew build + + - name: Upload BSTrees jar + uses: actions/upload-artifact@v3 + if: github.ref == 'refs/heads/main' + with: + name: BSTrees lib + path: BSTrees/libs/BSTrees.jar \ No newline at end of file From b62e9e597668d59889a4171a93695628a9c5de73 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 16 Apr 2023 01:03:51 +0300 Subject: [PATCH 036/135] fix: Some fixes in mergeable file --- .github/mergeable.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/mergeable.yml b/.github/mergeable.yml index 60d24c8..c042f8e 100644 --- a/.github/mergeable.yml +++ b/.github/mergeable.yml @@ -8,7 +8,7 @@ mergeable: message: "Description should not be empty." - do: approvals - min: - count: 1 - required: - assignees: true + min: + count: 1 + required: + assignees: true From c41a41f905b2f9827cc860a05871f80a1e296f1d Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 16 Apr 2023 01:15:20 +0300 Subject: [PATCH 037/135] fix: CI file moved to the correct directory --- .github/{workflow => workflows}/CI.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{workflow => workflows}/CI.yml (100%) diff --git a/.github/workflow/CI.yml b/.github/workflows/CI.yml similarity index 100% rename from .github/workflow/CI.yml rename to .github/workflows/CI.yml From 44a5a925b429cc7cfd6f94d8565580bfb79bd15e Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 16 Apr 2023 18:43:44 +0300 Subject: [PATCH 038/135] fix: Fixed the path to the jar file --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 7c98c76..8b44906 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -20,4 +20,4 @@ jobs: if: github.ref == 'refs/heads/main' with: name: BSTrees lib - path: BSTrees/libs/BSTrees.jar \ No newline at end of file + path: BSTrees/build/libs/BSTrees.jar \ No newline at end of file From 2470aaddbba7eeb084f57466c4e4aa10d0555ec1 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 16 Apr 2023 19:05:11 +0300 Subject: [PATCH 039/135] feat: Added new tests for RBTree --- BSTrees/build.gradle.kts | 2 - .../src/main/kotlin/redBlackTree/RBTree.kt | 8 +- .../test/kotlin/redBlackTree/RBTreeTest.kt | 78 ++++++++++++++++--- 3 files changed, 72 insertions(+), 16 deletions(-) diff --git a/BSTrees/build.gradle.kts b/BSTrees/build.gradle.kts index 3f46689..e2dc097 100644 --- a/BSTrees/build.gradle.kts +++ b/BSTrees/build.gradle.kts @@ -9,8 +9,6 @@ repositories { dependencies { testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.1") testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.1") - - testImplementation("org.mockito:mockito-core:3.9.0") } tasks.getByName("test") { diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt index a477d3c..f591622 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt @@ -14,8 +14,12 @@ class RBTree, V> : BTree>() { override fun add(node: RBNode) { - // if a node with such a key already exists, then we do nothing - if (findNodeByKey(node.getKey()) != null) return + // if a node with such a key already exists, then we update Value + val nodeWithEqualKey = findNodeByKey(node.getKey()) + if (nodeWithEqualKey != null){ + nodeWithEqualKey.setValue(node.getValue()) + return + } var root = this.root if (root == null) { diff --git a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt index 88b02ab..d6bd287 100644 --- a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt +++ b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt @@ -1,6 +1,7 @@ package redBlackTree import org.junit.jupiter.api.* +import org.junit.jupiter.api.Assertions.assertEquals import treeInvariants.TreesInvariants import kotlin.random.Random @@ -11,34 +12,87 @@ class RBTreeTest { private val randomizer = Random(seed) - private lateinit var keyValue: Array> + private lateinit var keyValue: List> + private lateinit var bigKeyValue: List> private val tree = RBTree() private val treeChecker = TreesInvariants>() @BeforeAll fun beforeAll() { - keyValue = Array(10000) { Pair(randomizer.nextInt(10000), randomizer.nextInt(10000)) } + keyValue = List(1000) { Pair(randomizer.nextInt(5000), randomizer.nextInt(5000)) }.distinctBy { it.first } + bigKeyValue = List(100000) { Pair(randomizer.nextInt(500000), randomizer.nextInt(500000)) }.distinctBy { it.first } + } + + @BeforeEach + fun beforeEach() { + tree.root = null } @Test - fun `invariants after addition`() { + fun `init null tree`() { val tree = RBTree() - for (i in 0 until 10000) { - tree.insert(keyValue[i].first, keyValue[i].second) - assert(treeChecker.checkRBTreeInvariants(tree.root)) { "Adding test error on $i iteration with params ${keyValue[i].first} ${keyValue[i].second}" } + assertEquals(null, tree.root) { "After initialization, the tree must have NULL root" } + } + + @Test + fun `adding a node`() { + keyValue.forEach { + tree.insert(it.first, it.second) + + assert(treeChecker.checkRBTreeInvariants(tree.root)) { "Error adding a node. The invariants of the tree are violated" } } } @Test - fun `invariants after deletion`(){ + fun `adding node with equal keys`() { keyValue.forEach { tree.insert(it.first, it.second) } - keyValue.shuffle() - for(i in 0 until 10000){ - tree.delete(keyValue[i].first) - assert(treeChecker.checkRBTreeInvariants(tree.root)) { "Adding test error on $i iteration with params ${keyValue[i].first} ${keyValue[i].second}" } + tree.insert(keyValue[0].first, keyValue[0].second + 1) + + assertEquals(keyValue[0].second + 1, tree.find(keyValue[0].first)) { "Error when adding nodes with equal key" } + } + + @Test + fun `big addition test`() { + val bigTree = RBTree() + + bigKeyValue.forEach { bigTree.insert(it.first, it.second) } + + assert(treeChecker.checkRBTreeInvariants(bigTree.root)) { "big adding test error" } + } + + @Test + fun `find test`() { + keyValue.forEach { tree.insert(it.first, it.second) } + + keyValue.forEach { + assertEquals(it.second, tree.find(it.first)) + } + } + + @Test + fun `deleting a node`() { + keyValue.forEach { tree.insert(it.first, it.second) } + + keyValue.forEach { + tree.delete(it.first) + + assertAll( "The tree must be balanced and must not contain a node after deletion", + { assertEquals(null, tree.find(it.first)) }, + { assert(treeChecker.checkRBTreeInvariants(tree.root)) } + ) } - assert(tree.root == null) { "tree is not null" } + } + + @Test + fun `big deletion test`() { + val bigTree = RBTree() + bigKeyValue.forEach { bigTree.insert(it.first, it.second) } + + bigKeyValue = bigKeyValue.shuffled() + bigKeyValue.forEach { bigTree.delete(it.first) } + + assertEquals(null, bigTree.root) { "big deletion test error. The tree should be empty" } } } \ No newline at end of file From 1e0343f54017159e8f8b25c4130ba4ffab557daf Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 17 Apr 2023 00:13:50 +0300 Subject: [PATCH 040/135] feat: The invariants of the AVL and BS trees can now be tested using the corresponding functions --- .../src/test/kotlin/treeInvariants/TreesInvariants.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt index c79868d..0ced5a4 100644 --- a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt +++ b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt @@ -1,6 +1,8 @@ package treeInvariants import Node +import avlTree.AvlNode +import binarySearchTree.BSNode import redBlackTree.RBNode import redBlackTree.RBNode.Color @@ -46,4 +48,13 @@ class TreesInvariants, V, NODE_TYPE : Node> { (node.getRightNode() == null || node.getRightNode()!!.getParent() == node && node.getRightNode()!!.getKey() > node.getKey() && checkNodeInvariants(node.getRightNode()!!)) } + + fun checkAvlTreeInvariants(root: AvlNode?): Boolean{ + return root == null || + ((root.getRightNode()?.getHeight() ?: 0) - (root.getLeftNode()?.getHeight() ?: 0) in -1..1) && + checkAvlTreeInvariants(root.getLeftNode()) && checkAvlTreeInvariants(root.getRightNode()) && + checkNodeInvariants(root as NODE_TYPE) + } + + fun checkBsTreeInvariants(root: BSNode?) = (root == null || checkNodeInvariants(root as NODE_TYPE)) } \ No newline at end of file From 0241de408c3cdf34b16066138fae3953c3463e89 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 17 Apr 2023 01:31:11 +0300 Subject: [PATCH 041/135] feat: Added insert tests for BSTree fix: a small naming bug in BSTree --- .../main/kotlin/binarySearchTree/BSTree.kt | 12 ++--- .../kotlin/binarySearchTree/BSTreeTest.kt | 52 +++++++++++++++++++ 2 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt index dbae400..7011e6d 100644 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt @@ -12,19 +12,19 @@ class BSTree, V> : BTree>() { add(BSNode(key, value)) } - private fun addRoot(root: BSNode): BSNode { + private fun addRoot(node: BSNode): BSNode { val temp = this.root - return if (temp == null) root + return if (temp == null) node else { val subTree = BSTree() - if (root.getKey() < temp.getKey()) { + if (node.getKey() < temp.getKey()) { subTree.root = temp.getLeftNode() - this.root?.setLeftNode(subTree.addRoot(root)) + this.root?.setLeftNode(subTree.addRoot(node)) balancer.rightRotate(temp) } else { subTree.root = temp.getRightNode() - this.root?.setRightNode(subTree.addRoot(root)) + this.root?.setRightNode(subTree.addRoot(node)) balancer.leftRotate(temp) } } @@ -34,7 +34,7 @@ class BSTree, V> : BTree>() { override fun add(node: BSNode) { val temp = this.root - if (temp == null || temp.getKey() == node.getKey()) this.root = root + if (temp == null || temp.getKey() == node.getKey()) this.root = node else { if (Random.nextInt() % (node.getSize() + 1) == 0) this.root = this.addRoot(node) diff --git a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt new file mode 100644 index 0000000..28fa039 --- /dev/null +++ b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt @@ -0,0 +1,52 @@ +package binarySearchTree + +import org.junit.jupiter.api.* +import treeInvariants.TreesInvariants +import kotlin.random.Random + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) + +class BSTreeTest { + + private lateinit var keyValue: List> + private lateinit var bigKeyValue: List> + private val tree = BSTree() + private val treeChecker = TreesInvariants>() + + @BeforeAll + fun prepareNodes() { + keyValue = List(1000) { Pair(Random.nextInt(5000), Random.nextInt(5000)) }.distinctBy { it.first } + bigKeyValue = List(100000) { Pair(Random.nextInt(500000), Random.nextInt(500000)) }.distinctBy { it.first } + } + + @BeforeEach + fun resetTree() { + tree.root = null + } + + @Test + fun `init null tree`() { + val tree = BSTree() + Assertions.assertNull(tree.root) { "After initialization, the tree must have NULL root" } + } + + @Test + fun `adding a node`(){ + tree.insert(keyValue[0].first, keyValue[0].second) + Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)){"Error adding a node"} + } + + @Test + fun `adding nodes`(){ + for (i in keyValue) tree.insert(i.first, i.second) + Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)){"Error adding nodes"} + } + + @Test + fun `adding a lot of nodes`() { + for (i in bigKeyValue) { + tree.insert(i.first, i.second) + } + Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) { "Error adding nodes" } + } +} \ No newline at end of file From 7d7b6475cc17b322f2c7042cb4d8c9cd81330b4b Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Tue, 18 Apr 2023 17:24:32 +0300 Subject: [PATCH 042/135] feat: Added find and deleting tests for BSTree --- .../kotlin/binarySearchTree/BSTreeTest.kt | 63 +++++++++++++++++-- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt index 28fa039..e28ec22 100644 --- a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt +++ b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt @@ -31,15 +31,15 @@ class BSTreeTest { } @Test - fun `adding a node`(){ + fun `adding a node`() { tree.insert(keyValue[0].first, keyValue[0].second) - Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)){"Error adding a node"} + Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) { "Error adding a node" } } @Test - fun `adding nodes`(){ + fun `adding nodes`() { for (i in keyValue) tree.insert(i.first, i.second) - Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)){"Error adding nodes"} + Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) { "Error adding nodes" } } @Test @@ -49,4 +49,59 @@ class BSTreeTest { } Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) { "Error adding nodes" } } + + @Test + fun `find test`() { + keyValue.forEach { tree.insert(it.first, it.second) } + + keyValue.forEach { + Assertions.assertEquals(it.second, tree.find(it.first)) { "Find test error" } + } + } + + @Test + fun `adding nodes with equal key`() { + keyValue.forEach { tree.insert(it.first, it.second) } + + tree.insert(keyValue[0].first, keyValue[0].second + 1) + + Assertions.assertEquals( + keyValue[0].second + 1, + tree.find(keyValue[0].first) + ) { "Error when adding nodes with equal key" } + } + + @Test + fun `deleting a node`() { + tree.insert(keyValue[0].first, keyValue[0].second) + tree.delete(keyValue[0].first) + assertAll("The tree must be balanced and must not contain a node after deletion", + { Assertions.assertNull(tree.find(keyValue[0].first)) }, + { Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) } + ) + } + + @Test + fun `deleting nodes`() { + keyValue.forEach { tree.insert(it.first, it.second) } + keyValue.forEach { + tree.delete(it.first) + assertAll("The tree must be balanced and must not contain a node after deletion", + { Assertions.assertNull(tree.find(it.first)) }, + { Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) } + ) + } + } + + @Test + fun `deleting a lot of nodes`() { + bigKeyValue.forEach { tree.insert(it.first, it.second) } + bigKeyValue.forEach { + tree.delete(it.first) + assertAll("The tree must be balanced and must not contain a node after deletion", + { Assertions.assertNull(tree.find(it.first)) }, + { Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) } + ) + } + } } \ No newline at end of file From 4ad44d8769d2920daabf6b4d0c47026ee10cbac5 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Tue, 18 Apr 2023 17:41:28 +0300 Subject: [PATCH 043/135] feat: Added AvlTests --- .../src/test/kotlin/avlTree/AVLTreeTest.kt | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt diff --git a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt b/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt new file mode 100644 index 0000000..35d42eb --- /dev/null +++ b/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt @@ -0,0 +1,107 @@ +package avlTree + +import org.junit.jupiter.api.* +import treeInvariants.TreesInvariants +import kotlin.random.Random + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) + +class AVLTreeTest { + + private lateinit var keyValue: List> + private lateinit var bigKeyValue: List> + private val tree = AvlTree() + private val treeChecker = TreesInvariants>() + + @BeforeAll + fun prepareNodes() { + keyValue = List(1000) { Pair(Random.nextInt(5000), Random.nextInt(5000)) }.distinctBy { it.first } + bigKeyValue = List(100000) { Pair(Random.nextInt(500000), Random.nextInt(500000)) }.distinctBy { it.first } + } + + @BeforeEach + fun resetTree() { + tree.root = null + } + + @Test + fun `init null tree`() { + val tree = AvlTree() + Assertions.assertNull(tree.root) { "After initialization, the tree must have NULL root" } + } + + @Test + fun `adding a node`() { + tree.insert(keyValue[0].first, keyValue[0].second) + Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) { "Error adding a node" } + } + + @Test + fun `adding nodes`() { + for (i in keyValue) tree.insert(i.first, i.second) + Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) { "Error adding nodes" } + } + + @Test + fun `adding a lot of nodes`() { + for (i in bigKeyValue) { + tree.insert(i.first, i.second) + } + Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) { "Error adding nodes" } + } + + @Test + fun `find test`() { + keyValue.forEach { tree.insert(it.first, it.second) } + + keyValue.forEach { + Assertions.assertEquals(it.second, tree.find(it.first)) { "Find test error" } + } + } + + @Test + fun `adding nodes with equal key`() { + keyValue.forEach { tree.insert(it.first, it.second) } + + tree.insert(keyValue[0].first, keyValue[0].second + 1) + + Assertions.assertEquals( + keyValue[0].second + 1, + tree.find(keyValue[0].first) + ) { "Error when adding nodes with equal key" } + } + + @Test + fun `deleting a node`() { + tree.insert(keyValue[0].first, keyValue[0].second) + tree.delete(keyValue[0].first) + assertAll("The tree must be balanced and must not contain a node after deletion", + { Assertions.assertNull(tree.find(keyValue[0].first)) }, + { Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) } + ) + } + + @Test + fun `deleting nodes`() { + keyValue.forEach { tree.insert(it.first, it.second) } + keyValue.forEach { + tree.delete(it.first) + assertAll("The tree must be balanced and must not contain a node after deletion", + { Assertions.assertNull(tree.find(it.first)) }, + { Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) } + ) + } + } + + @Test + fun `deleting a lot of nodes`() { + bigKeyValue.forEach { tree.insert(it.first, it.second) } + bigKeyValue.forEach { + tree.delete(it.first) + assertAll("The tree must be balanced and must not contain a node after deletion", + { Assertions.assertNull(tree.find(it.first)) }, + { Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) } + ) + } + } +} \ No newline at end of file From 172ed55f1d4dd42f9ede4cc32617098eb2dc964f Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Tue, 18 Apr 2023 18:46:40 +0300 Subject: [PATCH 044/135] fix: BSTree parent updating is fixed, recursive bug in TreeInvariants is fixed, changed one test --- .../main/kotlin/binarySearchTree/BSTree.kt | 8 +++- .../kotlin/binarySearchTree/BSTreeTest.kt | 10 ++--- .../kotlin/treeInvariants/TreesInvariants.kt | 40 ++++++++++++------- 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt index 7011e6d..bc174f8 100644 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt @@ -48,10 +48,12 @@ class BSTree, V> : BTree>() { if (temp.getKey() > node.getKey()) { subTree.root = temp.getLeftNode() subTree.add(node) + subTree.root?.setParent(this.root) this.root?.setLeftNode(subTree.root) } else { subTree.root = temp.getRightNode() subTree.add(node) + subTree.root?.setParent(this.root) this.root?.setRightNode(subTree.root) } } @@ -68,10 +70,12 @@ class BSTree, V> : BTree>() { return if (Random.nextInt() % (left.getSize() + right.getSize()) < left.getSize()) { left.setRightNode(join(left.getRightNode(), right)) + left.getRightNode()?.setParent(left) left.updateSize() left } else { - right.setLeftNode(join(right.getLeftNode(), left)) + right.setLeftNode(join(left, right.getLeftNode())) + right.getLeftNode()?.setParent(right) right.updateSize() right } @@ -89,11 +93,13 @@ class BSTree, V> : BTree>() { val subTree = BSTree() subTree.root = temp.getLeftNode() subTree.delete(key) + subTree.root?.setParent(this.root) this.root?.setLeftNode(subTree.root) } else { val subTree = BSTree() subTree.root = temp.getRightNode() subTree.delete(key) + subTree.root?.setParent(this.root) this.root?.setRightNode(subTree.root) } diff --git a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt index e28ec22..af16692 100644 --- a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt +++ b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt @@ -96,12 +96,8 @@ class BSTreeTest { @Test fun `deleting a lot of nodes`() { bigKeyValue.forEach { tree.insert(it.first, it.second) } - bigKeyValue.forEach { - tree.delete(it.first) - assertAll("The tree must be balanced and must not contain a node after deletion", - { Assertions.assertNull(tree.find(it.first)) }, - { Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) } - ) - } + bigKeyValue = bigKeyValue.shuffled() + bigKeyValue.forEach{ tree.delete(it.first) } + Assertions.assertNull(tree.root) } } \ No newline at end of file diff --git a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt index 0ced5a4..8156585 100644 --- a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt +++ b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt @@ -10,7 +10,7 @@ import redBlackTree.RBNode.Color class TreesInvariants, V, NODE_TYPE : Node> { fun checkRBTreeInvariants(root: RBNode?): Boolean { - return root == null || root.getParent() == null && checkNodeInvariants(root as NODE_TYPE) && root.color == Color.BLACK && + return root == null || root.getParent() == null && checkNodeInvariants(root as NODE_TYPE) && root.color == Color.BLACK && checkRBNodeBlackHeightInvariant(root, 0, getSomeBlackHeight(root)) && checkRBNodeBlackParentForRedInvariant(root) } @@ -21,20 +21,28 @@ class TreesInvariants, V, NODE_TYPE : Node> { (node.getRightNode() == null || checkRBNodeBlackParentForRedInvariant(node.getRightNode()!!)) } - private fun checkRBNodeBlackHeightInvariant(node: RBNode, curHeight: Int, rightHeight: Int): Boolean{ - val newCurHeight = curHeight + if(node.color == Color.BLACK) 1 else 0 - if(node.getLeftNode() == null && node.getRightNode() == null){ + private fun checkRBNodeBlackHeightInvariant(node: RBNode, curHeight: Int, rightHeight: Int): Boolean { + val newCurHeight = curHeight + if (node.color == Color.BLACK) 1 else 0 + if (node.getLeftNode() == null && node.getRightNode() == null) { return newCurHeight == rightHeight } - return (node.getLeftNode() == null || checkRBNodeBlackHeightInvariant(node.getLeftNode()!!, newCurHeight, rightHeight) && - node.getRightNode() == null || checkRBNodeBlackHeightInvariant(node.getRightNode()!!, newCurHeight, rightHeight)) + return (node.getLeftNode() == null || checkRBNodeBlackHeightInvariant( + node.getLeftNode()!!, + newCurHeight, + rightHeight + ) && + node.getRightNode() == null || checkRBNodeBlackHeightInvariant( + node.getRightNode()!!, + newCurHeight, + rightHeight + )) } - private fun getSomeBlackHeight(root: RBNode): Int{ + private fun getSomeBlackHeight(root: RBNode): Int { var curNode: RBNode? = root var blackHeight = 0 - while(curNode != null){ - if(curNode.color == Color.BLACK){ + while (curNode != null) { + if (curNode.color == Color.BLACK) { ++blackHeight } curNode = curNode.getLeftNode() @@ -49,12 +57,14 @@ class TreesInvariants, V, NODE_TYPE : Node> { node.getRightNode()!!.getKey() > node.getKey() && checkNodeInvariants(node.getRightNode()!!)) } - fun checkAvlTreeInvariants(root: AvlNode?): Boolean{ - return root == null || - ((root.getRightNode()?.getHeight() ?: 0) - (root.getLeftNode()?.getHeight() ?: 0) in -1..1) && - checkAvlTreeInvariants(root.getLeftNode()) && checkAvlTreeInvariants(root.getRightNode()) && - checkNodeInvariants(root as NODE_TYPE) - } + fun checkAvlTreeInvariants(root: AvlNode?): Boolean = root == null || checkAvlHeightInvariants(root) + && checkNodeInvariants(root as NODE_TYPE) + + private fun checkAvlHeightInvariants(node: AvlNode): Boolean = + ((node.getRightNode()?.getHeight() ?: 0) - (node.getLeftNode()?.getHeight() ?: 0) in -1..1) + && (node.getLeftNode() == null || checkAvlHeightInvariants(node.getLeftNode()!!)) + && (node.getRightNode() == null || checkAvlHeightInvariants(node.getRightNode()!!)) + fun checkBsTreeInvariants(root: BSNode?) = (root == null || checkNodeInvariants(root as NODE_TYPE)) } \ No newline at end of file From 878fc22ed12ccb09f6294c25ee3a3a66b524d49f Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Tue, 18 Apr 2023 20:03:12 +0300 Subject: [PATCH 045/135] fix: BSTree size update --- BSTrees/src/main/kotlin/Node.kt | 16 ++++++++-------- .../src/main/kotlin/binarySearchTree/BSTree.kt | 2 ++ .../test/kotlin/binarySearchTree/BSTreeTest.kt | 4 +++- .../kotlin/treeInvariants/TreesInvariants.kt | 11 ++++++++++- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/BSTrees/src/main/kotlin/Node.kt b/BSTrees/src/main/kotlin/Node.kt index 7286a24..791453c 100644 --- a/BSTrees/src/main/kotlin/Node.kt +++ b/BSTrees/src/main/kotlin/Node.kt @@ -10,7 +10,7 @@ abstract class Node, V, NODE_TYPE : Node>(pri fun getSize() = size - fun setSize(newSize: Int){ + fun setSize(newSize: Int) { this.size = newSize } @@ -24,19 +24,19 @@ abstract class Node, V, NODE_TYPE : Node>(pri fun getParent() = parent - fun setParent(newNode: NODE_TYPE?){ + fun setParent(newNode: NODE_TYPE?) { parent = newNode } fun getLeftNode() = leftNode - fun setLeftNode(newNode: NODE_TYPE?){ + fun setLeftNode(newNode: NODE_TYPE?) { leftNode = newNode } fun getRightNode() = rightNode - fun setRightNode(newNode: NODE_TYPE?){ + fun setRightNode(newNode: NODE_TYPE?) { rightNode = newNode } @@ -52,10 +52,10 @@ abstract class Node, V, NODE_TYPE : Node>(pri setHeight(max(leftHeight, rightHeight) + 1) } - fun updateSize(){ - val leftSize = getLeftNode()?.getHeight() ?: 0 - val rightSize = getRightNode()?.getHeight() ?: 0 - setHeight(leftSize + rightSize + 1) + fun updateSize() { + val leftSize = getLeftNode()?.getSize() ?: 0 + val rightSize = getRightNode()?.getSize() ?: 0 + setSize(leftSize + rightSize + 1) } } diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt index bc174f8..9cb66d7 100644 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt @@ -103,6 +103,8 @@ class BSTree, V> : BTree>() { this.root?.setRightNode(subTree.root) } + this.root?.updateSize() + } } diff --git a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt index af16692..dd9a7a3 100644 --- a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt +++ b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt @@ -96,8 +96,10 @@ class BSTreeTest { @Test fun `deleting a lot of nodes`() { bigKeyValue.forEach { tree.insert(it.first, it.second) } + bigKeyValue = bigKeyValue.shuffled() - bigKeyValue.forEach{ tree.delete(it.first) } + bigKeyValue.forEach { tree.delete(it.first) } + Assertions.assertNull(tree.root) } } \ No newline at end of file diff --git a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt index 8156585..816c255 100644 --- a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt +++ b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt @@ -66,5 +66,14 @@ class TreesInvariants, V, NODE_TYPE : Node> { && (node.getRightNode() == null || checkAvlHeightInvariants(node.getRightNode()!!)) - fun checkBsTreeInvariants(root: BSNode?) = (root == null || checkNodeInvariants(root as NODE_TYPE)) + private fun checkBSSizeInvariant(node: BSNode?): Boolean { + return node == null || + node.getSize() == (node.getLeftNode()?.getSize() ?: 0) + (node.getRightNode()?.getSize() ?: 0) + 1 + && checkBSSizeInvariant(node.getLeftNode()) && checkBSSizeInvariant(node.getRightNode()) + } + + fun checkBsTreeInvariants(root: BSNode?): Boolean { + return (root == null || checkNodeInvariants(root as NODE_TYPE)) && checkBSSizeInvariant(root) + } + } \ No newline at end of file From 499d1e542636fd6781dad3c0342d710fc02b77dd Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Tue, 18 Apr 2023 21:47:33 +0300 Subject: [PATCH 046/135] fix: AvlTree add and delete bugs with parents and some misspells --- BSTrees/src/main/kotlin/avlTree/AvlTree.kt | 20 +++++++++++++++---- .../src/main/kotlin/balancers/AvlBalancer.kt | 2 +- .../src/test/kotlin/avlTree/AVLTreeTest.kt | 12 +++++------ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt index 36d8b21..618b8c2 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt +++ b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt @@ -21,10 +21,12 @@ class AvlTree, V> : BTree>() { if (node.getKey() < temp.getKey()) { subTree.root = temp.getLeftNode() subTree.add(node) + subTree.root?.setParent(this.root) this.root?.setLeftNode(subTree.root) } else if (node.getKey() > temp.getKey()) { subTree.root = temp.getRightNode() subTree.add(node) + subTree.root?.setParent(this.root) this.root?.setRightNode(subTree.root) } @@ -41,7 +43,9 @@ class AvlTree, V> : BTree>() { private fun removeMin(node: AvlNode): AvlNode? { val temp = node.getLeftNode() if (temp == null) return node.getRightNode() - node.setLeftNode(removeMin(temp)) + val tempRemovedMin = removeMin(temp) + node.setLeftNode(tempRemovedMin) + tempRemovedMin?.setParent(node) return balancer.balance(node) } @@ -57,12 +61,14 @@ class AvlTree, V> : BTree>() { subTree.root = temp.getLeftNode() subTree.delete(key) + subTree.root?.setParent(this.root) this.root?.setLeftNode(subTree.root) } else if (key > temp.getKey()) { subTree.root = temp.getRightNode() subTree.delete(key) + subTree.root?.setParent(this.root) this.root?.setRightNode(subTree.root) } else { @@ -70,12 +76,18 @@ class AvlTree, V> : BTree>() { val leftNode = this.root?.getLeftNode() val rightNode = this.root?.getRightNode() - if (rightNode == null) this.root = leftNode - - else { + if (rightNode == null) { + leftNode?.setParent(this.root?.getParent()) + this.root = leftNode + } else { val tempMin: AvlNode = findMin(rightNode) tempMin.setRightNode(removeMin(rightNode)) + tempMin.getRightNode()?.setParent(tempMin) tempMin.setLeftNode(leftNode) + tempMin.getLeftNode()?.setParent(tempMin) + if (this.root?.getParent()?.getLeftNode() == this.root) this.root?.getParent()?.setLeftNode(tempMin) + else this.root?.getParent()?.setRightNode(tempMin) + tempMin.setParent(this.root?.getParent()) this.root = balancer.balance(tempMin) } diff --git a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt b/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt index 5bb8c54..456d1fa 100644 --- a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt @@ -31,7 +31,7 @@ class AvlBalancer, V> : Balancer>() { } } - return leftRotate(node) + return rightRotate(node) } return node diff --git a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt b/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt index 35d42eb..3a004c3 100644 --- a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt +++ b/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt @@ -96,12 +96,10 @@ class AVLTreeTest { @Test fun `deleting a lot of nodes`() { bigKeyValue.forEach { tree.insert(it.first, it.second) } - bigKeyValue.forEach { - tree.delete(it.first) - assertAll("The tree must be balanced and must not contain a node after deletion", - { Assertions.assertNull(tree.find(it.first)) }, - { Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) } - ) - } + + bigKeyValue = bigKeyValue.shuffled() + bigKeyValue.forEach { tree.delete(it.first) } + + Assertions.assertNull(tree.root) } } \ No newline at end of file From 4ba0b569e43a3d2cb1d50f20aec16b4d64a04a1c Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Tue, 18 Apr 2023 22:17:12 +0300 Subject: [PATCH 047/135] feat: Added some tests --- .../src/test/kotlin/avlTree/AVLTreeTest.kt | 45 ++++++++++++++++++ .../kotlin/binarySearchTree/BSTreeTest.kt | 45 ++++++++++++++++++ .../test/kotlin/redBlackTree/RBTreeTest.kt | 46 +++++++++++++++++++ 3 files changed, 136 insertions(+) diff --git a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt b/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt index 3a004c3..8abeed7 100644 --- a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt +++ b/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt @@ -102,4 +102,49 @@ class AVLTreeTest { Assertions.assertNull(tree.root) } + + @Test + fun `find in an empty tree`(){ + Assertions.assertNull(tree.find(bigKeyValue[0].first)) + try { + tree.find(bigKeyValue[0].first) + } catch (e: Exception){ + Assertions.assertTrue(false) + } + } + + @Test + fun `delete a node which isn't in a tree`(){ + + try { + tree.delete(bigKeyValue[0].first) + } catch (e: Exception){ + Assertions.assertTrue(false) + } + + Assertions.assertNull(tree.root) + } + + @Test + fun `delete a node which isn't in a tree(tree isn't empty)`(){ + + for (i in keyValue.indices){ + if (i == 0) continue + tree.insert(keyValue[i].first, keyValue[i].second) + } + + try { + tree.delete(bigKeyValue[0].first) + } catch (e: Exception){ + Assertions.assertTrue(false) + } + + Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) + + for (i in keyValue.indices){ + if (i == 0) continue + Assertions.assertEquals(keyValue[i].second, tree.find(keyValue[i].first)) + } + + } } \ No newline at end of file diff --git a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt index dd9a7a3..63e058c 100644 --- a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt +++ b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt @@ -102,4 +102,49 @@ class BSTreeTest { Assertions.assertNull(tree.root) } + + @Test + fun `find in an empty tree`(){ + Assertions.assertNull(tree.find(bigKeyValue[0].first)) + try { + tree.find(bigKeyValue[0].first) + } catch (e: Exception){ + Assertions.assertTrue(false) + } + } + + @Test + fun `delete a node which isn't in a tree`(){ + + try { + tree.delete(bigKeyValue[0].first) + } catch (e: Exception){ + Assertions.assertTrue(false) + } + + Assertions.assertNull(tree.root) + } + + @Test + fun `delete a node which isn't in a tree(tree isn't empty)`(){ + + for (i in keyValue.indices){ + if (i == 0) continue + tree.insert(keyValue[i].first, keyValue[i].second) + } + + try { + tree.delete(bigKeyValue[0].first) + } catch (e: Exception){ + Assertions.assertTrue(false) + } + + Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) + + for (i in keyValue.indices){ + if (i == 0) continue + Assertions.assertEquals(keyValue[i].second, tree.find(keyValue[i].first)) + } + + } } \ No newline at end of file diff --git a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt index d6bd287..0f99666 100644 --- a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt +++ b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt @@ -95,4 +95,50 @@ class RBTreeTest { assertEquals(null, bigTree.root) { "big deletion test error. The tree should be empty" } } + + + @Test + fun `find in an empty tree`(){ + Assertions.assertNull(tree.find(bigKeyValue[0].first)) + try { + tree.find(bigKeyValue[0].first) + } catch (e: Exception){ + Assertions.assertTrue(false) + } + } + + @Test + fun `delete a node which isn't in a tree`(){ + + try { + tree.delete(bigKeyValue[0].first) + } catch (e: Exception){ + Assertions.assertTrue(false) + } + + Assertions.assertNull(tree.root) + } + + @Test + fun `delete a node which isn't in a tree(tree isn't empty)`(){ + + for (i in keyValue.indices){ + if (i == 0) continue + tree.insert(keyValue[i].first, keyValue[i].second) + } + + try { + tree.delete(bigKeyValue[0].first) + } catch (e: Exception){ + Assertions.assertTrue(false) + } + + Assertions.assertTrue(treeChecker.checkRBTreeInvariants(tree.root)) + + for (i in keyValue.indices){ + if (i == 0) continue + assertEquals(keyValue[i].second, tree.find(keyValue[i].first)) + } + + } } \ No newline at end of file From aa5d4da924b7d646d9476739c0385a6ba1a057b4 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 18 Apr 2023 22:28:52 +0300 Subject: [PATCH 048/135] fix: All "!!" have been replaced with safer designs --- .../src/main/kotlin/balancers/RBBalancer.kt | 48 ++++++++++--------- .../src/main/kotlin/redBlackTree/RBTree.kt | 9 ++-- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt index 82aed38..f92f084 100644 --- a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/RBBalancer.kt @@ -20,7 +20,7 @@ open class RBBalancer, V> : Balancer>() { } // brother MUST exist, because we have a 2xBLACK curNode in leftTree - var nodeBrother = nodeParent.getRightNode()!! + var nodeBrother = nodeParent.getRightNode() ?: throw Exception("An attempt to take a non-existent son") // Consideration of the case 1. // nodeBrother is red @@ -36,15 +36,17 @@ open class RBBalancer, V> : Balancer>() { // these nodes MUST exist because we did leftRotate with theirs nodes - nodeParent = nodeParent.getLeftNode()!! - curNode = nodeParent.getLeftNode()!! - nodeBrother = nodeParent.getRightNode()!! + nodeParent = nodeParent.getLeftNode() ?: throw Exception("An attempt to take a non-existent son") + curNode = nodeParent.getLeftNode() ?: throw Exception("An attempt to take a non-existent son") + nodeBrother = nodeParent.getRightNode() ?: throw Exception("An attempt to take a non-existent son") } // Consideration of the case 2. // nodeBrother's sons are black - if ((nodeBrother.getLeftNode() == null || nodeBrother.getLeftNode()!!.color == Color.BLACK) && - (nodeBrother.getRightNode() == null || nodeBrother.getRightNode()!!.color == Color.BLACK) + val leftSonOfBrother = nodeBrother.getLeftNode() + val rightSonOfBrother = nodeBrother.getRightNode() + if ((leftSonOfBrother == null || leftSonOfBrother.color == Color.BLACK) && + (rightSonOfBrother == null || rightSonOfBrother.color == Color.BLACK) ) { nodeBrother.color = Color.RED curNode = nodeParent @@ -53,9 +55,9 @@ open class RBBalancer, V> : Balancer>() { // Consideration of the case 3. // nodeBrother's left son is red, right son is black - if (nodeBrother.getLeftNode() != null && nodeBrother.getLeftNode()!!.color == Color.RED && (nodeBrother.getRightNode() == null || nodeBrother.getRightNode()!!.color == Color.BLACK)) { + if (leftSonOfBrother != null && leftSonOfBrother.color == Color.RED && (rightSonOfBrother == null || rightSonOfBrother.color == Color.BLACK)) { nodeBrother.color = Color.RED - nodeBrother.getLeftNode()!!.color = Color.BLACK + leftSonOfBrother.color = Color.BLACK nodeBrother = rightRotate(nodeBrother) } @@ -63,7 +65,7 @@ open class RBBalancer, V> : Balancer>() { // nodeBrother's right son is red nodeBrother.color = nodeParent.color nodeParent.color = Color.BLACK - nodeBrother.getRightNode()!!.color = Color.BLACK + nodeBrother.getRightNode()?.color = Color.BLACK if (nodeParent.getParent() == null) { tree.root = leftRotate(nodeParent) } else { @@ -80,7 +82,7 @@ open class RBBalancer, V> : Balancer>() { } // brother MUST exist, because we have a 2xBLACK curNode in rightTree - var nodeBrother = nodeParent.getLeftNode()!! + var nodeBrother = nodeParent.getLeftNode() ?: throw Exception("An attempt to take a non-existent son") // Consideration of the case 1. // nodeBrother is red @@ -96,15 +98,17 @@ open class RBBalancer, V> : Balancer>() { } // these nodes MUST exist because we did rightRotate with theirs nodes - nodeParent = nodeParent.getRightNode()!! - curNode = nodeParent.getRightNode()!! - nodeBrother = nodeParent.getLeftNode()!! + nodeParent = nodeParent.getRightNode() ?: throw Exception("An attempt to take a non-existent son") + curNode = nodeParent.getRightNode() ?: throw Exception("An attempt to take a non-existent son") + nodeBrother = nodeParent.getLeftNode() ?: throw Exception("An attempt to take a non-existent son") } // Consideration of the case 2. // nodeBrother's sons are black - if ((nodeBrother.getLeftNode() == null || nodeBrother.getLeftNode()!!.color == Color.BLACK) && - (nodeBrother.getRightNode() == null || nodeBrother.getRightNode()!!.color == Color.BLACK) + val leftSonOfBrother = nodeBrother.getLeftNode() + val rightSonOfBrother = nodeBrother.getRightNode() + if ((leftSonOfBrother == null || leftSonOfBrother.color == Color.BLACK) && + (rightSonOfBrother == null || rightSonOfBrother.color == Color.BLACK) ) { nodeBrother.color = Color.RED curNode = nodeParent @@ -113,9 +117,9 @@ open class RBBalancer, V> : Balancer>() { // Consideration of the case 3. // nodeBrother's left son is black, right son is red - if ((nodeBrother.getLeftNode() == null || nodeBrother.getLeftNode()!!.color == Color.BLACK) && nodeBrother.getRightNode() != null && nodeBrother.getRightNode()!!.color == Color.RED) { + if ((leftSonOfBrother == null || leftSonOfBrother.color == Color.BLACK) && rightSonOfBrother != null && rightSonOfBrother.color == Color.RED) { nodeBrother.color = Color.RED - nodeBrother.getRightNode()!!.color = Color.BLACK + rightSonOfBrother.color = Color.BLACK nodeBrother = leftRotate(nodeBrother) } @@ -123,7 +127,7 @@ open class RBBalancer, V> : Balancer>() { // nodeBrother's right son is red nodeBrother.color = nodeParent.color nodeParent.color = Color.BLACK - nodeBrother.getLeftNode()!!.color = Color.BLACK + nodeBrother.getLeftNode()?.color = Color.BLACK if (nodeParent.getParent() == null) { tree.root = rightRotate(nodeParent) } else { @@ -142,7 +146,7 @@ open class RBBalancer, V> : Balancer>() { var curNode = node while (nodeParent != null && nodeParent.color == Color.RED) { // It must exist, since the root of the tree cannot be red - val nodeGrandParent = nodeParent.getParent() ?: error("RTTree structure error") + val nodeGrandParent = nodeParent.getParent() ?: throw Exception("An attempt to take a non-existent parent") if (nodeParent == nodeGrandParent.getLeftNode()) { val nodeUncle = nodeGrandParent.getRightNode() @@ -150,7 +154,7 @@ open class RBBalancer, V> : Balancer>() { if (nodeUncle == null || nodeUncle.color == Color.BLACK) { if (curNode == nodeParent.getRightNode()) { nodeParent = leftRotate(nodeParent) - curNode = nodeParent.getLeftNode()!! + curNode = nodeParent.getLeftNode() ?: throw Exception("An attempt to take a non-existent son") } nodeParent.color = Color.BLACK nodeGrandParent.color = Color.RED @@ -169,7 +173,7 @@ open class RBBalancer, V> : Balancer>() { if (nodeUncle == null || nodeUncle.color == Color.BLACK) { if (curNode == nodeParent.getLeftNode()) { nodeParent = rightRotate(nodeParent) - curNode = nodeParent.getRightNode()!! + curNode = nodeParent.getRightNode() ?: throw Exception("An attempt to take a non-existent son") } nodeParent.color = Color.BLACK nodeGrandParent.color = Color.RED @@ -185,7 +189,7 @@ open class RBBalancer, V> : Balancer>() { } } while (curNode.getParent() != null) { - curNode = curNode.getParent()!! + curNode = curNode.getParent() ?: throw Exception("An attempt to take a non-existent parent") } curNode.color = Color.BLACK diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt index f591622..904f37f 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt @@ -16,7 +16,7 @@ class RBTree, V> : BTree>() { // if a node with such a key already exists, then we update Value val nodeWithEqualKey = findNodeByKey(node.getKey()) - if (nodeWithEqualKey != null){ + if (nodeWithEqualKey != null) { nodeWithEqualKey.setValue(node.getValue()) return } @@ -99,7 +99,7 @@ class RBTree, V> : BTree>() { // If the color of the deleted node is black, then we have to balance the tree if (colorOfNodeForSwapping == Color.BLACK) { - balancer.balanceAfterDeletion(this, sonNodeForSwapping!!) + sonNodeForSwapping?.let { balancer.balanceAfterDeletion(this, sonNodeForSwapping) } } // If we used an imaginary(NILL) node, we have to remove unnecessary links @@ -158,7 +158,8 @@ class RBTree, V> : BTree>() { curNode } else { // If we got here, then curNode has both a left and a right son - nodeWithMinKey(curNode.getRightNode()!!) + val temp = curNode.getRightNode() ?: throw Exception("An attempt to take a non-existent son") + nodeWithMinKey(temp) } } @@ -182,7 +183,7 @@ class RBTree, V> : BTree>() { private fun , V> nodeWithMinKey(node: RBNode): RBNode { var curNode = node while (curNode.getLeftNode() != null) { - curNode = curNode.getLeftNode()!! + curNode = curNode.getLeftNode() ?: throw Exception("An attempt to take a non-existent son") } return curNode } From 829635191c895f1428438c0baa96d9b03127516f Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Tue, 18 Apr 2023 22:50:00 +0300 Subject: [PATCH 049/135] feat: Added some comments --- .../src/test/kotlin/avlTree/AVLTreeTest.kt | 65 +++++++++----- .../kotlin/binarySearchTree/BSTreeTest.kt | 66 +++++++++----- .../test/kotlin/redBlackTree/RBTreeTest.kt | 87 +++++++++++++------ 3 files changed, 146 insertions(+), 72 deletions(-) diff --git a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt b/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt index 8abeed7..1466c32 100644 --- a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt +++ b/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt @@ -47,7 +47,7 @@ class AVLTreeTest { for (i in bigKeyValue) { tree.insert(i.first, i.second) } - Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) { "Error adding nodes" } + Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) { "Error adding a lot of nodes" } } @Test @@ -55,27 +55,25 @@ class AVLTreeTest { keyValue.forEach { tree.insert(it.first, it.second) } keyValue.forEach { - Assertions.assertEquals(it.second, tree.find(it.first)) { "Find test error" } + Assertions.assertEquals(it.second, tree.find(it.first)) { "Error finding nodes" } } } @Test - fun `adding nodes with equal key`() { + fun `adding nodes with equal keys`() { keyValue.forEach { tree.insert(it.first, it.second) } tree.insert(keyValue[0].first, keyValue[0].second + 1) - Assertions.assertEquals( - keyValue[0].second + 1, - tree.find(keyValue[0].first) - ) { "Error when adding nodes with equal key" } + Assertions.assertEquals(keyValue[0].second + 1, tree.find(keyValue[0].first)) + { "Error adding nodes with equal keys" } } @Test fun `deleting a node`() { tree.insert(keyValue[0].first, keyValue[0].second) tree.delete(keyValue[0].first) - assertAll("The tree must be balanced and must not contain a node after deletion", + assertAll("Error deleting a node. The tree must be balanced and must not contain a node after deletion", { Assertions.assertNull(tree.find(keyValue[0].first)) }, { Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) } ) @@ -86,7 +84,7 @@ class AVLTreeTest { keyValue.forEach { tree.insert(it.first, it.second) } keyValue.forEach { tree.delete(it.first) - assertAll("The tree must be balanced and must not contain a node after deletion", + assertAll("Error deleting nodes. The tree must be balanced and must not contain a node after deletion", { Assertions.assertNull(tree.find(it.first)) }, { Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) } ) @@ -100,50 +98,69 @@ class AVLTreeTest { bigKeyValue = bigKeyValue.shuffled() bigKeyValue.forEach { tree.delete(it.first) } - Assertions.assertNull(tree.root) + Assertions.assertNull(tree.root) { "Error deleting nodes. The tree must be empty after deleting nodes" } } @Test - fun `find in an empty tree`(){ - Assertions.assertNull(tree.find(bigKeyValue[0].first)) + fun `find in an empty tree`() { + Assertions.assertNull(tree.find(bigKeyValue[0].first)) { + "Error finding a node which doesn't exist. " + + "It must return null." + } try { tree.find(bigKeyValue[0].first) - } catch (e: Exception){ - Assertions.assertTrue(false) + } catch (e: Exception) { + Assertions.assertTrue(false) { + "Error finding a node which doesn't exist. " + + "Exception is caught" + } } } @Test - fun `delete a node which isn't in a tree`(){ + fun `delete a node which isn't in a tree`() { try { tree.delete(bigKeyValue[0].first) - } catch (e: Exception){ - Assertions.assertTrue(false) + } catch (e: Exception) { + Assertions.assertTrue(false) { + "Error deleting a node which doesn't exist. " + + "Exception is caught" + } } - Assertions.assertNull(tree.root) + Assertions.assertNull(tree.root) { + "Error deleting a node which doesn't exist. " + + "Tree must stay null" + } } @Test - fun `delete a node which isn't in a tree(tree isn't empty)`(){ + fun `delete a node which isn't in a tree(tree isn't empty)`() { - for (i in keyValue.indices){ + for (i in keyValue.indices) { if (i == 0) continue tree.insert(keyValue[i].first, keyValue[i].second) } try { tree.delete(bigKeyValue[0].first) - } catch (e: Exception){ - Assertions.assertTrue(false) + } catch (e: Exception) { + Assertions.assertTrue(false) { + "Error deleting nodes which doesn't exist. " + + "Exception is caught" + } } - Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) + Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) { + "Error deleting nodes which doesn't exist. " + + "Tree invariants aren't executed" + } - for (i in keyValue.indices){ + for (i in keyValue.indices) { if (i == 0) continue Assertions.assertEquals(keyValue[i].second, tree.find(keyValue[i].first)) + { "Error deleting nodes which doesn't exist. Some of nodes are lost" } } } diff --git a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt index 63e058c..6846be3 100644 --- a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt +++ b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt @@ -47,7 +47,7 @@ class BSTreeTest { for (i in bigKeyValue) { tree.insert(i.first, i.second) } - Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) { "Error adding nodes" } + Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) { "Error adding a lot of nodes" } } @Test @@ -55,7 +55,7 @@ class BSTreeTest { keyValue.forEach { tree.insert(it.first, it.second) } keyValue.forEach { - Assertions.assertEquals(it.second, tree.find(it.first)) { "Find test error" } + Assertions.assertEquals(it.second, tree.find(it.first)) { "Error finding nodes" } } } @@ -65,17 +65,15 @@ class BSTreeTest { tree.insert(keyValue[0].first, keyValue[0].second + 1) - Assertions.assertEquals( - keyValue[0].second + 1, - tree.find(keyValue[0].first) - ) { "Error when adding nodes with equal key" } + Assertions.assertEquals(keyValue[0].second + 1, tree.find(keyValue[0].first)) + { "Error adding nodes with equal keys" } } @Test fun `deleting a node`() { tree.insert(keyValue[0].first, keyValue[0].second) tree.delete(keyValue[0].first) - assertAll("The tree must be balanced and must not contain a node after deletion", + assertAll("Error deleting a node. The tree must be balanced and must not contain a node after deletion", { Assertions.assertNull(tree.find(keyValue[0].first)) }, { Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) } ) @@ -86,7 +84,7 @@ class BSTreeTest { keyValue.forEach { tree.insert(it.first, it.second) } keyValue.forEach { tree.delete(it.first) - assertAll("The tree must be balanced and must not contain a node after deletion", + assertAll("Error deleting nodes. The tree must be balanced and must not contain a node after deletion", { Assertions.assertNull(tree.find(it.first)) }, { Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) } ) @@ -100,50 +98,72 @@ class BSTreeTest { bigKeyValue = bigKeyValue.shuffled() bigKeyValue.forEach { tree.delete(it.first) } - Assertions.assertNull(tree.root) + Assertions.assertNull(tree.root) { "Error deleting nodes. The tree must be empty after deleting nodes" } } @Test - fun `find in an empty tree`(){ - Assertions.assertNull(tree.find(bigKeyValue[0].first)) + fun `find in an empty tree`() { + + Assertions.assertNull(tree.find(bigKeyValue[0].first)) { + "Error finding a node which doesn't exist. " + + "It must return null." + } + try { tree.find(bigKeyValue[0].first) - } catch (e: Exception){ - Assertions.assertTrue(false) + } catch (e: Exception) { + Assertions.assertTrue(false) { + "Error finding a node which doesn't exist. " + + "Exception is caught" + } } + } @Test - fun `delete a node which isn't in a tree`(){ + fun `delete a node which isn't in a tree`() { try { tree.delete(bigKeyValue[0].first) - } catch (e: Exception){ - Assertions.assertTrue(false) + } catch (e: Exception) { + Assertions.assertTrue(false) { + "Error deleting a node which doesn't exist. " + + "Exception is caught" + } } - Assertions.assertNull(tree.root) + Assertions.assertNull(tree.root) { + "Error deleting a node which doesn't exist. " + + "Tree must stay null" + } } @Test - fun `delete a node which isn't in a tree(tree isn't empty)`(){ + fun `delete a node which isn't in a tree(tree isn't empty)`() { - for (i in keyValue.indices){ + for (i in keyValue.indices) { if (i == 0) continue tree.insert(keyValue[i].first, keyValue[i].second) } try { tree.delete(bigKeyValue[0].first) - } catch (e: Exception){ - Assertions.assertTrue(false) + } catch (e: Exception) { + Assertions.assertTrue(false) { + "Error deleting nodes which doesn't exist. " + + "Exception is caught" + } } - Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) + Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) { + "Error deleting nodes which doesn't exist. " + + "Tree invariants aren't executed" + } - for (i in keyValue.indices){ + for (i in keyValue.indices) { if (i == 0) continue Assertions.assertEquals(keyValue[i].second, tree.find(keyValue[i].first)) + { "Error deleting nodes which doesn't exist. Some of nodes are lost" } } } diff --git a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt index 0f99666..b47043d 100644 --- a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt +++ b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt @@ -19,13 +19,14 @@ class RBTreeTest { @BeforeAll - fun beforeAll() { + fun prepareNodes() { keyValue = List(1000) { Pair(randomizer.nextInt(5000), randomizer.nextInt(5000)) }.distinctBy { it.first } - bigKeyValue = List(100000) { Pair(randomizer.nextInt(500000), randomizer.nextInt(500000)) }.distinctBy { it.first } + bigKeyValue = + List(100000) { Pair(randomizer.nextInt(500000), randomizer.nextInt(500000)) }.distinctBy { it.first } } @BeforeEach - fun beforeEach() { + fun resetTree() { tree.root = null } @@ -37,10 +38,16 @@ class RBTreeTest { @Test fun `adding a node`() { + tree.insert(keyValue[0].first, keyValue[0].second) + Assertions.assertTrue(treeChecker.checkRBTreeInvariants(tree.root)) { "Error adding a node" } + } + + @Test + fun `adding nodes`() { keyValue.forEach { tree.insert(it.first, it.second) - assert(treeChecker.checkRBTreeInvariants(tree.root)) { "Error adding a node. The invariants of the tree are violated" } + assert(treeChecker.checkRBTreeInvariants(tree.root)) { "Error adding nodes" } } } @@ -50,16 +57,17 @@ class RBTreeTest { tree.insert(keyValue[0].first, keyValue[0].second + 1) - assertEquals(keyValue[0].second + 1, tree.find(keyValue[0].first)) { "Error when adding nodes with equal key" } + assertEquals(keyValue[0].second + 1, tree.find(keyValue[0].first)) + { "Error adding nodes with equal keys" } } @Test - fun `big addition test`() { + fun `adding a lot of nodes`() { val bigTree = RBTree() bigKeyValue.forEach { bigTree.insert(it.first, it.second) } - assert(treeChecker.checkRBTreeInvariants(bigTree.root)) { "big adding test error" } + assert(treeChecker.checkRBTreeInvariants(bigTree.root)) { "Error adding a lot of nodes" } } @Test @@ -67,18 +75,28 @@ class RBTreeTest { keyValue.forEach { tree.insert(it.first, it.second) } keyValue.forEach { - assertEquals(it.second, tree.find(it.first)) + assertEquals(it.second, tree.find(it.first)) { "Error finding nodes" } } } @Test fun `deleting a node`() { + tree.insert(keyValue[0].first, keyValue[0].second) + tree.delete(keyValue[0].first) + assertAll("Error deleting a node. The tree must be balanced and must not contain a node after deletion", + { Assertions.assertNull(tree.find(keyValue[0].first)) }, + { Assertions.assertTrue(treeChecker.checkRBTreeInvariants(tree.root)) } + ) + } + + @Test + fun `deleting nodes`() { keyValue.forEach { tree.insert(it.first, it.second) } keyValue.forEach { tree.delete(it.first) - assertAll( "The tree must be balanced and must not contain a node after deletion", + assertAll("Error deleting nodes. The tree must be balanced and must not contain a node after deletion", { assertEquals(null, tree.find(it.first)) }, { assert(treeChecker.checkRBTreeInvariants(tree.root)) } ) @@ -86,58 +104,77 @@ class RBTreeTest { } @Test - fun `big deletion test`() { + fun `deleting a lot of nodes`() { val bigTree = RBTree() bigKeyValue.forEach { bigTree.insert(it.first, it.second) } bigKeyValue = bigKeyValue.shuffled() bigKeyValue.forEach { bigTree.delete(it.first) } - assertEquals(null, bigTree.root) { "big deletion test error. The tree should be empty" } + assertEquals(null, bigTree.root) { "Error deleting nodes. The tree must be empty after deleting nodes" } } @Test - fun `find in an empty tree`(){ - Assertions.assertNull(tree.find(bigKeyValue[0].first)) + fun `find in an empty tree`() { + Assertions.assertNull(tree.find(bigKeyValue[0].first)) { + "Error finding a node which doesn't exist. " + + "It must return null." + } try { tree.find(bigKeyValue[0].first) - } catch (e: Exception){ - Assertions.assertTrue(false) + } catch (e: Exception) { + Assertions.assertTrue(false) { + "Error finding a node which doesn't exist. " + + "Exception is caught" + } } } @Test - fun `delete a node which isn't in a tree`(){ + fun `delete a node which isn't in a tree`() { try { tree.delete(bigKeyValue[0].first) - } catch (e: Exception){ - Assertions.assertTrue(false) + } catch (e: Exception) { + Assertions.assertTrue(false) { + "Error deleting a node which doesn't exist. " + + "Exception is caught" + } } - Assertions.assertNull(tree.root) + Assertions.assertNull(tree.root) { + "Error deleting a node which doesn't exist. " + + "Tree must stay null" + } } @Test - fun `delete a node which isn't in a tree(tree isn't empty)`(){ + fun `delete a node which isn't in a tree(tree isn't empty)`() { - for (i in keyValue.indices){ + for (i in keyValue.indices) { if (i == 0) continue tree.insert(keyValue[i].first, keyValue[i].second) } try { tree.delete(bigKeyValue[0].first) - } catch (e: Exception){ - Assertions.assertTrue(false) + } catch (e: Exception) { + Assertions.assertTrue(false) { + "Error deleting nodes which doesn't exist. " + + "Exception is caught" + } } - Assertions.assertTrue(treeChecker.checkRBTreeInvariants(tree.root)) + Assertions.assertTrue(treeChecker.checkRBTreeInvariants(tree.root)) { + "Error deleting nodes which doesn't exist. " + + "Tree invariants aren't executed" + } - for (i in keyValue.indices){ + for (i in keyValue.indices) { if (i == 0) continue assertEquals(keyValue[i].second, tree.find(keyValue[i].first)) + { "Error deleting nodes which doesn't exist. Some of nodes are lost" } } } From d1abf3a43b89efd349573b244a196d68e8e136fd Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Wed, 19 Apr 2023 00:49:25 +0300 Subject: [PATCH 050/135] fix: Unnecessary information is pushed out from Node to AvlNode and BsNode. Fixed codestyle --- BSTrees/src/main/kotlin/BTree.kt | 23 ++++----------- BSTrees/src/main/kotlin/Node.kt | 28 ------------------- BSTrees/src/main/kotlin/avlTree/AvlNode.kt | 17 ++++++++++- .../src/main/kotlin/balancers/AvlBalancer.kt | 28 ++++++++++++++++--- .../src/main/kotlin/balancers/BSBalancer.kt | 18 +++++++++++- BSTrees/src/main/kotlin/balancers/Balancer.kt | 22 +++------------ .../main/kotlin/binarySearchTree/BSNode.kt | 17 ++++++++++- .../main/kotlin/binarySearchTree/BSTree.kt | 4 +-- .../src/main/kotlin/redBlackTree/RBNode.kt | 4 +-- .../src/main/kotlin/redBlackTree/RBTree.kt | 2 +- 10 files changed, 87 insertions(+), 76 deletions(-) diff --git a/BSTrees/src/main/kotlin/BTree.kt b/BSTrees/src/main/kotlin/BTree.kt index 47286c8..b564ab2 100644 --- a/BSTrees/src/main/kotlin/BTree.kt +++ b/BSTrees/src/main/kotlin/BTree.kt @@ -1,19 +1,6 @@ -abstract class BTree, V, NODE_TYPE : Node>{ +abstract class BTree, V, NODE_TYPE : Node> { var root: NODE_TYPE? = null - get() = field - set(value){ - field = value - } - - - fun getHeight(): Int { - return root?.getHeight() ?: 0 - } - - fun setHeight(newValue: Int) { - this.root?.setHeight(newValue) - } abstract fun insert(key: K, value: V) @@ -21,11 +8,11 @@ abstract class BTree, V, NODE_TYPE : Node>{ fun find(key: K): V? { var temp: NODE_TYPE? = root ?: return null - while(temp != null){ - if(temp.getKey() == key)return temp.getValue() - temp = if(temp.getKey() > key){ + while (temp != null) { + if (temp.getKey() == key) return temp.getValue() + temp = if (temp.getKey() > key) { temp.getLeftNode() - } else{ + } else { temp.getRightNode() } } diff --git a/BSTrees/src/main/kotlin/Node.kt b/BSTrees/src/main/kotlin/Node.kt index 791453c..5761305 100644 --- a/BSTrees/src/main/kotlin/Node.kt +++ b/BSTrees/src/main/kotlin/Node.kt @@ -1,18 +1,8 @@ -import kotlin.math.max - abstract class Node, V, NODE_TYPE : Node>(private val key: K, private var value: V) { private var parent: NODE_TYPE? = null private var leftNode: NODE_TYPE? = null private var rightNode: NODE_TYPE? = null - private var height = 1 - private var size = 1 - - fun getSize() = size - - fun setSize(newSize: Int) { - this.size = newSize - } fun getKey() = this.key @@ -40,22 +30,4 @@ abstract class Node, V, NODE_TYPE : Node>(pri rightNode = newNode } - fun getHeight() = this.height - - fun setHeight(newValue: Int) { - this.height = newValue - } - - fun updateHeight() { - val leftHeight = leftNode?.getHeight() ?: 0 - val rightHeight = rightNode?.getHeight() ?: 0 - setHeight(max(leftHeight, rightHeight) + 1) - } - - fun updateSize() { - val leftSize = getLeftNode()?.getSize() ?: 0 - val rightSize = getRightNode()?.getSize() ?: 0 - setSize(leftSize + rightSize + 1) - } - } diff --git a/BSTrees/src/main/kotlin/avlTree/AvlNode.kt b/BSTrees/src/main/kotlin/avlTree/AvlNode.kt index 466e0aa..e8118b4 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlNode.kt +++ b/BSTrees/src/main/kotlin/avlTree/AvlNode.kt @@ -1,5 +1,20 @@ package avlTree import Node +import kotlin.math.max -class AvlNode, V>(key: K, value: V): Node>(key, value) +class AvlNode, V>(key: K, value: V) : Node>(key, value) { + + private var height = 1 + fun getHeight() = this.height + + fun setHeight(newValue: Int) { + this.height = newValue + } + + fun updateHeight() { + val leftHeight = this.getLeftNode()?.getHeight() ?: 0 + val rightHeight = this.getRightNode()?.getHeight() ?: 0 + setHeight(max(leftHeight, rightHeight) + 1) + } +} diff --git a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt b/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt index 456d1fa..944fcb0 100644 --- a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt @@ -5,6 +5,26 @@ import avlTree.AvlNode class AvlBalancer, V> : Balancer>() { + private fun balanceFactor(node: AvlNode): Int { + return (node.getRightNode()?.getHeight() ?: 0) - (node.getLeftNode()?.getHeight() ?: 0) + } + + private fun avlRightRotate(node: AvlNode): AvlNode { + val temp = rightRotate(node) + temp.getLeftNode()?.updateHeight() + temp.getRightNode()?.updateHeight() + temp.updateHeight() + return temp + } + + private fun avlLeftRotate(node: AvlNode): AvlNode { + val temp = leftRotate(node) + temp.getLeftNode()?.updateHeight() + temp.getRightNode()?.updateHeight() + temp.updateHeight() + return temp + } + override fun balance(node: AvlNode): AvlNode { node.updateHeight() @@ -15,11 +35,11 @@ class AvlBalancer, V> : Balancer>() { val temp = node.getRightNode() if (temp != null) { if (balanceFactor(temp) < 0) { - node.setRightNode(rightRotate(temp)) + node.setRightNode(avlRightRotate(temp)) } } - return leftRotate(node) + return avlLeftRotate(node) } if (bf == -2) { @@ -27,11 +47,11 @@ class AvlBalancer, V> : Balancer>() { val temp = node.getLeftNode() if (temp != null) { if (balanceFactor(temp) > 0) { - node.setLeftNode(leftRotate(temp)) + node.setLeftNode(avlLeftRotate(temp)) } } - return rightRotate(node) + return avlRightRotate(node) } return node diff --git a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt index 35b1e5d..ffcbd9f 100644 --- a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt +++ b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt @@ -2,7 +2,23 @@ package balancers import binarySearchTree.BSNode -class BSBalancer, V>: Balancer>() { +class BSBalancer, V> : Balancer>() { + + fun bsRightRotate(node: BSNode): BSNode { + val temp = rightRotate(node) + temp.getLeftNode()?.updateSize() + temp.getRightNode()?.updateSize() + temp.updateSize() + return temp + } + + fun bsLeftRotate(node: BSNode): BSNode { + val temp = leftRotate(node) + temp.getLeftNode()?.updateSize() + temp.getRightNode()?.updateSize() + temp.updateSize() + return temp + } override fun balance(node: BSNode): BSNode { //We don't need balance function in BSTree, but we need rotates diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt index 36e680d..fbf49e4 100644 --- a/BSTrees/src/main/kotlin/balancers/Balancer.kt +++ b/BSTrees/src/main/kotlin/balancers/Balancer.kt @@ -2,12 +2,12 @@ package balancers import Node -abstract class Balancer, V, NODE_TYPE : Node>{ +abstract class Balancer, V, NODE_TYPE : Node> { fun leftRotate(node: NODE_TYPE): NODE_TYPE { val nodeParent = node.getParent() val temp = node.getRightNode() temp?.setParent(nodeParent) - if(nodeParent?.getLeftNode() == node)nodeParent.setLeftNode(temp) else nodeParent?.setRightNode(temp) + if (nodeParent?.getLeftNode() == node) nodeParent.setLeftNode(temp) else nodeParent?.setRightNode(temp) node.setRightNode(temp?.getLeftNode()) node.getRightNode()?.setParent(node) @@ -15,19 +15,14 @@ abstract class Balancer, V, NODE_TYPE : Node> temp?.setLeftNode(node) node.setParent(temp) - node.updateHeight() - node.updateSize() - temp?.updateHeight() - temp?.updateSize() - return temp ?: node } - fun rightRotate(node: NODE_TYPE): NODE_TYPE{ + fun rightRotate(node: NODE_TYPE): NODE_TYPE { val nodeParent = node.getParent() val temp = node.getLeftNode() temp?.setParent(nodeParent) - if(nodeParent?.getLeftNode() == node)nodeParent.setLeftNode(temp) else nodeParent?.setRightNode(temp) + if (nodeParent?.getLeftNode() == node) nodeParent.setLeftNode(temp) else nodeParent?.setRightNode(temp) node.setLeftNode(temp?.getRightNode()) node.getLeftNode()?.setParent(node) @@ -35,17 +30,8 @@ abstract class Balancer, V, NODE_TYPE : Node> temp?.setRightNode(node) node.setParent(temp) - node.updateHeight() - node.updateSize() - temp?.updateHeight() - temp?.updateSize() - return temp ?: node } - fun balanceFactor(node: NODE_TYPE): Int { - return (node.getRightNode()?.getHeight() ?: 0) - (node.getLeftNode()?.getHeight() ?: 0) - } - abstract fun balance(node: NODE_TYPE): NODE_TYPE } diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt index 9c30a62..672dcf1 100644 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt @@ -2,4 +2,19 @@ package binarySearchTree import Node -class BSNode, V>(key: K, value: V): Node>(key, value) +class BSNode, V>(key: K, value: V) : Node>(key, value) { + + private var size = 1 + + fun getSize() = size + + fun setSize(newSize: Int) { + this.size = newSize + } + + fun updateSize() { + val leftSize = getLeftNode()?.getSize() ?: 0 + val rightSize = getRightNode()?.getSize() ?: 0 + setSize(leftSize + rightSize + 1) + } +} diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt index 9cb66d7..7e10cd8 100644 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt @@ -21,11 +21,11 @@ class BSTree, V> : BTree>() { if (node.getKey() < temp.getKey()) { subTree.root = temp.getLeftNode() this.root?.setLeftNode(subTree.addRoot(node)) - balancer.rightRotate(temp) + balancer.bsRightRotate(temp) } else { subTree.root = temp.getRightNode() this.root?.setRightNode(subTree.addRoot(node)) - balancer.leftRotate(temp) + balancer.bsLeftRotate(temp) } } diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt b/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt index 7d678bd..fed2f50 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt @@ -2,9 +2,9 @@ package redBlackTree import Node -class RBNode, V>(key: K, value: V): Node>(key, value){ +class RBNode, V>(key: K, value: V) : Node>(key, value) { - enum class Color{ + enum class Color { BLACK, RED } diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt index f591622..3f3d876 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt @@ -16,7 +16,7 @@ class RBTree, V> : BTree>() { // if a node with such a key already exists, then we update Value val nodeWithEqualKey = findNodeByKey(node.getKey()) - if (nodeWithEqualKey != null){ + if (nodeWithEqualKey != null) { nodeWithEqualKey.setValue(node.getValue()) return } From da3329bbafd4d78898958fc1e13c14798318cb54 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Wed, 19 Apr 2023 00:57:40 +0300 Subject: [PATCH 051/135] feat: Added the ability to store AVLTree in SQLite --- BSTrees/build.gradle.kts | 17 ++++ .../main/kotlin/serialize/SerializableTree.kt | 56 +++++++++++ .../serialize/postgreSQLRep/SQLTables.kt | 29 ++++++ .../postgreSQLRep/SQLTreeSerializer.kt | 93 +++++++++++++++++++ 4 files changed, 195 insertions(+) create mode 100644 BSTrees/src/main/kotlin/serialize/SerializableTree.kt create mode 100644 BSTrees/src/main/kotlin/serialize/postgreSQLRep/SQLTables.kt create mode 100644 BSTrees/src/main/kotlin/serialize/postgreSQLRep/SQLTreeSerializer.kt diff --git a/BSTrees/build.gradle.kts b/BSTrees/build.gradle.kts index e2dc097..2ad89ed 100644 --- a/BSTrees/build.gradle.kts +++ b/BSTrees/build.gradle.kts @@ -1,5 +1,9 @@ plugins { id("org.jetbrains.kotlin.jvm") version "1.8.10" + + kotlin("plugin.serialization") version "1.8.20" + + application } repositories { @@ -7,6 +11,14 @@ repositories { } dependencies { + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") + implementation("com.google.code.gson:gson:2.8.5") + implementation("org.jetbrains.exposed:exposed-core:0.38.1") + implementation("org.jetbrains.exposed:exposed-jdbc:0.38.1") + implementation("org.jetbrains.exposed:exposed-dao:0.38.1") + implementation("org.xerial:sqlite-jdbc:3.34.0") + implementation("org.slf4j:slf4j-nop:1.7.25") + testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.1") testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.1") } @@ -14,3 +26,8 @@ dependencies { tasks.getByName("test") { useJUnitPlatform() } + +application { + // Define the main class for the application. + mainClass.set("serialize/postgreSQLRep/SQLTreeSerializerKt") +} diff --git a/BSTrees/src/main/kotlin/serialize/SerializableTree.kt b/BSTrees/src/main/kotlin/serialize/SerializableTree.kt new file mode 100644 index 0000000..40a84bf --- /dev/null +++ b/BSTrees/src/main/kotlin/serialize/SerializableTree.kt @@ -0,0 +1,56 @@ +package serialize + +import kotlinx.serialization.Serializable +import redBlackTree.RBNode.Color + +@Serializable +class SerializableTree( + val name: String, + val nodes: Collection> +) + +@Serializable +class SerializableAvlTree( + val name: String, + val nodes: List +) + + +@Serializable +class SerializableNode( + val key: Int, + val value: Int, + val metaData: T, + val leftSonKey: Int? = null, + val rightSonKey: Int? = null, + val parentKey: Int? = null +) + +@Serializable +class RBNodeMetaData( + val key: Int, + val value: Int, + val height: Int, + val size: Int, + val color: Color, + val leftSonKey: Int? = null, + val rightSonKey: Int? = null, + val parentKey: Int? = null +) + +@Serializable +class AvlNodeMetaData( + val key: String, + val value: String, + val height: Int, + val size: Int, + val leftSonKey: String? = null, + val rightSonKey: String? = null, + val parentKey: String? = null +) + +@Serializable +class BSNodeMetaData( + val height: Int, + val size: Int +) \ No newline at end of file diff --git a/BSTrees/src/main/kotlin/serialize/postgreSQLRep/SQLTables.kt b/BSTrees/src/main/kotlin/serialize/postgreSQLRep/SQLTables.kt new file mode 100644 index 0000000..76e74b1 --- /dev/null +++ b/BSTrees/src/main/kotlin/serialize/postgreSQLRep/SQLTables.kt @@ -0,0 +1,29 @@ +package serialize.postgreSQLRep + +import org.jetbrains.exposed.dao.IntEntity +import org.jetbrains.exposed.dao.IntEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.IdTable +import org.jetbrains.exposed.dao.id.IntIdTable + + + +class AvlNode(name: String) : IdTable(name){ + override val id = varchar("key", 255).entityId() + val value = varchar("value", 255) + val height = integer("height") + val size = integer("size") + val leftNodeKey = varchar("leftNodeKey", 255).nullable() + val rightNodeKey = varchar("rightNodeKey", 255).nullable() + val parentKey = varchar("parent", 255).nullable() +} + +object TreeTable : IntIdTable() { + val nameTree = varchar("nameTree", 20).entityId() +} + +class TreeString(id: EntityID): IntEntity(id) { + companion object : IntEntityClass(TreeTable) + + var nameTree by TreeTable.nameTree +} \ No newline at end of file diff --git a/BSTrees/src/main/kotlin/serialize/postgreSQLRep/SQLTreeSerializer.kt b/BSTrees/src/main/kotlin/serialize/postgreSQLRep/SQLTreeSerializer.kt new file mode 100644 index 0000000..987a9e0 --- /dev/null +++ b/BSTrees/src/main/kotlin/serialize/postgreSQLRep/SQLTreeSerializer.kt @@ -0,0 +1,93 @@ +package serialize.postgreSQLRep + +import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.SchemaUtils +import org.jetbrains.exposed.sql.batchInsert +import org.jetbrains.exposed.sql.selectAll +import org.jetbrains.exposed.sql.transactions.transaction +import serialize.* +import java.io.File + +class SQLTreeSerializer { + + private fun connectBD(file: File){ + Database.connect("jdbc:sqlite:${file}", "org.sqlite.JDBC") + } + + private fun createNewTreeWithName(nameTree: String){ + connectBD(File("treesTable")) + + transaction { + SchemaUtils.create(TreeTable) + + val correctTable = TreeString.find { TreeTable.nameTree eq nameTree } + if (correctTable.empty()) { + TreeTable.batchInsert(mutableListOf(nameTree)) { + this[TreeTable.nameTree] = it + } + } + else{ + throw Exception("A tree with that name already exists") + } + } + } + + fun findTreeByName(inputNameTree: String): String { + connectBD(File("treesTable")) + + val nameTree = mutableListOf() + transaction { + SchemaUtils.create(TreeTable) + val correctTable = TreeString.find { TreeTable.nameTree eq inputNameTree } + if (!correctTable.empty()) { + correctTable.forEach { nameTree.add(it.nameTree.toString())} + } else { + throw Exception("There is no tree with that name") + } + } + return nameTree[0] + } + + fun serializeAvlTree(file: File, serializableAvlTree: SerializableAvlTree) { + createNewTreeWithName(serializableAvlTree.name) + + connectBD(file) + transaction { + val tree = AvlNode(serializableAvlTree.name) + SchemaUtils.drop(tree) + SchemaUtils.create(tree) + + tree.batchInsert(serializableAvlTree.nodes){ + this[tree.id] = it.key + this[tree.value] = it.value + this[tree.height] = it.height + this[tree.size] = it.size + this[tree.leftNodeKey] = it.leftSonKey.toString() + this[tree.rightNodeKey] = it.rightSonKey.toString() + this[tree.parentKey] = it.parentKey.toString() + } + } + } + + fun deserializeAvlTree(file: File, tableName: String): SerializableAvlTree { + connectBD(file) + + val tree = AvlNode(tableName) + val nodeList = mutableListOf() + transaction { + tree.selectAll().forEach{ + val node = AvlNodeMetaData( + key= it[tree.id].value, + value= it[tree.value], + height= it[tree.height], + size= it[tree.size], + leftSonKey= it[tree.leftNodeKey], + rightSonKey= it[tree.rightNodeKey], + parentKey= it[tree.parentKey] + ) + nodeList.add(node) + } + } + return SerializableAvlTree(tableName, nodeList) + } +} From 395844639641a545ee19a7b19974ac03d4b1e78b Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Wed, 19 Apr 2023 01:01:34 +0300 Subject: [PATCH 052/135] fix: The files have been moved to the correct directory --- .../kotlin/serialize/{postgreSQLRep => sqliteRep}/SQLTables.kt | 2 +- .../serialize/{postgreSQLRep => sqliteRep}/SQLTreeSerializer.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename BSTrees/src/main/kotlin/serialize/{postgreSQLRep => sqliteRep}/SQLTables.kt (96%) rename BSTrees/src/main/kotlin/serialize/{postgreSQLRep => sqliteRep}/SQLTreeSerializer.kt (98%) diff --git a/BSTrees/src/main/kotlin/serialize/postgreSQLRep/SQLTables.kt b/BSTrees/src/main/kotlin/serialize/sqliteRep/SQLTables.kt similarity index 96% rename from BSTrees/src/main/kotlin/serialize/postgreSQLRep/SQLTables.kt rename to BSTrees/src/main/kotlin/serialize/sqliteRep/SQLTables.kt index 76e74b1..d2c021b 100644 --- a/BSTrees/src/main/kotlin/serialize/postgreSQLRep/SQLTables.kt +++ b/BSTrees/src/main/kotlin/serialize/sqliteRep/SQLTables.kt @@ -1,4 +1,4 @@ -package serialize.postgreSQLRep +package serialize.sqliteRep import org.jetbrains.exposed.dao.IntEntity import org.jetbrains.exposed.dao.IntEntityClass diff --git a/BSTrees/src/main/kotlin/serialize/postgreSQLRep/SQLTreeSerializer.kt b/BSTrees/src/main/kotlin/serialize/sqliteRep/SQLTreeSerializer.kt similarity index 98% rename from BSTrees/src/main/kotlin/serialize/postgreSQLRep/SQLTreeSerializer.kt rename to BSTrees/src/main/kotlin/serialize/sqliteRep/SQLTreeSerializer.kt index 987a9e0..16eb55a 100644 --- a/BSTrees/src/main/kotlin/serialize/postgreSQLRep/SQLTreeSerializer.kt +++ b/BSTrees/src/main/kotlin/serialize/sqliteRep/SQLTreeSerializer.kt @@ -1,4 +1,4 @@ -package serialize.postgreSQLRep +package serialize.sqliteRep import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.SchemaUtils From 76dd979579b614b41d135920dcdb4c1f4902ac92 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Wed, 19 Apr 2023 07:28:17 +0300 Subject: [PATCH 053/135] feat: New implementation of tree storage in sql --- .../kotlin/serialization/SerializableType.kt | 20 ++++ .../serialization/reps/sqliteRep/SQLTables.kt | 44 ++++++++ .../reps/sqliteRep/SQLTreeSerializer.kt | 105 ++++++++++++++++++ .../main/kotlin/serialize/SerializableTree.kt | 56 ---------- .../kotlin/serialize/sqliteRep/SQLTables.kt | 29 ----- .../serialize/sqliteRep/SQLTreeSerializer.kt | 93 ---------------- 6 files changed, 169 insertions(+), 178 deletions(-) create mode 100644 BSTrees/src/main/kotlin/serialization/SerializableType.kt create mode 100644 BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTables.kt create mode 100644 BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt delete mode 100644 BSTrees/src/main/kotlin/serialize/SerializableTree.kt delete mode 100644 BSTrees/src/main/kotlin/serialize/sqliteRep/SQLTables.kt delete mode 100644 BSTrees/src/main/kotlin/serialize/sqliteRep/SQLTreeSerializer.kt diff --git a/BSTrees/src/main/kotlin/serialization/SerializableType.kt b/BSTrees/src/main/kotlin/serialization/SerializableType.kt new file mode 100644 index 0000000..614269f --- /dev/null +++ b/BSTrees/src/main/kotlin/serialization/SerializableType.kt @@ -0,0 +1,20 @@ +package serialization + +import kotlinx.serialization.Serializable + +@Serializable +class SerializableTree( + val name: String, + val typeOfTree: String, + val root: SerializableNode? +) + +@Serializable +class SerializableNode( + val key: String, + val value: String, + val metadata: String, + val leftNode: SerializableNode? = null, + val rightNode: SerializableNode? = null, + val parent: SerializableNode? = null, +) \ No newline at end of file diff --git a/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTables.kt b/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTables.kt new file mode 100644 index 0000000..a6ba79e --- /dev/null +++ b/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTables.kt @@ -0,0 +1,44 @@ +package serialization.reps.sqliteRep + +import org.jetbrains.exposed.dao.IntEntity +import org.jetbrains.exposed.dao.IntEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.IntIdTable +import org.jetbrains.exposed.sql.ReferenceOption + + +object TreesTable : IntIdTable() { + val nameTree = varchar("nameTree", 20).uniqueIndex().default("") + val typeTree = varchar("typeTree", 20).default("") + val root = reference("root", NodesTable).nullable() +} + +class TreeEntity(id: EntityID): IntEntity(id) { + companion object : IntEntityClass(TreesTable) + + var nameTree by TreesTable.nameTree + var typeTree by TreesTable.typeTree + var root by NodeEntity optionalReferencedOn TreesTable.root +} + +object NodesTable : IntIdTable(){ + val key = varchar("key", 255) + val value = varchar("value", 255) + val metadata = varchar("metadata", 255) + val leftNode = reference("leftNode", NodesTable).nullable() + val rightNode = reference("rightNode", NodesTable).nullable() + val parentNode = reference("parentNode", NodesTable).nullable() + val tree = reference("tree", TreesTable, onDelete = ReferenceOption.CASCADE) +} + +class NodeEntity(id: EntityID) : IntEntity(id){ + companion object : IntEntityClass(NodesTable) + + var key by NodesTable.key + var value by NodesTable.value + var metadata by NodesTable.metadata + var leftNode by NodeEntity optionalReferencedOn NodesTable.leftNode + var rightNode by NodeEntity optionalReferencedOn NodesTable.rightNode + var parentNode by NodeEntity optionalReferencedOn NodesTable.parentNode + var tree by TreeEntity referencedOn NodesTable.tree +} diff --git a/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt b/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt new file mode 100644 index 0000000..b3e331a --- /dev/null +++ b/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt @@ -0,0 +1,105 @@ +package serialization.reps.sqliteRep + +import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.SchemaUtils +import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.transactions.transaction +import serialization.* +import java.io.File + +object SQLTreeSerializer { + + private fun connectBD(file: File) { + Database.connect("jdbc:sqlite:${file}", "org.sqlite.JDBC") + } + + private fun createTables(){ + transaction { + SchemaUtils.create(TreesTable) + SchemaUtils.create(NodesTable) + } + } + + private fun deleteTree(serializableTree: SerializableTree) { + transaction { + val treeEntity = + TreeEntity.find { (TreesTable.nameTree eq serializableTree.name) and (TreesTable.typeTree eq serializableTree.typeOfTree) } + .firstOrNull() + treeEntity?.let{NodeEntity.find(NodesTable.tree eq treeEntity.id).forEach { it.delete() } } + + treeEntity?.delete() + } + } + + fun setTree(file: File, serializableTree: SerializableTree) { + connectBD(file) + createTables() + + deleteTree(serializableTree) + + transaction { + val newTree = TreeEntity.new { + nameTree=serializableTree.name + typeTree=serializableTree.typeOfTree + } + + newTree.root = serializableTree.root?.toNodeEntity(newTree) + } + } + + private fun SerializableNode.toNodeEntity(treeEntity: TreeEntity): NodeEntity { + return NodeEntity.new { + key = this@toNodeEntity.key + value = this@toNodeEntity.value + metadata = this@toNodeEntity.metadata + leftNode = this@toNodeEntity.leftNode?.toNodeEntity(treeEntity) + rightNode = this@toNodeEntity.rightNode?.toNodeEntity(treeEntity) + parentNode = this@toNodeEntity.parent?.toNodeEntity(treeEntity) + tree = treeEntity + } + } + + fun getTree(file: File, treeName: String): SerializableTree? { + connectBD(file) + + val treeEntity = TreeEntity.find { TreesTable.nameTree eq treeName }.firstOrNull() ?: return null + + return SerializableTree( + treeName, + treeEntity.typeTree, + treeEntity.root?.toSerializableEntity(treeEntity) + ) + } + + private fun NodeEntity.toSerializableEntity(treeEntity: TreeEntity): SerializableNode { + return SerializableNode( + this@toSerializableEntity.key, + this@toSerializableEntity.value, + this@toSerializableEntity.metadata, + this@toSerializableEntity.leftNode?.toSerializableEntity(treeEntity), + this@toSerializableEntity.rightNode?.toSerializableEntity(treeEntity), + this@toSerializableEntity.parentNode?.toSerializableEntity(treeEntity) + ) + } +} + + + +fun main(){ + val a = SerializableNode("1", "1", "1", null, null, null) + val b = SerializableNode("1", "1", "1", null, null, null) + val c = SerializableNode("1", "1", "1", a, b, null) + val tree = SerializableTree( + "azaza", + "BSTree", + c + ) + val tree2 = SerializableTree( + "azaza2", + "RBTRee", + c + ) + SQLTreeSerializer.setTree(File("KEK"), tree) + SQLTreeSerializer.setTree(File("KEK"), tree2) +} diff --git a/BSTrees/src/main/kotlin/serialize/SerializableTree.kt b/BSTrees/src/main/kotlin/serialize/SerializableTree.kt deleted file mode 100644 index 40a84bf..0000000 --- a/BSTrees/src/main/kotlin/serialize/SerializableTree.kt +++ /dev/null @@ -1,56 +0,0 @@ -package serialize - -import kotlinx.serialization.Serializable -import redBlackTree.RBNode.Color - -@Serializable -class SerializableTree( - val name: String, - val nodes: Collection> -) - -@Serializable -class SerializableAvlTree( - val name: String, - val nodes: List -) - - -@Serializable -class SerializableNode( - val key: Int, - val value: Int, - val metaData: T, - val leftSonKey: Int? = null, - val rightSonKey: Int? = null, - val parentKey: Int? = null -) - -@Serializable -class RBNodeMetaData( - val key: Int, - val value: Int, - val height: Int, - val size: Int, - val color: Color, - val leftSonKey: Int? = null, - val rightSonKey: Int? = null, - val parentKey: Int? = null -) - -@Serializable -class AvlNodeMetaData( - val key: String, - val value: String, - val height: Int, - val size: Int, - val leftSonKey: String? = null, - val rightSonKey: String? = null, - val parentKey: String? = null -) - -@Serializable -class BSNodeMetaData( - val height: Int, - val size: Int -) \ No newline at end of file diff --git a/BSTrees/src/main/kotlin/serialize/sqliteRep/SQLTables.kt b/BSTrees/src/main/kotlin/serialize/sqliteRep/SQLTables.kt deleted file mode 100644 index d2c021b..0000000 --- a/BSTrees/src/main/kotlin/serialize/sqliteRep/SQLTables.kt +++ /dev/null @@ -1,29 +0,0 @@ -package serialize.sqliteRep - -import org.jetbrains.exposed.dao.IntEntity -import org.jetbrains.exposed.dao.IntEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.IdTable -import org.jetbrains.exposed.dao.id.IntIdTable - - - -class AvlNode(name: String) : IdTable(name){ - override val id = varchar("key", 255).entityId() - val value = varchar("value", 255) - val height = integer("height") - val size = integer("size") - val leftNodeKey = varchar("leftNodeKey", 255).nullable() - val rightNodeKey = varchar("rightNodeKey", 255).nullable() - val parentKey = varchar("parent", 255).nullable() -} - -object TreeTable : IntIdTable() { - val nameTree = varchar("nameTree", 20).entityId() -} - -class TreeString(id: EntityID): IntEntity(id) { - companion object : IntEntityClass(TreeTable) - - var nameTree by TreeTable.nameTree -} \ No newline at end of file diff --git a/BSTrees/src/main/kotlin/serialize/sqliteRep/SQLTreeSerializer.kt b/BSTrees/src/main/kotlin/serialize/sqliteRep/SQLTreeSerializer.kt deleted file mode 100644 index 16eb55a..0000000 --- a/BSTrees/src/main/kotlin/serialize/sqliteRep/SQLTreeSerializer.kt +++ /dev/null @@ -1,93 +0,0 @@ -package serialize.sqliteRep - -import org.jetbrains.exposed.sql.Database -import org.jetbrains.exposed.sql.SchemaUtils -import org.jetbrains.exposed.sql.batchInsert -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction -import serialize.* -import java.io.File - -class SQLTreeSerializer { - - private fun connectBD(file: File){ - Database.connect("jdbc:sqlite:${file}", "org.sqlite.JDBC") - } - - private fun createNewTreeWithName(nameTree: String){ - connectBD(File("treesTable")) - - transaction { - SchemaUtils.create(TreeTable) - - val correctTable = TreeString.find { TreeTable.nameTree eq nameTree } - if (correctTable.empty()) { - TreeTable.batchInsert(mutableListOf(nameTree)) { - this[TreeTable.nameTree] = it - } - } - else{ - throw Exception("A tree with that name already exists") - } - } - } - - fun findTreeByName(inputNameTree: String): String { - connectBD(File("treesTable")) - - val nameTree = mutableListOf() - transaction { - SchemaUtils.create(TreeTable) - val correctTable = TreeString.find { TreeTable.nameTree eq inputNameTree } - if (!correctTable.empty()) { - correctTable.forEach { nameTree.add(it.nameTree.toString())} - } else { - throw Exception("There is no tree with that name") - } - } - return nameTree[0] - } - - fun serializeAvlTree(file: File, serializableAvlTree: SerializableAvlTree) { - createNewTreeWithName(serializableAvlTree.name) - - connectBD(file) - transaction { - val tree = AvlNode(serializableAvlTree.name) - SchemaUtils.drop(tree) - SchemaUtils.create(tree) - - tree.batchInsert(serializableAvlTree.nodes){ - this[tree.id] = it.key - this[tree.value] = it.value - this[tree.height] = it.height - this[tree.size] = it.size - this[tree.leftNodeKey] = it.leftSonKey.toString() - this[tree.rightNodeKey] = it.rightSonKey.toString() - this[tree.parentKey] = it.parentKey.toString() - } - } - } - - fun deserializeAvlTree(file: File, tableName: String): SerializableAvlTree { - connectBD(file) - - val tree = AvlNode(tableName) - val nodeList = mutableListOf() - transaction { - tree.selectAll().forEach{ - val node = AvlNodeMetaData( - key= it[tree.id].value, - value= it[tree.value], - height= it[tree.height], - size= it[tree.size], - leftSonKey= it[tree.leftNodeKey], - rightSonKey= it[tree.rightNodeKey], - parentKey= it[tree.parentKey] - ) - nodeList.add(node) - } - } - return SerializableAvlTree(tableName, nodeList) - } -} From bdc49dfd50b0d1fccf2de28fc1a048d45c4c07e7 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Wed, 19 Apr 2023 07:29:13 +0300 Subject: [PATCH 054/135] fix: Removed the extra part of the code --- .../reps/sqliteRep/SQLTreeSerializer.kt | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt b/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt index b3e331a..bc00a9f 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt @@ -82,24 +82,4 @@ object SQLTreeSerializer { this@toSerializableEntity.parentNode?.toSerializableEntity(treeEntity) ) } -} - - - -fun main(){ - val a = SerializableNode("1", "1", "1", null, null, null) - val b = SerializableNode("1", "1", "1", null, null, null) - val c = SerializableNode("1", "1", "1", a, b, null) - val tree = SerializableTree( - "azaza", - "BSTree", - c - ) - val tree2 = SerializableTree( - "azaza2", - "RBTRee", - c - ) - SQLTreeSerializer.setTree(File("KEK"), tree) - SQLTreeSerializer.setTree(File("KEK"), tree2) -} +} \ No newline at end of file From cf5bfec65e47b31a74aaf53c86146689295a3e31 Mon Sep 17 00:00:00 2001 From: Kirill Shishin <73890886+tepa46@users.noreply.github.com> Date: Wed, 19 Apr 2023 08:14:41 +0300 Subject: [PATCH 055/135] Create README.md --- README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c37efda --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# trees-6 +`BSTrees` is a library that allows you to use 3 types of binary search trees: randomized BSTree, AVLTree, RBTree. + +## How to use + +To build the library run +```bash + ./gradlew build +``` + To create each of the tree views, you can use: + ```kotlin +val rbTree = RBTree() // instantiate empty red-black tree +val avlTree = AvlTree() // instantiate empty AVL tree +val bsTree = BSTree() // instantiate empty simple tree +``` +The first type parameter is a comparable key. \ +The second type parameter is a stored value. It can be anything + +Each tree supports 3 basic operations: `insert`, `search`, `delete`. + ```kotlin +val bsTree = BSTree() + +bsTree.insert("bruh", 5) +bsTree.find("bruh") // 5 +bsTree.delete("bruh") +``` + +## Storing BSTs +Currently, only storage in SQLite is supported \ +(WIP) storing in JSON, neo4j + + +## License +Distributed under the Apache 2.0 License. See [LICENSE](https://github.com/spbu-coding-2022/trees-6/blob/main/LICENSE) for more information. From 05b540d73446e05e688b5b5ca8a1a80af79aa8f8 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Wed, 19 Apr 2023 09:01:56 +0300 Subject: [PATCH 056/135] fix: Added creation of tables in the getTree method --- .../kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt b/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt index bc00a9f..144853d 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt @@ -62,6 +62,7 @@ object SQLTreeSerializer { fun getTree(file: File, treeName: String): SerializableTree? { connectBD(file) + createTables() val treeEntity = TreeEntity.find { TreesTable.nameTree eq treeName }.firstOrNull() ?: return null From 92a5be5eed2c08c049959f5179e2ca08487268cd Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Wed, 19 Apr 2023 21:44:55 +0300 Subject: [PATCH 057/135] fix: Fixed a bug with adding equal keys. Fixed the test which checks it --- BSTrees/src/main/kotlin/avlTree/AvlTree.kt | 3 ++- BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt | 8 ++++++-- BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt | 11 ++++++----- .../src/test/kotlin/binarySearchTree/BSTreeTest.kt | 9 +++++---- BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt | 11 ++++++----- 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt index 618b8c2..2beee05 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt +++ b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt @@ -13,7 +13,8 @@ class AvlTree, V> : BTree>() { override fun add(node: AvlNode) { val temp = this.root - if (temp?.getKey() == node.getKey() || temp == null) this.root = node + if (temp == null) this.root = node + else if (temp.getKey() == node.getKey()) this.root?.setValue(node.getValue()) else { val subTree = AvlTree() diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt index 7e10cd8..4701804 100644 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt @@ -16,7 +16,10 @@ class BSTree, V> : BTree>() { val temp = this.root return if (temp == null) node - else { + else if (temp.getKey() == node.getKey()) { + temp.setValue(node.getValue()) + temp + } else { val subTree = BSTree() if (node.getKey() < temp.getKey()) { subTree.root = temp.getLeftNode() @@ -34,7 +37,8 @@ class BSTree, V> : BTree>() { override fun add(node: BSNode) { val temp = this.root - if (temp == null || temp.getKey() == node.getKey()) this.root = node + if (temp == null) this.root = node + else if (temp.getKey() == node.getKey()) this.root?.setValue(node.getValue()) else { if (Random.nextInt() % (node.getSize() + 1) == 0) this.root = this.addRoot(node) diff --git a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt b/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt index 1466c32..999e4d6 100644 --- a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt +++ b/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt @@ -60,13 +60,14 @@ class AVLTreeTest { } @Test - fun `adding nodes with equal keys`() { + fun `adding nodes with equal key`() { keyValue.forEach { tree.insert(it.first, it.second) } + keyValue.forEach { + tree.insert(it.first, it.second + 1) + Assertions.assertEquals(it.second + 1, tree.find(it.first)) + } - tree.insert(keyValue[0].first, keyValue[0].second + 1) - - Assertions.assertEquals(keyValue[0].second + 1, tree.find(keyValue[0].first)) - { "Error adding nodes with equal keys" } + Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) { "Error adding nodes with equal keys" } } @Test diff --git a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt index 6846be3..9866cfa 100644 --- a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt +++ b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt @@ -62,11 +62,12 @@ class BSTreeTest { @Test fun `adding nodes with equal key`() { keyValue.forEach { tree.insert(it.first, it.second) } + keyValue.forEach { + tree.insert(it.first, it.second + 1) + Assertions.assertEquals(it.second + 1, tree.find(it.first)) + } - tree.insert(keyValue[0].first, keyValue[0].second + 1) - - Assertions.assertEquals(keyValue[0].second + 1, tree.find(keyValue[0].first)) - { "Error adding nodes with equal keys" } + Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) { "Error adding nodes with equal keys" } } @Test diff --git a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt index b47043d..4ee6143 100644 --- a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt +++ b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt @@ -52,13 +52,14 @@ class RBTreeTest { } @Test - fun `adding node with equal keys`() { + fun `adding nodes with equal key`() { keyValue.forEach { tree.insert(it.first, it.second) } + keyValue.forEach { + tree.insert(it.first, it.second + 1) + assertEquals(it.second + 1, tree.find(it.first)) + } - tree.insert(keyValue[0].first, keyValue[0].second + 1) - - assertEquals(keyValue[0].second + 1, tree.find(keyValue[0].first)) - { "Error adding nodes with equal keys" } + Assertions.assertTrue(treeChecker.checkRBTreeInvariants(tree.root)) { "Error adding nodes with equal keys" } } @Test From 1396e09f93129477e95bb65f898d8dcb4271c894 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Thu, 20 Apr 2023 00:11:37 +0300 Subject: [PATCH 058/135] feat: added a parameterized test --- BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt | 14 ++++++++++++++ .../src/test/kotlin/binarySearchTree/BSTreeTest.kt | 14 ++++++++++++++ BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt | 14 ++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt b/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt index 999e4d6..a58967f 100644 --- a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt +++ b/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt @@ -1,6 +1,8 @@ package avlTree import org.junit.jupiter.api.* +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource import treeInvariants.TreesInvariants import kotlin.random.Random @@ -59,6 +61,18 @@ class AVLTreeTest { } } + @ParameterizedTest(name = "Function get returns correct value for key {0}") + @ValueSource(ints = [12, -121, 56, 1, 23728, 6464, 112]) + fun `find return a correct value`(key: Int) { + keyValue.forEach { tree.insert(it.first, it.second) } + + Assertions.assertEquals(keyValue.find { it.first == key }?.second, tree.find(key)) + + tree.delete(key) + + Assertions.assertEquals(null, tree.find(key)) + } + @Test fun `adding nodes with equal key`() { keyValue.forEach { tree.insert(it.first, it.second) } diff --git a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt index 9866cfa..af58d0b 100644 --- a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt +++ b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt @@ -1,6 +1,8 @@ package binarySearchTree import org.junit.jupiter.api.* +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource import treeInvariants.TreesInvariants import kotlin.random.Random @@ -59,6 +61,18 @@ class BSTreeTest { } } + @ParameterizedTest(name = "Function get returns correct value for key {0}") + @ValueSource(ints = [12, -121, 56, 1, 23728, 6464, 112]) + fun `find return a correct value`(key: Int) { + keyValue.forEach { tree.insert(it.first, it.second) } + + Assertions.assertEquals(keyValue.find { it.first == key }?.second, tree.find(key)) + + tree.delete(key) + + Assertions.assertEquals(null, tree.find(key)) + } + @Test fun `adding nodes with equal key`() { keyValue.forEach { tree.insert(it.first, it.second) } diff --git a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt index 4ee6143..c7a8675 100644 --- a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt +++ b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt @@ -2,6 +2,8 @@ package redBlackTree import org.junit.jupiter.api.* import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource import treeInvariants.TreesInvariants import kotlin.random.Random @@ -80,6 +82,18 @@ class RBTreeTest { } } + @ParameterizedTest(name = "Function get returns correct value for key {0}") + @ValueSource(ints = [12, -121, 56, 1, 23728, 6464, 112]) + fun `find return a correct value`(key: Int) { + keyValue.forEach { tree.insert(it.first, it.second) } + + assertEquals(keyValue.find { it.first == key }?.second, tree.find(key)) + + tree.delete(key) + + assertEquals(null, tree.find(key)) + } + @Test fun `deleting a node`() { tree.insert(keyValue[0].first, keyValue[0].second) From 9b0fdb434ee70ae7c9d56ec329a3dbdcf5ebe3f5 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Thu, 20 Apr 2023 02:20:02 +0300 Subject: [PATCH 059/135] fix: a small correction of the placement of brackets --- BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt index 816c255..44398db 100644 --- a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt +++ b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt @@ -26,16 +26,16 @@ class TreesInvariants, V, NODE_TYPE : Node> { if (node.getLeftNode() == null && node.getRightNode() == null) { return newCurHeight == rightHeight } - return (node.getLeftNode() == null || checkRBNodeBlackHeightInvariant( + return ((node.getLeftNode() == null || checkRBNodeBlackHeightInvariant( node.getLeftNode()!!, newCurHeight, rightHeight - ) && - node.getRightNode() == null || checkRBNodeBlackHeightInvariant( + )) && + (node.getRightNode() == null || checkRBNodeBlackHeightInvariant( node.getRightNode()!!, newCurHeight, rightHeight - )) + ))) } private fun getSomeBlackHeight(root: RBNode): Int { From d1e34e91b7bb10f743b2d350cf158c2eb4afa341 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Thu, 20 Apr 2023 03:45:17 +0300 Subject: [PATCH 060/135] feat: Added project build check on 3 types of os --- .github/workflows/CI.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 8b44906..7f9c1b7 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -4,7 +4,12 @@ on: push: jobs: build-gradle-project: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ ubuntu-latest, macos-latest, windows-latest ] + steps: - name: Checkout project sources uses: actions/checkout@v3 From e66609adc6b49b04a10bf4b1d47b1b7074bd7bc1 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Fri, 21 Apr 2023 02:16:07 +0300 Subject: [PATCH 061/135] fix: Fixed infinite recursion when saving and taking from the database. Removed storage of node parents --- .../src/main/kotlin/serialization/reps/sqliteRep/SQLTables.kt | 2 -- .../kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt | 2 -- 2 files changed, 4 deletions(-) diff --git a/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTables.kt b/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTables.kt index a6ba79e..1055af3 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTables.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTables.kt @@ -27,7 +27,6 @@ object NodesTable : IntIdTable(){ val metadata = varchar("metadata", 255) val leftNode = reference("leftNode", NodesTable).nullable() val rightNode = reference("rightNode", NodesTable).nullable() - val parentNode = reference("parentNode", NodesTable).nullable() val tree = reference("tree", TreesTable, onDelete = ReferenceOption.CASCADE) } @@ -39,6 +38,5 @@ class NodeEntity(id: EntityID) : IntEntity(id){ var metadata by NodesTable.metadata var leftNode by NodeEntity optionalReferencedOn NodesTable.leftNode var rightNode by NodeEntity optionalReferencedOn NodesTable.rightNode - var parentNode by NodeEntity optionalReferencedOn NodesTable.parentNode var tree by TreeEntity referencedOn NodesTable.tree } diff --git a/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt b/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt index 144853d..5b8ee41 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt @@ -55,7 +55,6 @@ object SQLTreeSerializer { metadata = this@toNodeEntity.metadata leftNode = this@toNodeEntity.leftNode?.toNodeEntity(treeEntity) rightNode = this@toNodeEntity.rightNode?.toNodeEntity(treeEntity) - parentNode = this@toNodeEntity.parent?.toNodeEntity(treeEntity) tree = treeEntity } } @@ -80,7 +79,6 @@ object SQLTreeSerializer { this@toSerializableEntity.metadata, this@toSerializableEntity.leftNode?.toSerializableEntity(treeEntity), this@toSerializableEntity.rightNode?.toSerializableEntity(treeEntity), - this@toSerializableEntity.parentNode?.toSerializableEntity(treeEntity) ) } } \ No newline at end of file From f08bf5bd81999ab02d4cc5bfe48abee55907985e Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sat, 22 Apr 2023 22:20:52 +0300 Subject: [PATCH 062/135] feat: Added Jacoco code coverage report --- .github/workflows/CI.yml | 13 ++++++++++++- BSTrees/build.gradle.kts | 11 ++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 7f9c1b7..de82535 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -25,4 +25,15 @@ jobs: if: github.ref == 'refs/heads/main' with: name: BSTrees lib - path: BSTrees/build/libs/BSTrees.jar \ No newline at end of file + path: BSTrees/build/libs/BSTrees.jar + + - if: matrix.os == 'ubuntu-latest' + name: Run Test Coverage + run: ./gradlew jacocoTestReport + + - if: matrix.os == 'ubuntu-latest' + name: Jacoco Code Coverage Report + uses: cicirello/jacoco-badge-generator@v2.8.0 + with: + generate-branches-badge: true + jacoco-html-file: BSTrees/build/jacocoHtml/index.html \ No newline at end of file diff --git a/BSTrees/build.gradle.kts b/BSTrees/build.gradle.kts index 2ad89ed..0e2107a 100644 --- a/BSTrees/build.gradle.kts +++ b/BSTrees/build.gradle.kts @@ -3,6 +3,8 @@ plugins { kotlin("plugin.serialization") version "1.8.20" + jacoco + application } @@ -27,7 +29,10 @@ tasks.getByName("test") { useJUnitPlatform() } -application { - // Define the main class for the application. - mainClass.set("serialize/postgreSQLRep/SQLTreeSerializerKt") +tasks.jacocoTestReport { + reports { + xml.required.set(false) + csv.required.set(false) + html.outputLocation.set(layout.buildDirectory.dir("jacocoHtml")) + } } From ff0b7114831a3ba64fd81d2a17a2f36a0a9571d3 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sat, 22 Apr 2023 22:35:46 +0300 Subject: [PATCH 063/135] fix: Fixed Jacoco code coverage report file --- .github/workflows/CI.yml | 2 +- BSTrees/build.gradle.kts | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index de82535..24a8d43 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -36,4 +36,4 @@ jobs: uses: cicirello/jacoco-badge-generator@v2.8.0 with: generate-branches-badge: true - jacoco-html-file: BSTrees/build/jacocoHtml/index.html \ No newline at end of file + jacoco-csv-file: BSTrees/build/jacoco/jacocoCsv \ No newline at end of file diff --git a/BSTrees/build.gradle.kts b/BSTrees/build.gradle.kts index 0e2107a..b871c9b 100644 --- a/BSTrees/build.gradle.kts +++ b/BSTrees/build.gradle.kts @@ -31,8 +31,7 @@ tasks.getByName("test") { tasks.jacocoTestReport { reports { - xml.required.set(false) - csv.required.set(false) - html.outputLocation.set(layout.buildDirectory.dir("jacocoHtml")) + csv.required.set(true) + csv.outputLocation.set(layout.buildDirectory.file("jacoco/jacocoCsv")) } } From 316e356be0f3d3189a4b78c13cc2e28cb82ae4de Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 23 Apr 2023 03:31:59 +0300 Subject: [PATCH 064/135] feat: Added gradle.properties file --- BSTrees/build.gradle.kts | 29 ++++++++++++++++------------- gradle.properties | 4 ++++ 2 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 gradle.properties diff --git a/BSTrees/build.gradle.kts b/BSTrees/build.gradle.kts index b871c9b..e1dec89 100644 --- a/BSTrees/build.gradle.kts +++ b/BSTrees/build.gradle.kts @@ -1,10 +1,13 @@ -plugins { - id("org.jetbrains.kotlin.jvm") version "1.8.10" +val jetbrainsExposedVersion: String? by rootProject +val junit5Version: String? by rootProject +val gsonVersion: String? by rootProject +val kotlinxSerializationVersion: String? by rootProject +plugins { + id("org.jetbrains.kotlin.jvm") version "1.8.20" kotlin("plugin.serialization") version "1.8.20" jacoco - application } @@ -13,16 +16,16 @@ repositories { } dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") - implementation("com.google.code.gson:gson:2.8.5") - implementation("org.jetbrains.exposed:exposed-core:0.38.1") - implementation("org.jetbrains.exposed:exposed-jdbc:0.38.1") - implementation("org.jetbrains.exposed:exposed-dao:0.38.1") - implementation("org.xerial:sqlite-jdbc:3.34.0") - implementation("org.slf4j:slf4j-nop:1.7.25") - - testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.1") - testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.1") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinxSerializationVersion") + + implementation("com.google.code.gson:gson:$gsonVersion") + + implementation("org.jetbrains.exposed:exposed-core:$jetbrainsExposedVersion") + implementation("org.jetbrains.exposed:exposed-jdbc:$jetbrainsExposedVersion") + implementation("org.jetbrains.exposed:exposed-dao:$jetbrainsExposedVersion") + + testImplementation("org.junit.jupiter:junit-jupiter-engine:$junit5Version") + testImplementation("org.junit.jupiter:junit-jupiter-params:$junit5Version") } tasks.getByName("test") { diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..0c1ab02 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,4 @@ +junit5Version=5.9.1 +jetbrainsExposedVersion=0.38.1 +gsonVersion=2.8.5 +kotlinxSerializationVersion=1.5.0 \ No newline at end of file From bdcce724cf208566719ef9eb894015abe90c2279 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 23 Apr 2023 22:26:32 +0300 Subject: [PATCH 065/135] feat: Added tree repository interface --- .../src/main/kotlin/serialization/reps/DBTreeRepo.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt diff --git a/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt new file mode 100644 index 0000000..8eec45a --- /dev/null +++ b/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt @@ -0,0 +1,11 @@ +package serialization.reps + +import serialization.SerializableTree + +interface DBTreeRepo { + fun getTree(typeTree: String, treeName: String): SerializableTree? + + fun setTree(serializableTree: SerializableTree) + + fun deleteTree(serializableTree: SerializableTree) +} \ No newline at end of file From 364b0d06dd511ca7617a47dd6c9e851c29ae556a Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 23 Apr 2023 22:27:36 +0300 Subject: [PATCH 066/135] feat: Added Json tree repository implementation --- .../kotlin/serialization/reps/JsonTreeRepo.kt | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt diff --git a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt new file mode 100644 index 0000000..b56256d --- /dev/null +++ b/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt @@ -0,0 +1,74 @@ +package serialization.reps + +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import serialization.SerializableTree +import kotlinx.serialization.encodeToString +import java.io.File +import java.io.FileReader +import java.io.FileWriter +import kotlin.io.path.Path + + +object JsonTreeRepo : DBTreeRepo { + private fun createDirPaths() { + File("JSONTreeRep").mkdir() + File(Path("JSONTreeRep", "BSTree").toUri()).mkdir() + File(Path("JSONTreeRep", "RBTree").toUri()).mkdir() + File(Path("JSONTreeRep", "AvlTree").toUri()).mkdir() + } + + private fun getPathToFile(typeTree: String, treeName: String): String { + return Path("JSONTreeRep", typeTree, "${treeName}.json").toString() + } + + override fun getTree(typeTree: String, treeName: String): SerializableTree? { + createDirPaths() + + val filePath = getPathToFile(typeTree, treeName) + lateinit var file: FileReader + + return try { + file = FileReader(filePath) + val jsonText = file.readText() + + Json.decodeFromString(jsonText) + } catch (e: NoSuchFileException) { + null + } catch (e: Exception) { + throw e + } finally { + file.close() + } + } + + override fun setTree(serializableTree: SerializableTree) { + createDirPaths() + + val filePath = getPathToFile(serializableTree.typeOfTree, serializableTree.name) + lateinit var file: FileWriter + + try { + file = FileWriter(filePath) + file.write(Json.encodeToString(serializableTree)) + + } catch (e: Exception) { + throw e + } finally { + file.flush() + file.close() + } + } + + override fun deleteTree(serializableTree: SerializableTree) { + createDirPaths() + + val path = getPathToFile(serializableTree.typeOfTree, serializableTree.name) + + try { + File(path).delete() + } catch (e: Exception) { + throw e + } + } +} \ No newline at end of file From bfe5ce4070a67da2e279e08098edcd8bb3abf07f Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 23 Apr 2023 22:31:47 +0300 Subject: [PATCH 067/135] fix: Files have been moved to the desired directory --- .../reps/{sqliteRep => }/SQLTables.kt | 2 +- .../SQLTreeSerializer.kt => SQLTreeRepo.kt} | 25 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) rename BSTrees/src/main/kotlin/serialization/reps/{sqliteRep => }/SQLTables.kt (97%) rename BSTrees/src/main/kotlin/serialization/reps/{sqliteRep/SQLTreeSerializer.kt => SQLTreeRepo.kt} (71%) diff --git a/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTables.kt b/BSTrees/src/main/kotlin/serialization/reps/SQLTables.kt similarity index 97% rename from BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTables.kt rename to BSTrees/src/main/kotlin/serialization/reps/SQLTables.kt index 1055af3..c46bab5 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTables.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/SQLTables.kt @@ -1,4 +1,4 @@ -package serialization.reps.sqliteRep +package serialization.reps import org.jetbrains.exposed.dao.IntEntity import org.jetbrains.exposed.dao.IntEntityClass diff --git a/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt b/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt similarity index 71% rename from BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt rename to BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt index 5b8ee41..a07314d 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/sqliteRep/SQLTreeSerializer.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt @@ -1,4 +1,4 @@ -package serialization.reps.sqliteRep +package serialization.reps import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.SchemaUtils @@ -8,10 +8,11 @@ import org.jetbrains.exposed.sql.transactions.transaction import serialization.* import java.io.File -object SQLTreeSerializer { +object SQLTreeRepo: DBTreeRepo{ - private fun connectBD(file: File) { - Database.connect("jdbc:sqlite:${file}", "org.sqlite.JDBC") + + private fun connectDB(dbName: String) { + Database.connect("jdbc:sqlite:${File(dbName)}", "org.sqlite.JDBC") } private fun createTables(){ @@ -21,19 +22,20 @@ object SQLTreeSerializer { } } - private fun deleteTree(serializableTree: SerializableTree) { + override fun deleteTree(serializableTree: SerializableTree) { transaction { val treeEntity = TreeEntity.find { (TreesTable.nameTree eq serializableTree.name) and (TreesTable.typeTree eq serializableTree.typeOfTree) } .firstOrNull() - treeEntity?.let{NodeEntity.find(NodesTable.tree eq treeEntity.id).forEach { it.delete() } } + treeEntity?.let{ NodeEntity.find(NodesTable.tree eq treeEntity.id).forEach { it.delete() } } treeEntity?.delete() } } - fun setTree(file: File, serializableTree: SerializableTree) { - connectBD(file) + override fun setTree(serializableTree: SerializableTree) { + //TODO: Create a config file in which dbName will be written + connectDB("SQLTreeDB") createTables() deleteTree(serializableTree) @@ -59,11 +61,12 @@ object SQLTreeSerializer { } } - fun getTree(file: File, treeName: String): SerializableTree? { - connectBD(file) + override fun getTree(typeTree: String, treeName: String): SerializableTree? { + //TODO: Create a config file in which dbName will be written + connectDB("SQLTreeDB") createTables() - val treeEntity = TreeEntity.find { TreesTable.nameTree eq treeName }.firstOrNull() ?: return null + val treeEntity = TreeEntity.find { (TreesTable.nameTree eq treeName) and (TreesTable.typeTree eq typeTree) }.firstOrNull() ?: return null return SerializableTree( treeName, From 742741ae9866b1f1213aa470c953ad743d33b6f5 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 23 Apr 2023 22:33:28 +0300 Subject: [PATCH 068/135] fix: Removed an unnecessary field in the SerializableNode class --- BSTrees/src/main/kotlin/serialization/SerializableType.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/BSTrees/src/main/kotlin/serialization/SerializableType.kt b/BSTrees/src/main/kotlin/serialization/SerializableType.kt index 614269f..52292a5 100644 --- a/BSTrees/src/main/kotlin/serialization/SerializableType.kt +++ b/BSTrees/src/main/kotlin/serialization/SerializableType.kt @@ -16,5 +16,4 @@ class SerializableNode( val metadata: String, val leftNode: SerializableNode? = null, val rightNode: SerializableNode? = null, - val parent: SerializableNode? = null, ) \ No newline at end of file From 77b86d71a002af141bf4484533855f5bf92916dc Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 23 Apr 2023 22:46:01 +0300 Subject: [PATCH 069/135] fix: The signature of the deleteTree method has been changed --- BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt | 2 +- BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt | 4 ++-- BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt index 8eec45a..70cf9bb 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt @@ -7,5 +7,5 @@ interface DBTreeRepo { fun setTree(serializableTree: SerializableTree) - fun deleteTree(serializableTree: SerializableTree) + fun deleteTree(typeTree: String, treeName: String) } \ No newline at end of file diff --git a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt index b56256d..6cd0642 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt @@ -60,10 +60,10 @@ object JsonTreeRepo : DBTreeRepo { } } - override fun deleteTree(serializableTree: SerializableTree) { + override fun deleteTree(typeTree: String, treeName: String) { createDirPaths() - val path = getPathToFile(serializableTree.typeOfTree, serializableTree.name) + val path = getPathToFile(typeTree, treeName) try { File(path).delete() diff --git a/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt index a07314d..bad04fd 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt @@ -22,10 +22,10 @@ object SQLTreeRepo: DBTreeRepo{ } } - override fun deleteTree(serializableTree: SerializableTree) { + override fun deleteTree(typeTree: String, treeName: String) { transaction { val treeEntity = - TreeEntity.find { (TreesTable.nameTree eq serializableTree.name) and (TreesTable.typeTree eq serializableTree.typeOfTree) } + TreeEntity.find { (TreesTable.nameTree eq treeName) and (TreesTable.typeTree eq typeTree) } .firstOrNull() treeEntity?.let{ NodeEntity.find(NodesTable.tree eq treeEntity.id).forEach { it.delete() } } @@ -38,7 +38,7 @@ object SQLTreeRepo: DBTreeRepo{ connectDB("SQLTreeDB") createTables() - deleteTree(serializableTree) + deleteTree(serializableTree.typeOfTree, serializableTree.name) transaction { val newTree = TreeEntity.new { From 7139d92bae624ee4ef2a31e3dbd09d9bfcefab4b Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 23 Apr 2023 22:55:39 +0300 Subject: [PATCH 070/135] fix: Fixed a bug closing a non-existent file --- .../src/main/kotlin/serialization/reps/JsonTreeRepo.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt index 6cd0642..3177e9d 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt @@ -5,6 +5,7 @@ import kotlinx.serialization.json.Json import serialization.SerializableTree import kotlinx.serialization.encodeToString import java.io.File +import java.io.FileNotFoundException import java.io.FileReader import java.io.FileWriter import kotlin.io.path.Path @@ -27,18 +28,22 @@ object JsonTreeRepo : DBTreeRepo { val filePath = getPathToFile(typeTree, treeName) lateinit var file: FileReader + var fileFound = true return try { file = FileReader(filePath) val jsonText = file.readText() Json.decodeFromString(jsonText) - } catch (e: NoSuchFileException) { + } catch (e: FileNotFoundException) { + fileFound = false null } catch (e: Exception) { throw e } finally { - file.close() + if (fileFound) { + file.close() + } } } @@ -51,7 +56,6 @@ object JsonTreeRepo : DBTreeRepo { try { file = FileWriter(filePath) file.write(Json.encodeToString(serializableTree)) - } catch (e: Exception) { throw e } finally { From 424c1f53a9bd3eceeab0f027fb5db1bd2794fa3b Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 24 Apr 2023 03:25:02 +0300 Subject: [PATCH 071/135] fix: Big changes in privacy of variables, classes and functions. Changed the way of accessing variables --- BSTrees/src/main/kotlin/BTree.kt | 13 +- BSTrees/src/main/kotlin/Balancer.kt | 31 +++++ BSTrees/src/main/kotlin/Node.kt | 36 +----- .../{balancers => avlTree}/AvlBalancer.kt | 26 ++-- BSTrees/src/main/kotlin/avlTree/AvlNode.kt | 13 +- BSTrees/src/main/kotlin/avlTree/AvlTree.kt | 67 +++++------ .../src/main/kotlin/balancers/BSBalancer.kt | 28 ----- BSTrees/src/main/kotlin/balancers/Balancer.kt | 37 ------ .../kotlin/binarySearchTree/BSBalancer.kt | 23 ++++ .../main/kotlin/binarySearchTree/BSNode.kt | 14 +-- .../main/kotlin/binarySearchTree/BSTree.kt | 61 +++++----- .../{balancers => redBlackTree}/RBBalancer.kt | 90 +++++++------- .../src/main/kotlin/redBlackTree/RBNode.kt | 2 +- .../src/main/kotlin/redBlackTree/RBTree.kt | 113 +++++++++--------- .../src/test/kotlin/balancers/BalancerTest.kt | 2 + .../kotlin/treeInvariants/TreesInvariants.kt | 38 +++--- BSTrees/src/test/kotlin/utils/BSTreeUtil.kt | 42 +++---- 17 files changed, 289 insertions(+), 347 deletions(-) create mode 100644 BSTrees/src/main/kotlin/Balancer.kt rename BSTrees/src/main/kotlin/{balancers => avlTree}/AvlBalancer.kt (56%) delete mode 100644 BSTrees/src/main/kotlin/balancers/BSBalancer.kt delete mode 100644 BSTrees/src/main/kotlin/balancers/Balancer.kt create mode 100644 BSTrees/src/main/kotlin/binarySearchTree/BSBalancer.kt rename BSTrees/src/main/kotlin/{balancers => redBlackTree}/RBBalancer.kt (64%) diff --git a/BSTrees/src/main/kotlin/BTree.kt b/BSTrees/src/main/kotlin/BTree.kt index b564ab2..58bab8e 100644 --- a/BSTrees/src/main/kotlin/BTree.kt +++ b/BSTrees/src/main/kotlin/BTree.kt @@ -1,19 +1,16 @@ abstract class BTree, V, NODE_TYPE : Node> { - var root: NODE_TYPE? = null - + internal var root: NODE_TYPE? = null abstract fun insert(key: K, value: V) - protected abstract fun add(node: NODE_TYPE) - fun find(key: K): V? { var temp: NODE_TYPE? = root ?: return null while (temp != null) { - if (temp.getKey() == key) return temp.getValue() - temp = if (temp.getKey() > key) { - temp.getLeftNode() + if (temp.key == key) return temp.value + temp = if (temp.key > key) { + temp.leftNode } else { - temp.getRightNode() + temp.rightNode } } return null diff --git a/BSTrees/src/main/kotlin/Balancer.kt b/BSTrees/src/main/kotlin/Balancer.kt new file mode 100644 index 0000000..4d9f607 --- /dev/null +++ b/BSTrees/src/main/kotlin/Balancer.kt @@ -0,0 +1,31 @@ +abstract class Balancer, V, NODE_TYPE : Node> { + protected fun leftRotate(node: NODE_TYPE): NODE_TYPE { + val nodeParent = node.parent + val temp = node.rightNode + temp?.parent = nodeParent + if (nodeParent?.leftNode == node) nodeParent.leftNode = temp else nodeParent?.rightNode = temp + + node.rightNode = temp?.leftNode + node.rightNode?.parent = node + + temp?.leftNode = node + node.parent = temp + + return temp ?: node + } + + protected fun rightRotate(node: NODE_TYPE): NODE_TYPE { + val nodeParent = node.parent + val temp = node.leftNode + temp?.parent = nodeParent + if (nodeParent?.leftNode == node) nodeParent.leftNode = temp else nodeParent?.rightNode = temp + + node.leftNode = temp?.rightNode + node.leftNode?.parent = node + + temp?.rightNode = node + node.parent = temp + + return temp ?: node + } +} diff --git a/BSTrees/src/main/kotlin/Node.kt b/BSTrees/src/main/kotlin/Node.kt index 5761305..c588115 100644 --- a/BSTrees/src/main/kotlin/Node.kt +++ b/BSTrees/src/main/kotlin/Node.kt @@ -1,33 +1,5 @@ -abstract class Node, V, NODE_TYPE : Node>(private val key: K, private var value: V) { - - private var parent: NODE_TYPE? = null - private var leftNode: NODE_TYPE? = null - private var rightNode: NODE_TYPE? = null - - fun getKey() = this.key - - fun getValue() = this.value - - fun setValue(newValue: V) { - this.value = newValue - } - - fun getParent() = parent - - fun setParent(newNode: NODE_TYPE?) { - parent = newNode - } - - fun getLeftNode() = leftNode - - fun setLeftNode(newNode: NODE_TYPE?) { - leftNode = newNode - } - - fun getRightNode() = rightNode - - fun setRightNode(newNode: NODE_TYPE?) { - rightNode = newNode - } - +abstract class Node, V, NODE_TYPE : Node>(val key: K, var value: V) { + internal var parent: NODE_TYPE? = null + internal var leftNode: NODE_TYPE? = null + internal var rightNode: NODE_TYPE? = null } diff --git a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt b/BSTrees/src/main/kotlin/avlTree/AvlBalancer.kt similarity index 56% rename from BSTrees/src/main/kotlin/balancers/AvlBalancer.kt rename to BSTrees/src/main/kotlin/avlTree/AvlBalancer.kt index 944fcb0..2c04ee2 100644 --- a/BSTrees/src/main/kotlin/balancers/AvlBalancer.kt +++ b/BSTrees/src/main/kotlin/avlTree/AvlBalancer.kt @@ -1,41 +1,41 @@ -package balancers +package avlTree -import avlTree.AvlNode +import Balancer -class AvlBalancer, V> : Balancer>() { +internal class AvlBalancer, V> : Balancer>() { private fun balanceFactor(node: AvlNode): Int { - return (node.getRightNode()?.getHeight() ?: 0) - (node.getLeftNode()?.getHeight() ?: 0) + return (node.rightNode?.height ?: 0) - (node.leftNode?.height ?: 0) } private fun avlRightRotate(node: AvlNode): AvlNode { val temp = rightRotate(node) - temp.getLeftNode()?.updateHeight() - temp.getRightNode()?.updateHeight() + temp.leftNode?.updateHeight() + temp.rightNode?.updateHeight() temp.updateHeight() return temp } private fun avlLeftRotate(node: AvlNode): AvlNode { val temp = leftRotate(node) - temp.getLeftNode()?.updateHeight() - temp.getRightNode()?.updateHeight() + temp.leftNode?.updateHeight() + temp.rightNode?.updateHeight() temp.updateHeight() return temp } - override fun balance(node: AvlNode): AvlNode { + internal fun balance(node: AvlNode): AvlNode { node.updateHeight() val bf = balanceFactor(node) if (bf == 2) { - val temp = node.getRightNode() + val temp = node.rightNode if (temp != null) { if (balanceFactor(temp) < 0) { - node.setRightNode(avlRightRotate(temp)) + node.rightNode = avlRightRotate(temp) } } @@ -44,10 +44,10 @@ class AvlBalancer, V> : Balancer>() { if (bf == -2) { - val temp = node.getLeftNode() + val temp = node.leftNode if (temp != null) { if (balanceFactor(temp) > 0) { - node.setLeftNode(avlLeftRotate(temp)) + node.leftNode = avlLeftRotate(temp) } } diff --git a/BSTrees/src/main/kotlin/avlTree/AvlNode.kt b/BSTrees/src/main/kotlin/avlTree/AvlNode.kt index e8118b4..e53fbd9 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlNode.kt +++ b/BSTrees/src/main/kotlin/avlTree/AvlNode.kt @@ -5,16 +5,11 @@ import kotlin.math.max class AvlNode, V>(key: K, value: V) : Node>(key, value) { - private var height = 1 - fun getHeight() = this.height - - fun setHeight(newValue: Int) { - this.height = newValue - } + internal var height = 1 fun updateHeight() { - val leftHeight = this.getLeftNode()?.getHeight() ?: 0 - val rightHeight = this.getRightNode()?.getHeight() ?: 0 - setHeight(max(leftHeight, rightHeight) + 1) + val leftHeight = this.leftNode?.height ?: 0 + val rightHeight = this.rightNode?.height ?: 0 + height = (max(leftHeight, rightHeight) + 1) } } diff --git a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt index 2beee05..b005906 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt +++ b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt @@ -1,7 +1,6 @@ package avlTree import BTree -import balancers.AvlBalancer class AvlTree, V> : BTree>() { @@ -11,24 +10,24 @@ class AvlTree, V> : BTree>() { add(AvlNode(key, value)) } - override fun add(node: AvlNode) { + private fun add(node: AvlNode) { val temp = this.root if (temp == null) this.root = node - else if (temp.getKey() == node.getKey()) this.root?.setValue(node.getValue()) + else if (temp.key == node.key) this.root?.value = node.value else { val subTree = AvlTree() - if (node.getKey() < temp.getKey()) { - subTree.root = temp.getLeftNode() + if (node.key < temp.key) { + subTree.root = temp.leftNode subTree.add(node) - subTree.root?.setParent(this.root) - this.root?.setLeftNode(subTree.root) - } else if (node.getKey() > temp.getKey()) { - subTree.root = temp.getRightNode() + subTree.root?.parent = this.root + this.root?.leftNode = subTree.root + } else if (node.key > temp.key) { + subTree.root = temp.rightNode subTree.add(node) - subTree.root?.setParent(this.root) - this.root?.setRightNode(subTree.root) + subTree.root?.parent = this.root + this.root?.rightNode = subTree.root } } @@ -37,16 +36,16 @@ class AvlTree, V> : BTree>() { } private fun findMin(node: AvlNode): AvlNode { - val temp = node.getLeftNode() + val temp = node.leftNode return if (temp != null) findMin(temp) else node } private fun removeMin(node: AvlNode): AvlNode? { - val temp = node.getLeftNode() - if (temp == null) return node.getRightNode() + val temp = node.leftNode + if (temp == null) return node.rightNode val tempRemovedMin = removeMin(temp) - node.setLeftNode(tempRemovedMin) - tempRemovedMin?.setParent(node) + node.leftNode = tempRemovedMin + tempRemovedMin?.parent = node return balancer.balance(node) } @@ -58,37 +57,37 @@ class AvlTree, V> : BTree>() { val subTree = AvlTree() - if (key < temp.getKey()) { + if (key < temp.key) { - subTree.root = temp.getLeftNode() + subTree.root = temp.leftNode subTree.delete(key) - subTree.root?.setParent(this.root) - this.root?.setLeftNode(subTree.root) + subTree.root?.parent = this.root + this.root?.leftNode = subTree.root - } else if (key > temp.getKey()) { + } else if (key > temp.key) { - subTree.root = temp.getRightNode() + subTree.root = temp.rightNode subTree.delete(key) - subTree.root?.setParent(this.root) - this.root?.setRightNode(subTree.root) + subTree.root?.parent = this.root + this.root?.rightNode = subTree.root } else { - val leftNode = this.root?.getLeftNode() - val rightNode = this.root?.getRightNode() + val leftNode = this.root?.leftNode + val rightNode = this.root?.rightNode if (rightNode == null) { - leftNode?.setParent(this.root?.getParent()) + leftNode?.parent = this.root?.parent this.root = leftNode } else { val tempMin: AvlNode = findMin(rightNode) - tempMin.setRightNode(removeMin(rightNode)) - tempMin.getRightNode()?.setParent(tempMin) - tempMin.setLeftNode(leftNode) - tempMin.getLeftNode()?.setParent(tempMin) - if (this.root?.getParent()?.getLeftNode() == this.root) this.root?.getParent()?.setLeftNode(tempMin) - else this.root?.getParent()?.setRightNode(tempMin) - tempMin.setParent(this.root?.getParent()) + tempMin.rightNode = removeMin(rightNode) + tempMin.rightNode?.parent = tempMin + tempMin.leftNode = leftNode + tempMin.leftNode?.parent = tempMin + if (this.root?.parent?.leftNode == this.root) this.root?.parent?.leftNode = tempMin + else this.root?.parent?.rightNode = tempMin + tempMin.parent = this.root?.parent this.root = balancer.balance(tempMin) } diff --git a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt b/BSTrees/src/main/kotlin/balancers/BSBalancer.kt deleted file mode 100644 index ffcbd9f..0000000 --- a/BSTrees/src/main/kotlin/balancers/BSBalancer.kt +++ /dev/null @@ -1,28 +0,0 @@ -package balancers - -import binarySearchTree.BSNode - -class BSBalancer, V> : Balancer>() { - - fun bsRightRotate(node: BSNode): BSNode { - val temp = rightRotate(node) - temp.getLeftNode()?.updateSize() - temp.getRightNode()?.updateSize() - temp.updateSize() - return temp - } - - fun bsLeftRotate(node: BSNode): BSNode { - val temp = leftRotate(node) - temp.getLeftNode()?.updateSize() - temp.getRightNode()?.updateSize() - temp.updateSize() - return temp - } - - override fun balance(node: BSNode): BSNode { - //We don't need balance function in BSTree, but we need rotates - TODO("Nothing") - } - -} diff --git a/BSTrees/src/main/kotlin/balancers/Balancer.kt b/BSTrees/src/main/kotlin/balancers/Balancer.kt deleted file mode 100644 index fbf49e4..0000000 --- a/BSTrees/src/main/kotlin/balancers/Balancer.kt +++ /dev/null @@ -1,37 +0,0 @@ -package balancers - -import Node - -abstract class Balancer, V, NODE_TYPE : Node> { - fun leftRotate(node: NODE_TYPE): NODE_TYPE { - val nodeParent = node.getParent() - val temp = node.getRightNode() - temp?.setParent(nodeParent) - if (nodeParent?.getLeftNode() == node) nodeParent.setLeftNode(temp) else nodeParent?.setRightNode(temp) - - node.setRightNode(temp?.getLeftNode()) - node.getRightNode()?.setParent(node) - - temp?.setLeftNode(node) - node.setParent(temp) - - return temp ?: node - } - - fun rightRotate(node: NODE_TYPE): NODE_TYPE { - val nodeParent = node.getParent() - val temp = node.getLeftNode() - temp?.setParent(nodeParent) - if (nodeParent?.getLeftNode() == node) nodeParent.setLeftNode(temp) else nodeParent?.setRightNode(temp) - - node.setLeftNode(temp?.getRightNode()) - node.getLeftNode()?.setParent(node) - - temp?.setRightNode(node) - node.setParent(temp) - - return temp ?: node - } - - abstract fun balance(node: NODE_TYPE): NODE_TYPE -} diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSBalancer.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSBalancer.kt new file mode 100644 index 0000000..7816694 --- /dev/null +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSBalancer.kt @@ -0,0 +1,23 @@ +package binarySearchTree + +import Balancer + +internal class BSBalancer, V> : Balancer>() { + + internal fun bsRightRotate(node: BSNode): BSNode { + val temp = rightRotate(node) + temp.leftNode?.updateSize() + temp.rightNode?.updateSize() + temp.updateSize() + return temp + } + + internal fun bsLeftRotate(node: BSNode): BSNode { + val temp = leftRotate(node) + temp.leftNode?.updateSize() + temp.rightNode?.updateSize() + temp.updateSize() + return temp + } + +} diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt index 672dcf1..83e3250 100644 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt @@ -4,17 +4,11 @@ import Node class BSNode, V>(key: K, value: V) : Node>(key, value) { - private var size = 1 - - fun getSize() = size - - fun setSize(newSize: Int) { - this.size = newSize - } + internal var size = 1 fun updateSize() { - val leftSize = getLeftNode()?.getSize() ?: 0 - val rightSize = getRightNode()?.getSize() ?: 0 - setSize(leftSize + rightSize + 1) + val leftSize = leftNode?.size ?: 0 + val rightSize = rightNode?.size ?: 0 + size = leftSize + rightSize + 1 } } diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt index 4701804..df1dc87 100644 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt +++ b/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt @@ -1,7 +1,6 @@ package binarySearchTree import BTree -import balancers.BSBalancer import kotlin.random.Random class BSTree, V> : BTree>() { @@ -16,32 +15,32 @@ class BSTree, V> : BTree>() { val temp = this.root return if (temp == null) node - else if (temp.getKey() == node.getKey()) { - temp.setValue(node.getValue()) + else if (temp.key == node.key) { + temp.value = node.value temp } else { val subTree = BSTree() - if (node.getKey() < temp.getKey()) { - subTree.root = temp.getLeftNode() - this.root?.setLeftNode(subTree.addRoot(node)) + if (node.key < temp.key) { + subTree.root = temp.leftNode + this.root?.leftNode = subTree.addRoot(node) balancer.bsRightRotate(temp) } else { - subTree.root = temp.getRightNode() - this.root?.setRightNode(subTree.addRoot(node)) + subTree.root = temp.rightNode + this.root?.rightNode = subTree.addRoot(node) balancer.bsLeftRotate(temp) } } } - override fun add(node: BSNode) { + private fun add(node: BSNode) { val temp = this.root if (temp == null) this.root = node - else if (temp.getKey() == node.getKey()) this.root?.setValue(node.getValue()) + else if (temp.key == node.key) this.root?.value = node.value else { - if (Random.nextInt() % (node.getSize() + 1) == 0) this.root = this.addRoot(node) + if (Random.nextInt() % (node.size + 1) == 0) this.root = this.addRoot(node) /* Randomized insertion into the root of the tree allows you to artificially balance it with a fairly small height. @@ -49,16 +48,16 @@ class BSTree, V> : BTree>() { */ else { val subTree = BSTree() - if (temp.getKey() > node.getKey()) { - subTree.root = temp.getLeftNode() + if (temp.key > node.key) { + subTree.root = temp.leftNode subTree.add(node) - subTree.root?.setParent(this.root) - this.root?.setLeftNode(subTree.root) + subTree.root?.parent = this.root + this.root?.leftNode = subTree.root } else { - subTree.root = temp.getRightNode() + subTree.root = temp.rightNode subTree.add(node) - subTree.root?.setParent(this.root) - this.root?.setRightNode(subTree.root) + subTree.root?.parent = this.root + this.root?.rightNode = subTree.root } } @@ -72,14 +71,14 @@ class BSTree, V> : BTree>() { if (left == null) return right if (right == null) return left - return if (Random.nextInt() % (left.getSize() + right.getSize()) < left.getSize()) { - left.setRightNode(join(left.getRightNode(), right)) - left.getRightNode()?.setParent(left) + return if (Random.nextInt() % (left.size + right.size) < left.size) { + left.rightNode = join(left.rightNode, right) + left.rightNode?.parent = left left.updateSize() left } else { - right.setLeftNode(join(left, right.getLeftNode())) - right.getLeftNode()?.setParent(right) + right.leftNode = join(left, right.leftNode) + right.leftNode?.parent = right right.updateSize() right } @@ -92,19 +91,19 @@ class BSTree, V> : BTree>() { if (temp != null) { - if (temp.getKey() == key) this.root = join(temp.getLeftNode(), temp.getRightNode()) - else if (key < temp.getKey()) { + if (temp.key == key) this.root = join(temp.leftNode, temp.rightNode) + else if (key < temp.key) { val subTree = BSTree() - subTree.root = temp.getLeftNode() + subTree.root = temp.leftNode subTree.delete(key) - subTree.root?.setParent(this.root) - this.root?.setLeftNode(subTree.root) + subTree.root?.parent = this.root + this.root?.leftNode = subTree.root } else { val subTree = BSTree() - subTree.root = temp.getRightNode() + subTree.root = temp.rightNode subTree.delete(key) - subTree.root?.setParent(this.root) - this.root?.setRightNode(subTree.root) + subTree.root?.parent = this.root + this.root?.rightNode = subTree.root } this.root?.updateSize() diff --git a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt b/BSTrees/src/main/kotlin/redBlackTree/RBBalancer.kt similarity index 64% rename from BSTrees/src/main/kotlin/balancers/RBBalancer.kt rename to BSTrees/src/main/kotlin/redBlackTree/RBBalancer.kt index f92f084..5fedb98 100644 --- a/BSTrees/src/main/kotlin/balancers/RBBalancer.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBBalancer.kt @@ -1,33 +1,32 @@ -package balancers +package redBlackTree -import redBlackTree.RBNode +import Balancer import redBlackTree.RBNode.Color -import redBlackTree.RBTree open class RBBalancer, V> : Balancer>() { - fun balanceAfterDeletion(tree: RBTree, node: RBNode) { + internal fun balanceAfterDeletion(tree: RBTree, node: RBNode) { var curNode = node - var nodeParent = node.getParent() + var nodeParent = node.parent while (nodeParent != null && curNode.color != Color.RED) { - if (nodeParent.getLeftNode() == curNode) { + if (nodeParent.leftNode == curNode) { - if (nodeParent.getLeftNode() == null) { + if (nodeParent.leftNode == null) { curNode = nodeParent - nodeParent = curNode.getParent() + nodeParent = curNode.parent continue } // brother MUST exist, because we have a 2xBLACK curNode in leftTree - var nodeBrother = nodeParent.getRightNode() ?: throw Exception("An attempt to take a non-existent son") + var nodeBrother = nodeParent.rightNode ?: throw Exception("An attempt to take a non-existent son") // Consideration of the case 1. // nodeBrother is red if (nodeBrother.color == Color.RED) { nodeBrother.color = Color.BLACK nodeParent.color = Color.RED - if (nodeParent.getParent() == null) { + if (nodeParent.parent == null) { nodeParent = leftRotate(nodeParent) tree.root = nodeParent } else { @@ -36,21 +35,21 @@ open class RBBalancer, V> : Balancer>() { // these nodes MUST exist because we did leftRotate with theirs nodes - nodeParent = nodeParent.getLeftNode() ?: throw Exception("An attempt to take a non-existent son") - curNode = nodeParent.getLeftNode() ?: throw Exception("An attempt to take a non-existent son") - nodeBrother = nodeParent.getRightNode() ?: throw Exception("An attempt to take a non-existent son") + nodeParent = nodeParent.leftNode ?: throw Exception("An attempt to take a non-existent son") + curNode = nodeParent.leftNode ?: throw Exception("An attempt to take a non-existent son") + nodeBrother = nodeParent.rightNode ?: throw Exception("An attempt to take a non-existent son") } // Consideration of the case 2. // nodeBrother's sons are black - val leftSonOfBrother = nodeBrother.getLeftNode() - val rightSonOfBrother = nodeBrother.getRightNode() + val leftSonOfBrother = nodeBrother.leftNode + val rightSonOfBrother = nodeBrother.rightNode if ((leftSonOfBrother == null || leftSonOfBrother.color == Color.BLACK) && (rightSonOfBrother == null || rightSonOfBrother.color == Color.BLACK) ) { nodeBrother.color = Color.RED curNode = nodeParent - nodeParent = curNode.getParent() + nodeParent = curNode.parent } else { // Consideration of the case 3. @@ -65,8 +64,8 @@ open class RBBalancer, V> : Balancer>() { // nodeBrother's right son is red nodeBrother.color = nodeParent.color nodeParent.color = Color.BLACK - nodeBrother.getRightNode()?.color = Color.BLACK - if (nodeParent.getParent() == null) { + nodeBrother.rightNode?.color = Color.BLACK + if (nodeParent.parent == null) { tree.root = leftRotate(nodeParent) } else { leftRotate(nodeParent) @@ -75,14 +74,14 @@ open class RBBalancer, V> : Balancer>() { } } else { - if (nodeParent.getLeftNode() == null) { + if (nodeParent.leftNode == null) { curNode = nodeParent - nodeParent = curNode.getParent() + nodeParent = curNode.parent continue } // brother MUST exist, because we have a 2xBLACK curNode in rightTree - var nodeBrother = nodeParent.getLeftNode() ?: throw Exception("An attempt to take a non-existent son") + var nodeBrother = nodeParent.leftNode ?: throw Exception("An attempt to take a non-existent son") // Consideration of the case 1. // nodeBrother is red @@ -90,7 +89,7 @@ open class RBBalancer, V> : Balancer>() { nodeBrother.color = Color.BLACK nodeParent.color = Color.RED - if (nodeParent.getParent() == null) { + if (nodeParent.parent == null) { nodeParent = rightRotate(nodeParent) tree.root = nodeParent } else { @@ -98,21 +97,21 @@ open class RBBalancer, V> : Balancer>() { } // these nodes MUST exist because we did rightRotate with theirs nodes - nodeParent = nodeParent.getRightNode() ?: throw Exception("An attempt to take a non-existent son") - curNode = nodeParent.getRightNode() ?: throw Exception("An attempt to take a non-existent son") - nodeBrother = nodeParent.getLeftNode() ?: throw Exception("An attempt to take a non-existent son") + nodeParent = nodeParent.rightNode ?: throw Exception("An attempt to take a non-existent son") + curNode = nodeParent.rightNode ?: throw Exception("An attempt to take a non-existent son") + nodeBrother = nodeParent.leftNode ?: throw Exception("An attempt to take a non-existent son") } // Consideration of the case 2. // nodeBrother's sons are black - val leftSonOfBrother = nodeBrother.getLeftNode() - val rightSonOfBrother = nodeBrother.getRightNode() + val leftSonOfBrother = nodeBrother.leftNode + val rightSonOfBrother = nodeBrother.rightNode if ((leftSonOfBrother == null || leftSonOfBrother.color == Color.BLACK) && (rightSonOfBrother == null || rightSonOfBrother.color == Color.BLACK) ) { nodeBrother.color = Color.RED curNode = nodeParent - nodeParent = curNode.getParent() + nodeParent = curNode.parent } else { // Consideration of the case 3. @@ -127,8 +126,8 @@ open class RBBalancer, V> : Balancer>() { // nodeBrother's right son is red nodeBrother.color = nodeParent.color nodeParent.color = Color.BLACK - nodeBrother.getLeftNode()?.color = Color.BLACK - if (nodeParent.getParent() == null) { + nodeBrother.leftNode?.color = Color.BLACK + if (nodeParent.parent == null) { tree.root = rightRotate(nodeParent) } else { rightRotate(nodeParent) @@ -141,20 +140,20 @@ open class RBBalancer, V> : Balancer>() { } - fun balanceAfterAdding(node: RBNode): RBNode { - var nodeParent = node.getParent() + internal fun balanceAfterAdding(node: RBNode): RBNode { + var nodeParent = node.parent var curNode = node while (nodeParent != null && nodeParent.color == Color.RED) { // It must exist, since the root of the tree cannot be red - val nodeGrandParent = nodeParent.getParent() ?: throw Exception("An attempt to take a non-existent parent") + val nodeGrandParent = nodeParent.parent ?: throw Exception("An attempt to take a non-existent parent") - if (nodeParent == nodeGrandParent.getLeftNode()) { - val nodeUncle = nodeGrandParent.getRightNode() + if (nodeParent == nodeGrandParent.leftNode) { + val nodeUncle = nodeGrandParent.rightNode if (nodeUncle == null || nodeUncle.color == Color.BLACK) { - if (curNode == nodeParent.getRightNode()) { + if (curNode == nodeParent.rightNode) { nodeParent = leftRotate(nodeParent) - curNode = nodeParent.getLeftNode() ?: throw Exception("An attempt to take a non-existent son") + curNode = nodeParent.leftNode ?: throw Exception("An attempt to take a non-existent son") } nodeParent.color = Color.BLACK nodeGrandParent.color = Color.RED @@ -165,15 +164,15 @@ open class RBBalancer, V> : Balancer>() { nodeGrandParent.color = Color.RED curNode = nodeGrandParent - nodeParent = curNode.getParent() + nodeParent = curNode.parent } } else { - val nodeUncle = nodeGrandParent.getLeftNode() + val nodeUncle = nodeGrandParent.leftNode if (nodeUncle == null || nodeUncle.color == Color.BLACK) { - if (curNode == nodeParent.getLeftNode()) { + if (curNode == nodeParent.leftNode) { nodeParent = rightRotate(nodeParent) - curNode = nodeParent.getRightNode() ?: throw Exception("An attempt to take a non-existent son") + curNode = nodeParent.rightNode ?: throw Exception("An attempt to take a non-existent son") } nodeParent.color = Color.BLACK nodeGrandParent.color = Color.RED @@ -184,19 +183,16 @@ open class RBBalancer, V> : Balancer>() { nodeGrandParent.color = Color.RED curNode = nodeGrandParent - nodeParent = curNode.getParent() + nodeParent = curNode.parent } } } - while (curNode.getParent() != null) { - curNode = curNode.getParent() ?: throw Exception("An attempt to take a non-existent parent") + while (curNode.parent != null) { + curNode = curNode.parent ?: throw Exception("An attempt to take a non-existent parent") } curNode.color = Color.BLACK return curNode } - override fun balance(node: RBNode): RBNode { - TODO("Not yet implemented") - } } \ No newline at end of file diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt b/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt index fed2f50..d2ada18 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt @@ -9,5 +9,5 @@ class RBNode, V>(key: K, value: V) : Node>( RED } - var color = Color.BLACK + internal var color = Color.BLACK } diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt index 904f37f..ec4d700 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt +++ b/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt @@ -1,7 +1,6 @@ package redBlackTree import BTree -import balancers.RBBalancer import redBlackTree.RBNode.Color class RBTree, V> : BTree>() { @@ -12,12 +11,12 @@ class RBTree, V> : BTree>() { add(RBNode(key, value)) } - override fun add(node: RBNode) { + private fun add(node: RBNode) { // if a node with such a key already exists, then we update Value - val nodeWithEqualKey = findNodeByKey(node.getKey()) + val nodeWithEqualKey = findNodeByKey(node.key) if (nodeWithEqualKey != null) { - nodeWithEqualKey.setValue(node.getValue()) + nodeWithEqualKey.value = node.value return } @@ -28,23 +27,23 @@ class RBTree, V> : BTree>() { } while (true) { root ?: error("adding error") - if (root.getKey() > node.getKey()) { - val leftNode = root.getLeftNode() + if (root.key > node.key) { + val leftNode = root.leftNode if (leftNode == null) { node.color = Color.RED - root.setLeftNode(node) - node.setParent(root) + root.leftNode = node + node.parent = root this.root = balancer.balanceAfterAdding(node) break } else { root = leftNode } } else { - val rightNode = root.getRightNode() + val rightNode = root.rightNode if (rightNode == null) { node.color = Color.RED - root.setRightNode(node) - node.setParent(root) + root.rightNode = node + node.parent = root this.root = balancer.balanceAfterAdding(node) break } else { @@ -57,11 +56,11 @@ class RBTree, V> : BTree>() { private fun findNodeByKey(key: K): RBNode? { var temp: RBNode? = root ?: return null while (temp != null) { - if (temp.getKey() == key) return temp - temp = if (temp.getKey() > key) { - temp.getLeftNode() + if (temp.key == key) return temp + temp = if (temp.key > key) { + temp.leftNode } else { - temp.getRightNode() + temp.rightNode } } return null @@ -74,20 +73,20 @@ class RBTree, V> : BTree>() { // This is the node that we will put in place of curNode val nodeForSwapping = getNodeForSwapping(curNode) - var sonIsNillNode = false + var sonIsNilNode = false // This is the node that will take the place of nodeForSwapping - // If nodeForSwapping has no sons, then we create an imaginary(NILL) sonNode + // If nodeForSwapping has no sons, then we create an imaginary(Nil) sonNode val sonNodeForSwapping = - if (nodeForSwapping.getLeftNode() == null && nodeForSwapping.getRightNode() == null) { - sonIsNillNode = true - getNillNode(curNode) + if (nodeForSwapping.leftNode == null && nodeForSwapping.rightNode == null) { + sonIsNilNode = true + getNilNode(curNode) } else { getSonNodeForSwapping(nodeForSwapping) } // We put the sonOfNodeForSwapping in the place of nodeForSwapping and establish the necessary links - setLinksWithSonOfNodeForSwapping(nodeForSwapping, sonNodeForSwapping, sonIsNillNode) + setLinksWithSonOfNodeForSwapping(nodeForSwapping, sonNodeForSwapping, sonIsNilNode) val colorOfNodeForSwapping = nodeForSwapping.color @@ -102,32 +101,32 @@ class RBTree, V> : BTree>() { sonNodeForSwapping?.let { balancer.balanceAfterDeletion(this, sonNodeForSwapping) } } - // If we used an imaginary(NILL) node, we have to remove unnecessary links - if (sonIsNillNode) { - if (sonNodeForSwapping?.getParent()?.getLeftNode() == sonNodeForSwapping) { - sonNodeForSwapping?.getParent()?.setLeftNode(null) + // If we used an imaginary(Nil) node, we have to remove unnecessary links + if (sonIsNilNode) { + if (sonNodeForSwapping?.parent?.leftNode == sonNodeForSwapping) { + sonNodeForSwapping?.parent?.leftNode = null } else { - sonNodeForSwapping?.getParent()?.setRightNode(null) + sonNodeForSwapping?.parent?.rightNode = null } } } private fun setLinksWithNodeForSwapping(curNode: RBNode, nodeForSwapping: RBNode) { - nodeForSwapping.setLeftNode(curNode.getLeftNode()) - nodeForSwapping.getLeftNode()?.setParent(nodeForSwapping) - nodeForSwapping.setRightNode(curNode.getRightNode()) - nodeForSwapping.getRightNode()?.setParent(nodeForSwapping) + nodeForSwapping.leftNode = curNode.leftNode + nodeForSwapping.leftNode?.parent = nodeForSwapping + nodeForSwapping.rightNode = curNode.rightNode + nodeForSwapping.rightNode?.parent = nodeForSwapping - val parentCurNode = curNode.getParent() + val parentCurNode = curNode.parent if (parentCurNode == null) { - nodeForSwapping.setParent(null) + nodeForSwapping.parent = null this.root = nodeForSwapping } else { - nodeForSwapping.setParent(parentCurNode) - if (curNode == parentCurNode.getLeftNode()) { - parentCurNode.setLeftNode(nodeForSwapping) + nodeForSwapping.parent = parentCurNode + if (curNode == parentCurNode.leftNode) { + parentCurNode.leftNode = nodeForSwapping } else { - parentCurNode.setRightNode(nodeForSwapping) + parentCurNode.rightNode = nodeForSwapping } } } @@ -135,55 +134,55 @@ class RBTree, V> : BTree>() { private fun setLinksWithSonOfNodeForSwapping( nodeForSwapping: RBNode, sonOfNodeForSwapping: RBNode?, - sonIsNillNode: Boolean + sonIsNilNode: Boolean ) { - sonOfNodeForSwapping?.setParent(nodeForSwapping.getParent()) + sonOfNodeForSwapping?.parent = nodeForSwapping.parent - val parentNodeForSwapping = nodeForSwapping.getParent() + val parentNodeForSwapping = nodeForSwapping.parent if (parentNodeForSwapping == null) { - sonOfNodeForSwapping?.setParent(null) - this.root = if (!sonIsNillNode) sonOfNodeForSwapping else null + sonOfNodeForSwapping?.parent = null + this.root = if (!sonIsNilNode) sonOfNodeForSwapping else null } else { - if (nodeForSwapping == parentNodeForSwapping.getLeftNode()) { - parentNodeForSwapping.setLeftNode(sonOfNodeForSwapping) + if (nodeForSwapping == parentNodeForSwapping.leftNode) { + parentNodeForSwapping.leftNode = sonOfNodeForSwapping } else { - parentNodeForSwapping.setRightNode(sonOfNodeForSwapping) + parentNodeForSwapping.rightNode = sonOfNodeForSwapping } } } - // nodeForSwapping is the node with the next largest key or the node itself if it has a NILL son + // nodeForSwapping is the node with the next largest key or the node itself if it has a Nil son private fun , V> getNodeForSwapping(curNode: RBNode): RBNode { - return if (curNode.getLeftNode() == null || curNode.getRightNode() == null) { + return if (curNode.leftNode == null || curNode.rightNode == null) { curNode } else { // If we got here, then curNode has both a left and a right son - val temp = curNode.getRightNode() ?: throw Exception("An attempt to take a non-existent son") + val temp = curNode.rightNode ?: throw Exception("An attempt to take a non-existent son") nodeWithMinKey(temp) } } private fun , V> getSonNodeForSwapping(nodeForSwapping: RBNode): RBNode? { - return if (nodeForSwapping.getLeftNode() != null) { - nodeForSwapping.getLeftNode() + return if (nodeForSwapping.leftNode != null) { + nodeForSwapping.leftNode } else { - nodeForSwapping.getRightNode() + nodeForSwapping.rightNode } } - // We get an imaginary(NILL) node filled with some unnecessary data - private fun , V> getNillNode(nodeExample: RBNode): RBNode { - val nillSonNodeOfSwapping = RBNode(nodeExample.getKey(), nodeExample.getValue()) - nillSonNodeOfSwapping.color = Color.BLACK + // We get an imaginary(Nil) node filled with some unnecessary data + private fun , V> getNilNode(nodeExample: RBNode): RBNode { + val nilSonNodeOfSwapping = RBNode(nodeExample.key, nodeExample.value) + nilSonNodeOfSwapping.color = Color.BLACK - return nillSonNodeOfSwapping + return nilSonNodeOfSwapping } // We are looking for a node with the minimum key available from this node private fun , V> nodeWithMinKey(node: RBNode): RBNode { var curNode = node - while (curNode.getLeftNode() != null) { - curNode = curNode.getLeftNode() ?: throw Exception("An attempt to take a non-existent son") + while (curNode.leftNode != null) { + curNode = curNode.leftNode ?: throw Exception("An attempt to take a non-existent son") } return curNode } diff --git a/BSTrees/src/test/kotlin/balancers/BalancerTest.kt b/BSTrees/src/test/kotlin/balancers/BalancerTest.kt index e9e3d9b..04a9656 100644 --- a/BSTrees/src/test/kotlin/balancers/BalancerTest.kt +++ b/BSTrees/src/test/kotlin/balancers/BalancerTest.kt @@ -1,6 +1,8 @@ package balancers +import Balancer import Node +import binarySearchTree.BSBalancer import binarySearchTree.BSNode import org.junit.jupiter.api.Test diff --git a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt index 44398db..24319dc 100644 --- a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt +++ b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt @@ -10,29 +10,29 @@ import redBlackTree.RBNode.Color class TreesInvariants, V, NODE_TYPE : Node> { fun checkRBTreeInvariants(root: RBNode?): Boolean { - return root == null || root.getParent() == null && checkNodeInvariants(root as NODE_TYPE) && root.color == Color.BLACK && + return root == null || root.parent == null && checkNodeInvariants(root as NODE_TYPE) && root.color == Color.BLACK && checkRBNodeBlackHeightInvariant(root, 0, getSomeBlackHeight(root)) && checkRBNodeBlackParentForRedInvariant(root) } private fun checkRBNodeBlackParentForRedInvariant(node: RBNode): Boolean { - return (node.color == Color.BLACK || node.getParent()!!.color == Color.BLACK) && - (node.getLeftNode() == null || checkRBNodeBlackParentForRedInvariant(node.getLeftNode()!!)) && - (node.getRightNode() == null || checkRBNodeBlackParentForRedInvariant(node.getRightNode()!!)) + return (node.color == Color.BLACK || node.parent!!.color == Color.BLACK) && + (node.leftNode == null || checkRBNodeBlackParentForRedInvariant(node.leftNode!!)) && + (node.rightNode == null || checkRBNodeBlackParentForRedInvariant(node.rightNode!!)) } private fun checkRBNodeBlackHeightInvariant(node: RBNode, curHeight: Int, rightHeight: Int): Boolean { val newCurHeight = curHeight + if (node.color == Color.BLACK) 1 else 0 - if (node.getLeftNode() == null && node.getRightNode() == null) { + if (node.leftNode == null && node.rightNode == null) { return newCurHeight == rightHeight } - return ((node.getLeftNode() == null || checkRBNodeBlackHeightInvariant( - node.getLeftNode()!!, + return ((node.leftNode == null || checkRBNodeBlackHeightInvariant( + node.leftNode!!, newCurHeight, rightHeight )) && - (node.getRightNode() == null || checkRBNodeBlackHeightInvariant( - node.getRightNode()!!, + (node.rightNode == null || checkRBNodeBlackHeightInvariant( + node.rightNode!!, newCurHeight, rightHeight ))) @@ -45,31 +45,31 @@ class TreesInvariants, V, NODE_TYPE : Node> { if (curNode.color == Color.BLACK) { ++blackHeight } - curNode = curNode.getLeftNode() + curNode = curNode.leftNode } return blackHeight } private fun checkNodeInvariants(node: NODE_TYPE): Boolean { - return (node.getLeftNode() == null || node.getLeftNode()!!.getParent() == node && - node.getLeftNode()!!.getKey() < node.getKey() && checkNodeInvariants(node.getLeftNode()!!)) && - (node.getRightNode() == null || node.getRightNode()!!.getParent() == node && - node.getRightNode()!!.getKey() > node.getKey() && checkNodeInvariants(node.getRightNode()!!)) + return (node.leftNode == null || node.leftNode!!.parent == node && + node.leftNode!!.key < node.key && checkNodeInvariants(node.leftNode!!)) && + (node.rightNode == null || node.rightNode!!.parent == node && + node.rightNode!!.key > node.key && checkNodeInvariants(node.rightNode!!)) } fun checkAvlTreeInvariants(root: AvlNode?): Boolean = root == null || checkAvlHeightInvariants(root) && checkNodeInvariants(root as NODE_TYPE) private fun checkAvlHeightInvariants(node: AvlNode): Boolean = - ((node.getRightNode()?.getHeight() ?: 0) - (node.getLeftNode()?.getHeight() ?: 0) in -1..1) - && (node.getLeftNode() == null || checkAvlHeightInvariants(node.getLeftNode()!!)) - && (node.getRightNode() == null || checkAvlHeightInvariants(node.getRightNode()!!)) + ((node.rightNode?.height ?: 0) - (node.leftNode?.height ?: 0) in -1..1) + && (node.leftNode == null || checkAvlHeightInvariants(node.leftNode!!)) + && (node.rightNode == null || checkAvlHeightInvariants(node.rightNode!!)) private fun checkBSSizeInvariant(node: BSNode?): Boolean { return node == null || - node.getSize() == (node.getLeftNode()?.getSize() ?: 0) + (node.getRightNode()?.getSize() ?: 0) + 1 - && checkBSSizeInvariant(node.getLeftNode()) && checkBSSizeInvariant(node.getRightNode()) + node.size == (node.leftNode?.size ?: 0) + (node.rightNode?.size ?: 0) + 1 + && checkBSSizeInvariant(node.leftNode) && checkBSSizeInvariant(node.rightNode) } fun checkBsTreeInvariants(root: BSNode?): Boolean { diff --git a/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt b/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt index 2b82113..ba42edd 100644 --- a/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt +++ b/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt @@ -13,9 +13,9 @@ object BSTreeUtil { if (root1 == null || root2 == null) { return root1 == null && root2 == null } - return root1.getKey() == root2.getKey() && root1.getValue() == root1.getValue() && - checkNodeEquals(root1.getLeftNode(), root2.getLeftNode()) && - checkNodeEquals(root1.getRightNode(), root2.getRightNode()) + return root1.key == root2.key && root1.value == root1.value && + checkNodeEquals(root1.leftNode, root2.leftNode) && + checkNodeEquals(root1.rightNode, root2.rightNode) } @@ -28,18 +28,18 @@ object BSTreeUtil { val leftSubTestBSTree: BSTree = BSTree() leftSubTestBSTree.root = BSNode(-2, 2) val leftSubTestBSTreeRoot = leftSubTestBSTree.root!! - leftSubTestBSTreeRoot.setLeftNode(BSNode(-3, 5)) - leftSubTestBSTreeRoot.setRightNode(BSNode(-1, 6)) + leftSubTestBSTreeRoot.leftNode = BSNode(-3, 5) + leftSubTestBSTreeRoot.rightNode = BSNode(-1, 6) val rightSubTestBSTree: BSTree = BSTree() rightSubTestBSTree.root = BSNode(2, 3) val rightSubTestBSTreeRoot = rightSubTestBSTree.root!! - rightSubTestBSTreeRoot.setLeftNode(BSNode(1, 7)) - rightSubTestBSTreeRoot.setRightNode(BSNode(3, 8)) + rightSubTestBSTreeRoot.leftNode = BSNode(1, 7) + rightSubTestBSTreeRoot.rightNode = BSNode(3, 8) - testBSTreeRoot.setLeftNode(leftSubTestBSTreeRoot) - testBSTreeRoot.setRightNode(rightSubTestBSTreeRoot) + testBSTreeRoot.leftNode = leftSubTestBSTreeRoot + testBSTreeRoot.rightNode = rightSubTestBSTreeRoot return testBSTree } @@ -49,17 +49,17 @@ object BSTreeUtil { leftRotatedTestBSTree.root = BSNode(2, 3) val leftRotatedTestBSTreeRoot = leftRotatedTestBSTree.root!! - leftRotatedTestBSTreeRoot.setRightNode(BSNode(3, 8)) - leftRotatedTestBSTreeRoot.setLeftNode(BSNode(0, 0)) + leftRotatedTestBSTreeRoot.rightNode = BSNode(3, 8) + leftRotatedTestBSTreeRoot.leftNode = BSNode(0, 0) val leftRotatedSubTestBSTree: BSTree = BSTree() leftRotatedSubTestBSTree.root = BSNode(-2, 2) val leftRotatedSubTestBSTreeRoot = leftRotatedSubTestBSTree.root!! - leftRotatedSubTestBSTreeRoot.setLeftNode(BSNode(-3, 5)) - leftRotatedSubTestBSTreeRoot.setRightNode(BSNode(-1, 6)) + leftRotatedSubTestBSTreeRoot.leftNode = BSNode(-3, 5) + leftRotatedSubTestBSTreeRoot.rightNode = BSNode(-1, 6) - leftRotatedTestBSTreeRoot.getLeftNode()?.setRightNode(BSNode(1, 7)) - leftRotatedTestBSTreeRoot.getLeftNode()?.setLeftNode(leftRotatedSubTestBSTreeRoot) + leftRotatedTestBSTreeRoot.leftNode?.rightNode = BSNode(1, 7) + leftRotatedTestBSTreeRoot.leftNode?.leftNode = leftRotatedSubTestBSTreeRoot return leftRotatedTestBSTree } @@ -69,17 +69,17 @@ object BSTreeUtil { rightRotatedTestBSTree.root = BSNode(-2, 2) val rightRotatedTestBSTreeRoot = rightRotatedTestBSTree.root!! - rightRotatedTestBSTreeRoot.setLeftNode(BSNode(-3, 5)) - rightRotatedTestBSTreeRoot.setRightNode(BSNode(0, 0)) + rightRotatedTestBSTreeRoot.leftNode = BSNode(-3, 5) + rightRotatedTestBSTreeRoot.rightNode = BSNode(0, 0) val rightRotatedSubTestBSTree: BSTree = BSTree() rightRotatedSubTestBSTree.root = BSNode(2, 3) val rightRotatedSubTestBSTreeRoot = rightRotatedSubTestBSTree.root!! - rightRotatedSubTestBSTreeRoot.setLeftNode(BSNode(1, 7)) - rightRotatedSubTestBSTreeRoot.setRightNode(BSNode(3, 8)) + rightRotatedSubTestBSTreeRoot.leftNode = BSNode(1, 7) + rightRotatedSubTestBSTreeRoot.rightNode = BSNode(3, 8) - rightRotatedTestBSTreeRoot.getRightNode()?.setLeftNode(BSNode(-1, 6)) - rightRotatedTestBSTreeRoot.getRightNode()?.setRightNode(rightRotatedSubTestBSTreeRoot) + rightRotatedTestBSTreeRoot.rightNode?.leftNode = BSNode(-1, 6) + rightRotatedTestBSTreeRoot.rightNode?.rightNode = rightRotatedSubTestBSTreeRoot return rightRotatedTestBSTree } From 57a0a2ddf28371455626acb2a48e046d67f92194 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 24 Apr 2023 04:43:17 +0300 Subject: [PATCH 072/135] feat: Added a lot of comments to abstract classes and to AVL classes --- BSTrees/src/main/kotlin/BTree.kt | 30 ++++++- BSTrees/src/main/kotlin/Balancer.kt | 23 +++++ BSTrees/src/main/kotlin/Node.kt | 28 +++++- .../src/main/kotlin/avlTree/AvlBalancer.kt | 32 ++++++- BSTrees/src/main/kotlin/avlTree/AvlTree.kt | 88 ++++++++++++++++--- 5 files changed, 183 insertions(+), 18 deletions(-) diff --git a/BSTrees/src/main/kotlin/BTree.kt b/BSTrees/src/main/kotlin/BTree.kt index 58bab8e..2a4ac3b 100644 --- a/BSTrees/src/main/kotlin/BTree.kt +++ b/BSTrees/src/main/kotlin/BTree.kt @@ -1,8 +1,31 @@ +/** + * An abstract class representing a binary search tree. + * + * @generic the type of key stored in the tree. It must be comparable + * @generic the type of value stored in the tree + * @generic the type of node used in the tree + */ abstract class BTree, V, NODE_TYPE : Node> { + /** + * The root node of the tree. + */ + var root: NODE_TYPE? = null + internal set - internal var root: NODE_TYPE? = null + /** + * Insert a node to the tree. + * + * @param value the value to add + * @param key the key under which the value is stored + */ abstract fun insert(key: K, value: V) + /** + * Looking for a value in the tree by its key. + * + * @param key the key by which the search is performed + * @return value if it is in the tree, false otherwise + */ fun find(key: K): V? { var temp: NODE_TYPE? = root ?: return null while (temp != null) { @@ -16,5 +39,10 @@ abstract class BTree, V, NODE_TYPE : Node> { return null } + /** + * Delete a value from the tree. + * + * @param key the key under which the value is stored + */ abstract fun delete(key: K) } diff --git a/BSTrees/src/main/kotlin/Balancer.kt b/BSTrees/src/main/kotlin/Balancer.kt index 4d9f607..ae28458 100644 --- a/BSTrees/src/main/kotlin/Balancer.kt +++ b/BSTrees/src/main/kotlin/Balancer.kt @@ -1,8 +1,23 @@ +/** + * An abstract class representing a binary search tree. + * + * @generic the type of key stored in the tree. It must be comparable + * @generic the type of value stored in the tree + * @generic the type of node used in the tree + */ abstract class Balancer, V, NODE_TYPE : Node> { + /** + * Do a left rotate around this node + * + * @param node the node around which the rotation is done + */ protected fun leftRotate(node: NODE_TYPE): NODE_TYPE { + val nodeParent = node.parent val temp = node.rightNode + temp?.parent = nodeParent + //We should change parent's son. It depends on what son is our node if (nodeParent?.leftNode == node) nodeParent.leftNode = temp else nodeParent?.rightNode = temp node.rightNode = temp?.leftNode @@ -14,10 +29,18 @@ abstract class Balancer, V, NODE_TYPE : Node> return temp ?: node } + /** + * Do a right rotate around this node + * + * @param node the node around which the rotation is done + */ protected fun rightRotate(node: NODE_TYPE): NODE_TYPE { + val nodeParent = node.parent val temp = node.leftNode + temp?.parent = nodeParent + //We should change parent's son. It depends on what son is our node if (nodeParent?.leftNode == node) nodeParent.leftNode = temp else nodeParent?.rightNode = temp node.leftNode = temp?.rightNode diff --git a/BSTrees/src/main/kotlin/Node.kt b/BSTrees/src/main/kotlin/Node.kt index c588115..471446d 100644 --- a/BSTrees/src/main/kotlin/Node.kt +++ b/BSTrees/src/main/kotlin/Node.kt @@ -1,5 +1,27 @@ +/** + * An abstract class representing a binary search tree node. + * It's constructed with key and value and contains parent, left and right sons + * + * @generic the type of key stored in the tree. It must be comparable + * @generic the type of value stored in the tree + * @generic the type of node used in the tree + */ abstract class Node, V, NODE_TYPE : Node>(val key: K, var value: V) { - internal var parent: NODE_TYPE? = null - internal var leftNode: NODE_TYPE? = null - internal var rightNode: NODE_TYPE? = null + /** + * The parent of the node + */ + var parent: NODE_TYPE? = null + internal set + + /** + * The left son of the node + */ + var leftNode: NODE_TYPE? = null + internal set + + /** + * The right son of the node + */ + var rightNode: NODE_TYPE? = null + internal set } diff --git a/BSTrees/src/main/kotlin/avlTree/AvlBalancer.kt b/BSTrees/src/main/kotlin/avlTree/AvlBalancer.kt index 2c04ee2..32a0466 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlBalancer.kt +++ b/BSTrees/src/main/kotlin/avlTree/AvlBalancer.kt @@ -2,13 +2,29 @@ package avlTree import Balancer - +/** + * A class representing an AVL binary search tree balancer. + * Provides all the necessary functions for balancing the tree + * + * @generic the type of key stored in the tree. It must be comparable + * @generic the type of value stored in the tree + */ internal class AvlBalancer, V> : Balancer>() { + /** + * Provides information about the need for balancing by calculating the imbalance of the tree + * + * @param node node that has been checked + */ private fun balanceFactor(node: AvlNode): Int { return (node.rightNode?.height ?: 0) - (node.leftNode?.height ?: 0) } + /** + * Do a right rotate around this node with updating height + * + * @param node the node around which the rotation is done + */ private fun avlRightRotate(node: AvlNode): AvlNode { val temp = rightRotate(node) temp.leftNode?.updateHeight() @@ -17,6 +33,11 @@ internal class AvlBalancer, V> : Balancer> return temp } + /** + * Do a left rotate around this node with updating height + * + * @param node the node around which the rotation is done + */ private fun avlLeftRotate(node: AvlNode): AvlNode { val temp = leftRotate(node) temp.leftNode?.updateHeight() @@ -25,6 +46,11 @@ internal class AvlBalancer, V> : Balancer> return temp } + /** + * Balance current node + * + * @param node node that are balanced + */ internal fun balance(node: AvlNode): AvlNode { node.updateHeight() @@ -35,7 +61,7 @@ internal class AvlBalancer, V> : Balancer> val temp = node.rightNode if (temp != null) { if (balanceFactor(temp) < 0) { - node.rightNode = avlRightRotate(temp) + node.rightNode = avlRightRotate(temp)//big left rotate } } @@ -47,7 +73,7 @@ internal class AvlBalancer, V> : Balancer> val temp = node.leftNode if (temp != null) { if (balanceFactor(temp) > 0) { - node.leftNode = avlLeftRotate(temp) + node.leftNode = avlLeftRotate(temp)//big right rotate } } diff --git a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt index b005906..6ef1e95 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt +++ b/BSTrees/src/main/kotlin/avlTree/AvlTree.kt @@ -2,20 +2,48 @@ package avlTree import BTree +/** + * A class representing an AVL binary search tree. + * It maintains balance by checking heights of right and left sons. It has to differ by no more than one + * + * @generic the type of key stored in the tree. It must be comparable + * @generic the type of value stored in the tree + */ class AvlTree, V> : BTree>() { + /** + * A balancer class providing balancing of the curr node of the tree + */ private val balancer = AvlBalancer() + /** + * Insert a node to the tree. + * It is actually a wrapper for the add function. Necessary to implement recursion + * + * @param value the value to add + * @param key the key under which the value is stored + */ override fun insert(key: K, value: V) { add(AvlNode(key, value)) } + /** + * Add a node to the tree + * + * @param node the node to add + */ private fun add(node: AvlNode) { + //temp is needed to avoid possibility of changing the root val temp = this.root if (temp == null) this.root = node else if (temp.key == node.key) this.root?.value = node.value else { + /** + * Some kind of recursive implementation + * Creating subtree to execute add function again + * Then we return the node to the desired son + */ val subTree = AvlTree() if (node.key < temp.key) { @@ -32,17 +60,33 @@ class AvlTree, V> : BTree>() { } + //Balancing this node before leaving recursion this.root = this.root?.let { balancer.balance(it) } } + /** + * Find a node with a minimum key in a tree + * It is an auxiliary function for the delete function + * + * @param node the root of the tree where to find the minimum node + */ private fun findMin(node: AvlNode): AvlNode { + //temp is needed to avoid possibility of changing the root val temp = node.leftNode return if (temp != null) findMin(temp) else node } + /** + * Find a node with a minimum key in a tree and delete it. + * It is an auxiliary function for the delete function + * + * @param node the root of the tree where to remove the minimum node + */ private fun removeMin(node: AvlNode): AvlNode? { + //temp is needed to avoid possibility of changing the root val temp = node.leftNode if (temp == null) return node.rightNode + val tempRemovedMin = removeMin(temp) node.leftNode = tempRemovedMin tempRemovedMin?.parent = node @@ -50,11 +94,15 @@ class AvlTree, V> : BTree>() { } override fun delete(key: K) { - + //temp is needed to avoid possibility of changing the root val temp = this.root if (temp != null) { - + /** + * Some kind of recursive implementation + * Creating subtree to execute delete function again + * Then we return the node to the desired son + */ val subTree = AvlTree() if (key < temp.key) { @@ -72,27 +120,45 @@ class AvlTree, V> : BTree>() { this.root?.rightNode = subTree.root } else { + //The left and right sons of the node being deleted + val left = this.root?.leftNode + val right = this.root?.rightNode - val leftNode = this.root?.leftNode - val rightNode = this.root?.rightNode - - if (rightNode == null) { - leftNode?.parent = this.root?.parent - this.root = leftNode + if (right == null) { + left?.parent = this.root?.parent + this.root = left } else { - val tempMin: AvlNode = findMin(rightNode) - tempMin.rightNode = removeMin(rightNode) + /** + * Temp is needed to avoid possibility of changing the root + * + * Finding the minimum node and giving her the correct links to the sons and the parent + */ + val tempMin = findMin(right) + tempMin.rightNode = removeMin(right) tempMin.rightNode?.parent = tempMin - tempMin.leftNode = leftNode + tempMin.leftNode = left tempMin.leftNode?.parent = tempMin + + /** + * Giving correct links to the new node for the parent + * The son recognizes the parent, but the parent of the son does not + */ if (this.root?.parent?.leftNode == this.root) this.root?.parent?.leftNode = tempMin else this.root?.parent?.rightNode = tempMin + tempMin.parent = this.root?.parent + /** + * Balancing th new node + * + * Everything at the bottom is already balanced, + * because it was done coming out of recursion + */ this.root = balancer.balance(tempMin) } } + //Balancing this node before leaving recursion val nullCheck = this.root if (nullCheck != null) this.root = balancer.balance(nullCheck) From 2c57bf4078717a41f661056f494d5a9d9621507b Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 24 Apr 2023 11:11:31 +0300 Subject: [PATCH 073/135] feat: Added Neo4jTreeRepo implementation and renamed some variables --- BSTrees/build.gradle.kts | 3 + .../kotlin/serialization/SerializableType.kt | 2 +- .../kotlin/serialization/reps/DBTreeRepo.kt | 4 +- .../kotlin/serialization/reps/JsonTreeRepo.kt | 10 +- .../serialization/reps/Neo4jTreeRepo.kt | 146 ++++++++++++++++++ .../kotlin/serialization/reps/SQLTables.kt | 8 +- .../kotlin/serialization/reps/SQLTreeRepo.kt | 17 +- gradle.properties | 3 +- 8 files changed, 171 insertions(+), 22 deletions(-) create mode 100644 BSTrees/src/main/kotlin/serialization/reps/Neo4jTreeRepo.kt diff --git a/BSTrees/build.gradle.kts b/BSTrees/build.gradle.kts index e1dec89..ef70972 100644 --- a/BSTrees/build.gradle.kts +++ b/BSTrees/build.gradle.kts @@ -2,6 +2,7 @@ val jetbrainsExposedVersion: String? by rootProject val junit5Version: String? by rootProject val gsonVersion: String? by rootProject val kotlinxSerializationVersion: String? by rootProject +val neo4jDriverVersion: String? by project plugins { id("org.jetbrains.kotlin.jvm") version "1.8.20" @@ -20,6 +21,8 @@ dependencies { implementation("com.google.code.gson:gson:$gsonVersion") + implementation("org.neo4j.driver:neo4j-java-driver:$neo4jDriverVersion") + implementation("org.jetbrains.exposed:exposed-core:$jetbrainsExposedVersion") implementation("org.jetbrains.exposed:exposed-jdbc:$jetbrainsExposedVersion") implementation("org.jetbrains.exposed:exposed-dao:$jetbrainsExposedVersion") diff --git a/BSTrees/src/main/kotlin/serialization/SerializableType.kt b/BSTrees/src/main/kotlin/serialization/SerializableType.kt index 52292a5..75256d4 100644 --- a/BSTrees/src/main/kotlin/serialization/SerializableType.kt +++ b/BSTrees/src/main/kotlin/serialization/SerializableType.kt @@ -5,7 +5,7 @@ import kotlinx.serialization.Serializable @Serializable class SerializableTree( val name: String, - val typeOfTree: String, + val treeType: String, val root: SerializableNode? ) diff --git a/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt index 70cf9bb..59b2a9b 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt @@ -3,9 +3,9 @@ package serialization.reps import serialization.SerializableTree interface DBTreeRepo { - fun getTree(typeTree: String, treeName: String): SerializableTree? + fun getTree(treeType: String, treeName: String): SerializableTree? fun setTree(serializableTree: SerializableTree) - fun deleteTree(typeTree: String, treeName: String) + fun deleteTree(treeType: String, treeName: String) } \ No newline at end of file diff --git a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt index 3177e9d..88a3f9c 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt @@ -23,10 +23,10 @@ object JsonTreeRepo : DBTreeRepo { return Path("JSONTreeRep", typeTree, "${treeName}.json").toString() } - override fun getTree(typeTree: String, treeName: String): SerializableTree? { + override fun getTree(treeType: String, treeName: String): SerializableTree? { createDirPaths() - val filePath = getPathToFile(typeTree, treeName) + val filePath = getPathToFile(treeType, treeName) lateinit var file: FileReader var fileFound = true @@ -50,7 +50,7 @@ object JsonTreeRepo : DBTreeRepo { override fun setTree(serializableTree: SerializableTree) { createDirPaths() - val filePath = getPathToFile(serializableTree.typeOfTree, serializableTree.name) + val filePath = getPathToFile(serializableTree.treeType, serializableTree.name) lateinit var file: FileWriter try { @@ -64,10 +64,10 @@ object JsonTreeRepo : DBTreeRepo { } } - override fun deleteTree(typeTree: String, treeName: String) { + override fun deleteTree(treeType: String, treeName: String) { createDirPaths() - val path = getPathToFile(typeTree, treeName) + val path = getPathToFile(treeType, treeName) try { File(path).delete() diff --git a/BSTrees/src/main/kotlin/serialization/reps/Neo4jTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/Neo4jTreeRepo.kt new file mode 100644 index 0000000..c832cd0 --- /dev/null +++ b/BSTrees/src/main/kotlin/serialization/reps/Neo4jTreeRepo.kt @@ -0,0 +1,146 @@ +package serialization.reps + +import org.neo4j.driver.AuthTokens +import org.neo4j.driver.GraphDatabase +import org.neo4j.driver.TransactionContext +import serialization.SerializableNode +import serialization.SerializableTree +import java.io.Closeable + +object Neo4jTreeRepo : Closeable, DBTreeRepo { + private val driver = GraphDatabase.driver("bolt://localhost:7687", AuthTokens.basic("neo4j", "qwertyui")) + private val session = driver.session() + + override fun getTree(treeType: String, treeName: String): SerializableTree? { + var serializableTree: SerializableTree? = null + + session.executeRead { tx -> + val resultRootKey = tx.run( + "MATCH (tree:Tree {name: \$name, type: \$type})" + + "WITH tree MATCH (tree)-[:root]->(root) RETURN root.key AS key", + mutableMapOf( + "name" to treeName, + "type" to treeType, + ) as Map? + ) + if (resultRootKey.hasNext()) { + val info: Map = resultRootKey.next().asMap() + serializableTree = SerializableTree( + treeName, + treeType, + getSerializedNodes(tx, info["key"].toString()) + ) + } + } + + return serializableTree + } + + + private fun getSerializedNodes(tx: TransactionContext, nodeKey: String): SerializableNode? { + var nodeData = mapOf() + var leftSonKey = mapOf() + var rightSonKey = mapOf() + + val resultNodeData = tx.run( + "MATCH (node:Node {key: $nodeKey}) RETURN node.key AS key, node.value AS value, node.metadata AS metadata " + ) + val resultLeftSonKey = tx.run( + "MATCH (node:Node {key: $nodeKey}) MATCH (node)-[:leftSon]->(leftSon) RETURN leftSon.key as key " + ) + val resultRightSonKey = tx.run( + "MATCH (node:Node {key: $nodeKey}) MATCH (node)-[:rightSon]->(rightSon) RETURN rightSon.key as key " + ) + + if (resultNodeData.hasNext()) { + nodeData = resultNodeData.next().asMap() + } + if (resultLeftSonKey.hasNext()) { + leftSonKey = resultLeftSonKey.next().asMap() + } + if (resultRightSonKey.hasNext()) { + rightSonKey = resultRightSonKey.next().asMap() + } + + if (nodeData.isEmpty()) return null + return SerializableNode( + nodeData["key"].toString(), + nodeData["value"].toString(), + nodeData["metadata"].toString(), + getSerializedNodes(tx, leftSonKey["key"].toString()), + getSerializedNodes(tx, rightSonKey["key"].toString()), + ) + } + + override fun setTree(serializableTree: SerializableTree) { + + deleteTree(serializableTree.treeType, serializableTree.name) + + session.executeWrite { tx -> + tx.run( + "CREATE (:Tree {name: \$name, type: \$type})", + mutableMapOf( + "name" to serializableTree.name, + "type" to serializableTree.treeType, + ) as Map? + ) + + serializableTree.root?.let { root -> + setNeo4jNodes(tx, root) + tx.run( + "MATCH (tree: Tree {name: \$name, type: \$type})" + + "MATCH (node: NewNode {key: ${root.key} })" + + "CREATE (tree)-[:root]->(node)" + + "REMOVE node:NewNode", + mutableMapOf( + "name" to serializableTree.name, + "type" to serializableTree.treeType, + ) as Map? + ) + } + } + } + + private fun setNeo4jNodes(tx: TransactionContext, node: SerializableNode) { + tx.run( + "CREATE (:Node:NewNode {key: ${node.key}, value: ${node.value}, metadata: ${node.metadata} })" + ) + node.leftNode?.let { leftNode -> + setNeo4jNodes(tx, leftNode) + tx.run( + "MATCH (node: NewNode {key: ${node.key}})" + + "MATCH (leftSon: NewNode {key: ${leftNode.key}})" + + "CREATE (node)-[:leftSon]->(leftSon)" + + "REMOVE leftSon:NewNode" + ) + } + node.rightNode?.let { rightNode -> + setNeo4jNodes(tx, rightNode) + tx.run( + "MATCH (node: NewNode {key: ${node.key}})" + + "MATCH (rightSon: NewNode {key: ${rightNode.key}})" + + "CREATE (node)-[:rightSon]->(rightSon)" + + "REMOVE rightSon:NewNode" + ) + } + } + + override fun deleteTree(treeType: String, treeName: String) { + session.executeWrite { tx -> + tx.run( + "MATCH (tree: Tree {name: \$name, type: \$type})" + + "MATCH (tree)-[*]->(node:Node) " + + "DETACH DELETE tree, node", + mutableMapOf( + "name" to treeName, + "type" to treeType, + ) as Map? + ) + } + } + + override fun close() { + session.close() + driver.close() + } +} \ No newline at end of file diff --git a/BSTrees/src/main/kotlin/serialization/reps/SQLTables.kt b/BSTrees/src/main/kotlin/serialization/reps/SQLTables.kt index c46bab5..7cbb1bb 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/SQLTables.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/SQLTables.kt @@ -8,16 +8,16 @@ import org.jetbrains.exposed.sql.ReferenceOption object TreesTable : IntIdTable() { - val nameTree = varchar("nameTree", 20).uniqueIndex().default("") - val typeTree = varchar("typeTree", 20).default("") + val treeName = varchar("nameTree", 20).uniqueIndex().default("") + val treeType = varchar("typeTree", 20).default("") val root = reference("root", NodesTable).nullable() } class TreeEntity(id: EntityID): IntEntity(id) { companion object : IntEntityClass(TreesTable) - var nameTree by TreesTable.nameTree - var typeTree by TreesTable.typeTree + var treeName by TreesTable.treeName + var treeType by TreesTable.treeType var root by NodeEntity optionalReferencedOn TreesTable.root } diff --git a/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt index bad04fd..a4a7f42 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt @@ -10,7 +10,6 @@ import java.io.File object SQLTreeRepo: DBTreeRepo{ - private fun connectDB(dbName: String) { Database.connect("jdbc:sqlite:${File(dbName)}", "org.sqlite.JDBC") } @@ -22,10 +21,10 @@ object SQLTreeRepo: DBTreeRepo{ } } - override fun deleteTree(typeTree: String, treeName: String) { + override fun deleteTree(treeType: String, treeName: String) { transaction { val treeEntity = - TreeEntity.find { (TreesTable.nameTree eq treeName) and (TreesTable.typeTree eq typeTree) } + TreeEntity.find { (TreesTable.treeName eq treeName) and (TreesTable.treeType eq treeType) } .firstOrNull() treeEntity?.let{ NodeEntity.find(NodesTable.tree eq treeEntity.id).forEach { it.delete() } } @@ -38,12 +37,12 @@ object SQLTreeRepo: DBTreeRepo{ connectDB("SQLTreeDB") createTables() - deleteTree(serializableTree.typeOfTree, serializableTree.name) + deleteTree(serializableTree.treeType, serializableTree.name) transaction { val newTree = TreeEntity.new { - nameTree=serializableTree.name - typeTree=serializableTree.typeOfTree + treeName=serializableTree.name + treeType=serializableTree.treeType } newTree.root = serializableTree.root?.toNodeEntity(newTree) @@ -61,16 +60,16 @@ object SQLTreeRepo: DBTreeRepo{ } } - override fun getTree(typeTree: String, treeName: String): SerializableTree? { + override fun getTree(treeType: String, treeName: String): SerializableTree? { //TODO: Create a config file in which dbName will be written connectDB("SQLTreeDB") createTables() - val treeEntity = TreeEntity.find { (TreesTable.nameTree eq treeName) and (TreesTable.typeTree eq typeTree) }.firstOrNull() ?: return null + val treeEntity = TreeEntity.find { (TreesTable.treeName eq treeName) and (TreesTable.treeType eq treeType) }.firstOrNull() ?: return null return SerializableTree( treeName, - treeEntity.typeTree, + treeEntity.treeType, treeEntity.root?.toSerializableEntity(treeEntity) ) } diff --git a/gradle.properties b/gradle.properties index 0c1ab02..787e190 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,5 @@ junit5Version=5.9.1 jetbrainsExposedVersion=0.38.1 gsonVersion=2.8.5 -kotlinxSerializationVersion=1.5.0 \ No newline at end of file +kotlinxSerializationVersion=1.5.0 +neo4jDriverVersion=5.6.0 \ No newline at end of file From f84201e72cec2e2d208213f8be774f7d492fad63 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 24 Apr 2023 14:26:50 +0300 Subject: [PATCH 074/135] feat: Added logging of databases --- BSTrees/build.gradle.kts | 4 + .../kotlin/serialization/reps/JsonTreeRepo.kt | 11 +++ .../serialization/reps/Neo4jTreeRepo.kt | 11 +++ .../kotlin/serialization/reps/SQLTreeRepo.kt | 89 ++++++++++++------- 4 files changed, 85 insertions(+), 30 deletions(-) diff --git a/BSTrees/build.gradle.kts b/BSTrees/build.gradle.kts index ef70972..5c02e08 100644 --- a/BSTrees/build.gradle.kts +++ b/BSTrees/build.gradle.kts @@ -26,6 +26,10 @@ dependencies { implementation("org.jetbrains.exposed:exposed-core:$jetbrainsExposedVersion") implementation("org.jetbrains.exposed:exposed-jdbc:$jetbrainsExposedVersion") implementation("org.jetbrains.exposed:exposed-dao:$jetbrainsExposedVersion") + implementation("org.xerial:sqlite-jdbc:3.34.0") + + implementation("io.github.microutils", "kotlin-logging-jvm", "2.0.6") + implementation("org.slf4j", "slf4j-simple", "1.7.29") testImplementation("org.junit.jupiter:junit-jupiter-engine:$junit5Version") testImplementation("org.junit.jupiter:junit-jupiter-params:$junit5Version") diff --git a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt index 88a3f9c..77621f4 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt @@ -4,12 +4,14 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import serialization.SerializableTree import kotlinx.serialization.encodeToString +import mu.KotlinLogging import java.io.File import java.io.FileNotFoundException import java.io.FileReader import java.io.FileWriter import kotlin.io.path.Path +private val logger = KotlinLogging.logger { } object JsonTreeRepo : DBTreeRepo { private fun createDirPaths() { @@ -17,6 +19,8 @@ object JsonTreeRepo : DBTreeRepo { File(Path("JSONTreeRep", "BSTree").toUri()).mkdir() File(Path("JSONTreeRep", "RBTree").toUri()).mkdir() File(Path("JSONTreeRep", "AvlTree").toUri()).mkdir() + + logger.info { "[JSON] Dir paths was created" } } private fun getPathToFile(typeTree: String, treeName: String): String { @@ -36,13 +40,16 @@ object JsonTreeRepo : DBTreeRepo { Json.decodeFromString(jsonText) } catch (e: FileNotFoundException) { + logger.warn { "[JSON] Tree file not found"} fileFound = false null } catch (e: Exception) { + logger.error { "[JSON] Error getting the tree: $e" } throw e } finally { if (fileFound) { file.close() + logger.info { "[JSON] Got tree - treeName: $treeName, treeType: $treeType" } } } } @@ -57,11 +64,13 @@ object JsonTreeRepo : DBTreeRepo { file = FileWriter(filePath) file.write(Json.encodeToString(serializableTree)) } catch (e: Exception) { + logger.error { "[JSON] Error getting the tree: $e" } throw e } finally { file.flush() file.close() } + logger.info { "[JSON] Set tree - treeName: ${serializableTree.name}, treeType: ${serializableTree.treeType}" } } override fun deleteTree(treeType: String, treeName: String) { @@ -72,7 +81,9 @@ object JsonTreeRepo : DBTreeRepo { try { File(path).delete() } catch (e: Exception) { + logger.error { "[JSON] Error getting the tree: $e" } throw e } + logger.info { "[JSON] Deleted tree - treeName: $treeName, treeType: $treeType" } } } \ No newline at end of file diff --git a/BSTrees/src/main/kotlin/serialization/reps/Neo4jTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/Neo4jTreeRepo.kt index c832cd0..6b58009 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/Neo4jTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/Neo4jTreeRepo.kt @@ -1,5 +1,6 @@ package serialization.reps +import mu.KotlinLogging import org.neo4j.driver.AuthTokens import org.neo4j.driver.GraphDatabase import org.neo4j.driver.TransactionContext @@ -7,6 +8,8 @@ import serialization.SerializableNode import serialization.SerializableTree import java.io.Closeable +private val logger = KotlinLogging.logger { } + object Neo4jTreeRepo : Closeable, DBTreeRepo { private val driver = GraphDatabase.driver("bolt://localhost:7687", AuthTokens.basic("neo4j", "qwertyui")) private val session = driver.session() @@ -33,6 +36,8 @@ object Neo4jTreeRepo : Closeable, DBTreeRepo { } } + logger.info { "[NEO4J] Got tree - treeName: $treeName, treeType: $treeType" } + return serializableTree } @@ -99,6 +104,8 @@ object Neo4jTreeRepo : Closeable, DBTreeRepo { ) } } + + logger.info { "[NEO4J] Set tree - treeName: ${serializableTree.name}, treeType: ${serializableTree.treeType}" } } private fun setNeo4jNodes(tx: TransactionContext, node: SerializableNode) { @@ -137,10 +144,14 @@ object Neo4jTreeRepo : Closeable, DBTreeRepo { ) as Map? ) } + + logger.info { "[NEO4J] Deleted tree - treeName: $treeName, treeType: $treeType" } } override fun close() { session.close() driver.close() + + logger.info { "[NEO4J] The connection to the database is finished" } } } \ No newline at end of file diff --git a/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt index a4a7f42..a9b9145 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt @@ -1,5 +1,6 @@ package serialization.reps +import mu.KotlinLogging import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq @@ -8,28 +9,65 @@ import org.jetbrains.exposed.sql.transactions.transaction import serialization.* import java.io.File -object SQLTreeRepo: DBTreeRepo{ +private val logger = KotlinLogging.logger { } + +object SQLTreeRepo : DBTreeRepo { private fun connectDB(dbName: String) { Database.connect("jdbc:sqlite:${File(dbName)}", "org.sqlite.JDBC") + + logger.info { "[SQLite] The connection to the database is established" } } - private fun createTables(){ + private fun createTables() { transaction { SchemaUtils.create(TreesTable) SchemaUtils.create(NodesTable) } + + logger.info { "[SQLite] Database tables have been created successfully" } } - override fun deleteTree(treeType: String, treeName: String) { + override fun getTree(treeType: String, treeName: String): SerializableTree? { + //TODO: Create a config file in which dbName will be written + connectDB("SQLTreeDB") + createTables() + + var treeEntity: TreeEntity? = null transaction { - val treeEntity = - TreeEntity.find { (TreesTable.treeName eq treeName) and (TreesTable.treeType eq treeType) } - .firstOrNull() - treeEntity?.let{ NodeEntity.find(NodesTable.tree eq treeEntity.id).forEach { it.delete() } } + treeEntity = TreeEntity.find { (TreesTable.treeName eq treeName) and (TreesTable.treeType eq treeType) } + .firstOrNull() + } - treeEntity?.delete() + if (treeEntity == null) { + logger.info { "[SQLite] Tree not found - treeName: $treeName, treeType: $treeType" } + return null } + + var serializableTree: SerializableTree? = null + transaction { + treeEntity?.let { tree -> + serializableTree = SerializableTree( + treeName, + tree.treeType, + tree.root?.toSerializableEntity(tree) + ) + } + } + + logger.info { "[SQLite] Got tree - treeName: $treeName, treeType: $treeType" } + + return serializableTree + } + + private fun NodeEntity.toSerializableEntity(treeEntity: TreeEntity): SerializableNode { + return SerializableNode( + this@toSerializableEntity.key, + this@toSerializableEntity.value, + this@toSerializableEntity.metadata, + this@toSerializableEntity.leftNode?.toSerializableEntity(treeEntity), + this@toSerializableEntity.rightNode?.toSerializableEntity(treeEntity), + ) } override fun setTree(serializableTree: SerializableTree) { @@ -41,12 +79,14 @@ object SQLTreeRepo: DBTreeRepo{ transaction { val newTree = TreeEntity.new { - treeName=serializableTree.name - treeType=serializableTree.treeType + treeName = serializableTree.name + treeType = serializableTree.treeType } newTree.root = serializableTree.root?.toNodeEntity(newTree) } + + logger.info { "[SQLite] Set tree - treeName: ${serializableTree.name}, treeType: ${serializableTree.treeType}" } } private fun SerializableNode.toNodeEntity(treeEntity: TreeEntity): NodeEntity { @@ -60,27 +100,16 @@ object SQLTreeRepo: DBTreeRepo{ } } - override fun getTree(treeType: String, treeName: String): SerializableTree? { - //TODO: Create a config file in which dbName will be written - connectDB("SQLTreeDB") - createTables() - - val treeEntity = TreeEntity.find { (TreesTable.treeName eq treeName) and (TreesTable.treeType eq treeType) }.firstOrNull() ?: return null + override fun deleteTree(treeType: String, treeName: String) { + transaction { + val treeEntity = + TreeEntity.find { (TreesTable.treeName eq treeName) and (TreesTable.treeType eq treeType) } + .firstOrNull() + treeEntity?.let { NodeEntity.find(NodesTable.tree eq treeEntity.id).forEach { it.delete() } } - return SerializableTree( - treeName, - treeEntity.treeType, - treeEntity.root?.toSerializableEntity(treeEntity) - ) - } + treeEntity?.delete() + } - private fun NodeEntity.toSerializableEntity(treeEntity: TreeEntity): SerializableNode { - return SerializableNode( - this@toSerializableEntity.key, - this@toSerializableEntity.value, - this@toSerializableEntity.metadata, - this@toSerializableEntity.leftNode?.toSerializableEntity(treeEntity), - this@toSerializableEntity.rightNode?.toSerializableEntity(treeEntity), - ) + logger.info { "[SQLite] Deleted tree - treeName: $treeName, treeType: $treeType" } } } \ No newline at end of file From 25262e63c067ea2707efaf12bd97d7fde133f1f9 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 24 Apr 2023 19:11:37 +0300 Subject: [PATCH 075/135] feat: Added config files for neo4j --- CONTAINER.conf | 3 +++ neo4j_up.sh | 12 ++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 CONTAINER.conf create mode 100755 neo4j_up.sh diff --git a/CONTAINER.conf b/CONTAINER.conf new file mode 100644 index 0000000..6c88181 --- /dev/null +++ b/CONTAINER.conf @@ -0,0 +1,3 @@ +CONTAINER_NAME=neo4j-db +PASSWORD="qwertyui" +EXAMPLE_DIR="/example" diff --git a/neo4j_up.sh b/neo4j_up.sh new file mode 100755 index 0000000..dbf552b --- /dev/null +++ b/neo4j_up.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +BASEDIR=$(realpath "$(dirname "$0")") + +. "${BASEDIR}/CONTAINER.conf" + +docker run \ + --rm \ + --name "$CONTAINER_NAME" \ + --publish=7474:7474 --publish=7687:7687 \ + --env NEO4J_AUTH=neo4j/"$PASSWORD" \ + neo4j:latest From fabc86cb2f07a89d6aa8aba8efb2dc4f12e7bb27 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 24 Apr 2023 19:12:31 +0300 Subject: [PATCH 076/135] feat: DB files added to .gitignore --- .gitignore | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index d736a56..198fc2f 100644 --- a/.gitignore +++ b/.gitignore @@ -26,5 +26,6 @@ build/ *.DS_Store .AppleDouble -# Ignore Gradle build output directory -build +# db files +*.json +*/SQLTreeDB From becf0efe090996c549aa1bee5ba8ef9e2156ab65 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 24 Apr 2023 21:09:41 +0300 Subject: [PATCH 077/135] feat: db objects -> db classes. Database configuration is done using the dbConfig file --- .gitignore | 2 +- .../kotlin/serialization/reps/DBTreeRepo.kt | 4 +- .../kotlin/serialization/reps/JsonTreeRepo.kt | 48 +++++++------ .../serialization/reps/Neo4jTreeRepo.kt | 28 ++++++-- .../kotlin/serialization/reps/SQLTables.kt | 42 ----------- .../kotlin/serialization/reps/SQLTreeRepo.kt | 71 +++++++++++++++---- BSTrees/src/main/kotlin/utils/PathsUtil.kt | 5 ++ 7 files changed, 115 insertions(+), 85 deletions(-) delete mode 100644 BSTrees/src/main/kotlin/serialization/reps/SQLTables.kt create mode 100644 BSTrees/src/main/kotlin/utils/PathsUtil.kt diff --git a/.gitignore b/.gitignore index 198fc2f..1363458 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,4 @@ build/ # db files *.json -*/SQLTreeDB +*/SQLTrees diff --git a/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt index 59b2a9b..4ecb94a 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt @@ -3,9 +3,9 @@ package serialization.reps import serialization.SerializableTree interface DBTreeRepo { - fun getTree(treeType: String, treeName: String): SerializableTree? + fun getTree(treeName: String, treeType: String): SerializableTree? fun setTree(serializableTree: SerializableTree) - fun deleteTree(treeType: String, treeName: String) + fun deleteTree(treeName: String, treeType: String) } \ No newline at end of file diff --git a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt index 77621f4..364f547 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt @@ -5,32 +5,38 @@ import kotlinx.serialization.json.Json import serialization.SerializableTree import kotlinx.serialization.encodeToString import mu.KotlinLogging -import java.io.File -import java.io.FileNotFoundException -import java.io.FileReader -import java.io.FileWriter +import java.io.* +import java.util.* import kotlin.io.path.Path +import utils.PathsUtil.PROPERTIES_FILE_PATH private val logger = KotlinLogging.logger { } -object JsonTreeRepo : DBTreeRepo { - private fun createDirPaths() { - File("JSONTreeRep").mkdir() - File(Path("JSONTreeRep", "BSTree").toUri()).mkdir() - File(Path("JSONTreeRep", "RBTree").toUri()).mkdir() - File(Path("JSONTreeRep", "AvlTree").toUri()).mkdir() + +class JsonTreeRepo : DBTreeRepo { + private var dir : String + + init { + val property = Properties() + val propertiesFile = FileInputStream(PROPERTIES_FILE_PATH) + property.load(propertiesFile) + + dir = property.getProperty("json.dir") + + File(dir).mkdir() + File(Path(dir, "BSTree").toUri()).mkdir() + File(Path(dir, "RBTree").toUri()).mkdir() + File(Path(dir, "AvlTree").toUri()).mkdir() logger.info { "[JSON] Dir paths was created" } } - private fun getPathToFile(typeTree: String, treeName: String): String { - return Path("JSONTreeRep", typeTree, "${treeName}.json").toString() + private fun getPathToFile(treeName: String, typeTree: String): String { + return Path(dir, typeTree, "${treeName}.json").toString() } - override fun getTree(treeType: String, treeName: String): SerializableTree? { - createDirPaths() - - val filePath = getPathToFile(treeType, treeName) + override fun getTree(treeName: String, treeType: String): SerializableTree? { + val filePath = getPathToFile(treeName, treeType) lateinit var file: FileReader var fileFound = true @@ -55,9 +61,7 @@ object JsonTreeRepo : DBTreeRepo { } override fun setTree(serializableTree: SerializableTree) { - createDirPaths() - - val filePath = getPathToFile(serializableTree.treeType, serializableTree.name) + val filePath = getPathToFile(serializableTree.name, serializableTree.treeType) lateinit var file: FileWriter try { @@ -73,10 +77,8 @@ object JsonTreeRepo : DBTreeRepo { logger.info { "[JSON] Set tree - treeName: ${serializableTree.name}, treeType: ${serializableTree.treeType}" } } - override fun deleteTree(treeType: String, treeName: String) { - createDirPaths() - - val path = getPathToFile(treeType, treeName) + override fun deleteTree(treeName: String, treeType: String) { + val path = getPathToFile(treeName, treeType) try { File(path).delete() diff --git a/BSTrees/src/main/kotlin/serialization/reps/Neo4jTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/Neo4jTreeRepo.kt index 6b58009..8e9d11a 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/Neo4jTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/Neo4jTreeRepo.kt @@ -7,14 +7,32 @@ import org.neo4j.driver.TransactionContext import serialization.SerializableNode import serialization.SerializableTree import java.io.Closeable +import java.io.FileInputStream +import java.util.* +import utils.PathsUtil.PROPERTIES_FILE_PATH private val logger = KotlinLogging.logger { } -object Neo4jTreeRepo : Closeable, DBTreeRepo { - private val driver = GraphDatabase.driver("bolt://localhost:7687", AuthTokens.basic("neo4j", "qwertyui")) +class Neo4jTreeRepo : Closeable, DBTreeRepo { + private var host: String + private var username: String + private var password: String + + init { + val property = Properties() + + val propertiesFile = FileInputStream(PROPERTIES_FILE_PATH) + property.load(propertiesFile) + + host = property.getProperty("neo4j.host") + username = property.getProperty("neo4j.username") + password = property.getProperty("neo4j.password") + } + + private val driver = GraphDatabase.driver(host, AuthTokens.basic(username, password)) private val session = driver.session() - override fun getTree(treeType: String, treeName: String): SerializableTree? { + override fun getTree(treeName: String, treeType: String): SerializableTree? { var serializableTree: SerializableTree? = null session.executeRead { tx -> @@ -79,7 +97,7 @@ object Neo4jTreeRepo : Closeable, DBTreeRepo { override fun setTree(serializableTree: SerializableTree) { - deleteTree(serializableTree.treeType, serializableTree.name) + deleteTree(serializableTree.name, serializableTree.treeType) session.executeWrite { tx -> tx.run( @@ -132,7 +150,7 @@ object Neo4jTreeRepo : Closeable, DBTreeRepo { } } - override fun deleteTree(treeType: String, treeName: String) { + override fun deleteTree(treeName: String, treeType: String) { session.executeWrite { tx -> tx.run( "MATCH (tree: Tree {name: \$name, type: \$type})" + diff --git a/BSTrees/src/main/kotlin/serialization/reps/SQLTables.kt b/BSTrees/src/main/kotlin/serialization/reps/SQLTables.kt deleted file mode 100644 index 7cbb1bb..0000000 --- a/BSTrees/src/main/kotlin/serialization/reps/SQLTables.kt +++ /dev/null @@ -1,42 +0,0 @@ -package serialization.reps - -import org.jetbrains.exposed.dao.IntEntity -import org.jetbrains.exposed.dao.IntEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.ReferenceOption - - -object TreesTable : IntIdTable() { - val treeName = varchar("nameTree", 20).uniqueIndex().default("") - val treeType = varchar("typeTree", 20).default("") - val root = reference("root", NodesTable).nullable() -} - -class TreeEntity(id: EntityID): IntEntity(id) { - companion object : IntEntityClass(TreesTable) - - var treeName by TreesTable.treeName - var treeType by TreesTable.treeType - var root by NodeEntity optionalReferencedOn TreesTable.root -} - -object NodesTable : IntIdTable(){ - val key = varchar("key", 255) - val value = varchar("value", 255) - val metadata = varchar("metadata", 255) - val leftNode = reference("leftNode", NodesTable).nullable() - val rightNode = reference("rightNode", NodesTable).nullable() - val tree = reference("tree", TreesTable, onDelete = ReferenceOption.CASCADE) -} - -class NodeEntity(id: EntityID) : IntEntity(id){ - companion object : IntEntityClass(NodesTable) - - var key by NodesTable.key - var value by NodesTable.value - var metadata by NodesTable.metadata - var leftNode by NodeEntity optionalReferencedOn NodesTable.leftNode - var rightNode by NodeEntity optionalReferencedOn NodesTable.rightNode - var tree by TreeEntity referencedOn NodesTable.tree -} diff --git a/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt index a9b9145..1cf8f79 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt @@ -6,12 +6,67 @@ import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.and import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.dao.IntEntity +import org.jetbrains.exposed.dao.IntEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.IntIdTable +import org.jetbrains.exposed.sql.ReferenceOption import serialization.* import java.io.File +import java.io.FileInputStream +import java.util.* +import utils.PathsUtil.PROPERTIES_FILE_PATH + + +object TreesTable : IntIdTable() { + val treeName = varchar("nameTree", 20) + val treeType = varchar("typeTree", 20) + val root = reference("root", NodesTable).nullable() +} + +class TreeEntity(id: EntityID) : IntEntity(id) { + companion object : IntEntityClass(TreesTable) + + var treeName by TreesTable.treeName + var treeType by TreesTable.treeType + var root by NodeEntity optionalReferencedOn TreesTable.root +} + +object NodesTable : IntIdTable() { + val key = varchar("key", 255) + val value = varchar("value", 255) + val metadata = varchar("metadata", 255) + val leftNode = reference("leftNode", NodesTable).nullable() + val rightNode = reference("rightNode", NodesTable).nullable() + val tree = reference("tree", TreesTable, onDelete = ReferenceOption.CASCADE) +} + +class NodeEntity(id: EntityID) : IntEntity(id) { + companion object : IntEntityClass(NodesTable) + + var key by NodesTable.key + var value by NodesTable.value + var metadata by NodesTable.metadata + var leftNode by NodeEntity optionalReferencedOn NodesTable.leftNode + var rightNode by NodeEntity optionalReferencedOn NodesTable.rightNode + var tree by TreeEntity referencedOn NodesTable.tree +} private val logger = KotlinLogging.logger { } -object SQLTreeRepo : DBTreeRepo { +class SQLTreeRepo : DBTreeRepo { + private var dbName: String + + init { + val property = Properties() + val propertiesFile = FileInputStream(PROPERTIES_FILE_PATH) + property.load(propertiesFile) + + dbName = property.getProperty("sql.dbName") + + connectDB(dbName) + createTables() + } private fun connectDB(dbName: String) { Database.connect("jdbc:sqlite:${File(dbName)}", "org.sqlite.JDBC") @@ -28,11 +83,7 @@ object SQLTreeRepo : DBTreeRepo { logger.info { "[SQLite] Database tables have been created successfully" } } - override fun getTree(treeType: String, treeName: String): SerializableTree? { - //TODO: Create a config file in which dbName will be written - connectDB("SQLTreeDB") - createTables() - + override fun getTree(treeName: String, treeType: String): SerializableTree? { var treeEntity: TreeEntity? = null transaction { treeEntity = TreeEntity.find { (TreesTable.treeName eq treeName) and (TreesTable.treeType eq treeType) } @@ -71,11 +122,7 @@ object SQLTreeRepo : DBTreeRepo { } override fun setTree(serializableTree: SerializableTree) { - //TODO: Create a config file in which dbName will be written - connectDB("SQLTreeDB") - createTables() - - deleteTree(serializableTree.treeType, serializableTree.name) + deleteTree(serializableTree.name, serializableTree.treeType) transaction { val newTree = TreeEntity.new { @@ -100,7 +147,7 @@ object SQLTreeRepo : DBTreeRepo { } } - override fun deleteTree(treeType: String, treeName: String) { + override fun deleteTree(treeName: String, treeType: String) { transaction { val treeEntity = TreeEntity.find { (TreesTable.treeName eq treeName) and (TreesTable.treeType eq treeType) } diff --git a/BSTrees/src/main/kotlin/utils/PathsUtil.kt b/BSTrees/src/main/kotlin/utils/PathsUtil.kt new file mode 100644 index 0000000..8a64432 --- /dev/null +++ b/BSTrees/src/main/kotlin/utils/PathsUtil.kt @@ -0,0 +1,5 @@ +package utils + +object PathsUtil { + const val PROPERTIES_FILE_PATH = "src/main/resources/dbConfig.properties" +} \ No newline at end of file From 4396f2b845fed178f0163e32d38ef39daa2a12f7 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 24 Apr 2023 22:34:43 +0300 Subject: [PATCH 078/135] fix: Fixed a typo in BSTreeUtil --- BSTrees/src/test/kotlin/utils/BSTreeUtil.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt b/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt index 2b82113..39cba58 100644 --- a/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt +++ b/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt @@ -13,7 +13,7 @@ object BSTreeUtil { if (root1 == null || root2 == null) { return root1 == null && root2 == null } - return root1.getKey() == root2.getKey() && root1.getValue() == root1.getValue() && + return root1.getKey() == root2.getKey() && root1.getValue() == root2.getValue() && checkNodeEquals(root1.getLeftNode(), root2.getLeftNode()) && checkNodeEquals(root1.getRightNode(), root2.getRightNode()) } From a3e91e773970fc4f8a97aeaac1569796c53f1f31 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 24 Apr 2023 22:39:29 +0300 Subject: [PATCH 079/135] fix: Fixed a bug in Json when writing trees with the same names --- .../kotlin/serialization/reps/JsonTreeRepo.kt | 24 +++++++++++++++---- .../kotlin/serialization/reps/SQLTreeRepo.kt | 4 ++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt index 364f547..0cf102b 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt @@ -9,6 +9,7 @@ import java.io.* import java.util.* import kotlin.io.path.Path import utils.PathsUtil.PROPERTIES_FILE_PATH +import java.nio.file.FileAlreadyExistsException private val logger = KotlinLogging.logger { } @@ -22,13 +23,16 @@ class JsonTreeRepo : DBTreeRepo { property.load(propertiesFile) dir = property.getProperty("json.dir") + makeDir(dir) + logger.info { "[JSON] Dir paths was created" } + } + + private fun makeDir(dir: String){ File(dir).mkdir() File(Path(dir, "BSTree").toUri()).mkdir() File(Path(dir, "RBTree").toUri()).mkdir() File(Path(dir, "AvlTree").toUri()).mkdir() - - logger.info { "[JSON] Dir paths was created" } } private fun getPathToFile(treeName: String, typeTree: String): String { @@ -63,16 +67,26 @@ class JsonTreeRepo : DBTreeRepo { override fun setTree(serializableTree: SerializableTree) { val filePath = getPathToFile(serializableTree.name, serializableTree.treeType) lateinit var file: FileWriter + var fileAlreadyExists = false try { + if(File(filePath).exists()){ + fileAlreadyExists = true + throw FileAlreadyExistsException("") + } file = FileWriter(filePath) file.write(Json.encodeToString(serializableTree)) - } catch (e: Exception) { + }catch (e: FileAlreadyExistsException){ + logger.warn { "[JSON] A tree with that name already exists" } + } + catch (e: Exception) { logger.error { "[JSON] Error getting the tree: $e" } throw e } finally { - file.flush() - file.close() + if(!fileAlreadyExists) { + file.flush() + file.close() + } } logger.info { "[JSON] Set tree - treeName: ${serializableTree.name}, treeType: ${serializableTree.treeType}" } } diff --git a/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt b/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt index 1cf8f79..d854649 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt +++ b/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt @@ -18,6 +18,8 @@ import java.util.* import utils.PathsUtil.PROPERTIES_FILE_PATH +private val logger = KotlinLogging.logger { } + object TreesTable : IntIdTable() { val treeName = varchar("nameTree", 20) val treeType = varchar("typeTree", 20) @@ -52,8 +54,6 @@ class NodeEntity(id: EntityID) : IntEntity(id) { var tree by TreeEntity referencedOn NodesTable.tree } -private val logger = KotlinLogging.logger { } - class SQLTreeRepo : DBTreeRepo { private var dbName: String From c55626a9e4fca1a3fd14d28c623fab3db351cee8 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Mon, 24 Apr 2023 22:43:12 +0300 Subject: [PATCH 080/135] feat: Added a lot of comments to RBTree fix: some changes in packages --- BSTrees/src/main/kotlin/avlTree/AvlNode.kt | 15 ---- .../kotlin/binarySearchTree/BSBalancer.kt | 23 ----- .../main/kotlin/binarySearchTree/BSNode.kt | 14 --- .../SerializableType.kt | 2 +- .../reps/DBTreeRepo.kt | 4 +- .../reps/JsonTreeRepo.kt | 4 +- .../reps/SQLTables.kt | 2 +- .../reps/SQLTreeRepo.kt | 4 +- .../src/main/kotlin/redBlackTree/RBNode.kt | 13 --- BSTrees/src/main/kotlin/{ => trees}/BTree.kt | 2 + .../src/main/kotlin/{ => trees}/Balancer.kt | 2 + BSTrees/src/main/kotlin/{ => trees}/Node.kt | 2 + .../{avlTree => trees/avl}/AvlBalancer.kt | 4 +- BSTrees/src/main/kotlin/trees/avl/AvlNode.kt | 28 ++++++ .../kotlin/{avlTree => trees/avl}/AvlTree.kt | 11 ++- .../kotlin/trees/binarySearch/BSBalancer.kt | 40 +++++++++ .../main/kotlin/trees/binarySearch/BSNode.kt | 29 +++++++ .../binarySearch}/BSTree.kt | 68 ++++++++++++++- .../redBlack}/RBBalancer.kt | 33 +++++-- .../src/main/kotlin/trees/redBlack/RBNode.kt | 28 ++++++ .../redBlack}/RBTree.kt | 87 ++++++++++++++----- .../src/test/kotlin/avlTree/AVLTreeTest.kt | 2 + .../src/test/kotlin/balancers/BalancerTest.kt | 8 +- .../kotlin/binarySearchTree/BSTreeTest.kt | 2 + .../test/kotlin/redBlackTree/RBTreeTest.kt | 2 + .../kotlin/treeInvariants/TreesInvariants.kt | 10 +-- BSTrees/src/test/kotlin/utils/BSTreeUtil.kt | 4 +- 27 files changed, 322 insertions(+), 121 deletions(-) delete mode 100644 BSTrees/src/main/kotlin/avlTree/AvlNode.kt delete mode 100644 BSTrees/src/main/kotlin/binarySearchTree/BSBalancer.kt delete mode 100644 BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt rename BSTrees/src/main/kotlin/{serialization => dataBases}/SerializableType.kt (94%) rename BSTrees/src/main/kotlin/{serialization => dataBases}/reps/DBTreeRepo.kt (76%) rename BSTrees/src/main/kotlin/{serialization => dataBases}/reps/JsonTreeRepo.kt (97%) rename BSTrees/src/main/kotlin/{serialization => dataBases}/reps/SQLTables.kt (98%) rename BSTrees/src/main/kotlin/{serialization => dataBases}/reps/SQLTreeRepo.kt (98%) delete mode 100644 BSTrees/src/main/kotlin/redBlackTree/RBNode.kt rename BSTrees/src/main/kotlin/{ => trees}/BTree.kt (98%) rename BSTrees/src/main/kotlin/{ => trees}/Balancer.kt (99%) rename BSTrees/src/main/kotlin/{ => trees}/Node.kt (98%) rename BSTrees/src/main/kotlin/{avlTree => trees/avl}/AvlBalancer.kt (98%) create mode 100644 BSTrees/src/main/kotlin/trees/avl/AvlNode.kt rename BSTrees/src/main/kotlin/{avlTree => trees/avl}/AvlTree.kt (96%) create mode 100644 BSTrees/src/main/kotlin/trees/binarySearch/BSBalancer.kt create mode 100644 BSTrees/src/main/kotlin/trees/binarySearch/BSNode.kt rename BSTrees/src/main/kotlin/{binarySearchTree => trees/binarySearch}/BSTree.kt (59%) rename BSTrees/src/main/kotlin/{redBlackTree => trees/redBlack}/RBBalancer.kt (92%) create mode 100644 BSTrees/src/main/kotlin/trees/redBlack/RBNode.kt rename BSTrees/src/main/kotlin/{redBlackTree => trees/redBlack}/RBTree.kt (75%) diff --git a/BSTrees/src/main/kotlin/avlTree/AvlNode.kt b/BSTrees/src/main/kotlin/avlTree/AvlNode.kt deleted file mode 100644 index e53fbd9..0000000 --- a/BSTrees/src/main/kotlin/avlTree/AvlNode.kt +++ /dev/null @@ -1,15 +0,0 @@ -package avlTree - -import Node -import kotlin.math.max - -class AvlNode, V>(key: K, value: V) : Node>(key, value) { - - internal var height = 1 - - fun updateHeight() { - val leftHeight = this.leftNode?.height ?: 0 - val rightHeight = this.rightNode?.height ?: 0 - height = (max(leftHeight, rightHeight) + 1) - } -} diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSBalancer.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSBalancer.kt deleted file mode 100644 index 7816694..0000000 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSBalancer.kt +++ /dev/null @@ -1,23 +0,0 @@ -package binarySearchTree - -import Balancer - -internal class BSBalancer, V> : Balancer>() { - - internal fun bsRightRotate(node: BSNode): BSNode { - val temp = rightRotate(node) - temp.leftNode?.updateSize() - temp.rightNode?.updateSize() - temp.updateSize() - return temp - } - - internal fun bsLeftRotate(node: BSNode): BSNode { - val temp = leftRotate(node) - temp.leftNode?.updateSize() - temp.rightNode?.updateSize() - temp.updateSize() - return temp - } - -} diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt b/BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt deleted file mode 100644 index 83e3250..0000000 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSNode.kt +++ /dev/null @@ -1,14 +0,0 @@ -package binarySearchTree - -import Node - -class BSNode, V>(key: K, value: V) : Node>(key, value) { - - internal var size = 1 - - fun updateSize() { - val leftSize = leftNode?.size ?: 0 - val rightSize = rightNode?.size ?: 0 - size = leftSize + rightSize + 1 - } -} diff --git a/BSTrees/src/main/kotlin/serialization/SerializableType.kt b/BSTrees/src/main/kotlin/dataBases/SerializableType.kt similarity index 94% rename from BSTrees/src/main/kotlin/serialization/SerializableType.kt rename to BSTrees/src/main/kotlin/dataBases/SerializableType.kt index 52292a5..ed3ab54 100644 --- a/BSTrees/src/main/kotlin/serialization/SerializableType.kt +++ b/BSTrees/src/main/kotlin/dataBases/SerializableType.kt @@ -1,4 +1,4 @@ -package serialization +package dataBases import kotlinx.serialization.Serializable diff --git a/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt b/BSTrees/src/main/kotlin/dataBases/reps/DBTreeRepo.kt similarity index 76% rename from BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt rename to BSTrees/src/main/kotlin/dataBases/reps/DBTreeRepo.kt index 70cf9bb..b20f4ab 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/DBTreeRepo.kt +++ b/BSTrees/src/main/kotlin/dataBases/reps/DBTreeRepo.kt @@ -1,6 +1,6 @@ -package serialization.reps +package dataBases.reps -import serialization.SerializableTree +import dataBases.SerializableTree interface DBTreeRepo { fun getTree(typeTree: String, treeName: String): SerializableTree? diff --git a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt b/BSTrees/src/main/kotlin/dataBases/reps/JsonTreeRepo.kt similarity index 97% rename from BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt rename to BSTrees/src/main/kotlin/dataBases/reps/JsonTreeRepo.kt index 3177e9d..27c8d76 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/JsonTreeRepo.kt +++ b/BSTrees/src/main/kotlin/dataBases/reps/JsonTreeRepo.kt @@ -1,8 +1,8 @@ -package serialization.reps +package dataBases.reps import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json -import serialization.SerializableTree +import dataBases.SerializableTree import kotlinx.serialization.encodeToString import java.io.File import java.io.FileNotFoundException diff --git a/BSTrees/src/main/kotlin/serialization/reps/SQLTables.kt b/BSTrees/src/main/kotlin/dataBases/reps/SQLTables.kt similarity index 98% rename from BSTrees/src/main/kotlin/serialization/reps/SQLTables.kt rename to BSTrees/src/main/kotlin/dataBases/reps/SQLTables.kt index c46bab5..4ff6a9d 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/SQLTables.kt +++ b/BSTrees/src/main/kotlin/dataBases/reps/SQLTables.kt @@ -1,4 +1,4 @@ -package serialization.reps +package dataBases.reps import org.jetbrains.exposed.dao.IntEntity import org.jetbrains.exposed.dao.IntEntityClass diff --git a/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt b/BSTrees/src/main/kotlin/dataBases/reps/SQLTreeRepo.kt similarity index 98% rename from BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt rename to BSTrees/src/main/kotlin/dataBases/reps/SQLTreeRepo.kt index bad04fd..1b80943 100644 --- a/BSTrees/src/main/kotlin/serialization/reps/SQLTreeRepo.kt +++ b/BSTrees/src/main/kotlin/dataBases/reps/SQLTreeRepo.kt @@ -1,11 +1,11 @@ -package serialization.reps +package dataBases.reps import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.and import org.jetbrains.exposed.sql.transactions.transaction -import serialization.* +import dataBases.* import java.io.File object SQLTreeRepo: DBTreeRepo{ diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt b/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt deleted file mode 100644 index d2ada18..0000000 --- a/BSTrees/src/main/kotlin/redBlackTree/RBNode.kt +++ /dev/null @@ -1,13 +0,0 @@ -package redBlackTree - -import Node - -class RBNode, V>(key: K, value: V) : Node>(key, value) { - - enum class Color { - BLACK, - RED - } - - internal var color = Color.BLACK -} diff --git a/BSTrees/src/main/kotlin/BTree.kt b/BSTrees/src/main/kotlin/trees/BTree.kt similarity index 98% rename from BSTrees/src/main/kotlin/BTree.kt rename to BSTrees/src/main/kotlin/trees/BTree.kt index 2a4ac3b..022b926 100644 --- a/BSTrees/src/main/kotlin/BTree.kt +++ b/BSTrees/src/main/kotlin/trees/BTree.kt @@ -1,3 +1,5 @@ +package trees + /** * An abstract class representing a binary search tree. * diff --git a/BSTrees/src/main/kotlin/Balancer.kt b/BSTrees/src/main/kotlin/trees/Balancer.kt similarity index 99% rename from BSTrees/src/main/kotlin/Balancer.kt rename to BSTrees/src/main/kotlin/trees/Balancer.kt index ae28458..ba1fcfc 100644 --- a/BSTrees/src/main/kotlin/Balancer.kt +++ b/BSTrees/src/main/kotlin/trees/Balancer.kt @@ -1,3 +1,5 @@ +package trees + /** * An abstract class representing a binary search tree. * diff --git a/BSTrees/src/main/kotlin/Node.kt b/BSTrees/src/main/kotlin/trees/Node.kt similarity index 98% rename from BSTrees/src/main/kotlin/Node.kt rename to BSTrees/src/main/kotlin/trees/Node.kt index 471446d..5830d9f 100644 --- a/BSTrees/src/main/kotlin/Node.kt +++ b/BSTrees/src/main/kotlin/trees/Node.kt @@ -1,3 +1,5 @@ +package trees + /** * An abstract class representing a binary search tree node. * It's constructed with key and value and contains parent, left and right sons diff --git a/BSTrees/src/main/kotlin/avlTree/AvlBalancer.kt b/BSTrees/src/main/kotlin/trees/avl/AvlBalancer.kt similarity index 98% rename from BSTrees/src/main/kotlin/avlTree/AvlBalancer.kt rename to BSTrees/src/main/kotlin/trees/avl/AvlBalancer.kt index 32a0466..7f676c3 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlBalancer.kt +++ b/BSTrees/src/main/kotlin/trees/avl/AvlBalancer.kt @@ -1,6 +1,6 @@ -package avlTree +package trees.avl -import Balancer +import trees.Balancer /** * A class representing an AVL binary search tree balancer. diff --git a/BSTrees/src/main/kotlin/trees/avl/AvlNode.kt b/BSTrees/src/main/kotlin/trees/avl/AvlNode.kt new file mode 100644 index 0000000..bc64761 --- /dev/null +++ b/BSTrees/src/main/kotlin/trees/avl/AvlNode.kt @@ -0,0 +1,28 @@ +package trees.avl + +import trees.Node +import kotlin.math.max + +/** + * A class representing an AVL binary search tree node. + * The difference from the abstract node class is in the presence of a height and the function of updating it + * + * @generic the type of key stored in the tree. It must be comparable + * @generic the type of value stored in the tree + */ +class AvlNode, V>(key: K, value: V) : Node>(key, value) { + + /** + * The variable that contains a height of the tree + */ + internal var height = 1 + + /** + * Update a height of the tree to set the correct value + */ + fun updateHeight() { + val leftHeight = this.leftNode?.height ?: 0 + val rightHeight = this.rightNode?.height ?: 0 + height = (max(leftHeight, rightHeight) + 1) + } +} diff --git a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt b/BSTrees/src/main/kotlin/trees/avl/AvlTree.kt similarity index 96% rename from BSTrees/src/main/kotlin/avlTree/AvlTree.kt rename to BSTrees/src/main/kotlin/trees/avl/AvlTree.kt index 6ef1e95..eddaa2a 100644 --- a/BSTrees/src/main/kotlin/avlTree/AvlTree.kt +++ b/BSTrees/src/main/kotlin/trees/avl/AvlTree.kt @@ -1,6 +1,6 @@ -package avlTree +package trees.avl -import BTree +import trees.BTree /** * A class representing an AVL binary search tree. @@ -12,7 +12,7 @@ import BTree class AvlTree, V> : BTree>() { /** - * A balancer class providing balancing of the curr node of the tree + * A balancer class providing balancing of the current node of the tree */ private val balancer = AvlBalancer() @@ -93,6 +93,11 @@ class AvlTree, V> : BTree>() { return balancer.balance(node) } + /** + * Delete a value from the tree. + * + * @param key the key under which the value is stored + */ override fun delete(key: K) { //temp is needed to avoid possibility of changing the root val temp = this.root diff --git a/BSTrees/src/main/kotlin/trees/binarySearch/BSBalancer.kt b/BSTrees/src/main/kotlin/trees/binarySearch/BSBalancer.kt new file mode 100644 index 0000000..f86cffe --- /dev/null +++ b/BSTrees/src/main/kotlin/trees/binarySearch/BSBalancer.kt @@ -0,0 +1,40 @@ +package trees.binarySearch + +import trees.Balancer + +/** + * A class representing a randomized binary search tree balancer. + * Provides all the necessary functions for rotating the tree + * + * @generic the type of key stored in the tree. It must be comparable + * @generic the type of value stored in the tree + */ +internal class BSBalancer, V> : Balancer>() { + + /** + * Do a right rotate around this node with updating size + * + * @param node the node around which the rotation is done + */ + internal fun bsRightRotate(node: BSNode): BSNode { + val temp = rightRotate(node) + temp.leftNode?.updateSize() + temp.rightNode?.updateSize() + temp.updateSize() + return temp + } + + /** + * Do a left rotate around this node with updating size + * + * @param node the node around which the rotation is done + */ + internal fun bsLeftRotate(node: BSNode): BSNode { + val temp = leftRotate(node) + temp.leftNode?.updateSize() + temp.rightNode?.updateSize() + temp.updateSize() + return temp + } + +} diff --git a/BSTrees/src/main/kotlin/trees/binarySearch/BSNode.kt b/BSTrees/src/main/kotlin/trees/binarySearch/BSNode.kt new file mode 100644 index 0000000..f95d6b1 --- /dev/null +++ b/BSTrees/src/main/kotlin/trees/binarySearch/BSNode.kt @@ -0,0 +1,29 @@ +package trees.binarySearch + +import trees.Node + +/** + * A class representing a randomized binary search tree node. + * The difference from the abstract node class is in the presence of size and the function of updating it + * + * @generic the type of key stored in the tree. It must be comparable + * @generic the type of value stored in the tree + */ +class BSNode, V>(key: K, value: V) : Node>(key, value) { + + /** + * The variable that contains size of the tree + * It isn't a height. + * This variable contains the height, which is measured in the number of nodes in the tree including the root + */ + internal var size = 1 + + /** + * Update size of the tree to set the correct value + */ + fun updateSize() { + val leftSize = leftNode?.size ?: 0 + val rightSize = rightNode?.size ?: 0 + size = leftSize + rightSize + 1 + } +} diff --git a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt b/BSTrees/src/main/kotlin/trees/binarySearch/BSTree.kt similarity index 59% rename from BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt rename to BSTrees/src/main/kotlin/trees/binarySearch/BSTree.kt index df1dc87..81c5511 100644 --- a/BSTrees/src/main/kotlin/binarySearchTree/BSTree.kt +++ b/BSTrees/src/main/kotlin/trees/binarySearch/BSTree.kt @@ -1,25 +1,54 @@ -package binarySearchTree +package trees.binarySearch -import BTree +import trees.BTree import kotlin.random.Random +/** + * A class representing a randomized binary search tree. + * + * + * @generic the type of key stored in the tree. It must be comparable + * @generic the type of value stored in the tree + */ class BSTree, V> : BTree>() { + /** + * A balancer class providing rotations of the tree with updating the size + */ private val balancer = BSBalancer() + /** + * Insert a node to the tree. + * It is actually a wrapper for the add function. Necessary to implement recursion + * + * @param value the value to add + * @param key the key under which the value is stored + */ override fun insert(key: K, value: V) { add(BSNode(key, value)) } + /** + * Add a node to the root of the tree. + * It's necessary to implement random adding. + * + * @param node the node to add + */ private fun addRoot(node: BSNode): BSNode { - + //temp is needed to avoid possibility of changing the root val temp = this.root return if (temp == null) node else if (temp.key == node.key) { temp.value = node.value temp } else { + /** + * Some kind of recursive implementation + * Creating subtree to execute add function again + * Then we return the node to the desired son + */ val subTree = BSTree() + //We make the usual adding, then we put the node in the root by rotation it tom the top if (node.key < temp.key) { subTree.root = temp.leftNode this.root?.leftNode = subTree.addRoot(node) @@ -33,8 +62,13 @@ class BSTree, V> : BTree>() { } + /** + * Add a node to the tree + * + * @param node the node to add + */ private fun add(node: BSNode) { - + //temp is needed to avoid possibility of changing the root val temp = this.root if (temp == null) this.root = node else if (temp.key == node.key) this.root?.value = node.value @@ -44,9 +78,18 @@ class BSTree, V> : BTree>() { /* Randomized insertion into the root of the tree allows you to artificially balance it with a fairly small height. + The idea is that inserting into the root shuffles the tree well, which provides a relatively small height. + The tree is not perfectly balanced, but differs from the logarithm on average by no more than twice, + which is a constant + Otherwise, we perform the usual insertion */ else { + /** + * Some kind of recursive implementation + * Creating subtree to execute add function again + * Then we return the node to the desired son + */ val subTree = BSTree() if (temp.key > node.key) { subTree.root = temp.leftNode @@ -61,16 +104,27 @@ class BSTree, V> : BTree>() { } } + //Updating this node before leaving recursion this.root?.updateSize() } } + /** + * Merge two nodes into one. + * One of the ways to implement removal from the tree + * + * @param left + * @param right + * The nodes to merge + */ private fun join(left: BSNode?, right: BSNode?): BSNode? { + //If one of the nodes is null then we can just return the second one if (left == null) return right if (right == null) return left + //Choosing the node that would be a new root return if (Random.nextInt() % (left.size + right.size) < left.size) { left.rightNode = join(left.rightNode, right) left.rightNode?.parent = left @@ -85,6 +139,11 @@ class BSTree, V> : BTree>() { } + /** + * Delete a value from the tree. + * + * @param key the key under which the value is stored + */ override fun delete(key: K) { val temp = this.root @@ -106,6 +165,7 @@ class BSTree, V> : BTree>() { this.root?.rightNode = subTree.root } + //Updating this node before leaving recursion this.root?.updateSize() } diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBBalancer.kt b/BSTrees/src/main/kotlin/trees/redBlack/RBBalancer.kt similarity index 92% rename from BSTrees/src/main/kotlin/redBlackTree/RBBalancer.kt rename to BSTrees/src/main/kotlin/trees/redBlack/RBBalancer.kt index 5fedb98..ea4229d 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBBalancer.kt +++ b/BSTrees/src/main/kotlin/trees/redBlack/RBBalancer.kt @@ -1,10 +1,24 @@ -package redBlackTree - -import Balancer -import redBlackTree.RBNode.Color - +package trees.redBlack + +import trees.Balancer +import trees.redBlack.RBNode.Color + +/** + * A class representing a red black binary search tree balancer. + * Provides all the necessary functions for balancing the tree + * + * @generic the type of key stored in the tree. It must be comparable + * @generic the type of value stored in the tree + */ open class RBBalancer, V> : Balancer>() { + /** + * Balance the tree after deletion a red node + * TODO write more about the situations in which it is used + * + * @param tree TODO + * @param node TODO + */ internal fun balanceAfterDeletion(tree: RBTree, node: RBNode) { var curNode = node var nodeParent = node.parent @@ -139,7 +153,12 @@ open class RBBalancer, V> : Balancer>() { curNode.color = Color.BLACK } - + /** + * Balance the tree after adding a red node + * TODO write more about the situations in which it is used + * + * @param node TODO + */ internal fun balanceAfterAdding(node: RBNode): RBNode { var nodeParent = node.parent var curNode = node @@ -195,4 +214,4 @@ open class RBBalancer, V> : Balancer>() { return curNode } -} \ No newline at end of file +} diff --git a/BSTrees/src/main/kotlin/trees/redBlack/RBNode.kt b/BSTrees/src/main/kotlin/trees/redBlack/RBNode.kt new file mode 100644 index 0000000..3a1ce5b --- /dev/null +++ b/BSTrees/src/main/kotlin/trees/redBlack/RBNode.kt @@ -0,0 +1,28 @@ +package trees.redBlack + +import trees.Node + +/** + * A class representing an AVL binary search tree node. + * The difference from the abstract node class is in the presence of a color which can be black of red + * + * @generic the type of key stored in the tree. It must be comparable + * @generic the type of value stored in the tree + */ +class RBNode, V>(key: K, value: V) : Node>(key, value) { + + /** + * An auxiliary enum class that contains the color of the node + * It can be only black or red + */ + enum class Color { + BLACK, + RED + } + + /** + * A variable that displays the current node color. + * It is always black by default + */ + internal var color = Color.BLACK +} diff --git a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt b/BSTrees/src/main/kotlin/trees/redBlack/RBTree.kt similarity index 75% rename from BSTrees/src/main/kotlin/redBlackTree/RBTree.kt rename to BSTrees/src/main/kotlin/trees/redBlack/RBTree.kt index ec4d700..9f66019 100644 --- a/BSTrees/src/main/kotlin/redBlackTree/RBTree.kt +++ b/BSTrees/src/main/kotlin/trees/redBlack/RBTree.kt @@ -1,16 +1,38 @@ -package redBlackTree - -import BTree -import redBlackTree.RBNode.Color - +package trees.redBlack + +import trees.BTree +import trees.redBlack.RBNode.Color + +/** + * A class representing a red black binary search tree. + * It maintains balance through a strict hierarchy of red and black vertices, + * as well as some rules that they follow + * + * @generic the type of key stored in the tree. It must be comparable + * @generic the type of value stored in the tree + */ class RBTree, V> : BTree>() { - + /** + * A balancer class providing balancing the tree when adding or deleting nodes + */ private val balancer = RBBalancer() + /** + * Insert a node to the tree. + * It is actually a wrapper for the add function. + * + * @param value the value to add + * @param key the key under which the value is stored + */ override fun insert(key: K, value: V) { add(RBNode(key, value)) } + /** + * Add a node to the root of the tree. + * + * @param node the node to add + */ private fun add(node: RBNode) { // if a node with such a key already exists, then we update Value @@ -53,6 +75,11 @@ class RBTree, V> : BTree>() { } } + /** + * Looking for a node in the tree by its key. + * + * @param key the key by which the search is performed + */ private fun findNodeByKey(key: K): RBNode? { var temp: RBNode? = root ?: return null while (temp != null) { @@ -66,6 +93,11 @@ class RBTree, V> : BTree>() { return null } + /** + * Delete a value from the tree. + * + * @param key the key under which the value is stored + */ override fun delete(key: K) { // This is the node that needs to be deleted val curNode = findNodeByKey(key) ?: return @@ -82,7 +114,7 @@ class RBTree, V> : BTree>() { sonIsNilNode = true getNilNode(curNode) } else { - getSonNodeForSwapping(nodeForSwapping) + if (nodeForSwapping.leftNode != null) nodeForSwapping.leftNode else nodeForSwapping.rightNode } // We put the sonOfNodeForSwapping in the place of nodeForSwapping and establish the necessary links @@ -111,6 +143,9 @@ class RBTree, V> : BTree>() { } } + /** + * TODO ?? + */ private fun setLinksWithNodeForSwapping(curNode: RBNode, nodeForSwapping: RBNode) { nodeForSwapping.leftNode = curNode.leftNode nodeForSwapping.leftNode?.parent = nodeForSwapping @@ -131,6 +166,9 @@ class RBTree, V> : BTree>() { } } + /** + * TODO ?? + */ private fun setLinksWithSonOfNodeForSwapping( nodeForSwapping: RBNode, sonOfNodeForSwapping: RBNode?, @@ -151,26 +189,28 @@ class RBTree, V> : BTree>() { } } - // nodeForSwapping is the node with the next largest key or the node itself if it has a Nil son + /** + * Find the node with the next largest key or the node itself if it has a Nil son + * It is an auxiliary function for the delete function + * + * @param curNode the node that we are swapping + */ private fun , V> getNodeForSwapping(curNode: RBNode): RBNode { return if (curNode.leftNode == null || curNode.rightNode == null) { curNode } else { // If we got here, then curNode has both a left and a right son - val temp = curNode.rightNode ?: throw Exception("An attempt to take a non-existent son") + val temp = requireNotNull(curNode.rightNode) { "An attempt to take a non-existent son" } nodeWithMinKey(temp) } } - private fun , V> getSonNodeForSwapping(nodeForSwapping: RBNode): RBNode? { - return if (nodeForSwapping.leftNode != null) { - nodeForSwapping.leftNode - } else { - nodeForSwapping.rightNode - } - } - - // We get an imaginary(Nil) node filled with some unnecessary data + /** + * Create an imaginary(Nil) node + * It's filled with some unnecessary data + * + * @param nodeExample some kind of pattern for Nil son + */ private fun , V> getNilNode(nodeExample: RBNode): RBNode { val nilSonNodeOfSwapping = RBNode(nodeExample.key, nodeExample.value) nilSonNodeOfSwapping.color = Color.BLACK @@ -178,12 +218,17 @@ class RBTree, V> : BTree>() { return nilSonNodeOfSwapping } - // We are looking for a node with the minimum key available from this node + /** + * Find a node with a minimum key in a tree + * It is an auxiliary function for the delete function + * + * @param node the root of the tree where to find the minimum node + */ private fun , V> nodeWithMinKey(node: RBNode): RBNode { var curNode = node while (curNode.leftNode != null) { - curNode = curNode.leftNode ?: throw Exception("An attempt to take a non-existent son") + curNode = requireNotNull(curNode.leftNode) { "An attempt to take a non-existent son" } } return curNode } -} \ No newline at end of file +} diff --git a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt b/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt index a58967f..c218e02 100644 --- a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt +++ b/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt @@ -4,6 +4,8 @@ import org.junit.jupiter.api.* import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import treeInvariants.TreesInvariants +import trees.avl.AvlNode +import trees.avl.AvlTree import kotlin.random.Random @TestInstance(TestInstance.Lifecycle.PER_CLASS) diff --git a/BSTrees/src/test/kotlin/balancers/BalancerTest.kt b/BSTrees/src/test/kotlin/balancers/BalancerTest.kt index 04a9656..a8d28fe 100644 --- a/BSTrees/src/test/kotlin/balancers/BalancerTest.kt +++ b/BSTrees/src/test/kotlin/balancers/BalancerTest.kt @@ -1,9 +1,9 @@ package balancers -import Balancer -import Node -import binarySearchTree.BSBalancer -import binarySearchTree.BSNode +import trees.Balancer +import trees.Node +import trees.binarySearch.BSBalancer +import trees.binarySearch.BSNode import org.junit.jupiter.api.Test import utils.BSTreeUtil diff --git a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt index af58d0b..295a533 100644 --- a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt +++ b/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt @@ -4,6 +4,8 @@ import org.junit.jupiter.api.* import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import treeInvariants.TreesInvariants +import trees.binarySearch.BSNode +import trees.binarySearch.BSTree import kotlin.random.Random @TestInstance(TestInstance.Lifecycle.PER_CLASS) diff --git a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt index c7a8675..e5816e8 100644 --- a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt +++ b/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt @@ -5,6 +5,8 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import treeInvariants.TreesInvariants +import trees.redBlack.RBNode +import trees.redBlack.RBTree import kotlin.random.Random const val seed = 10 diff --git a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt index 24319dc..0425279 100644 --- a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt +++ b/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt @@ -1,10 +1,10 @@ package treeInvariants -import Node -import avlTree.AvlNode -import binarySearchTree.BSNode -import redBlackTree.RBNode -import redBlackTree.RBNode.Color +import trees.Node +import trees.avl.AvlNode +import trees.binarySearch.BSNode +import trees.redBlack.RBNode +import trees.redBlack.RBNode.Color @Suppress("UNCHECKED_CAST") class TreesInvariants, V, NODE_TYPE : Node> { diff --git a/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt b/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt index ba42edd..f06dc27 100644 --- a/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt +++ b/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt @@ -1,7 +1,7 @@ package utils -import binarySearchTree.BSNode -import binarySearchTree.BSTree +import trees.binarySearch.BSNode +import trees.binarySearch.BSTree /** From 34ec394c8cba517d1cdd33cd615c23bc9ff8ab50 Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Tue, 25 Apr 2023 00:50:07 +0300 Subject: [PATCH 081/135] fix: changed the name of the project --- {BSTrees => lib}/build.gradle.kts | 0 .../main/kotlin/bstrees}/dataBases/SerializableType.kt | 2 +- .../main/kotlin/bstrees}/dataBases/reps/DBTreeRepo.kt | 4 ++-- .../kotlin/bstrees}/dataBases/reps/JsonTreeRepo.kt | 4 ++-- .../main/kotlin/bstrees}/dataBases/reps/SQLTables.kt | 2 +- .../main/kotlin/bstrees}/dataBases/reps/SQLTreeRepo.kt | 7 ++++--- .../src/main/kotlin/bstrees}/trees/BTree.kt | 2 +- .../src/main/kotlin/bstrees}/trees/Balancer.kt | 2 +- .../src/main/kotlin/bstrees}/trees/Node.kt | 2 +- .../src/main/kotlin/bstrees}/trees/avl/AvlBalancer.kt | 4 ++-- .../src/main/kotlin/bstrees}/trees/avl/AvlNode.kt | 4 ++-- .../src/main/kotlin/bstrees}/trees/avl/AvlTree.kt | 4 ++-- .../kotlin/bstrees}/trees/binarySearch/BSBalancer.kt | 4 ++-- .../main/kotlin/bstrees}/trees/binarySearch/BSNode.kt | 4 ++-- .../main/kotlin/bstrees}/trees/binarySearch/BSTree.kt | 4 ++-- .../main/kotlin/bstrees}/trees/redBlack/RBBalancer.kt | 6 +++--- .../src/main/kotlin/bstrees}/trees/redBlack/RBNode.kt | 4 ++-- .../src/main/kotlin/bstrees}/trees/redBlack/RBTree.kt | 6 +++--- .../src/test/kotlin/avlTree/AVLTreeTest.kt | 4 ++-- .../src/test/kotlin/balancers/BalancerTest.kt | 8 ++++---- .../src/test/kotlin/binarySearchTree/BSTreeTest.kt | 4 ++-- .../src/test/kotlin/redBlackTree/RBTreeTest.kt | 4 ++-- .../src/test/kotlin/treeInvariants/TreesInvariants.kt | 10 +++++----- {BSTrees => lib}/src/test/kotlin/utils/BSTreeUtil.kt | 4 ++-- settings.gradle.kts | 2 +- 25 files changed, 51 insertions(+), 50 deletions(-) rename {BSTrees => lib}/build.gradle.kts (100%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/dataBases/SerializableType.kt (93%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/dataBases/reps/DBTreeRepo.kt (73%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/dataBases/reps/JsonTreeRepo.kt (96%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/dataBases/reps/SQLTables.kt (97%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/dataBases/reps/SQLTreeRepo.kt (95%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/trees/BTree.kt (98%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/trees/Balancer.kt (98%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/trees/Node.kt (97%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/trees/avl/AvlBalancer.kt (97%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/trees/avl/AvlNode.kt (93%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/trees/avl/AvlTree.kt (99%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/trees/binarySearch/BSBalancer.kt (94%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/trees/binarySearch/BSNode.kt (93%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/trees/binarySearch/BSTree.kt (98%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/trees/redBlack/RBBalancer.kt (98%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/trees/redBlack/RBNode.kt (92%) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees}/trees/redBlack/RBTree.kt (98%) rename {BSTrees => lib}/src/test/kotlin/avlTree/AVLTreeTest.kt (98%) rename {BSTrees => lib}/src/test/kotlin/balancers/BalancerTest.kt (88%) rename {BSTrees => lib}/src/test/kotlin/binarySearchTree/BSTreeTest.kt (98%) rename {BSTrees => lib}/src/test/kotlin/redBlackTree/RBTreeTest.kt (98%) rename {BSTrees => lib}/src/test/kotlin/treeInvariants/TreesInvariants.kt (94%) rename {BSTrees => lib}/src/test/kotlin/utils/BSTreeUtil.kt (97%) diff --git a/BSTrees/build.gradle.kts b/lib/build.gradle.kts similarity index 100% rename from BSTrees/build.gradle.kts rename to lib/build.gradle.kts diff --git a/BSTrees/src/main/kotlin/dataBases/SerializableType.kt b/lib/src/main/kotlin/bstrees/dataBases/SerializableType.kt similarity index 93% rename from BSTrees/src/main/kotlin/dataBases/SerializableType.kt rename to lib/src/main/kotlin/bstrees/dataBases/SerializableType.kt index ed3ab54..e9cb6e9 100644 --- a/BSTrees/src/main/kotlin/dataBases/SerializableType.kt +++ b/lib/src/main/kotlin/bstrees/dataBases/SerializableType.kt @@ -1,4 +1,4 @@ -package dataBases +package bstrees.dataBases import kotlinx.serialization.Serializable diff --git a/BSTrees/src/main/kotlin/dataBases/reps/DBTreeRepo.kt b/lib/src/main/kotlin/bstrees/dataBases/reps/DBTreeRepo.kt similarity index 73% rename from BSTrees/src/main/kotlin/dataBases/reps/DBTreeRepo.kt rename to lib/src/main/kotlin/bstrees/dataBases/reps/DBTreeRepo.kt index b20f4ab..9b0374f 100644 --- a/BSTrees/src/main/kotlin/dataBases/reps/DBTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/dataBases/reps/DBTreeRepo.kt @@ -1,6 +1,6 @@ -package dataBases.reps +package bstrees.dataBases.reps -import dataBases.SerializableTree +import bstrees.dataBases.SerializableTree interface DBTreeRepo { fun getTree(typeTree: String, treeName: String): SerializableTree? diff --git a/BSTrees/src/main/kotlin/dataBases/reps/JsonTreeRepo.kt b/lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt similarity index 96% rename from BSTrees/src/main/kotlin/dataBases/reps/JsonTreeRepo.kt rename to lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt index 27c8d76..1a64e2d 100644 --- a/BSTrees/src/main/kotlin/dataBases/reps/JsonTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt @@ -1,8 +1,8 @@ -package dataBases.reps +package bstrees.dataBases.reps import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json -import dataBases.SerializableTree +import bstrees.dataBases.SerializableTree import kotlinx.serialization.encodeToString import java.io.File import java.io.FileNotFoundException diff --git a/BSTrees/src/main/kotlin/dataBases/reps/SQLTables.kt b/lib/src/main/kotlin/bstrees/dataBases/reps/SQLTables.kt similarity index 97% rename from BSTrees/src/main/kotlin/dataBases/reps/SQLTables.kt rename to lib/src/main/kotlin/bstrees/dataBases/reps/SQLTables.kt index 4ff6a9d..cad97c8 100644 --- a/BSTrees/src/main/kotlin/dataBases/reps/SQLTables.kt +++ b/lib/src/main/kotlin/bstrees/dataBases/reps/SQLTables.kt @@ -1,4 +1,4 @@ -package dataBases.reps +package bstrees.dataBases.reps import org.jetbrains.exposed.dao.IntEntity import org.jetbrains.exposed.dao.IntEntityClass diff --git a/BSTrees/src/main/kotlin/dataBases/reps/SQLTreeRepo.kt b/lib/src/main/kotlin/bstrees/dataBases/reps/SQLTreeRepo.kt similarity index 95% rename from BSTrees/src/main/kotlin/dataBases/reps/SQLTreeRepo.kt rename to lib/src/main/kotlin/bstrees/dataBases/reps/SQLTreeRepo.kt index 1b80943..cf67551 100644 --- a/BSTrees/src/main/kotlin/dataBases/reps/SQLTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/dataBases/reps/SQLTreeRepo.kt @@ -1,14 +1,15 @@ -package dataBases.reps +package bstrees.dataBases.reps +import bstrees.dataBases.SerializableNode +import bstrees.dataBases.SerializableTree import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.and import org.jetbrains.exposed.sql.transactions.transaction -import dataBases.* import java.io.File -object SQLTreeRepo: DBTreeRepo{ +object SQLTreeRepo: DBTreeRepo { private fun connectDB(dbName: String) { diff --git a/BSTrees/src/main/kotlin/trees/BTree.kt b/lib/src/main/kotlin/bstrees/trees/BTree.kt similarity index 98% rename from BSTrees/src/main/kotlin/trees/BTree.kt rename to lib/src/main/kotlin/bstrees/trees/BTree.kt index 022b926..0d11a9f 100644 --- a/BSTrees/src/main/kotlin/trees/BTree.kt +++ b/lib/src/main/kotlin/bstrees/trees/BTree.kt @@ -1,4 +1,4 @@ -package trees +package bstrees.trees /** * An abstract class representing a binary search tree. diff --git a/BSTrees/src/main/kotlin/trees/Balancer.kt b/lib/src/main/kotlin/bstrees/trees/Balancer.kt similarity index 98% rename from BSTrees/src/main/kotlin/trees/Balancer.kt rename to lib/src/main/kotlin/bstrees/trees/Balancer.kt index ba1fcfc..9f805e0 100644 --- a/BSTrees/src/main/kotlin/trees/Balancer.kt +++ b/lib/src/main/kotlin/bstrees/trees/Balancer.kt @@ -1,4 +1,4 @@ -package trees +package bstrees.trees /** * An abstract class representing a binary search tree. diff --git a/BSTrees/src/main/kotlin/trees/Node.kt b/lib/src/main/kotlin/bstrees/trees/Node.kt similarity index 97% rename from BSTrees/src/main/kotlin/trees/Node.kt rename to lib/src/main/kotlin/bstrees/trees/Node.kt index 5830d9f..7f35e88 100644 --- a/BSTrees/src/main/kotlin/trees/Node.kt +++ b/lib/src/main/kotlin/bstrees/trees/Node.kt @@ -1,4 +1,4 @@ -package trees +package bstrees.trees /** * An abstract class representing a binary search tree node. diff --git a/BSTrees/src/main/kotlin/trees/avl/AvlBalancer.kt b/lib/src/main/kotlin/bstrees/trees/avl/AvlBalancer.kt similarity index 97% rename from BSTrees/src/main/kotlin/trees/avl/AvlBalancer.kt rename to lib/src/main/kotlin/bstrees/trees/avl/AvlBalancer.kt index 7f676c3..1ef8673 100644 --- a/BSTrees/src/main/kotlin/trees/avl/AvlBalancer.kt +++ b/lib/src/main/kotlin/bstrees/trees/avl/AvlBalancer.kt @@ -1,6 +1,6 @@ -package trees.avl +package bstrees.trees.avl -import trees.Balancer +import bstrees.trees.Balancer /** * A class representing an AVL binary search tree balancer. diff --git a/BSTrees/src/main/kotlin/trees/avl/AvlNode.kt b/lib/src/main/kotlin/bstrees/trees/avl/AvlNode.kt similarity index 93% rename from BSTrees/src/main/kotlin/trees/avl/AvlNode.kt rename to lib/src/main/kotlin/bstrees/trees/avl/AvlNode.kt index bc64761..68ddd17 100644 --- a/BSTrees/src/main/kotlin/trees/avl/AvlNode.kt +++ b/lib/src/main/kotlin/bstrees/trees/avl/AvlNode.kt @@ -1,6 +1,6 @@ -package trees.avl +package bstrees.trees.avl -import trees.Node +import bstrees.trees.Node import kotlin.math.max /** diff --git a/BSTrees/src/main/kotlin/trees/avl/AvlTree.kt b/lib/src/main/kotlin/bstrees/trees/avl/AvlTree.kt similarity index 99% rename from BSTrees/src/main/kotlin/trees/avl/AvlTree.kt rename to lib/src/main/kotlin/bstrees/trees/avl/AvlTree.kt index eddaa2a..ed63a14 100644 --- a/BSTrees/src/main/kotlin/trees/avl/AvlTree.kt +++ b/lib/src/main/kotlin/bstrees/trees/avl/AvlTree.kt @@ -1,6 +1,6 @@ -package trees.avl +package bstrees.trees.avl -import trees.BTree +import bstrees.trees.BTree /** * A class representing an AVL binary search tree. diff --git a/BSTrees/src/main/kotlin/trees/binarySearch/BSBalancer.kt b/lib/src/main/kotlin/bstrees/trees/binarySearch/BSBalancer.kt similarity index 94% rename from BSTrees/src/main/kotlin/trees/binarySearch/BSBalancer.kt rename to lib/src/main/kotlin/bstrees/trees/binarySearch/BSBalancer.kt index f86cffe..ad50bfb 100644 --- a/BSTrees/src/main/kotlin/trees/binarySearch/BSBalancer.kt +++ b/lib/src/main/kotlin/bstrees/trees/binarySearch/BSBalancer.kt @@ -1,6 +1,6 @@ -package trees.binarySearch +package bstrees.trees.binarySearch -import trees.Balancer +import bstrees.trees.Balancer /** * A class representing a randomized binary search tree balancer. diff --git a/BSTrees/src/main/kotlin/trees/binarySearch/BSNode.kt b/lib/src/main/kotlin/bstrees/trees/binarySearch/BSNode.kt similarity index 93% rename from BSTrees/src/main/kotlin/trees/binarySearch/BSNode.kt rename to lib/src/main/kotlin/bstrees/trees/binarySearch/BSNode.kt index f95d6b1..ae2bcb3 100644 --- a/BSTrees/src/main/kotlin/trees/binarySearch/BSNode.kt +++ b/lib/src/main/kotlin/bstrees/trees/binarySearch/BSNode.kt @@ -1,6 +1,6 @@ -package trees.binarySearch +package bstrees.trees.binarySearch -import trees.Node +import bstrees.trees.Node /** * A class representing a randomized binary search tree node. diff --git a/BSTrees/src/main/kotlin/trees/binarySearch/BSTree.kt b/lib/src/main/kotlin/bstrees/trees/binarySearch/BSTree.kt similarity index 98% rename from BSTrees/src/main/kotlin/trees/binarySearch/BSTree.kt rename to lib/src/main/kotlin/bstrees/trees/binarySearch/BSTree.kt index 81c5511..2d3dc3f 100644 --- a/BSTrees/src/main/kotlin/trees/binarySearch/BSTree.kt +++ b/lib/src/main/kotlin/bstrees/trees/binarySearch/BSTree.kt @@ -1,6 +1,6 @@ -package trees.binarySearch +package bstrees.trees.binarySearch -import trees.BTree +import bstrees.trees.BTree import kotlin.random.Random /** diff --git a/BSTrees/src/main/kotlin/trees/redBlack/RBBalancer.kt b/lib/src/main/kotlin/bstrees/trees/redBlack/RBBalancer.kt similarity index 98% rename from BSTrees/src/main/kotlin/trees/redBlack/RBBalancer.kt rename to lib/src/main/kotlin/bstrees/trees/redBlack/RBBalancer.kt index ea4229d..5adbe98 100644 --- a/BSTrees/src/main/kotlin/trees/redBlack/RBBalancer.kt +++ b/lib/src/main/kotlin/bstrees/trees/redBlack/RBBalancer.kt @@ -1,7 +1,7 @@ -package trees.redBlack +package bstrees.trees.redBlack -import trees.Balancer -import trees.redBlack.RBNode.Color +import bstrees.trees.Balancer +import bstrees.trees.redBlack.RBNode.Color /** * A class representing a red black binary search tree balancer. diff --git a/BSTrees/src/main/kotlin/trees/redBlack/RBNode.kt b/lib/src/main/kotlin/bstrees/trees/redBlack/RBNode.kt similarity index 92% rename from BSTrees/src/main/kotlin/trees/redBlack/RBNode.kt rename to lib/src/main/kotlin/bstrees/trees/redBlack/RBNode.kt index 3a1ce5b..5d776ba 100644 --- a/BSTrees/src/main/kotlin/trees/redBlack/RBNode.kt +++ b/lib/src/main/kotlin/bstrees/trees/redBlack/RBNode.kt @@ -1,6 +1,6 @@ -package trees.redBlack +package bstrees.trees.redBlack -import trees.Node +import bstrees.trees.Node /** * A class representing an AVL binary search tree node. diff --git a/BSTrees/src/main/kotlin/trees/redBlack/RBTree.kt b/lib/src/main/kotlin/bstrees/trees/redBlack/RBTree.kt similarity index 98% rename from BSTrees/src/main/kotlin/trees/redBlack/RBTree.kt rename to lib/src/main/kotlin/bstrees/trees/redBlack/RBTree.kt index 9f66019..d0d72d7 100644 --- a/BSTrees/src/main/kotlin/trees/redBlack/RBTree.kt +++ b/lib/src/main/kotlin/bstrees/trees/redBlack/RBTree.kt @@ -1,7 +1,7 @@ -package trees.redBlack +package bstrees.trees.redBlack -import trees.BTree -import trees.redBlack.RBNode.Color +import bstrees.trees.BTree +import bstrees.trees.redBlack.RBNode.Color /** * A class representing a red black binary search tree. diff --git a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt b/lib/src/test/kotlin/avlTree/AVLTreeTest.kt similarity index 98% rename from BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt rename to lib/src/test/kotlin/avlTree/AVLTreeTest.kt index c218e02..9e358c7 100644 --- a/BSTrees/src/test/kotlin/avlTree/AVLTreeTest.kt +++ b/lib/src/test/kotlin/avlTree/AVLTreeTest.kt @@ -4,8 +4,8 @@ import org.junit.jupiter.api.* import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import treeInvariants.TreesInvariants -import trees.avl.AvlNode -import trees.avl.AvlTree +import bstrees.trees.avl.AvlNode +import bstrees.trees.avl.AvlTree import kotlin.random.Random @TestInstance(TestInstance.Lifecycle.PER_CLASS) diff --git a/BSTrees/src/test/kotlin/balancers/BalancerTest.kt b/lib/src/test/kotlin/balancers/BalancerTest.kt similarity index 88% rename from BSTrees/src/test/kotlin/balancers/BalancerTest.kt rename to lib/src/test/kotlin/balancers/BalancerTest.kt index a8d28fe..8f52ee6 100644 --- a/BSTrees/src/test/kotlin/balancers/BalancerTest.kt +++ b/lib/src/test/kotlin/balancers/BalancerTest.kt @@ -1,9 +1,9 @@ package balancers -import trees.Balancer -import trees.Node -import trees.binarySearch.BSBalancer -import trees.binarySearch.BSNode +import bstrees.trees.Balancer +import bstrees.trees.Node +import bstrees.trees.binarySearch.BSBalancer +import bstrees.trees.binarySearch.BSNode import org.junit.jupiter.api.Test import utils.BSTreeUtil diff --git a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt similarity index 98% rename from BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt rename to lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt index 295a533..2768970 100644 --- a/BSTrees/src/test/kotlin/binarySearchTree/BSTreeTest.kt +++ b/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt @@ -4,8 +4,8 @@ import org.junit.jupiter.api.* import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import treeInvariants.TreesInvariants -import trees.binarySearch.BSNode -import trees.binarySearch.BSTree +import bstrees.trees.binarySearch.BSNode +import bstrees.trees.binarySearch.BSTree import kotlin.random.Random @TestInstance(TestInstance.Lifecycle.PER_CLASS) diff --git a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt b/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt similarity index 98% rename from BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt rename to lib/src/test/kotlin/redBlackTree/RBTreeTest.kt index e5816e8..294b458 100644 --- a/BSTrees/src/test/kotlin/redBlackTree/RBTreeTest.kt +++ b/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt @@ -5,8 +5,8 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import treeInvariants.TreesInvariants -import trees.redBlack.RBNode -import trees.redBlack.RBTree +import bstrees.trees.redBlack.RBNode +import bstrees.trees.redBlack.RBTree import kotlin.random.Random const val seed = 10 diff --git a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt b/lib/src/test/kotlin/treeInvariants/TreesInvariants.kt similarity index 94% rename from BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt rename to lib/src/test/kotlin/treeInvariants/TreesInvariants.kt index 0425279..cd64081 100644 --- a/BSTrees/src/test/kotlin/treeInvariants/TreesInvariants.kt +++ b/lib/src/test/kotlin/treeInvariants/TreesInvariants.kt @@ -1,10 +1,10 @@ package treeInvariants -import trees.Node -import trees.avl.AvlNode -import trees.binarySearch.BSNode -import trees.redBlack.RBNode -import trees.redBlack.RBNode.Color +import bstrees.trees.Node +import bstrees.trees.avl.AvlNode +import bstrees.trees.binarySearch.BSNode +import bstrees.trees.redBlack.RBNode +import bstrees.trees.redBlack.RBNode.Color @Suppress("UNCHECKED_CAST") class TreesInvariants, V, NODE_TYPE : Node> { diff --git a/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt b/lib/src/test/kotlin/utils/BSTreeUtil.kt similarity index 97% rename from BSTrees/src/test/kotlin/utils/BSTreeUtil.kt rename to lib/src/test/kotlin/utils/BSTreeUtil.kt index f06dc27..d309ed6 100644 --- a/BSTrees/src/test/kotlin/utils/BSTreeUtil.kt +++ b/lib/src/test/kotlin/utils/BSTreeUtil.kt @@ -1,7 +1,7 @@ package utils -import trees.binarySearch.BSNode -import trees.binarySearch.BSTree +import bstrees.trees.binarySearch.BSNode +import bstrees.trees.binarySearch.BSTree /** diff --git a/settings.gradle.kts b/settings.gradle.kts index 9eb9fb1..d4d88e1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1,3 @@ rootProject.name = "trees-6" include("app") -include("BSTrees") +include("lib") From 53a52b871d4f32ca075a9681d22d6b995630812f Mon Sep 17 00:00:00 2001 From: LeonidElkin Date: Tue, 25 Apr 2023 00:57:19 +0300 Subject: [PATCH 082/135] fix: CI fixed due to the latest changes --- .github/workflows/CI.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 24a8d43..6818d2d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -20,12 +20,12 @@ jobs: - name: Run build with Gradle Wrapper run: ./gradlew build - - name: Upload BSTrees jar + - name: Upload lib jar uses: actions/upload-artifact@v3 if: github.ref == 'refs/heads/main' with: name: BSTrees lib - path: BSTrees/build/libs/BSTrees.jar + path: lib/build/libs/lib.jar - if: matrix.os == 'ubuntu-latest' name: Run Test Coverage @@ -36,4 +36,4 @@ jobs: uses: cicirello/jacoco-badge-generator@v2.8.0 with: generate-branches-badge: true - jacoco-csv-file: BSTrees/build/jacoco/jacocoCsv \ No newline at end of file + jacoco-csv-file: lib/build/jacoco/jacocoCsv \ No newline at end of file From 7c8eb7ff9f7a41de70089ea1e11ead9d867d6ef0 Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Tue, 25 Apr 2023 01:41:09 +0300 Subject: [PATCH 083/135] fix: Resolved merge conflict --- lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt b/lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt index c832cd0..ae11315 100644 --- a/lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt @@ -1,10 +1,10 @@ -package serialization.reps +package bstrees.dataBases.reps import org.neo4j.driver.AuthTokens import org.neo4j.driver.GraphDatabase import org.neo4j.driver.TransactionContext -import serialization.SerializableNode -import serialization.SerializableTree +import bstrees.dataBases.SerializableNode +import bstrees.dataBases.SerializableTree import java.io.Closeable object Neo4jTreeRepo : Closeable, DBTreeRepo { From 1f3c18a6b7f68fe0c528d065eaa58b620938df87 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 25 Apr 2023 02:08:49 +0300 Subject: [PATCH 084/135] feat: a small refactoring of build.gradle --- BSTrees/build.gradle.kts | 9 ++++++--- gradle.properties | 5 ++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/BSTrees/build.gradle.kts b/BSTrees/build.gradle.kts index 5c02e08..26aefe4 100644 --- a/BSTrees/build.gradle.kts +++ b/BSTrees/build.gradle.kts @@ -3,6 +3,9 @@ val junit5Version: String? by rootProject val gsonVersion: String? by rootProject val kotlinxSerializationVersion: String? by rootProject val neo4jDriverVersion: String? by project +val sqliteJdbcVersion: String? by project +val kotlinLoggingVersion: String? by project +val slf4jVersion: String? by project plugins { id("org.jetbrains.kotlin.jvm") version "1.8.20" @@ -26,10 +29,10 @@ dependencies { implementation("org.jetbrains.exposed:exposed-core:$jetbrainsExposedVersion") implementation("org.jetbrains.exposed:exposed-jdbc:$jetbrainsExposedVersion") implementation("org.jetbrains.exposed:exposed-dao:$jetbrainsExposedVersion") - implementation("org.xerial:sqlite-jdbc:3.34.0") + implementation("org.xerial:sqlite-jdbc:$sqliteJdbcVersion") - implementation("io.github.microutils", "kotlin-logging-jvm", "2.0.6") - implementation("org.slf4j", "slf4j-simple", "1.7.29") + implementation("io.github.microutils:kotlin-logging-jvm:$kotlinLoggingVersion") + implementation("org.slf4j:slf4j-simple:$slf4jVersion") testImplementation("org.junit.jupiter:junit-jupiter-engine:$junit5Version") testImplementation("org.junit.jupiter:junit-jupiter-params:$junit5Version") diff --git a/gradle.properties b/gradle.properties index 787e190..945d0b3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,4 +2,7 @@ junit5Version=5.9.1 jetbrainsExposedVersion=0.38.1 gsonVersion=2.8.5 kotlinxSerializationVersion=1.5.0 -neo4jDriverVersion=5.6.0 \ No newline at end of file +neo4jDriverVersion=5.6.0 +sqliteJdbcVersion=3.34.0 +kotlinLoggingVersion=2.0.6 +slf4jVersion=1.7.29 \ No newline at end of file From 5513510147dd850129f8d628174ee148ee5b5bf6 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 25 Apr 2023 02:12:11 +0300 Subject: [PATCH 085/135] feat: Added dbConfig.properties file --- BSTrees/src/main/resources/dbConfig.properties | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 BSTrees/src/main/resources/dbConfig.properties diff --git a/BSTrees/src/main/resources/dbConfig.properties b/BSTrees/src/main/resources/dbConfig.properties new file mode 100644 index 0000000..1e31e2d --- /dev/null +++ b/BSTrees/src/main/resources/dbConfig.properties @@ -0,0 +1,5 @@ +neo4j.host = bolt://localhost:7687 +neo4j.username = neo4j +neo4j.password = qwertyui +json.dir = JSONTrees +sql.dbName = SQLTrees \ No newline at end of file From 92c7b97a6fc84aa09a8f4ecd54a2f3b9ae53660c Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 25 Apr 2023 03:49:00 +0300 Subject: [PATCH 086/135] fix: Added PathsUtil and dbConfig.properties --- lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt | 2 +- lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt | 2 +- .../src/main/kotlin/bstrees/dataBases}/utils/PathsUtil.kt | 2 +- lib/src/main/resources/dbConfig.properties | 5 +++++ 4 files changed, 8 insertions(+), 3 deletions(-) rename {BSTrees/src/main/kotlin => lib/src/main/kotlin/bstrees/dataBases}/utils/PathsUtil.kt (75%) create mode 100644 lib/src/main/resources/dbConfig.properties diff --git a/lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt b/lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt index 9f81c3d..dee3b8a 100644 --- a/lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt @@ -8,7 +8,7 @@ import mu.KotlinLogging import java.io.* import java.util.* import kotlin.io.path.Path -import utils.PathsUtil.PROPERTIES_FILE_PATH +import bstrees.dataBases.utils.PathsUtil.PROPERTIES_FILE_PATH import java.nio.file.FileAlreadyExistsException private val logger = KotlinLogging.logger { } diff --git a/lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt b/lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt index edcf526..8042150 100644 --- a/lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt @@ -9,7 +9,7 @@ import bstrees.dataBases.SerializableTree import java.io.Closeable import java.io.FileInputStream import java.util.* -import utils.PathsUtil.PROPERTIES_FILE_PATH +import bstrees.dataBases.utils.PathsUtil.PROPERTIES_FILE_PATH private val logger = KotlinLogging.logger { } diff --git a/BSTrees/src/main/kotlin/utils/PathsUtil.kt b/lib/src/main/kotlin/bstrees/dataBases/utils/PathsUtil.kt similarity index 75% rename from BSTrees/src/main/kotlin/utils/PathsUtil.kt rename to lib/src/main/kotlin/bstrees/dataBases/utils/PathsUtil.kt index 8a64432..24a6626 100644 --- a/BSTrees/src/main/kotlin/utils/PathsUtil.kt +++ b/lib/src/main/kotlin/bstrees/dataBases/utils/PathsUtil.kt @@ -1,4 +1,4 @@ -package utils +package bstrees.dataBases.utils object PathsUtil { const val PROPERTIES_FILE_PATH = "src/main/resources/dbConfig.properties" diff --git a/lib/src/main/resources/dbConfig.properties b/lib/src/main/resources/dbConfig.properties new file mode 100644 index 0000000..1e31e2d --- /dev/null +++ b/lib/src/main/resources/dbConfig.properties @@ -0,0 +1,5 @@ +neo4j.host = bolt://localhost:7687 +neo4j.username = neo4j +neo4j.password = qwertyui +json.dir = JSONTrees +sql.dbName = SQLTrees \ No newline at end of file From 73208f91dd9d99dccff380a14e8a44f370023266 Mon Sep 17 00:00:00 2001 From: Kirill Shishin <73890886+tepa46@users.noreply.github.com> Date: Tue, 25 Apr 2023 03:54:30 +0300 Subject: [PATCH 087/135] Delete extra directory --- BSTrees/src/main/resources/dbConfig.properties | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 BSTrees/src/main/resources/dbConfig.properties diff --git a/BSTrees/src/main/resources/dbConfig.properties b/BSTrees/src/main/resources/dbConfig.properties deleted file mode 100644 index 1e31e2d..0000000 --- a/BSTrees/src/main/resources/dbConfig.properties +++ /dev/null @@ -1,5 +0,0 @@ -neo4j.host = bolt://localhost:7687 -neo4j.username = neo4j -neo4j.password = qwertyui -json.dir = JSONTrees -sql.dbName = SQLTrees \ No newline at end of file From 463c48998ed7c7bc47cec630129ddac3f0fb70b6 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Wed, 26 Apr 2023 00:56:15 +0300 Subject: [PATCH 088/135] feat: Added new database class constructor --- .../bstrees/dataBases/reps/JsonTreeRepo.kt | 24 ++++++------------- .../bstrees/dataBases/reps/Neo4jTreeRepo.kt | 20 +--------------- .../bstrees/dataBases/reps/SQLTreeRepo.kt | 12 +--------- .../bstrees/dataBases/utils/PathsUtil.kt | 5 ---- 4 files changed, 9 insertions(+), 52 deletions(-) delete mode 100644 lib/src/main/kotlin/bstrees/dataBases/utils/PathsUtil.kt diff --git a/lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt b/lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt index dee3b8a..cb4e7e7 100644 --- a/lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt @@ -6,29 +6,20 @@ import bstrees.dataBases.SerializableTree import kotlinx.serialization.encodeToString import mu.KotlinLogging import java.io.* -import java.util.* import kotlin.io.path.Path -import bstrees.dataBases.utils.PathsUtil.PROPERTIES_FILE_PATH import java.nio.file.FileAlreadyExistsException private val logger = KotlinLogging.logger { } -class JsonTreeRepo : DBTreeRepo { - private var dir : String +class JsonTreeRepo(private val dir: String) : DBTreeRepo { init { - val property = Properties() - val propertiesFile = FileInputStream(PROPERTIES_FILE_PATH) - property.load(propertiesFile) - - dir = property.getProperty("json.dir") makeDir(dir) - logger.info { "[JSON] Dir paths was created" } } - private fun makeDir(dir: String){ + private fun makeDir(dir: String) { File(dir).mkdir() File(Path(dir, "BSTree").toUri()).mkdir() File(Path(dir, "RBTree").toUri()).mkdir() @@ -50,7 +41,7 @@ class JsonTreeRepo : DBTreeRepo { Json.decodeFromString(jsonText) } catch (e: FileNotFoundException) { - logger.warn { "[JSON] Tree file not found"} + logger.warn { "[JSON] Tree file not found" } fileFound = false null } catch (e: Exception) { @@ -70,20 +61,19 @@ class JsonTreeRepo : DBTreeRepo { var fileAlreadyExists = false try { - if(File(filePath).exists()){ + if (File(filePath).exists()) { fileAlreadyExists = true throw FileAlreadyExistsException("") } file = FileWriter(filePath) file.write(Json.encodeToString(serializableTree)) - }catch (e: FileAlreadyExistsException){ + } catch (e: FileAlreadyExistsException) { logger.warn { "[JSON] A tree with that name already exists" } - } - catch (e: Exception) { + } catch (e: Exception) { logger.error { "[JSON] Error getting the tree: $e" } throw e } finally { - if(!fileAlreadyExists) { + if (!fileAlreadyExists) { file.flush() file.close() } diff --git a/lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt b/lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt index 8042150..6ae17a9 100644 --- a/lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt @@ -7,28 +7,10 @@ import org.neo4j.driver.TransactionContext import bstrees.dataBases.SerializableNode import bstrees.dataBases.SerializableTree import java.io.Closeable -import java.io.FileInputStream -import java.util.* -import bstrees.dataBases.utils.PathsUtil.PROPERTIES_FILE_PATH private val logger = KotlinLogging.logger { } -class Neo4jTreeRepo : Closeable, DBTreeRepo { - private var host: String - private var username: String - private var password: String - - init { - val property = Properties() - - val propertiesFile = FileInputStream(PROPERTIES_FILE_PATH) - property.load(propertiesFile) - - host = property.getProperty("neo4j.host") - username = property.getProperty("neo4j.username") - password = property.getProperty("neo4j.password") - } - +class Neo4jTreeRepo(host: String, username: String, password: String) : Closeable, DBTreeRepo { private val driver = GraphDatabase.driver(host, AuthTokens.basic(username, password)) private val session = driver.session() diff --git a/lib/src/main/kotlin/bstrees/dataBases/reps/SQLTreeRepo.kt b/lib/src/main/kotlin/bstrees/dataBases/reps/SQLTreeRepo.kt index ec9d280..4dff232 100644 --- a/lib/src/main/kotlin/bstrees/dataBases/reps/SQLTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/dataBases/reps/SQLTreeRepo.kt @@ -14,9 +14,6 @@ import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.dao.id.IntIdTable import org.jetbrains.exposed.sql.ReferenceOption import java.io.File -import java.io.FileInputStream -import java.util.* -import bstrees.dataBases.utils.PathsUtil.PROPERTIES_FILE_PATH private val logger = KotlinLogging.logger { } @@ -55,16 +52,9 @@ class NodeEntity(id: EntityID) : IntEntity(id) { var tree by TreeEntity referencedOn NodesTable.tree } -class SQLTreeRepo : DBTreeRepo { - private var dbName: String +class SQLTreeRepo(dbName: String) : DBTreeRepo { init { - val property = Properties() - val propertiesFile = FileInputStream(PROPERTIES_FILE_PATH) - property.load(propertiesFile) - - dbName = property.getProperty("sql.dbName") - connectDB(dbName) createTables() } diff --git a/lib/src/main/kotlin/bstrees/dataBases/utils/PathsUtil.kt b/lib/src/main/kotlin/bstrees/dataBases/utils/PathsUtil.kt deleted file mode 100644 index 24a6626..0000000 --- a/lib/src/main/kotlin/bstrees/dataBases/utils/PathsUtil.kt +++ /dev/null @@ -1,5 +0,0 @@ -package bstrees.dataBases.utils - -object PathsUtil { - const val PROPERTIES_FILE_PATH = "src/main/resources/dbConfig.properties" -} \ No newline at end of file From d6a946a78b39f0501d02a098c862e06e45aad4a6 Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Wed, 26 Apr 2023 02:48:35 +0300 Subject: [PATCH 089/135] feat: Preparing repository for ui. Implemented BsStrategy fix: Serializable types were divided into two classes --- .../{ => model}/dataBases/reps/DBTreeRepo.kt | 4 +- .../dataBases/reps/JsonTreeRepo.kt | 6 +-- .../dataBases/reps/Neo4jTreeRepo.kt | 8 +-- .../{ => model}/dataBases/reps/SQLTreeRepo.kt | 8 +-- .../dataBases/serialize/SerializeStrategy.kt | 29 ++++++++++ .../serialize/strategies/AvlStrategy.kt | 37 +++++++++++++ .../serialize/strategies/BsStrategy.kt | 54 +++++++++++++++++++ .../serialize/strategies/RbStrategy.kt | 36 +++++++++++++ .../serialize/types/SerializableNode.kt} | 9 +--- .../serialize/types/SerializableTree.kt | 9 ++++ .../{ => model}/dataBases/utils/PathsUtil.kt | 2 +- .../kotlin/bstrees/{ => model}/trees/BTree.kt | 2 +- .../bstrees/{ => model}/trees/Balancer.kt | 2 +- .../kotlin/bstrees/{ => model}/trees/Node.kt | 2 +- .../{ => model}/trees/avl/AvlBalancer.kt | 4 +- .../bstrees/{ => model}/trees/avl/AvlNode.kt | 4 +- .../bstrees/{ => model}/trees/avl/AvlTree.kt | 4 +- .../trees/binarySearch/BSBalancer.kt | 4 +- .../{ => model}/trees/binarySearch/BSNode.kt | 4 +- .../{ => model}/trees/binarySearch/BSTree.kt | 4 +- .../{ => model}/trees/redBlack/RBBalancer.kt | 6 +-- .../{ => model}/trees/redBlack/RBNode.kt | 4 +- .../{ => model}/trees/redBlack/RBTree.kt | 6 +-- lib/src/test/kotlin/avlTree/AVLTreeTest.kt | 4 +- lib/src/test/kotlin/balancers/BalancerTest.kt | 8 +-- .../kotlin/binarySearchTree/BSTreeTest.kt | 4 +- .../test/kotlin/redBlackTree/RBTreeTest.kt | 4 +- .../kotlin/treeInvariants/TreesInvariants.kt | 10 ++-- lib/src/test/kotlin/utils/BSTreeUtil.kt | 4 +- 29 files changed, 220 insertions(+), 62 deletions(-) rename lib/src/main/kotlin/bstrees/{ => model}/dataBases/reps/DBTreeRepo.kt (67%) rename lib/src/main/kotlin/bstrees/{ => model}/dataBases/reps/JsonTreeRepo.kt (95%) rename lib/src/main/kotlin/bstrees/{ => model}/dataBases/reps/Neo4jTreeRepo.kt (96%) rename lib/src/main/kotlin/bstrees/{ => model}/dataBases/reps/SQLTreeRepo.kt (95%) create mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt create mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/AvlStrategy.kt create mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt create mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt rename lib/src/main/kotlin/bstrees/{dataBases/SerializableType.kt => model/dataBases/serialize/types/SerializableNode.kt} (62%) create mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt rename lib/src/main/kotlin/bstrees/{ => model}/dataBases/utils/PathsUtil.kt (72%) rename lib/src/main/kotlin/bstrees/{ => model}/trees/BTree.kt (97%) rename lib/src/main/kotlin/bstrees/{ => model}/trees/Balancer.kt (98%) rename lib/src/main/kotlin/bstrees/{ => model}/trees/Node.kt (96%) rename lib/src/main/kotlin/bstrees/{ => model}/trees/avl/AvlBalancer.kt (97%) rename lib/src/main/kotlin/bstrees/{ => model}/trees/avl/AvlNode.kt (92%) rename lib/src/main/kotlin/bstrees/{ => model}/trees/avl/AvlTree.kt (98%) rename lib/src/main/kotlin/bstrees/{ => model}/trees/binarySearch/BSBalancer.kt (93%) rename lib/src/main/kotlin/bstrees/{ => model}/trees/binarySearch/BSNode.kt (92%) rename lib/src/main/kotlin/bstrees/{ => model}/trees/binarySearch/BSTree.kt (98%) rename lib/src/main/kotlin/bstrees/{ => model}/trees/redBlack/RBBalancer.kt (98%) rename lib/src/main/kotlin/bstrees/{ => model}/trees/redBlack/RBNode.kt (91%) rename lib/src/main/kotlin/bstrees/{ => model}/trees/redBlack/RBTree.kt (98%) diff --git a/lib/src/main/kotlin/bstrees/dataBases/reps/DBTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/DBTreeRepo.kt similarity index 67% rename from lib/src/main/kotlin/bstrees/dataBases/reps/DBTreeRepo.kt rename to lib/src/main/kotlin/bstrees/model/dataBases/reps/DBTreeRepo.kt index bf5b973..890c1c1 100644 --- a/lib/src/main/kotlin/bstrees/dataBases/reps/DBTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/DBTreeRepo.kt @@ -1,6 +1,6 @@ -package bstrees.dataBases.reps +package bstrees.model.dataBases.reps -import bstrees.dataBases.SerializableTree +import bstrees.model.dataBases.serialize.types.SerializableTree interface DBTreeRepo { fun getTree(treeName: String, treeType: String): SerializableTree? diff --git a/lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt similarity index 95% rename from lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt rename to lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt index dee3b8a..2d44c47 100644 --- a/lib/src/main/kotlin/bstrees/dataBases/reps/JsonTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt @@ -1,14 +1,14 @@ -package bstrees.dataBases.reps +package bstrees.model.dataBases.reps import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json -import bstrees.dataBases.SerializableTree +import bstrees.model.dataBases.serialize.types.SerializableTree import kotlinx.serialization.encodeToString import mu.KotlinLogging import java.io.* import java.util.* import kotlin.io.path.Path -import bstrees.dataBases.utils.PathsUtil.PROPERTIES_FILE_PATH +import bstrees.model.dataBases.utils.PathsUtil.PROPERTIES_FILE_PATH import java.nio.file.FileAlreadyExistsException private val logger = KotlinLogging.logger { } diff --git a/lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt similarity index 96% rename from lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt rename to lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt index 8042150..dd976f9 100644 --- a/lib/src/main/kotlin/bstrees/dataBases/reps/Neo4jTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt @@ -1,15 +1,15 @@ -package bstrees.dataBases.reps +package bstrees.model.dataBases.reps import mu.KotlinLogging import org.neo4j.driver.AuthTokens import org.neo4j.driver.GraphDatabase import org.neo4j.driver.TransactionContext -import bstrees.dataBases.SerializableNode -import bstrees.dataBases.SerializableTree +import bstrees.model.dataBases.serialize.types.SerializableNode +import bstrees.model.dataBases.serialize.types.SerializableTree import java.io.Closeable import java.io.FileInputStream import java.util.* -import bstrees.dataBases.utils.PathsUtil.PROPERTIES_FILE_PATH +import bstrees.model.dataBases.utils.PathsUtil.PROPERTIES_FILE_PATH private val logger = KotlinLogging.logger { } diff --git a/lib/src/main/kotlin/bstrees/dataBases/reps/SQLTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt similarity index 95% rename from lib/src/main/kotlin/bstrees/dataBases/reps/SQLTreeRepo.kt rename to lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt index ec9d280..ab6debd 100644 --- a/lib/src/main/kotlin/bstrees/dataBases/reps/SQLTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt @@ -1,7 +1,7 @@ -package bstrees.dataBases.reps +package bstrees.model.dataBases.reps -import bstrees.dataBases.SerializableNode -import bstrees.dataBases.SerializableTree +import bstrees.model.dataBases.serialize.types.SerializableNode +import bstrees.model.dataBases.serialize.types.SerializableTree import mu.KotlinLogging import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.SchemaUtils @@ -16,7 +16,7 @@ import org.jetbrains.exposed.sql.ReferenceOption import java.io.File import java.io.FileInputStream import java.util.* -import bstrees.dataBases.utils.PathsUtil.PROPERTIES_FILE_PATH +import bstrees.model.dataBases.utils.PathsUtil.PROPERTIES_FILE_PATH private val logger = KotlinLogging.logger { } diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt new file mode 100644 index 0000000..8136b94 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt @@ -0,0 +1,29 @@ +package bstrees.model.dataBases.serialize + +import bstrees.model.dataBases.serialize.types.SerializableNode +import bstrees.model.dataBases.serialize.types.SerializableTree +import bstrees.model.trees.Node + +abstract class SerializeStrategy, V, NODE_TYPE: Node, TREE_TYPE>( + val serializeKey: (K) -> String, + val serializeValue: (V) -> String, + val deserializeKey: (String) -> K, + val deserializeValue: (String) -> V +) { + + abstract fun serializeNode(node: NODE_TYPE): SerializableNode + + abstract fun deserializeNode(node: SerializableNode): NODE_TYPE + + abstract fun serializeTree(tree: TREE_TYPE, treeName: String): SerializableTree + + abstract fun deserializeTree(tree: SerializableTree): TREE_TYPE + + protected fun linkParents(node: NODE_TYPE){ + node.leftNode?.parent = node + node.rightNode?.parent = node + node.leftNode?.let { linkParents(it) } + node.rightNode?.let { linkParents(it) } + } + +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/AvlStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/AvlStrategy.kt new file mode 100644 index 0000000..398de43 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/AvlStrategy.kt @@ -0,0 +1,37 @@ +package bstrees.model.dataBases.serialize.strategies + +import bstrees.model.dataBases.serialize.SerializeStrategy +import bstrees.model.dataBases.serialize.types.SerializableNode +import bstrees.model.dataBases.serialize.types.SerializableTree +import bstrees.model.trees.avl.AvlNode +import bstrees.model.trees.avl.AvlTree + + +class AvlStrategy, V>( + serializeKey: (K) -> String, + serializeValue: (V) -> String, + deserializeKey: (String) -> K, + deserializeValue: (String) -> V +) : SerializeStrategy, AvlTree>( + serializeKey, + serializeValue, + deserializeKey, + deserializeValue +) { + override fun serializeNode(node: AvlNode): SerializableNode { + TODO("Not yet implemented") + } + + override fun deserializeNode(node: SerializableNode): AvlNode { + TODO("Not yet implemented") + } + + override fun serializeTree(tree: AvlTree, treeName: String): SerializableTree { + TODO("Not yet implemented") + } + + override fun deserializeTree(tree: SerializableTree): AvlTree { + TODO("Not yet implemented") + } + +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt new file mode 100644 index 0000000..2abf180 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt @@ -0,0 +1,54 @@ +package bstrees.model.dataBases.serialize.strategies + +import bstrees.model.dataBases.serialize.types.SerializableNode +import bstrees.model.dataBases.serialize.types.SerializableTree +import bstrees.model.dataBases.serialize.SerializeStrategy +import bstrees.model.trees.binarySearch.BSNode +import bstrees.model.trees.binarySearch.BSTree + +class BsStrategy, V>( + serializeKey: (K) -> String, + serializeValue: (V) -> String, + deserializeKey: (String) -> K, + deserializeValue: (String) -> V +) : SerializeStrategy, BSTree>( + serializeKey, + serializeValue, + deserializeKey, + deserializeValue +) { + + override fun serializeNode(node: BSNode): SerializableNode = SerializableNode( + serializeKey(node.key), + serializeValue(node.value), + "S${node.size}", + node.leftNode?.let { serializeNode(it) }, + node.rightNode?.let { serializeNode(it) } + ) + + override fun deserializeNode(node: SerializableNode): BSNode { + val bsnode: BSNode = BSNode(deserializeKey(node.key), deserializeValue(node.value)) + if (node.metadata[0] != 'S') throw Exception("Wrong metadata. Impossible to deserialize") + bsnode.size = deserializeMetadata(node.metadata) + node.leftNode?.let { deserializeNode(it) } + node.rightNode?.let { deserializeNode(it) } + linkParents(bsnode) + return bsnode + } + + override fun deserializeTree(tree: SerializableTree): BSTree{ + if (tree.treeType != "BS") throw Exception("Wrong tree type. Impossible to deserialize") + val bstree = BSTree() + bstree.root = tree.root?.let { deserializeNode(it) } + return bstree + } + + override fun serializeTree(tree: BSTree, treeName: String) = SerializableTree( + name = treeName, + treeType = "BS", + root = tree.root?.let { serializeNode(it) } + ) + + private fun deserializeMetadata(meta: String) = meta.substring(1).toInt() + +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt new file mode 100644 index 0000000..786b0fd --- /dev/null +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt @@ -0,0 +1,36 @@ +package bstrees.model.dataBases.serialize.strategies + +import bstrees.model.dataBases.serialize.SerializeStrategy +import bstrees.model.dataBases.serialize.types.SerializableNode +import bstrees.model.dataBases.serialize.types.SerializableTree +import bstrees.model.trees.redBlack.RBNode +import bstrees.model.trees.redBlack.RBTree + +class RbStrategy, V>( + serializeKey: (K) -> String, + serializeValue: (V) -> String, + deserializeKey: (String) -> K, + deserializeValue: (String) -> V +) : SerializeStrategy, RBTree>( + serializeKey, + serializeValue, + deserializeKey, + deserializeValue +){ + override fun serializeNode(node: RBNode): SerializableNode { + TODO("Not yet implemented") + } + + override fun deserializeNode(node: SerializableNode): RBNode { + TODO("Not yet implemented") + } + + override fun serializeTree(tree: RBTree, treeName: String): SerializableTree { + TODO("Not yet implemented") + } + + override fun deserializeTree(tree: SerializableTree): RBTree { + TODO("Not yet implemented") + } + +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/dataBases/SerializableType.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt similarity index 62% rename from lib/src/main/kotlin/bstrees/dataBases/SerializableType.kt rename to lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt index a63e619..d47b267 100644 --- a/lib/src/main/kotlin/bstrees/dataBases/SerializableType.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt @@ -1,14 +1,7 @@ -package bstrees.dataBases +package bstrees.model.dataBases.serialize.types import kotlinx.serialization.Serializable -@Serializable -class SerializableTree( - val name: String, - val treeType: String, - val root: SerializableNode? -) - @Serializable class SerializableNode( val key: String, diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt new file mode 100644 index 0000000..600d28d --- /dev/null +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt @@ -0,0 +1,9 @@ +package bstrees.model.dataBases.serialize.types +import kotlinx.serialization.Serializable + +@Serializable +class SerializableTree( + val name: String, + val treeType: String, + val root: SerializableNode? +) \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/dataBases/utils/PathsUtil.kt b/lib/src/main/kotlin/bstrees/model/dataBases/utils/PathsUtil.kt similarity index 72% rename from lib/src/main/kotlin/bstrees/dataBases/utils/PathsUtil.kt rename to lib/src/main/kotlin/bstrees/model/dataBases/utils/PathsUtil.kt index 24a6626..a46956c 100644 --- a/lib/src/main/kotlin/bstrees/dataBases/utils/PathsUtil.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/utils/PathsUtil.kt @@ -1,4 +1,4 @@ -package bstrees.dataBases.utils +package bstrees.model.dataBases.utils object PathsUtil { const val PROPERTIES_FILE_PATH = "src/main/resources/dbConfig.properties" diff --git a/lib/src/main/kotlin/bstrees/trees/BTree.kt b/lib/src/main/kotlin/bstrees/model/trees/BTree.kt similarity index 97% rename from lib/src/main/kotlin/bstrees/trees/BTree.kt rename to lib/src/main/kotlin/bstrees/model/trees/BTree.kt index 0d11a9f..964c57a 100644 --- a/lib/src/main/kotlin/bstrees/trees/BTree.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/BTree.kt @@ -1,4 +1,4 @@ -package bstrees.trees +package bstrees.model.trees /** * An abstract class representing a binary search tree. diff --git a/lib/src/main/kotlin/bstrees/trees/Balancer.kt b/lib/src/main/kotlin/bstrees/model/trees/Balancer.kt similarity index 98% rename from lib/src/main/kotlin/bstrees/trees/Balancer.kt rename to lib/src/main/kotlin/bstrees/model/trees/Balancer.kt index 9f805e0..c4f6b9f 100644 --- a/lib/src/main/kotlin/bstrees/trees/Balancer.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/Balancer.kt @@ -1,4 +1,4 @@ -package bstrees.trees +package bstrees.model.trees /** * An abstract class representing a binary search tree. diff --git a/lib/src/main/kotlin/bstrees/trees/Node.kt b/lib/src/main/kotlin/bstrees/model/trees/Node.kt similarity index 96% rename from lib/src/main/kotlin/bstrees/trees/Node.kt rename to lib/src/main/kotlin/bstrees/model/trees/Node.kt index 7f35e88..18a5908 100644 --- a/lib/src/main/kotlin/bstrees/trees/Node.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/Node.kt @@ -1,4 +1,4 @@ -package bstrees.trees +package bstrees.model.trees /** * An abstract class representing a binary search tree node. diff --git a/lib/src/main/kotlin/bstrees/trees/avl/AvlBalancer.kt b/lib/src/main/kotlin/bstrees/model/trees/avl/AvlBalancer.kt similarity index 97% rename from lib/src/main/kotlin/bstrees/trees/avl/AvlBalancer.kt rename to lib/src/main/kotlin/bstrees/model/trees/avl/AvlBalancer.kt index 1ef8673..d58bb1b 100644 --- a/lib/src/main/kotlin/bstrees/trees/avl/AvlBalancer.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/avl/AvlBalancer.kt @@ -1,6 +1,6 @@ -package bstrees.trees.avl +package bstrees.model.trees.avl -import bstrees.trees.Balancer +import bstrees.model.trees.Balancer /** * A class representing an AVL binary search tree balancer. diff --git a/lib/src/main/kotlin/bstrees/trees/avl/AvlNode.kt b/lib/src/main/kotlin/bstrees/model/trees/avl/AvlNode.kt similarity index 92% rename from lib/src/main/kotlin/bstrees/trees/avl/AvlNode.kt rename to lib/src/main/kotlin/bstrees/model/trees/avl/AvlNode.kt index 68ddd17..ae3b9ab 100644 --- a/lib/src/main/kotlin/bstrees/trees/avl/AvlNode.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/avl/AvlNode.kt @@ -1,6 +1,6 @@ -package bstrees.trees.avl +package bstrees.model.trees.avl -import bstrees.trees.Node +import bstrees.model.trees.Node import kotlin.math.max /** diff --git a/lib/src/main/kotlin/bstrees/trees/avl/AvlTree.kt b/lib/src/main/kotlin/bstrees/model/trees/avl/AvlTree.kt similarity index 98% rename from lib/src/main/kotlin/bstrees/trees/avl/AvlTree.kt rename to lib/src/main/kotlin/bstrees/model/trees/avl/AvlTree.kt index ed63a14..78d5202 100644 --- a/lib/src/main/kotlin/bstrees/trees/avl/AvlTree.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/avl/AvlTree.kt @@ -1,6 +1,6 @@ -package bstrees.trees.avl +package bstrees.model.trees.avl -import bstrees.trees.BTree +import bstrees.model.trees.BTree /** * A class representing an AVL binary search tree. diff --git a/lib/src/main/kotlin/bstrees/trees/binarySearch/BSBalancer.kt b/lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSBalancer.kt similarity index 93% rename from lib/src/main/kotlin/bstrees/trees/binarySearch/BSBalancer.kt rename to lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSBalancer.kt index ad50bfb..f52ffda 100644 --- a/lib/src/main/kotlin/bstrees/trees/binarySearch/BSBalancer.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSBalancer.kt @@ -1,6 +1,6 @@ -package bstrees.trees.binarySearch +package bstrees.model.trees.binarySearch -import bstrees.trees.Balancer +import bstrees.model.trees.Balancer /** * A class representing a randomized binary search tree balancer. diff --git a/lib/src/main/kotlin/bstrees/trees/binarySearch/BSNode.kt b/lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSNode.kt similarity index 92% rename from lib/src/main/kotlin/bstrees/trees/binarySearch/BSNode.kt rename to lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSNode.kt index ae2bcb3..6570778 100644 --- a/lib/src/main/kotlin/bstrees/trees/binarySearch/BSNode.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSNode.kt @@ -1,6 +1,6 @@ -package bstrees.trees.binarySearch +package bstrees.model.trees.binarySearch -import bstrees.trees.Node +import bstrees.model.trees.Node /** * A class representing a randomized binary search tree node. diff --git a/lib/src/main/kotlin/bstrees/trees/binarySearch/BSTree.kt b/lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSTree.kt similarity index 98% rename from lib/src/main/kotlin/bstrees/trees/binarySearch/BSTree.kt rename to lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSTree.kt index 2d3dc3f..5dbd674 100644 --- a/lib/src/main/kotlin/bstrees/trees/binarySearch/BSTree.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSTree.kt @@ -1,6 +1,6 @@ -package bstrees.trees.binarySearch +package bstrees.model.trees.binarySearch -import bstrees.trees.BTree +import bstrees.model.trees.BTree import kotlin.random.Random /** diff --git a/lib/src/main/kotlin/bstrees/trees/redBlack/RBBalancer.kt b/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBBalancer.kt similarity index 98% rename from lib/src/main/kotlin/bstrees/trees/redBlack/RBBalancer.kt rename to lib/src/main/kotlin/bstrees/model/trees/redBlack/RBBalancer.kt index 5adbe98..34a71d5 100644 --- a/lib/src/main/kotlin/bstrees/trees/redBlack/RBBalancer.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBBalancer.kt @@ -1,7 +1,7 @@ -package bstrees.trees.redBlack +package bstrees.model.trees.redBlack -import bstrees.trees.Balancer -import bstrees.trees.redBlack.RBNode.Color +import bstrees.model.trees.Balancer +import bstrees.model.trees.redBlack.RBNode.Color /** * A class representing a red black binary search tree balancer. diff --git a/lib/src/main/kotlin/bstrees/trees/redBlack/RBNode.kt b/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBNode.kt similarity index 91% rename from lib/src/main/kotlin/bstrees/trees/redBlack/RBNode.kt rename to lib/src/main/kotlin/bstrees/model/trees/redBlack/RBNode.kt index 5d776ba..8367ca2 100644 --- a/lib/src/main/kotlin/bstrees/trees/redBlack/RBNode.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBNode.kt @@ -1,6 +1,6 @@ -package bstrees.trees.redBlack +package bstrees.model.trees.redBlack -import bstrees.trees.Node +import bstrees.model.trees.Node /** * A class representing an AVL binary search tree node. diff --git a/lib/src/main/kotlin/bstrees/trees/redBlack/RBTree.kt b/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBTree.kt similarity index 98% rename from lib/src/main/kotlin/bstrees/trees/redBlack/RBTree.kt rename to lib/src/main/kotlin/bstrees/model/trees/redBlack/RBTree.kt index d0d72d7..9956e2c 100644 --- a/lib/src/main/kotlin/bstrees/trees/redBlack/RBTree.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBTree.kt @@ -1,7 +1,7 @@ -package bstrees.trees.redBlack +package bstrees.model.trees.redBlack -import bstrees.trees.BTree -import bstrees.trees.redBlack.RBNode.Color +import bstrees.model.trees.BTree +import bstrees.model.trees.redBlack.RBNode.Color /** * A class representing a red black binary search tree. diff --git a/lib/src/test/kotlin/avlTree/AVLTreeTest.kt b/lib/src/test/kotlin/avlTree/AVLTreeTest.kt index 9e358c7..10641cc 100644 --- a/lib/src/test/kotlin/avlTree/AVLTreeTest.kt +++ b/lib/src/test/kotlin/avlTree/AVLTreeTest.kt @@ -4,8 +4,8 @@ import org.junit.jupiter.api.* import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import treeInvariants.TreesInvariants -import bstrees.trees.avl.AvlNode -import bstrees.trees.avl.AvlTree +import bstrees.model.trees.avl.AvlNode +import bstrees.model.trees.avl.AvlTree import kotlin.random.Random @TestInstance(TestInstance.Lifecycle.PER_CLASS) diff --git a/lib/src/test/kotlin/balancers/BalancerTest.kt b/lib/src/test/kotlin/balancers/BalancerTest.kt index 8f52ee6..184bee3 100644 --- a/lib/src/test/kotlin/balancers/BalancerTest.kt +++ b/lib/src/test/kotlin/balancers/BalancerTest.kt @@ -1,9 +1,9 @@ package balancers -import bstrees.trees.Balancer -import bstrees.trees.Node -import bstrees.trees.binarySearch.BSBalancer -import bstrees.trees.binarySearch.BSNode +import bstrees.model.trees.Balancer +import bstrees.model.trees.Node +import bstrees.model.trees.binarySearch.BSBalancer +import bstrees.model.trees.binarySearch.BSNode import org.junit.jupiter.api.Test import utils.BSTreeUtil diff --git a/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt index 2768970..d01f595 100644 --- a/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt +++ b/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt @@ -4,8 +4,8 @@ import org.junit.jupiter.api.* import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import treeInvariants.TreesInvariants -import bstrees.trees.binarySearch.BSNode -import bstrees.trees.binarySearch.BSTree +import bstrees.model.trees.binarySearch.BSNode +import bstrees.model.trees.binarySearch.BSTree import kotlin.random.Random @TestInstance(TestInstance.Lifecycle.PER_CLASS) diff --git a/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt b/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt index 294b458..8e9ac52 100644 --- a/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt +++ b/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt @@ -5,8 +5,8 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import treeInvariants.TreesInvariants -import bstrees.trees.redBlack.RBNode -import bstrees.trees.redBlack.RBTree +import bstrees.model.trees.redBlack.RBNode +import bstrees.model.trees.redBlack.RBTree import kotlin.random.Random const val seed = 10 diff --git a/lib/src/test/kotlin/treeInvariants/TreesInvariants.kt b/lib/src/test/kotlin/treeInvariants/TreesInvariants.kt index cd64081..37d9f80 100644 --- a/lib/src/test/kotlin/treeInvariants/TreesInvariants.kt +++ b/lib/src/test/kotlin/treeInvariants/TreesInvariants.kt @@ -1,10 +1,10 @@ package treeInvariants -import bstrees.trees.Node -import bstrees.trees.avl.AvlNode -import bstrees.trees.binarySearch.BSNode -import bstrees.trees.redBlack.RBNode -import bstrees.trees.redBlack.RBNode.Color +import bstrees.model.trees.Node +import bstrees.model.trees.avl.AvlNode +import bstrees.model.trees.binarySearch.BSNode +import bstrees.model.trees.redBlack.RBNode +import bstrees.model.trees.redBlack.RBNode.Color @Suppress("UNCHECKED_CAST") class TreesInvariants, V, NODE_TYPE : Node> { diff --git a/lib/src/test/kotlin/utils/BSTreeUtil.kt b/lib/src/test/kotlin/utils/BSTreeUtil.kt index 9afff3e..a741b1f 100644 --- a/lib/src/test/kotlin/utils/BSTreeUtil.kt +++ b/lib/src/test/kotlin/utils/BSTreeUtil.kt @@ -1,7 +1,7 @@ package utils -import bstrees.trees.binarySearch.BSNode -import bstrees.trees.binarySearch.BSTree +import bstrees.model.trees.binarySearch.BSNode +import bstrees.model.trees.binarySearch.BSTree /** From 546cbf41e64cbfc763a8b64fcf55d04d37f0ef52 Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Wed, 26 Apr 2023 03:15:05 +0300 Subject: [PATCH 090/135] feat: All strategies were implemented --- .../dataBases/serialize/SerializeStrategy.kt | 14 +++++-- .../serialize/strategies/AvlStrategy.kt | 39 ++++++++++++----- .../serialize/strategies/BsStrategy.kt | 23 +++++----- .../serialize/strategies/RbStrategy.kt | 42 ++++++++++++++----- .../serialize/types/SerializableNode.kt | 2 +- .../serialize/types/SerializableTree.kt | 5 ++- 6 files changed, 86 insertions(+), 39 deletions(-) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt index 8136b94..2b9e797 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt @@ -2,9 +2,13 @@ package bstrees.model.dataBases.serialize import bstrees.model.dataBases.serialize.types.SerializableNode import bstrees.model.dataBases.serialize.types.SerializableTree +import bstrees.model.trees.BTree import bstrees.model.trees.Node -abstract class SerializeStrategy, V, NODE_TYPE: Node, TREE_TYPE>( +abstract class SerializeStrategy< + K : Comparable, V, M, + NODE_TYPE : Node, + TREE_TYPE : BTree>( val serializeKey: (K) -> String, val serializeValue: (V) -> String, val deserializeKey: (String) -> K, @@ -19,11 +23,15 @@ abstract class SerializeStrategy, V, NODE_TYPE: Node, V>( serializeKey: (K) -> String, serializeValue: (V) -> String, deserializeKey: (String) -> K, deserializeValue: (String) -> V -) : SerializeStrategy, AvlTree>( +) : SerializeStrategy, AvlTree>( serializeKey, serializeValue, deserializeKey, deserializeValue ) { - override fun serializeNode(node: AvlNode): SerializableNode { - TODO("Not yet implemented") - } + override fun serializeNode(node: AvlNode): SerializableNode = SerializableNode( + serializeKey(node.key), + serializeValue(node.value), + serializeMetadata(node.height), + node.leftNode?.let { serializeNode(it) }, + node.rightNode?.let { serializeNode(it) } + ) override fun deserializeNode(node: SerializableNode): AvlNode { - TODO("Not yet implemented") + val avlnode: AvlNode = AvlNode(deserializeKey(node.key), deserializeValue(node.value)) + if (node.metadata[0] != 'H') throw Exception("Wrong metadata. Impossible to deserialize") + avlnode.height = deserializeMetadata(node.metadata) + node.leftNode?.let { deserializeNode(it) } + node.rightNode?.let { deserializeNode(it) } + linkParents(avlnode) + return avlnode } - override fun serializeTree(tree: AvlTree, treeName: String): SerializableTree { - TODO("Not yet implemented") - } + override fun serializeTree(tree: AvlTree, treeName: String) = SerializableTree( + name = treeName, + treeType = "AVL", + root = tree.root?.let { serializeNode(it) } + ) override fun deserializeTree(tree: SerializableTree): AvlTree { - TODO("Not yet implemented") + if (tree.treeType != "AVL") throw Exception("Wrong tree type. Impossible to deserialize") + val avltree = AvlTree() + avltree.root = tree.root?.let { deserializeNode(it) } + return avltree } -} \ No newline at end of file + override fun serializeMetadata(meta: Int) = "H$meta" + + override fun deserializeMetadata(meta: String) = meta.substring(1).toInt() +} diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt index 2abf180..78e5b11 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt @@ -11,7 +11,7 @@ class BsStrategy, V>( serializeValue: (V) -> String, deserializeKey: (String) -> K, deserializeValue: (String) -> V -) : SerializeStrategy, BSTree>( +) : SerializeStrategy, BSTree>( serializeKey, serializeValue, deserializeKey, @@ -21,7 +21,7 @@ class BsStrategy, V>( override fun serializeNode(node: BSNode): SerializableNode = SerializableNode( serializeKey(node.key), serializeValue(node.value), - "S${node.size}", + serializeMetadata(node.size), node.leftNode?.let { serializeNode(it) }, node.rightNode?.let { serializeNode(it) } ) @@ -36,19 +36,20 @@ class BsStrategy, V>( return bsnode } - override fun deserializeTree(tree: SerializableTree): BSTree{ - if (tree.treeType != "BS") throw Exception("Wrong tree type. Impossible to deserialize") - val bstree = BSTree() - bstree.root = tree.root?.let { deserializeNode(it) } - return bstree - } - override fun serializeTree(tree: BSTree, treeName: String) = SerializableTree( name = treeName, treeType = "BS", root = tree.root?.let { serializeNode(it) } ) - private fun deserializeMetadata(meta: String) = meta.substring(1).toInt() + override fun deserializeTree(tree: SerializableTree): BSTree { + if (tree.treeType != "BS") throw Exception("Wrong tree type. Impossible to deserialize") + val bstree = BSTree() + bstree.root = tree.root?.let { deserializeNode(it) } + return bstree + } + + override fun serializeMetadata(meta: Int) = "S$meta" -} \ No newline at end of file + override fun deserializeMetadata(meta: String) = meta.substring(1).toInt() +} diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt index 786b0fd..82207a0 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt @@ -5,32 +5,52 @@ import bstrees.model.dataBases.serialize.types.SerializableNode import bstrees.model.dataBases.serialize.types.SerializableTree import bstrees.model.trees.redBlack.RBNode import bstrees.model.trees.redBlack.RBTree +import bstrees.model.trees.redBlack.RBNode.Color class RbStrategy, V>( serializeKey: (K) -> String, serializeValue: (V) -> String, deserializeKey: (String) -> K, deserializeValue: (String) -> V -) : SerializeStrategy, RBTree>( +) : SerializeStrategy, RBTree>( serializeKey, serializeValue, deserializeKey, deserializeValue -){ - override fun serializeNode(node: RBNode): SerializableNode { - TODO("Not yet implemented") - } +) { + override fun serializeNode(node: RBNode): SerializableNode = SerializableNode( + serializeKey(node.key), + serializeValue(node.value), + serializeMetadata(node.color), + node.leftNode?.let { serializeNode(it) }, + node.rightNode?.let { serializeNode(it) } + ) override fun deserializeNode(node: SerializableNode): RBNode { - TODO("Not yet implemented") + val rbnode: RBNode = RBNode(deserializeKey(node.key), deserializeValue(node.value)) + if (node.metadata != "RED" && node.metadata != "BLACK") throw Exception("Wrong metadata. Impossible to deserialize") + rbnode.color = deserializeMetadata(node.metadata) + node.leftNode?.let { deserializeNode(it) } + node.rightNode?.let { deserializeNode(it) } + linkParents(rbnode) + return rbnode } - override fun serializeTree(tree: RBTree, treeName: String): SerializableTree { - TODO("Not yet implemented") - } + override fun serializeTree(tree: RBTree, treeName: String) = SerializableTree( + name = treeName, + treeType = "RB", + root = tree.root?.let { serializeNode(it) } + ) override fun deserializeTree(tree: SerializableTree): RBTree { - TODO("Not yet implemented") + if (tree.treeType != "RB") throw Exception("Wrong tree type. Impossible to deserialize") + val rbtree = RBTree() + rbtree.root = tree.root?.let { deserializeNode(it) } + return rbtree } -} \ No newline at end of file + override fun deserializeMetadata(meta: String): Color = if (meta == "RED") Color.RED else Color.BLACK + + override fun serializeMetadata(meta: Color): String = if (meta == Color.RED) "RED" else "BLACK" + +} diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt index d47b267..6f52142 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt @@ -9,4 +9,4 @@ class SerializableNode( val metadata: String, val leftNode: SerializableNode? = null, val rightNode: SerializableNode? = null, -) \ No newline at end of file +) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt index 600d28d..ced8601 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt @@ -1,9 +1,10 @@ package bstrees.model.dataBases.serialize.types + import kotlinx.serialization.Serializable @Serializable class SerializableTree( val name: String, - val treeType: String, + val treeType: String, //RB, AVL or BS in capital letters!!! val root: SerializableNode? -) \ No newline at end of file +) From 470ce49d84c9893e16d7e7ace8e27e699176e03a Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:30:06 +0300 Subject: [PATCH 091/135] fix: Resolved merge conflict --- .../main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt | 1 - .../main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt | 3 --- .../main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt | 3 --- 3 files changed, 7 deletions(-) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt index a4d1bfc..ae7d0d7 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt @@ -7,7 +7,6 @@ import kotlinx.serialization.encodeToString import mu.KotlinLogging import java.io.* import kotlin.io.path.Path -import bstrees.model.dataBases.utils.PathsUtil.PROPERTIES_FILE_PATH import java.nio.file.FileAlreadyExistsException private val logger = KotlinLogging.logger { } diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt index 637d206..9669852 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt @@ -7,9 +7,6 @@ import org.neo4j.driver.TransactionContext import bstrees.model.dataBases.serialize.types.SerializableNode import bstrees.model.dataBases.serialize.types.SerializableTree import java.io.Closeable -import java.io.FileInputStream -import java.util.* -import bstrees.model.dataBases.utils.PathsUtil.PROPERTIES_FILE_PATH private val logger = KotlinLogging.logger { } diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt index e792fa0..27f2672 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt @@ -14,9 +14,6 @@ import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.dao.id.IntIdTable import org.jetbrains.exposed.sql.ReferenceOption import java.io.File -import java.io.FileInputStream -import java.util.* -import bstrees.model.dataBases.utils.PathsUtil.PROPERTIES_FILE_PATH private val logger = KotlinLogging.logger { } From 9843e261e92634576a79d037efb0bf36b2e640d1 Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Fri, 28 Apr 2023 22:23:35 +0300 Subject: [PATCH 092/135] feat: UI implementing is started. The sketch is ready in a very raw form --- lib/build.gradle.kts | 4 + .../kotlin/bstrees/view/Assets/HomeScreen.kt | 102 ++++++++++++++++++ .../bstrees/view/Assets/TreeSelector.kt | 87 +++++++++++++++ lib/src/main/kotlin/bstrees/view/app.kt | 73 +++++++++++++ 4 files changed, 266 insertions(+) create mode 100644 lib/src/main/kotlin/bstrees/view/Assets/HomeScreen.kt create mode 100644 lib/src/main/kotlin/bstrees/view/Assets/TreeSelector.kt create mode 100644 lib/src/main/kotlin/bstrees/view/app.kt diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 26aefe4..7f9ea12 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -10,6 +10,7 @@ val slf4jVersion: String? by project plugins { id("org.jetbrains.kotlin.jvm") version "1.8.20" kotlin("plugin.serialization") version "1.8.20" + id("org.jetbrains.compose") version "1.4.0" jacoco application @@ -36,6 +37,9 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-engine:$junit5Version") testImplementation("org.junit.jupiter:junit-jupiter-params:$junit5Version") + + implementation(compose.desktop.currentOs) + implementation(compose.material3) } tasks.getByName("test") { diff --git a/lib/src/main/kotlin/bstrees/view/Assets/HomeScreen.kt b/lib/src/main/kotlin/bstrees/view/Assets/HomeScreen.kt new file mode 100644 index 0000000..497163b --- /dev/null +++ b/lib/src/main/kotlin/bstrees/view/Assets/HomeScreen.kt @@ -0,0 +1,102 @@ +package bstrees.view.Assets + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun DatabaseSelector(header: State, onClickChanges: (String) -> Unit) { + var expanded by remember { mutableStateOf(false) } + val items = listOf("Neo4j", "Json", "SQLite") + var selectedIndex by remember { mutableStateOf(0) } + Box(modifier = Modifier.wrapContentSize(Alignment.TopStart)) { + + Text( + header.value, + fontSize = 30.sp, + modifier = Modifier + .clickable(onClick = { expanded = true }) + .background(Color.White) + .border(width = 1.dp, shape = RectangleShape, color = Color.Blue) + ) + + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + modifier = Modifier + .fillMaxWidth() + .background(Color.White) + ) { + items.forEachIndexed { index, s -> + DropdownMenuItem(onClick = { + selectedIndex = index + onClickChanges(items[selectedIndex]) + expanded = false + }) { + Text(text = s) + } + } + } + } +} + +@Composable +fun dataBaseConnectionNeo4j( + host: State, + username: State, + password: State, + hostChange: (String) -> Unit, + usernameChange: (String) -> Unit, + passwordChange: (String) -> Unit, + approve: State, + approveChange: (Boolean) -> Unit +) { + Row { + Column { + OutlinedTextField(value = host.value, onValueChange = hostChange) + OutlinedTextField(value = username.value, onValueChange = usernameChange) + OutlinedTextField(value = password.value, onValueChange = passwordChange) + } + Checkbox(checked = approve.value, onCheckedChange = approveChange) + } +} + +@Composable +fun HomeScreen( + header: State, + onClickChanges: (String) -> Unit, + host: State, + username: State, + password: State, + hostChange: (String) -> Unit, + usernameChange: (String) -> Unit, + passwordChange: (String) -> Unit, + approve: State, + approveChange: (Boolean) -> Unit +) { + println("I'm at HomeScreen") + Column(modifier = Modifier) { + DatabaseSelector(header, onClickChanges) + if (header.value == "Neo4j") { + dataBaseConnectionNeo4j( + host, + username, + password, + hostChange, + usernameChange, + passwordChange, + approve, + approveChange + ) + } + } +} diff --git a/lib/src/main/kotlin/bstrees/view/Assets/TreeSelector.kt b/lib/src/main/kotlin/bstrees/view/Assets/TreeSelector.kt new file mode 100644 index 0000000..308191c --- /dev/null +++ b/lib/src/main/kotlin/bstrees/view/Assets/TreeSelector.kt @@ -0,0 +1,87 @@ +package bstrees.view.Assets + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun DropdownTree(header: State, onClickChanges: (String) -> Unit) { + var expanded by remember { mutableStateOf(false) } + val items = listOf("Randomized binary search", "AVL", "Red black") + var selectedIndex by remember { mutableStateOf(0) } + Box(modifier = Modifier.wrapContentSize(Alignment.TopStart)) { + + Text( + header.value, + fontSize = 30.sp, + modifier = Modifier + .clickable(onClick = { expanded = true }) + .background(Color.White) + .border(width = 1.dp, shape = RectangleShape, color = Color.Blue) + ) + + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + modifier = Modifier + .fillMaxWidth() + .background(Color.White) + ) { + items.forEachIndexed { index, s -> + DropdownMenuItem(onClick = { + selectedIndex = index + onClickChanges(items[selectedIndex]) + expanded = false + }) { + Text(text = s) + } + } + } + } +} + +@Composable +fun TreeActions( + add: () -> Unit, + load: () -> Unit +){ + Column { + + Button(onClick = add) { + Text("Create Tree") + } + Button(onClick = load){ + Text(text = "Load Tree") + } + } +} + +@Composable +fun TreeSelector( + header: State, + onClickChanges: (String) -> Unit, + add: () -> Unit, + load: () -> Unit, + treeName: State, + treeNameChange: (String) -> Unit +){ + Column{ + DropdownTree(header, onClickChanges) + if (header.value != "Choose your tree") { + OutlinedTextField(value = treeName.value, onValueChange = treeNameChange) + TreeActions(add, load) + } + } +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/view/app.kt b/lib/src/main/kotlin/bstrees/view/app.kt new file mode 100644 index 0000000..12285cf --- /dev/null +++ b/lib/src/main/kotlin/bstrees/view/app.kt @@ -0,0 +1,73 @@ +package bstrees.view + +import androidx.compose.runtime.* +import androidx.compose.ui.unit.dp +import androidx.compose.ui.Alignment +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.window.Window +import androidx.compose.ui.window.WindowPosition +import androidx.compose.ui.window.application +import androidx.compose.ui.window.rememberWindowState +import bstrees.view.Assets.HomeScreen +import bstrees.view.Assets.TreeSelector + +fun main() { + application { + Window( + onCloseRequest = ::exitApplication, + title = "graph", + state = rememberWindowState( + position = WindowPosition(alignment = Alignment.Center), + size = DpSize(800.dp, 800.dp) + ), + ) { + + val header = remember { mutableStateOf("Choose your database") } + val host = remember { mutableStateOf("Write host") } + val username = remember { mutableStateOf("Write username") } + val password = remember { mutableStateOf("Write password") } + val approve = remember { mutableStateOf(false) } + val homeScreenFlag = remember { mutableStateOf(true) } + + if (homeScreenFlag.value) { + HomeScreen( + header, + { newHeader -> header.value = newHeader }, + host, + username, + password, + { newHost -> host.value = newHost }, + { newUsername -> username.value = newUsername }, + { newPassword -> password.value = newPassword }, + approve, + { newApprovement -> approve.value = true } + ) + } + /** + * SQL -Название базы + * Json - название папки, в которой хранится база данных + */ + + if (approve.value == true) { + if (header.value == "Neo4j") { + //checkAccess(host.value, username.value, password.value) + homeScreenFlag.value = false + } + } + + val treeType = remember { mutableStateOf("Choose your tree") } + val treeName = remember { mutableStateOf("Enter tree name") } + + if (!homeScreenFlag.value) { + TreeSelector( + treeType, + { newHeader -> treeType.value = newHeader }, + { println("CreateTest") }, + { println("LoadTest") }, + treeName = treeName, + { newName -> treeName.value = newName } + ) + } + } + } +} From 13b14938798ec6bee5b8a014792ba094c7c3c660 Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Sat, 29 Apr 2023 02:51:33 +0300 Subject: [PATCH 093/135] feat: Tree and Node view is implemented in a very raw form --- .../kotlin/bstrees/view/Assets/HomeScreen.kt | 1 - .../bstrees/view/Assets/TreeSelector.kt | 1 + .../kotlin/bstrees/view/Assets/TreeView.kt | 96 +++++++++++++++++++ lib/src/main/kotlin/bstrees/view/app.kt | 5 +- 4 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 lib/src/main/kotlin/bstrees/view/Assets/TreeView.kt diff --git a/lib/src/main/kotlin/bstrees/view/Assets/HomeScreen.kt b/lib/src/main/kotlin/bstrees/view/Assets/HomeScreen.kt index 497163b..cdebc57 100644 --- a/lib/src/main/kotlin/bstrees/view/Assets/HomeScreen.kt +++ b/lib/src/main/kotlin/bstrees/view/Assets/HomeScreen.kt @@ -83,7 +83,6 @@ fun HomeScreen( approve: State, approveChange: (Boolean) -> Unit ) { - println("I'm at HomeScreen") Column(modifier = Modifier) { DatabaseSelector(header, onClickChanges) if (header.value == "Neo4j") { diff --git a/lib/src/main/kotlin/bstrees/view/Assets/TreeSelector.kt b/lib/src/main/kotlin/bstrees/view/Assets/TreeSelector.kt index 308191c..4bcf649 100644 --- a/lib/src/main/kotlin/bstrees/view/Assets/TreeSelector.kt +++ b/lib/src/main/kotlin/bstrees/view/Assets/TreeSelector.kt @@ -62,6 +62,7 @@ fun TreeActions( Button(onClick = add) { Text("Create Tree") } + Button(onClick = load){ Text(text = "Load Tree") } diff --git a/lib/src/main/kotlin/bstrees/view/Assets/TreeView.kt b/lib/src/main/kotlin/bstrees/view/Assets/TreeView.kt new file mode 100644 index 0000000..56cba9b --- /dev/null +++ b/lib/src/main/kotlin/bstrees/view/Assets/TreeView.kt @@ -0,0 +1,96 @@ +package bstrees.view.Assets + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import bstrees.model.dataBases.serialize.types.SerializableNode + +@Composable +fun Tree(root: State) { + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.TopCenter) { + Column { + Node(root) + Row { + + val checkLeftSon = root.value.leftNode + if (checkLeftSon != null) { + val temp = remember { mutableStateOf(checkLeftSon) } + Tree(temp) + } + + val checkRightSon = root.value.rightNode + if (checkRightSon != null) { + val temp = remember { mutableStateOf(checkRightSon) } + Tree(temp) + } + + } + } + } +} + +@Composable +fun Node(node: State) { + + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .background(color = Color.Cyan, shape = CircleShape) + .width(100.dp) + .height(100.dp) + .border( + width = 1.dp, + color = Color.Black, + shape = CircleShape + ) + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "Key: ${node.value.key}", + textAlign = TextAlign.Center, + color = Color.Black + ) + Text( + text = "Value: ${node.value.value}", + textAlign = TextAlign.Center, + color = Color.Black + ) + } + } + +} + +@Composable +fun ActionButtons( + add: () -> Unit, + delete: () -> Unit +) { + + Button(onClick = add) { + Text("Add Node") + } + + Button(onClick = delete) { + Text(text = "Delete Node") + } + +} + +@Composable +fun TreeView() { + Row { + //OptionTools() + //Tree() + } +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/view/app.kt b/lib/src/main/kotlin/bstrees/view/app.kt index 12285cf..58aea9e 100644 --- a/lib/src/main/kotlin/bstrees/view/app.kt +++ b/lib/src/main/kotlin/bstrees/view/app.kt @@ -4,10 +4,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.unit.dp import androidx.compose.ui.Alignment import androidx.compose.ui.unit.DpSize -import androidx.compose.ui.window.Window -import androidx.compose.ui.window.WindowPosition -import androidx.compose.ui.window.application -import androidx.compose.ui.window.rememberWindowState +import androidx.compose.ui.window.* import bstrees.view.Assets.HomeScreen import bstrees.view.Assets.TreeSelector From 3204ae675a6b7e6bd29c24b4f7538c292055369f Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Thu, 27 Apr 2023 02:15:40 +0300 Subject: [PATCH 094/135] feat: Added support for node coordinates to work with UI --- .../model/dataBases/reps/Neo4jTreeRepo.kt | 6 ++++-- .../bstrees/model/dataBases/reps/SQLTreeRepo.kt | 8 ++++++++ .../serialize/types/SerializableNode.kt | 4 ++++ .../bstrees/model/layout/LayoutAlgorithm.kt | 17 +++++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 lib/src/main/kotlin/bstrees/model/layout/LayoutAlgorithm.kt diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt index 9669852..bee0a6d 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt @@ -48,7 +48,7 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl var rightSonKey = mapOf() val resultNodeData = tx.run( - "MATCH (node:Node {key: $nodeKey}) RETURN node.key AS key, node.value AS value, node.metadata AS metadata " + "MATCH (node:Node {key: $nodeKey}) RETURN node.key AS key, node.value AS value, node.metadata AS metadata, node.posX AS posX, node.posY AS posY" ) val resultLeftSonKey = tx.run( "MATCH (node:Node {key: $nodeKey}) MATCH (node)-[:leftSon]->(leftSon) RETURN leftSon.key as key " @@ -74,6 +74,8 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl nodeData["metadata"].toString(), getSerializedNodes(tx, leftSonKey["key"].toString()), getSerializedNodes(tx, rightSonKey["key"].toString()), + nodeData["posX"].toString().toDouble(), + nodeData["posY"].toString().toDouble(), ) } @@ -110,7 +112,7 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl private fun setNeo4jNodes(tx: TransactionContext, node: SerializableNode) { tx.run( - "CREATE (:Node:NewNode {key: ${node.key}, value: ${node.value}, metadata: ${node.metadata} })" + "CREATE (:Node:NewNode {key: ${node.key}, value: ${node.value}, metadata: ${node.metadata}, posX: ${node.posX}, posY: ${node.posY} })" ) node.leftNode?.let { leftNode -> setNeo4jNodes(tx, leftNode) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt index 27f2672..e76a1bd 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt @@ -38,6 +38,8 @@ object NodesTable : IntIdTable() { val metadata = varchar("metadata", 255) val leftNode = reference("leftNode", NodesTable).nullable() val rightNode = reference("rightNode", NodesTable).nullable() + val posX = double("posX") + val posY = double("posY") val tree = reference("tree", TreesTable, onDelete = ReferenceOption.CASCADE) } @@ -49,6 +51,8 @@ class NodeEntity(id: EntityID) : IntEntity(id) { var metadata by NodesTable.metadata var leftNode by NodeEntity optionalReferencedOn NodesTable.leftNode var rightNode by NodeEntity optionalReferencedOn NodesTable.rightNode + var posX by NodesTable.posX + var posY by NodesTable.posY var tree by TreeEntity referencedOn NodesTable.tree } @@ -109,6 +113,8 @@ class SQLTreeRepo(dbName: String) : DBTreeRepo { this@toSerializableEntity.metadata, this@toSerializableEntity.leftNode?.toSerializableEntity(treeEntity), this@toSerializableEntity.rightNode?.toSerializableEntity(treeEntity), + this@toSerializableEntity.posX, + this@toSerializableEntity.posY, ) } @@ -134,6 +140,8 @@ class SQLTreeRepo(dbName: String) : DBTreeRepo { metadata = this@toNodeEntity.metadata leftNode = this@toNodeEntity.leftNode?.toNodeEntity(treeEntity) rightNode = this@toNodeEntity.rightNode?.toNodeEntity(treeEntity) + posX = this@toNodeEntity.posX + posY = this@toNodeEntity.posY tree = treeEntity } } diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt index 6f52142..ab91e41 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt @@ -9,4 +9,8 @@ class SerializableNode( val metadata: String, val leftNode: SerializableNode? = null, val rightNode: SerializableNode? = null, + + //layout + var posX: Double = 0.0, + var posY: Double = 0.0, ) diff --git a/lib/src/main/kotlin/bstrees/model/layout/LayoutAlgorithm.kt b/lib/src/main/kotlin/bstrees/model/layout/LayoutAlgorithm.kt new file mode 100644 index 0000000..db32f10 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/model/layout/LayoutAlgorithm.kt @@ -0,0 +1,17 @@ +package bstrees.model.layout + +import bstrees.model.dataBases.serialize.types.SerializableNode + +object LayoutAlgorithm { + + // This method will assign coordinates to the nodes of the tree + fun setNodesLayout(node: SerializableNode){ + node.posX = 0.0 + node.posY = 0.0 + + node.leftNode?.let { setNodesLayout(it) } + node.rightNode?.let { setNodesLayout(it) } + + } + +} \ No newline at end of file From 2bac1202fe64b6f05ee889f76dd34c14301198f0 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Sun, 30 Apr 2023 21:01:32 +0300 Subject: [PATCH 095/135] feat: Added DataBasePresenter and TreePresenter implementation --- lib/build.gradle.kts | 5 ++ .../model/dataBases/reps/JsonTreeRepo.kt | 6 +-- .../bstrees/model/layout/LayoutAlgorithm.kt | 17 ------- .../bstrees/presenter/DataBasePresenter.kt | 19 ++++++++ .../bstrees/presenter/LayoutPresenter.kt | 26 ++++++++++ .../kotlin/bstrees/presenter/TreePresenter.kt | 18 +++++++ .../kotlin/bstrees/view/{app.kt => App.kt} | 16 ++++--- .../view/{Assets => assets}/HomeScreen.kt | 2 +- .../view/{Assets => assets}/TreeSelector.kt | 47 ++++++++++++------- .../view/{Assets => assets}/TreeView.kt | 18 +++---- 10 files changed, 122 insertions(+), 52 deletions(-) delete mode 100644 lib/src/main/kotlin/bstrees/model/layout/LayoutAlgorithm.kt create mode 100644 lib/src/main/kotlin/bstrees/presenter/DataBasePresenter.kt create mode 100644 lib/src/main/kotlin/bstrees/presenter/LayoutPresenter.kt create mode 100644 lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt rename lib/src/main/kotlin/bstrees/view/{app.kt => App.kt} (82%) rename lib/src/main/kotlin/bstrees/view/{Assets => assets}/HomeScreen.kt (99%) rename lib/src/main/kotlin/bstrees/view/{Assets => assets}/TreeSelector.kt (65%) rename lib/src/main/kotlin/bstrees/view/{Assets => assets}/TreeView.kt (82%) diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 7f9ea12..c584e46 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -52,3 +52,8 @@ tasks.jacocoTestReport { csv.outputLocation.set(layout.buildDirectory.file("jacoco/jacocoCsv")) } } + +application { + // Define the main class for the application. + mainClass.set("bstrees/view/AppKt") +} diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt index ae7d0d7..b7e4dff 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt @@ -21,9 +21,9 @@ class JsonTreeRepo(private val dir: String) : DBTreeRepo { private fun makeDir(dir: String) { File(dir).mkdir() - File(Path(dir, "BSTree").toUri()).mkdir() - File(Path(dir, "RBTree").toUri()).mkdir() - File(Path(dir, "AvlTree").toUri()).mkdir() + File(Path(dir, "BS").toUri()).mkdir() + File(Path(dir, "RB").toUri()).mkdir() + File(Path(dir, "AVL").toUri()).mkdir() } private fun getPathToFile(treeName: String, typeTree: String): String { diff --git a/lib/src/main/kotlin/bstrees/model/layout/LayoutAlgorithm.kt b/lib/src/main/kotlin/bstrees/model/layout/LayoutAlgorithm.kt deleted file mode 100644 index db32f10..0000000 --- a/lib/src/main/kotlin/bstrees/model/layout/LayoutAlgorithm.kt +++ /dev/null @@ -1,17 +0,0 @@ -package bstrees.model.layout - -import bstrees.model.dataBases.serialize.types.SerializableNode - -object LayoutAlgorithm { - - // This method will assign coordinates to the nodes of the tree - fun setNodesLayout(node: SerializableNode){ - node.posX = 0.0 - node.posY = 0.0 - - node.leftNode?.let { setNodesLayout(it) } - node.rightNode?.let { setNodesLayout(it) } - - } - -} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/presenter/DataBasePresenter.kt b/lib/src/main/kotlin/bstrees/presenter/DataBasePresenter.kt new file mode 100644 index 0000000..f4e6d55 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/presenter/DataBasePresenter.kt @@ -0,0 +1,19 @@ +package bstrees.presenter + +import bstrees.model.dataBases.reps.JsonTreeRepo +import bstrees.model.dataBases.reps.Neo4jTreeRepo +import bstrees.model.dataBases.reps.SQLTreeRepo + +object DataBasePresenter { + fun connectNeo4j(host: String, username: String, password: String): TreePresenter{ + return TreePresenter(Neo4jTreeRepo(host, username, password)) + } + + fun connectSQL(bdName: String): TreePresenter{ + return TreePresenter(SQLTreeRepo(bdName)) + } + + fun connectJson(dirName: String): TreePresenter{ + return TreePresenter(JsonTreeRepo(dirName)) + } +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/presenter/LayoutPresenter.kt b/lib/src/main/kotlin/bstrees/presenter/LayoutPresenter.kt new file mode 100644 index 0000000..c4de2ee --- /dev/null +++ b/lib/src/main/kotlin/bstrees/presenter/LayoutPresenter.kt @@ -0,0 +1,26 @@ +package bstrees.presenter + +import bstrees.model.dataBases.serialize.types.SerializableNode +import bstrees.model.dataBases.serialize.types.SerializableTree + +object LayoutPresenter { + + private val defaultNodeLength = 1 + private val windowHeight = 800 + private val windowWidth = 800 + + fun setTreeLayout(tree: SerializableTree, height: Int, width: Int){ + + } + + // This method will assign coordinates to the nodes of the tree + private fun setNodesLayout(node: SerializableNode){ + node.posX = 0.0 + node.posY = 0.0 + + node.leftNode?.let { setNodesLayout(it) } + node.rightNode?.let { setNodesLayout(it) } + + } + +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt b/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt new file mode 100644 index 0000000..30a4fbe --- /dev/null +++ b/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt @@ -0,0 +1,18 @@ +package bstrees.presenter + +import bstrees.model.dataBases.reps.DBTreeRepo +import bstrees.model.dataBases.serialize.types.SerializableTree + +class TreePresenter(private val db: DBTreeRepo) { + var tree: SerializableTree? = null + private set + + fun loadTree(treeName: String, treeType: String) { + tree = db.getTree(treeName, treeType) + } + + fun createTree(treeName: String, treeType: String) { + tree = SerializableTree(treeName, treeType, null) + tree?.let { db.setTree(it) } + } +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/view/app.kt b/lib/src/main/kotlin/bstrees/view/App.kt similarity index 82% rename from lib/src/main/kotlin/bstrees/view/app.kt rename to lib/src/main/kotlin/bstrees/view/App.kt index 58aea9e..ed3914b 100644 --- a/lib/src/main/kotlin/bstrees/view/app.kt +++ b/lib/src/main/kotlin/bstrees/view/App.kt @@ -5,8 +5,10 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.Alignment import androidx.compose.ui.unit.DpSize import androidx.compose.ui.window.* -import bstrees.view.Assets.HomeScreen -import bstrees.view.Assets.TreeSelector +import bstrees.view.assets.HomeScreen +import bstrees.view.assets.TreeSelector +import bstrees.presenter.DataBasePresenter +import bstrees.presenter.TreePresenter fun main() { application { @@ -45,22 +47,24 @@ fun main() { * Json - название папки, в которой хранится база данных */ + var treePresenter: TreePresenter? = null + if (approve.value == true) { if (header.value == "Neo4j") { - //checkAccess(host.value, username.value, password.value) + treePresenter = DataBasePresenter.connectNeo4j(host.value, username.value, password.value) homeScreenFlag.value = false } + // Similarly for other DB } val treeType = remember { mutableStateOf("Choose your tree") } val treeName = remember { mutableStateOf("Enter tree name") } - if (!homeScreenFlag.value) { + if (!homeScreenFlag.value && treePresenter != null) { TreeSelector( treeType, { newHeader -> treeType.value = newHeader }, - { println("CreateTest") }, - { println("LoadTest") }, + treePresenter, treeName = treeName, { newName -> treeName.value = newName } ) diff --git a/lib/src/main/kotlin/bstrees/view/Assets/HomeScreen.kt b/lib/src/main/kotlin/bstrees/view/assets/HomeScreen.kt similarity index 99% rename from lib/src/main/kotlin/bstrees/view/Assets/HomeScreen.kt rename to lib/src/main/kotlin/bstrees/view/assets/HomeScreen.kt index cdebc57..55a380b 100644 --- a/lib/src/main/kotlin/bstrees/view/Assets/HomeScreen.kt +++ b/lib/src/main/kotlin/bstrees/view/assets/HomeScreen.kt @@ -1,4 +1,4 @@ -package bstrees.view.Assets +package bstrees.view.assets import androidx.compose.foundation.background import androidx.compose.foundation.border diff --git a/lib/src/main/kotlin/bstrees/view/Assets/TreeSelector.kt b/lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt similarity index 65% rename from lib/src/main/kotlin/bstrees/view/Assets/TreeSelector.kt rename to lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt index 4bcf649..fd447bd 100644 --- a/lib/src/main/kotlin/bstrees/view/Assets/TreeSelector.kt +++ b/lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt @@ -1,4 +1,4 @@ -package bstrees.view.Assets +package bstrees.view.assets import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -15,11 +15,12 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import bstrees.presenter.TreePresenter @Composable fun DropdownTree(header: State, onClickChanges: (String) -> Unit) { var expanded by remember { mutableStateOf(false) } - val items = listOf("Randomized binary search", "AVL", "Red black") + val items = listOf("BS", "AVL", "RB") var selectedIndex by remember { mutableStateOf(0) } Box(modifier = Modifier.wrapContentSize(Alignment.TopStart)) { @@ -54,35 +55,49 @@ fun DropdownTree(header: State, onClickChanges: (String) -> Unit) { @Composable fun TreeActions( - add: () -> Unit, - load: () -> Unit -){ + treePresenter: TreePresenter, + treeName: State, + treeType: State +) { + Column { - Button(onClick = add) { + val isClickedAdd = remember { mutableStateOf(false) } + Button(onClick = { isClickedAdd.value = true }) { Text("Create Tree") } - Button(onClick = load){ - Text(text = "Load Tree") + val isClickedLoad = remember { mutableStateOf(false) } + Button(onClick = { isClickedLoad.value = true }){ + Text("Load Tree") + } + + if(isClickedAdd.value){ + treePresenter.createTree(treeName.value, treeType.value) + TreeView(treePresenter) + //isClickedAdd.value = false + } + if(isClickedLoad.value){ + treePresenter.loadTree(treeName.value, treeType.value) + TreeView(treePresenter) + //isClickedLoad.value = false } } } @Composable fun TreeSelector( - header: State, + treeType: State, onClickChanges: (String) -> Unit, - add: () -> Unit, - load: () -> Unit, + treePresenter: TreePresenter, treeName: State, treeNameChange: (String) -> Unit -){ - Column{ - DropdownTree(header, onClickChanges) - if (header.value != "Choose your tree") { +) { + Column { + DropdownTree(treeType, onClickChanges) + if (treeType.value != "Choose your tree") { OutlinedTextField(value = treeName.value, onValueChange = treeNameChange) - TreeActions(add, load) + TreeActions(treePresenter, treeName, treeType) } } } \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/view/Assets/TreeView.kt b/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt similarity index 82% rename from lib/src/main/kotlin/bstrees/view/Assets/TreeView.kt rename to lib/src/main/kotlin/bstrees/view/assets/TreeView.kt index 56cba9b..d4eedc3 100644 --- a/lib/src/main/kotlin/bstrees/view/Assets/TreeView.kt +++ b/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt @@ -1,4 +1,4 @@ -package bstrees.view.Assets +package bstrees.view.assets import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -13,6 +13,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import bstrees.model.dataBases.serialize.types.SerializableNode +import bstrees.presenter.TreePresenter @Composable fun Tree(root: State) { @@ -22,17 +23,16 @@ fun Tree(root: State) { Row { val checkLeftSon = root.value.leftNode - if (checkLeftSon != null) { - val temp = remember { mutableStateOf(checkLeftSon) } + checkLeftSon?.let{ leftSon -> + val temp = remember { mutableStateOf(leftSon) } Tree(temp) } val checkRightSon = root.value.rightNode - if (checkRightSon != null) { - val temp = remember { mutableStateOf(checkRightSon) } + checkRightSon?.let { rightSon -> + val temp = remember { mutableStateOf(rightSon) } Tree(temp) } - } } } @@ -88,9 +88,9 @@ fun ActionButtons( } @Composable -fun TreeView() { +fun TreeView(treePresenter: TreePresenter) { + val tree = treePresenter.tree ?: return Row { - //OptionTools() - //Tree() + tree.root?.let { Tree(mutableStateOf(tree.root)) } } } \ No newline at end of file From 38263bfdc81c0947506d2b711149227f1ae0ef20 Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Sun, 30 Apr 2023 22:19:17 +0300 Subject: [PATCH 096/135] feat: Changed Tree view. Added Json support --- .../serialize/types/SerializableNode.kt | 2 +- .../kotlin/bstrees/presenter/TreePresenter.kt | 8 +++ lib/src/main/kotlin/bstrees/view/App.kt | 5 +- .../kotlin/bstrees/view/assets/HomeScreen.kt | 25 ++++++++- .../bstrees/view/assets/TreeSelector.kt | 1 + .../kotlin/bstrees/view/assets/TreeView.kt | 51 ++++++++++--------- 6 files changed, 63 insertions(+), 29 deletions(-) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt index ab91e41..67bc089 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt @@ -6,7 +6,7 @@ import kotlinx.serialization.Serializable class SerializableNode( val key: String, val value: String, - val metadata: String, + val metadata: String, //If Rb meta is RED or BLACK in capital letters val leftNode: SerializableNode? = null, val rightNode: SerializableNode? = null, diff --git a/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt b/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt index 30a4fbe..efbd550 100644 --- a/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt +++ b/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt @@ -15,4 +15,12 @@ class TreePresenter(private val db: DBTreeRepo) { tree = SerializableTree(treeName, treeType, null) tree?.let { db.setTree(it) } } + + fun addNode() { + TODO() + } + + fun deleteNode() { + TODO() + } } \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/view/App.kt b/lib/src/main/kotlin/bstrees/view/App.kt index ed3914b..a8863f8 100644 --- a/lib/src/main/kotlin/bstrees/view/App.kt +++ b/lib/src/main/kotlin/bstrees/view/App.kt @@ -54,7 +54,10 @@ fun main() { treePresenter = DataBasePresenter.connectNeo4j(host.value, username.value, password.value) homeScreenFlag.value = false } - // Similarly for other DB + if (header.value == "Json"){ + treePresenter = DataBasePresenter.connectJson(host.value) + homeScreenFlag.value = false + } } val treeType = remember { mutableStateOf("Choose your tree") } diff --git a/lib/src/main/kotlin/bstrees/view/assets/HomeScreen.kt b/lib/src/main/kotlin/bstrees/view/assets/HomeScreen.kt index 55a380b..dc658ff 100644 --- a/lib/src/main/kotlin/bstrees/view/assets/HomeScreen.kt +++ b/lib/src/main/kotlin/bstrees/view/assets/HomeScreen.kt @@ -49,6 +49,19 @@ fun DatabaseSelector(header: State, onClickChanges: (String) -> Unit) { } } +@Composable +fun dataBaseConnectionJson( + host: State, + hostChange: (String) -> Unit, + approve: State, + approveChange: (Boolean) -> Unit +) { + Row { + OutlinedTextField(value = host.value, onValueChange = hostChange) + Checkbox(checked = approve.value, onCheckedChange = approveChange) + } +} + @Composable fun dataBaseConnectionNeo4j( host: State, @@ -85,8 +98,8 @@ fun HomeScreen( ) { Column(modifier = Modifier) { DatabaseSelector(header, onClickChanges) - if (header.value == "Neo4j") { - dataBaseConnectionNeo4j( + when (header.value) { + "Neo4j" -> dataBaseConnectionNeo4j( host, username, password, @@ -96,6 +109,14 @@ fun HomeScreen( approve, approveChange ) + "Json" -> dataBaseConnectionJson( + host, + hostChange, + approve, + approveChange + ) } } } + + diff --git a/lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt b/lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt index fd447bd..fc861d1 100644 --- a/lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt +++ b/lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt @@ -77,6 +77,7 @@ fun TreeActions( TreeView(treePresenter) //isClickedAdd.value = false } + if(isClickedLoad.value){ treePresenter.loadTree(treeName.value, treeType.value) TreeView(treePresenter) diff --git a/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt b/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt index d4eedc3..3e53b3c 100644 --- a/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt +++ b/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt @@ -17,25 +17,26 @@ import bstrees.presenter.TreePresenter @Composable fun Tree(root: State) { - Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.TopCenter) { - Column { - Node(root) - Row { - val checkLeftSon = root.value.leftNode - checkLeftSon?.let{ leftSon -> - val temp = remember { mutableStateOf(leftSon) } - Tree(temp) - } + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Node(root) + Row { - val checkRightSon = root.value.rightNode - checkRightSon?.let { rightSon -> - val temp = remember { mutableStateOf(rightSon) } - Tree(temp) - } + val checkLeftSon = root.value.leftNode + checkLeftSon?.let { leftSon -> + val temp = remember { mutableStateOf(leftSon) } + Tree(temp) } + + val checkRightSon = root.value.rightNode + checkRightSon?.let { rightSon -> + val temp = remember { mutableStateOf(rightSon) } + Tree(temp) + } + } } + } @Composable @@ -72,17 +73,16 @@ fun Node(node: State) { } @Composable -fun ActionButtons( - add: () -> Unit, - delete: () -> Unit -) { +fun TreeActionButtons(treePresenter: TreePresenter) { - Button(onClick = add) { - Text("Add Node") - } + Column { + Button(onClick = { treePresenter.addNode() }) { + Text("Add Node") + } - Button(onClick = delete) { - Text(text = "Delete Node") + Button(onClick = { treePresenter.deleteNode() }) { + Text(text = "Delete Node") + } } } @@ -91,6 +91,7 @@ fun ActionButtons( fun TreeView(treePresenter: TreePresenter) { val tree = treePresenter.tree ?: return Row { - tree.root?.let { Tree(mutableStateOf(tree.root)) } + TreeActionButtons(treePresenter) + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { tree.root?.let { Tree(mutableStateOf(tree.root)) } } } -} \ No newline at end of file +} From 0abdd1a7279ebfbfd3f9eb76e6fa5228286655f4 Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Mon, 1 May 2023 02:57:59 +0300 Subject: [PATCH 097/135] feat: Improved navigation. Added animation :). Changed NodeView. DropdownMenu(Selector) moved to a separate file. Added a convenient ScreenManager --- lib/build.gradle.kts | 3 + lib/src/main/kotlin/bstrees/view/App.kt | 139 ++++++++++++------ .../view/assets/DatabaseConnections.kt | 64 ++++++++ .../kotlin/bstrees/view/assets/HomeScreen.kt | 122 --------------- .../kotlin/bstrees/view/assets/Navigation.kt | 47 ++++++ .../kotlin/bstrees/view/assets/Selector.kt | 51 +++++++ .../bstrees/view/assets/TreeSelector.kt | 104 ------------- .../kotlin/bstrees/view/assets/TreeView.kt | 21 ++- .../kotlin/bstrees/view/screens/HomeScreen.kt | 53 +++++++ .../bstrees/view/screens/ScreenManager.kt | 13 ++ .../kotlin/bstrees/view/screens/TreeScreen.kt | 72 +++++++++ 11 files changed, 409 insertions(+), 280 deletions(-) create mode 100644 lib/src/main/kotlin/bstrees/view/assets/DatabaseConnections.kt delete mode 100644 lib/src/main/kotlin/bstrees/view/assets/HomeScreen.kt create mode 100644 lib/src/main/kotlin/bstrees/view/assets/Navigation.kt create mode 100644 lib/src/main/kotlin/bstrees/view/assets/Selector.kt delete mode 100644 lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt create mode 100644 lib/src/main/kotlin/bstrees/view/screens/HomeScreen.kt create mode 100644 lib/src/main/kotlin/bstrees/view/screens/ScreenManager.kt create mode 100644 lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index c584e46..7d6d9cf 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -38,6 +38,9 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-engine:$junit5Version") testImplementation("org.junit.jupiter:junit-jupiter-params:$junit5Version") + implementation("com.arkivanov.decompose:extensions-compose-jetbrains:2.0.0-alpha-02") + implementation("com.arkivanov.decompose:decompose:2.0.0-alpha-02") + implementation(compose.desktop.currentOs) implementation(compose.material3) } diff --git a/lib/src/main/kotlin/bstrees/view/App.kt b/lib/src/main/kotlin/bstrees/view/App.kt index a8863f8..721f4b4 100644 --- a/lib/src/main/kotlin/bstrees/view/App.kt +++ b/lib/src/main/kotlin/bstrees/view/App.kt @@ -5,12 +5,28 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.Alignment import androidx.compose.ui.unit.DpSize import androidx.compose.ui.window.* -import bstrees.view.assets.HomeScreen -import bstrees.view.assets.TreeSelector import bstrees.presenter.DataBasePresenter import bstrees.presenter.TreePresenter +import bstrees.view.assets.ChildStack +import bstrees.view.assets.ProvideComponentContext +import bstrees.view.screens.HomeScreen +import bstrees.view.screens.ScreenManager +import bstrees.view.screens.TreeSelector +import com.arkivanov.decompose.DefaultComponentContext +import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.fade +import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.plus +import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.scale +import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.stackAnimation +import com.arkivanov.decompose.router.stack.StackNavigation +import com.arkivanov.decompose.router.stack.pop +import com.arkivanov.decompose.router.stack.push +import com.arkivanov.essenty.lifecycle.LifecycleRegistry fun main() { + + val lifecycle = LifecycleRegistry() + val rootComponentContext = DefaultComponentContext(lifecycle = lifecycle) + application { Window( onCloseRequest = ::exitApplication, @@ -21,56 +37,81 @@ fun main() { ), ) { - val header = remember { mutableStateOf("Choose your database") } - val host = remember { mutableStateOf("Write host") } - val username = remember { mutableStateOf("Write username") } - val password = remember { mutableStateOf("Write password") } - val approve = remember { mutableStateOf(false) } - val homeScreenFlag = remember { mutableStateOf(true) } - - if (homeScreenFlag.value) { - HomeScreen( - header, - { newHeader -> header.value = newHeader }, - host, - username, - password, - { newHost -> host.value = newHost }, - { newUsername -> username.value = newUsername }, - { newPassword -> password.value = newPassword }, - approve, - { newApprovement -> approve.value = true } - ) - } - /** - * SQL -Название базы - * Json - название папки, в которой хранится база данных - */ + ProvideComponentContext(rootComponentContext) { - var treePresenter: TreePresenter? = null + val header = remember { mutableStateOf("Choose your database") } + val databaseMetadata = remember { mutableStateOf("") } + val username = remember { mutableStateOf("Enter username") } + val password = remember { mutableStateOf("Enter password") } + val navigation = remember { StackNavigation() } + val treeType = remember { mutableStateOf("Choose your tree") } + val treeName = remember { mutableStateOf("Enter tree name") } + var treePresenter: TreePresenter - if (approve.value == true) { - if (header.value == "Neo4j") { - treePresenter = DataBasePresenter.connectNeo4j(host.value, username.value, password.value) - homeScreenFlag.value = false - } - if (header.value == "Json"){ - treePresenter = DataBasePresenter.connectJson(host.value) - homeScreenFlag.value = false - } - } + ChildStack( + source = navigation, + initialStack = { listOf(ScreenManager.HomeScreen) }, + handleBackButton = true, + animation = stackAnimation(fade() + scale()), + ) { screen -> + when (screen) { + + is ScreenManager.HomeScreen -> { + + when (header.value) { + + "Neo4j" -> databaseMetadata.value = "Enter host" + + "Json" -> databaseMetadata.value = "Enter the directory name" + + "SQLite" -> databaseMetadata.value = "Enter the database name" + + } - val treeType = remember { mutableStateOf("Choose your tree") } - val treeName = remember { mutableStateOf("Enter tree name") } - - if (!homeScreenFlag.value && treePresenter != null) { - TreeSelector( - treeType, - { newHeader -> treeType.value = newHeader }, - treePresenter, - treeName = treeName, - { newName -> treeName.value = newName } - ) + HomeScreen( + header, + { newHeader -> header.value = newHeader }, + databaseMetadata, + username, + password, + { newMeta -> databaseMetadata.value = newMeta }, + { newUsername -> username.value = newUsername }, + { newPassword -> password.value = newPassword }, + { navigation.push(ScreenManager.TreeSelector) } + ) + + } + + is ScreenManager.TreeSelector -> { + + when (header.value) { + + "Neo4j" -> treePresenter = DataBasePresenter.connectNeo4j( + databaseMetadata.value, + username.value, + password.value + ) + + "Json" -> treePresenter = DataBasePresenter.connectJson(databaseMetadata.value) + + "SQLite" -> treePresenter = DataBasePresenter.connectSQL(databaseMetadata.value) + + else -> throw Exception("Incorrect database") + + } + + TreeSelector( + treeType, + { newHeader -> treeType.value = newHeader }, + treePresenter, + treeName = treeName, + { newName -> treeName.value = newName }, + back = navigation::pop + ) + + } + } + } } } } diff --git a/lib/src/main/kotlin/bstrees/view/assets/DatabaseConnections.kt b/lib/src/main/kotlin/bstrees/view/assets/DatabaseConnections.kt new file mode 100644 index 0000000..ff3c231 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/view/assets/DatabaseConnections.kt @@ -0,0 +1,64 @@ +package bstrees.view.assets + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Button +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun databaseConnectionJson( + host: State, + hostChange: (String) -> Unit, + approveChange: () -> Unit +) { + Column(modifier = Modifier.padding(vertical = 16.dp)) { + OutlinedTextField(value = host.value, onValueChange = hostChange) + Button(onClick = approveChange){ + Text("Approve") + } + } +} + +@Composable +fun databaseConnectionSQL( + host: State, + hostChange: (String) -> Unit, + approveChange: () -> Unit +) { + Column(modifier = Modifier.padding(vertical = 16.dp)) { + OutlinedTextField(value = host.value, onValueChange = hostChange) + Button(onClick = approveChange){ + Text("Approve") + } + } +} + +@Composable +fun databaseConnectionNeo4j( + host: State, + username: State, + password: State, + hostChange: (String) -> Unit, + usernameChange: (String) -> Unit, + passwordChange: (String) -> Unit, + approveChange: () -> Unit +) { + Column(modifier = Modifier.padding(vertical = 16.dp)) { + + OutlinedTextField(value = host.value, onValueChange = hostChange) + + OutlinedTextField(value = username.value, onValueChange = usernameChange) + + OutlinedTextField(value = password.value, onValueChange = passwordChange) + + Button(onClick = approveChange){ + Text("Approve") + } + + } +} diff --git a/lib/src/main/kotlin/bstrees/view/assets/HomeScreen.kt b/lib/src/main/kotlin/bstrees/view/assets/HomeScreen.kt deleted file mode 100644 index dc658ff..0000000 --- a/lib/src/main/kotlin/bstrees/view/assets/HomeScreen.kt +++ /dev/null @@ -1,122 +0,0 @@ -package bstrees.view.assets - -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* -import androidx.compose.material.* -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.RectangleShape -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp - -@Composable -fun DatabaseSelector(header: State, onClickChanges: (String) -> Unit) { - var expanded by remember { mutableStateOf(false) } - val items = listOf("Neo4j", "Json", "SQLite") - var selectedIndex by remember { mutableStateOf(0) } - Box(modifier = Modifier.wrapContentSize(Alignment.TopStart)) { - - Text( - header.value, - fontSize = 30.sp, - modifier = Modifier - .clickable(onClick = { expanded = true }) - .background(Color.White) - .border(width = 1.dp, shape = RectangleShape, color = Color.Blue) - ) - - DropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false }, - modifier = Modifier - .fillMaxWidth() - .background(Color.White) - ) { - items.forEachIndexed { index, s -> - DropdownMenuItem(onClick = { - selectedIndex = index - onClickChanges(items[selectedIndex]) - expanded = false - }) { - Text(text = s) - } - } - } - } -} - -@Composable -fun dataBaseConnectionJson( - host: State, - hostChange: (String) -> Unit, - approve: State, - approveChange: (Boolean) -> Unit -) { - Row { - OutlinedTextField(value = host.value, onValueChange = hostChange) - Checkbox(checked = approve.value, onCheckedChange = approveChange) - } -} - -@Composable -fun dataBaseConnectionNeo4j( - host: State, - username: State, - password: State, - hostChange: (String) -> Unit, - usernameChange: (String) -> Unit, - passwordChange: (String) -> Unit, - approve: State, - approveChange: (Boolean) -> Unit -) { - Row { - Column { - OutlinedTextField(value = host.value, onValueChange = hostChange) - OutlinedTextField(value = username.value, onValueChange = usernameChange) - OutlinedTextField(value = password.value, onValueChange = passwordChange) - } - Checkbox(checked = approve.value, onCheckedChange = approveChange) - } -} - -@Composable -fun HomeScreen( - header: State, - onClickChanges: (String) -> Unit, - host: State, - username: State, - password: State, - hostChange: (String) -> Unit, - usernameChange: (String) -> Unit, - passwordChange: (String) -> Unit, - approve: State, - approveChange: (Boolean) -> Unit -) { - Column(modifier = Modifier) { - DatabaseSelector(header, onClickChanges) - when (header.value) { - "Neo4j" -> dataBaseConnectionNeo4j( - host, - username, - password, - hostChange, - usernameChange, - passwordChange, - approve, - approveChange - ) - "Json" -> dataBaseConnectionJson( - host, - hostChange, - approve, - approveChange - ) - } - } -} - - diff --git a/lib/src/main/kotlin/bstrees/view/assets/Navigation.kt b/lib/src/main/kotlin/bstrees/view/assets/Navigation.kt new file mode 100644 index 0000000..122339d --- /dev/null +++ b/lib/src/main/kotlin/bstrees/view/assets/Navigation.kt @@ -0,0 +1,47 @@ +package bstrees.view.assets + +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.decompose.extensions.compose.jetbrains.stack.Children +import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.StackAnimation +import com.arkivanov.decompose.router.stack.StackNavigationSource +import com.arkivanov.decompose.router.stack.childStack +import com.arkivanov.essenty.parcelable.Parcelable + +val LocalComponentContext: ProvidableCompositionLocal = + staticCompositionLocalOf { error("Root component context was not provided") } + +@Composable +fun ProvideComponentContext(componentContext: ComponentContext, content: @Composable () -> Unit) { + CompositionLocalProvider(LocalComponentContext provides componentContext, content = content) +} + +@Composable +inline fun ChildStack( + source: StackNavigationSource, + noinline initialStack: () -> List, + modifier: Modifier = Modifier, + handleBackButton: Boolean = false, + animation: StackAnimation? = null, + noinline content: @Composable (C) -> Unit, +) { + val componentContext = LocalComponentContext.current + + Children( + stack = remember { + componentContext.childStack( + source = source, + initialStack = initialStack, + handleBackButton = handleBackButton, + childFactory = { _, childComponentContext -> childComponentContext }, + ) + }, + modifier = modifier, + animation = animation, + ) { child -> + ProvideComponentContext(child.instance) { + content(child.configuration) + } + } +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/view/assets/Selector.kt b/lib/src/main/kotlin/bstrees/view/assets/Selector.kt new file mode 100644 index 0000000..d6990ab --- /dev/null +++ b/lib/src/main/kotlin/bstrees/view/assets/Selector.kt @@ -0,0 +1,51 @@ +package bstrees.view.assets + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun Selector(header: State, onClickChanges: (String) -> Unit, items: List) { + var expanded by remember { mutableStateOf(false) } + var selectedIndex by remember { mutableStateOf(0) } + Column(horizontalAlignment = Alignment.CenterHorizontally) { + + Text( + header.value, + fontSize = 30.sp, + modifier = Modifier + .clickable(onClick = { expanded = true }) + .background(Color.White) + .border(width = 1.dp, shape = RectangleShape, color = Color.Blue) + ) + + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + modifier = Modifier + .fillMaxWidth() + .background(Color.White) + ) { + items.forEachIndexed { index, s -> + DropdownMenuItem(onClick = { + selectedIndex = index + onClickChanges(items[selectedIndex]) + expanded = false + }) { + Text(text = s) + } + } + } + } +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt b/lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt deleted file mode 100644 index fc861d1..0000000 --- a/lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt +++ /dev/null @@ -1,104 +0,0 @@ -package bstrees.view.assets - -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.wrapContentSize -import androidx.compose.material.* -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.RectangleShape -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import bstrees.presenter.TreePresenter - -@Composable -fun DropdownTree(header: State, onClickChanges: (String) -> Unit) { - var expanded by remember { mutableStateOf(false) } - val items = listOf("BS", "AVL", "RB") - var selectedIndex by remember { mutableStateOf(0) } - Box(modifier = Modifier.wrapContentSize(Alignment.TopStart)) { - - Text( - header.value, - fontSize = 30.sp, - modifier = Modifier - .clickable(onClick = { expanded = true }) - .background(Color.White) - .border(width = 1.dp, shape = RectangleShape, color = Color.Blue) - ) - - DropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false }, - modifier = Modifier - .fillMaxWidth() - .background(Color.White) - ) { - items.forEachIndexed { index, s -> - DropdownMenuItem(onClick = { - selectedIndex = index - onClickChanges(items[selectedIndex]) - expanded = false - }) { - Text(text = s) - } - } - } - } -} - -@Composable -fun TreeActions( - treePresenter: TreePresenter, - treeName: State, - treeType: State -) { - - Column { - - val isClickedAdd = remember { mutableStateOf(false) } - Button(onClick = { isClickedAdd.value = true }) { - Text("Create Tree") - } - - val isClickedLoad = remember { mutableStateOf(false) } - Button(onClick = { isClickedLoad.value = true }){ - Text("Load Tree") - } - - if(isClickedAdd.value){ - treePresenter.createTree(treeName.value, treeType.value) - TreeView(treePresenter) - //isClickedAdd.value = false - } - - if(isClickedLoad.value){ - treePresenter.loadTree(treeName.value, treeType.value) - TreeView(treePresenter) - //isClickedLoad.value = false - } - } -} - -@Composable -fun TreeSelector( - treeType: State, - onClickChanges: (String) -> Unit, - treePresenter: TreePresenter, - treeName: State, - treeNameChange: (String) -> Unit -) { - Column { - DropdownTree(treeType, onClickChanges) - if (treeType.value != "Choose your tree") { - OutlinedTextField(value = treeName.value, onValueChange = treeNameChange) - TreeActions(treePresenter, treeName, treeType) - } - } -} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt b/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt index 3e53b3c..7860f78 100644 --- a/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt +++ b/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt @@ -45,12 +45,17 @@ fun Node(node: State) { Box( contentAlignment = Alignment.Center, modifier = Modifier - .background(color = Color.Cyan, shape = CircleShape) + .background( + color = if (node.value.metadata == "RED") Color.Red + else if (node.value.metadata == "BLACK") Color.Black + else Color.Magenta, + shape = CircleShape + ) .width(100.dp) .height(100.dp) .border( width = 1.dp, - color = Color.Black, + color = Color.Blue, shape = CircleShape ) ) { @@ -60,12 +65,12 @@ fun Node(node: State) { Text( text = "Key: ${node.value.key}", textAlign = TextAlign.Center, - color = Color.Black + color = Color.White ) Text( text = "Value: ${node.value.value}", textAlign = TextAlign.Center, - color = Color.Black + color = Color.White ) } } @@ -92,6 +97,12 @@ fun TreeView(treePresenter: TreePresenter) { val tree = treePresenter.tree ?: return Row { TreeActionButtons(treePresenter) - Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { tree.root?.let { Tree(mutableStateOf(tree.root)) } } + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + tree.root?.let { + Tree( + mutableStateOf(tree.root) + ) + } + } } } diff --git a/lib/src/main/kotlin/bstrees/view/screens/HomeScreen.kt b/lib/src/main/kotlin/bstrees/view/screens/HomeScreen.kt new file mode 100644 index 0000000..3f8197f --- /dev/null +++ b/lib/src/main/kotlin/bstrees/view/screens/HomeScreen.kt @@ -0,0 +1,53 @@ +package bstrees.view.screens + +import androidx.compose.foundation.layout.* +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import bstrees.view.assets.Selector +import bstrees.view.assets.databaseConnectionJson +import bstrees.view.assets.databaseConnectionNeo4j +import bstrees.view.assets.databaseConnectionSQL + +@Composable +fun HomeScreen( + header: State, + onClickChanges: (String) -> Unit, + host: State, + username: State, + password: State, + hostChange: (String) -> Unit, + usernameChange: (String) -> Unit, + passwordChange: (String) -> Unit, + approveChange: () -> Unit +) { + Column(modifier = Modifier.padding(16.dp)) { + Selector(header, onClickChanges, listOf("Neo4j", "Json", "SQLite")) + when (header.value) { + "Neo4j" -> databaseConnectionNeo4j( + host, + username, + password, + hostChange, + usernameChange, + passwordChange, + approveChange + ) + + "Json" -> databaseConnectionJson( + host, + hostChange, + approveChange + ) + + "SQLite" -> databaseConnectionSQL( + host, + hostChange, + approveChange + ) + } + } +} + + + diff --git a/lib/src/main/kotlin/bstrees/view/screens/ScreenManager.kt b/lib/src/main/kotlin/bstrees/view/screens/ScreenManager.kt new file mode 100644 index 0000000..76ef0cf --- /dev/null +++ b/lib/src/main/kotlin/bstrees/view/screens/ScreenManager.kt @@ -0,0 +1,13 @@ +package bstrees.view.screens + +import com.arkivanov.essenty.parcelable.Parcelable +import com.arkivanov.essenty.parcelable.Parcelize + +sealed class ScreenManager : Parcelable { + + @Parcelize + object HomeScreen : ScreenManager() + + @Parcelize + object TreeSelector : ScreenManager() +} diff --git a/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt b/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt new file mode 100644 index 0000000..a885a48 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt @@ -0,0 +1,72 @@ +package bstrees.view.screens + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import bstrees.presenter.TreePresenter +import bstrees.view.assets.Selector +import bstrees.view.assets.TreeView + +@Composable +fun TreeActions( + treePresenter: TreePresenter, + treeName: State, + treeType: State +) { + + Column { + + val isClickedAdd = remember { mutableStateOf(false) } + Button(onClick = { isClickedAdd.value = true }) { + Text("Create Tree") + } + + val isClickedLoad = remember { mutableStateOf(false) } + Button(onClick = { isClickedLoad.value = true }){ + Text("Load Tree") + } + + if(isClickedAdd.value){ + treePresenter.createTree(treeName.value, treeType.value) + TreeView(treePresenter) + //isClickedAdd.value = false + } + + if(isClickedLoad.value){ + treePresenter.loadTree(treeName.value, treeType.value) + TreeView(treePresenter) + //isClickedLoad.value = false + } + + + } +} + +@Composable +fun TreeSelector( + treeType: State, + onClickChanges: (String) -> Unit, + treePresenter: TreePresenter, + treeName: State, + treeNameChange: (String) -> Unit, + back: () -> Unit +) { + Column(modifier = Modifier.padding(16.dp)) { + Selector(treeType, onClickChanges, listOf("BS", "AVL", "RB")) + + if (treeType.value != "Choose your tree") { + Spacer(modifier = Modifier.height(16.dp)) + OutlinedTextField(value = treeName.value, onValueChange = treeNameChange) + TreeActions(treePresenter, treeName, treeType) + } + + Button(onClick = back){ + Text("Back") + } + } +} \ No newline at end of file From 785137fc8ba4c096a31d94812c4038533cf176ec Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 1 May 2023 02:58:03 +0300 Subject: [PATCH 098/135] feat: Added keyType and valueType storage in databases --- .../model/dataBases/reps/Neo4jTreeRepo.kt | 17 +++++++++++------ .../bstrees/model/dataBases/reps/SQLTreeRepo.kt | 16 ++++++++++++---- .../dataBases/serialize/SerializeStrategy.kt | 4 +++- .../serialize/strategies/AvlStrategy.kt | 12 ++++++++++-- .../serialize/strategies/BsStrategy.kt | 12 ++++++++++-- .../serialize/strategies/RbStrategy.kt | 12 ++++++++++-- .../serialize/types/SerializableNode.kt | 11 ++++++----- .../serialize/types/SerializableTree.kt | 4 +++- .../kotlin/bstrees/presenter/LayoutPresenter.kt | 4 ++-- .../kotlin/bstrees/presenter/TreePresenter.kt | 4 ++-- .../kotlin/bstrees/view/assets/TreeSelector.kt | 3 ++- 11 files changed, 71 insertions(+), 28 deletions(-) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt index bee0a6d..eaaea42 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt @@ -20,7 +20,7 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl session.executeRead { tx -> val resultRootKey = tx.run( "MATCH (tree:Tree {name: \$name, type: \$type})" + - "WITH tree MATCH (tree)-[:root]->(root) RETURN root.key AS key", + "WITH tree MATCH (tree)-[:root]->(root) RETURN tree.keyType as keyType, tree.valueType as valueType, root.key AS rootKey", mutableMapOf( "name" to treeName, "type" to treeType, @@ -31,7 +31,9 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl serializableTree = SerializableTree( treeName, treeType, - getSerializedNodes(tx, info["key"].toString()) + info["keyType"].toString(), + info["valueType"].toString(), + getSerializedNodes(tx, info["rootKey"].toString()) ) } } @@ -72,10 +74,10 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl nodeData["key"].toString(), nodeData["value"].toString(), nodeData["metadata"].toString(), + nodeData["posX"].toString().toInt(), + nodeData["posY"].toString().toInt(), getSerializedNodes(tx, leftSonKey["key"].toString()), getSerializedNodes(tx, rightSonKey["key"].toString()), - nodeData["posX"].toString().toDouble(), - nodeData["posY"].toString().toDouble(), ) } @@ -85,10 +87,12 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl session.executeWrite { tx -> tx.run( - "CREATE (:Tree {name: \$name, type: \$type})", + "CREATE (:Tree {name: \$name, type: \$type, keyType: \$keyType, valueType: \$valueType})", mutableMapOf( "name" to serializableTree.name, "type" to serializableTree.treeType, + "keyType" to serializableTree.keyType, + "valueType" to serializableTree.valueType, ) as Map? ) @@ -112,7 +116,8 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl private fun setNeo4jNodes(tx: TransactionContext, node: SerializableNode) { tx.run( - "CREATE (:Node:NewNode {key: ${node.key}, value: ${node.value}, metadata: ${node.metadata}, posX: ${node.posX}, posY: ${node.posY} })" + "CREATE (:Node:NewNode {key: ${node.key}, value: ${node.value}, " + + "metadata: ${node.metadata}, posX: ${node.posX}, posY: ${node.posY} })" ) node.leftNode?.let { leftNode -> setNeo4jNodes(tx, leftNode) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt index e76a1bd..d80cbd3 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt @@ -21,6 +21,8 @@ private val logger = KotlinLogging.logger { } object TreesTable : IntIdTable() { val treeName = varchar("nameTree", 20) val treeType = varchar("typeTree", 20) + val keyType = varchar("keyType", 20) + val valueType = varchar("valueType", 20) val root = reference("root", NodesTable).nullable() } @@ -29,6 +31,8 @@ class TreeEntity(id: EntityID) : IntEntity(id) { var treeName by TreesTable.treeName var treeType by TreesTable.treeType + var keyType by TreesTable.keyType + var valueType by TreesTable.valueType var root by NodeEntity optionalReferencedOn TreesTable.root } @@ -38,8 +42,8 @@ object NodesTable : IntIdTable() { val metadata = varchar("metadata", 255) val leftNode = reference("leftNode", NodesTable).nullable() val rightNode = reference("rightNode", NodesTable).nullable() - val posX = double("posX") - val posY = double("posY") + val posX = integer("posX") + val posY = integer("posY") val tree = reference("tree", TreesTable, onDelete = ReferenceOption.CASCADE) } @@ -96,6 +100,8 @@ class SQLTreeRepo(dbName: String) : DBTreeRepo { serializableTree = SerializableTree( treeName, tree.treeType, + tree.keyType, + tree.valueType, tree.root?.toSerializableEntity(tree) ) } @@ -111,10 +117,10 @@ class SQLTreeRepo(dbName: String) : DBTreeRepo { this@toSerializableEntity.key, this@toSerializableEntity.value, this@toSerializableEntity.metadata, - this@toSerializableEntity.leftNode?.toSerializableEntity(treeEntity), - this@toSerializableEntity.rightNode?.toSerializableEntity(treeEntity), this@toSerializableEntity.posX, this@toSerializableEntity.posY, + this@toSerializableEntity.leftNode?.toSerializableEntity(treeEntity), + this@toSerializableEntity.rightNode?.toSerializableEntity(treeEntity), ) } @@ -125,6 +131,8 @@ class SQLTreeRepo(dbName: String) : DBTreeRepo { val newTree = TreeEntity.new { treeName = serializableTree.name treeType = serializableTree.treeType + keyType = serializableTree.keyType + valueType = serializableTree.valueType } newTree.root = serializableTree.root?.toNodeEntity(newTree) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt index 2b9e797..5e03742 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt @@ -12,7 +12,9 @@ abstract class SerializeStrategy< val serializeKey: (K) -> String, val serializeValue: (V) -> String, val deserializeKey: (String) -> K, - val deserializeValue: (String) -> V + val deserializeValue: (String) -> V, + val keyType: String, + val valueType: String, ) { abstract fun serializeNode(node: NODE_TYPE): SerializableNode diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/AvlStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/AvlStrategy.kt index 06807b4..ca58816 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/AvlStrategy.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/AvlStrategy.kt @@ -10,17 +10,23 @@ class AvlStrategy, V>( serializeKey: (K) -> String, serializeValue: (V) -> String, deserializeKey: (String) -> K, - deserializeValue: (String) -> V + deserializeValue: (String) -> V, + keyType: String, + valueType: String, ) : SerializeStrategy, AvlTree>( serializeKey, serializeValue, deserializeKey, - deserializeValue + deserializeValue, + keyType, + valueType, ) { override fun serializeNode(node: AvlNode): SerializableNode = SerializableNode( serializeKey(node.key), serializeValue(node.value), serializeMetadata(node.height), + 0, + 0, node.leftNode?.let { serializeNode(it) }, node.rightNode?.let { serializeNode(it) } ) @@ -38,6 +44,8 @@ class AvlStrategy, V>( override fun serializeTree(tree: AvlTree, treeName: String) = SerializableTree( name = treeName, treeType = "AVL", + keyType = keyType, + valueType = valueType, root = tree.root?.let { serializeNode(it) } ) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt index 78e5b11..e0ea457 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt @@ -10,18 +10,24 @@ class BsStrategy, V>( serializeKey: (K) -> String, serializeValue: (V) -> String, deserializeKey: (String) -> K, - deserializeValue: (String) -> V + deserializeValue: (String) -> V, + keyType: String, + valueType: String, ) : SerializeStrategy, BSTree>( serializeKey, serializeValue, deserializeKey, - deserializeValue + deserializeValue, + keyType, + valueType ) { override fun serializeNode(node: BSNode): SerializableNode = SerializableNode( serializeKey(node.key), serializeValue(node.value), serializeMetadata(node.size), + 0, + 0, node.leftNode?.let { serializeNode(it) }, node.rightNode?.let { serializeNode(it) } ) @@ -39,6 +45,8 @@ class BsStrategy, V>( override fun serializeTree(tree: BSTree, treeName: String) = SerializableTree( name = treeName, treeType = "BS", + keyType = keyType, + valueType = valueType, root = tree.root?.let { serializeNode(it) } ) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt index 82207a0..3a0aa7c 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt @@ -11,17 +11,23 @@ class RbStrategy, V>( serializeKey: (K) -> String, serializeValue: (V) -> String, deserializeKey: (String) -> K, - deserializeValue: (String) -> V + deserializeValue: (String) -> V, + keyType: String, + valueType: String, ) : SerializeStrategy, RBTree>( serializeKey, serializeValue, deserializeKey, - deserializeValue + deserializeValue, + keyType, + valueType, ) { override fun serializeNode(node: RBNode): SerializableNode = SerializableNode( serializeKey(node.key), serializeValue(node.value), serializeMetadata(node.color), + 0, + 0, node.leftNode?.let { serializeNode(it) }, node.rightNode?.let { serializeNode(it) } ) @@ -39,6 +45,8 @@ class RbStrategy, V>( override fun serializeTree(tree: RBTree, treeName: String) = SerializableTree( name = treeName, treeType = "RB", + keyType = keyType, + valueType = valueType, root = tree.root?.let { serializeNode(it) } ) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt index 67bc089..7f6d86a 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt @@ -7,10 +7,11 @@ class SerializableNode( val key: String, val value: String, val metadata: String, //If Rb meta is RED or BLACK in capital letters - val leftNode: SerializableNode? = null, - val rightNode: SerializableNode? = null, //layout - var posX: Double = 0.0, - var posY: Double = 0.0, -) + var posX: Int, + var posY: Int, + + val leftNode: SerializableNode? = null, + val rightNode: SerializableNode? = null, +) \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt index ced8601..f3b4c71 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt @@ -6,5 +6,7 @@ import kotlinx.serialization.Serializable class SerializableTree( val name: String, val treeType: String, //RB, AVL or BS in capital letters!!! - val root: SerializableNode? + val keyType: String, + val valueType: String, + val root: SerializableNode?, ) diff --git a/lib/src/main/kotlin/bstrees/presenter/LayoutPresenter.kt b/lib/src/main/kotlin/bstrees/presenter/LayoutPresenter.kt index c4de2ee..974e6f5 100644 --- a/lib/src/main/kotlin/bstrees/presenter/LayoutPresenter.kt +++ b/lib/src/main/kotlin/bstrees/presenter/LayoutPresenter.kt @@ -15,8 +15,8 @@ object LayoutPresenter { // This method will assign coordinates to the nodes of the tree private fun setNodesLayout(node: SerializableNode){ - node.posX = 0.0 - node.posY = 0.0 + node.posX = 0 + node.posY = 0 node.leftNode?.let { setNodesLayout(it) } node.rightNode?.let { setNodesLayout(it) } diff --git a/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt b/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt index efbd550..497ec51 100644 --- a/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt +++ b/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt @@ -11,8 +11,8 @@ class TreePresenter(private val db: DBTreeRepo) { tree = db.getTree(treeName, treeType) } - fun createTree(treeName: String, treeType: String) { - tree = SerializableTree(treeName, treeType, null) + fun createTree(treeName: String, treeType: String, keyType: String, valueType: String) { + tree = SerializableTree(treeName, treeType, keyType, valueType, null) tree?.let { db.setTree(it) } } diff --git a/lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt b/lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt index fc861d1..afa515e 100644 --- a/lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt +++ b/lib/src/main/kotlin/bstrees/view/assets/TreeSelector.kt @@ -73,7 +73,8 @@ fun TreeActions( } if(isClickedAdd.value){ - treePresenter.createTree(treeName.value, treeType.value) + //TODO(when a user wants to create a tree, he has to choose the keyType and the valueType) + treePresenter.createTree(treeName.value, treeType.value, "", "") TreeView(treePresenter) //isClickedAdd.value = false } From 8464935850b877de7ceca8aec5ffb52f2f5288ea Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Mon, 1 May 2023 03:26:16 +0300 Subject: [PATCH 099/135] fix: Github actions JDK version was updated --- .github/workflows/CI.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 6818d2d..a024294 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -11,6 +11,12 @@ jobs: os: [ ubuntu-latest, macos-latest, windows-latest ] steps: + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: zulu + - name: Checkout project sources uses: actions/checkout@v3 From ccd9222a5783d45594141dc36f6f8c9fa1aee721 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 1 May 2023 03:30:45 +0300 Subject: [PATCH 100/135] feat: CI set up JDK 17 --- .github/workflows/CI.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 6818d2d..a024294 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -11,6 +11,12 @@ jobs: os: [ ubuntu-latest, macos-latest, windows-latest ] steps: + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: zulu + - name: Checkout project sources uses: actions/checkout@v3 From 2415e54514936b62268dd5e31d6a491f8ac8b7d0 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 1 May 2023 04:13:13 +0300 Subject: [PATCH 101/135] fix: Added the necessary parameters to the treePresenter.createTree() method --- lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt b/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt index a885a48..57fc775 100644 --- a/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt +++ b/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt @@ -32,7 +32,7 @@ fun TreeActions( } if(isClickedAdd.value){ - treePresenter.createTree(treeName.value, treeType.value) + treePresenter.createTree(treeName.value, treeType.value, "", "") TreeView(treePresenter) //isClickedAdd.value = false } From d91f6760a6aa7738c8059e47dc50fe7af79f241b Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Mon, 1 May 2023 06:31:02 +0300 Subject: [PATCH 102/135] fix: Added ChosingTypesScreen --- lib/src/main/kotlin/bstrees/view/App.kt | 38 +++++++-- .../kotlin/bstrees/view/assets/TreeView.kt | 83 +++++++++++++------ .../view/screens/ChosingTypesScreen.kt | 51 ++++++++++++ .../bstrees/view/screens/ScreenManager.kt | 5 +- .../kotlin/bstrees/view/screens/TreeScreen.kt | 43 +++++----- 5 files changed, 167 insertions(+), 53 deletions(-) create mode 100644 lib/src/main/kotlin/bstrees/view/screens/ChosingTypesScreen.kt diff --git a/lib/src/main/kotlin/bstrees/view/App.kt b/lib/src/main/kotlin/bstrees/view/App.kt index 721f4b4..ce8b0ab 100644 --- a/lib/src/main/kotlin/bstrees/view/App.kt +++ b/lib/src/main/kotlin/bstrees/view/App.kt @@ -1,17 +1,28 @@ package bstrees.view +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width import androidx.compose.runtime.* import androidx.compose.ui.unit.dp import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.DpSize import androidx.compose.ui.window.* +import bstrees.model.dataBases.serialize.types.SerializableNode import bstrees.presenter.DataBasePresenter import bstrees.presenter.TreePresenter import bstrees.view.assets.ChildStack import bstrees.view.assets.ProvideComponentContext +import bstrees.view.assets.Tree +import bstrees.view.assets.TreeView +import bstrees.view.screens.ChosingTypesScreen import bstrees.view.screens.HomeScreen import bstrees.view.screens.ScreenManager -import bstrees.view.screens.TreeSelector +import bstrees.view.screens.TreeSreen import com.arkivanov.decompose.DefaultComponentContext import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.fade import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.plus @@ -46,6 +57,10 @@ fun main() { val navigation = remember { StackNavigation() } val treeType = remember { mutableStateOf("Choose your tree") } val treeName = remember { mutableStateOf("Enter tree name") } + val keyType = + remember { mutableStateOf("Choose the key type from the following options") } + val valueType = + remember { mutableStateOf("Choose the value type from the following options") } var treePresenter: TreePresenter ChildStack( @@ -77,12 +92,12 @@ fun main() { { newMeta -> databaseMetadata.value = newMeta }, { newUsername -> username.value = newUsername }, { newPassword -> password.value = newPassword }, - { navigation.push(ScreenManager.TreeSelector) } + { navigation.push(ScreenManager.TreeScreen) } ) } - is ScreenManager.TreeSelector -> { + is ScreenManager.TreeScreen -> { when (header.value) { @@ -100,16 +115,29 @@ fun main() { } - TreeSelector( + TreeSreen( treeType, { newHeader -> treeType.value = newHeader }, treePresenter, treeName = treeName, { newName -> treeName.value = newName }, - back = navigation::pop + back = navigation::pop, + { navigation.push(ScreenManager.ChosingTypesScreen) }, + keyType, + valueType ) } + + is ScreenManager.ChosingTypesScreen -> { + ChosingTypesScreen( + keyType, + valueType, + { newKeyType -> keyType.value = newKeyType }, + { newValueType -> valueType.value = newValueType }, + approve = navigation::pop + ) + } } } } diff --git a/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt b/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt index 7860f78..640bb40 100644 --- a/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt +++ b/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt @@ -11,36 +11,54 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import bstrees.model.dataBases.serialize.types.SerializableNode import bstrees.presenter.TreePresenter @Composable -fun Tree(root: State) { +fun Tree( + root: State, + nodeSize: Double, + xOffset: Double, + yOffset: Double, + modifier: Modifier = Modifier +) { + Box(modifier = modifier) { + Node(root, nodeSize) - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Node(root) - Row { - - val checkLeftSon = root.value.leftNode - checkLeftSon?.let { leftSon -> - val temp = remember { mutableStateOf(leftSon) } - Tree(temp) - } - - val checkRightSon = root.value.rightNode - checkRightSon?.let { rightSon -> - val temp = remember { mutableStateOf(rightSon) } - Tree(temp) - } + val checkLeftSon = root.value.leftNode + checkLeftSon?.let { leftSon -> + val temp = remember { mutableStateOf(leftSon) } + Tree( + temp, + nodeSize, + xOffset - nodeSize / 2, + yOffset + nodeSize, + modifier = Modifier.absoluteOffset(x = (xOffset - nodeSize / 1.5).dp, y = (yOffset + nodeSize).dp) + ) + } + val checkRightSon = root.value.rightNode + checkRightSon?.let { rightSon -> + val temp = remember { mutableStateOf(rightSon) } + Tree( + temp, + nodeSize, + xOffset + nodeSize / 2, + yOffset + nodeSize, + modifier = Modifier.absoluteOffset(x = (xOffset + nodeSize / 1.5).dp, y = (yOffset + nodeSize).dp) + ) } } - } @Composable -fun Node(node: State) { +fun Node( + node: State, + nodeSize: Double, +) { Box( contentAlignment = Alignment.Center, @@ -51,8 +69,8 @@ fun Node(node: State) { else Color.Magenta, shape = CircleShape ) - .width(100.dp) - .height(100.dp) + .width(nodeSize.dp) + .height(nodeSize.dp) .border( width = 1.dp, color = Color.Blue, @@ -65,12 +83,14 @@ fun Node(node: State) { Text( text = "Key: ${node.value.key}", textAlign = TextAlign.Center, - color = Color.White + color = Color.White, + fontSize = if (((nodeSize / 4).toInt()) > 20) 20.sp else (nodeSize / 4).toInt().sp ) Text( text = "Value: ${node.value.value}", textAlign = TextAlign.Center, - color = Color.White + color = Color.White, + fontSize = if (((nodeSize / 4).toInt()) > 20) 20.sp else (nodeSize / 4).toInt().sp ) } } @@ -93,14 +113,27 @@ fun TreeActionButtons(treePresenter: TreePresenter) { } @Composable -fun TreeView(treePresenter: TreePresenter) { +fun TreeView( + treePresenter: TreePresenter, + treeWidth: Double, + treeHeight: Double, + nodeSize: Double, + xOffset: Double = 0.0, + yOffset: Double = 0.0 +) { val tree = treePresenter.tree ?: return Row { TreeActionButtons(treePresenter) - Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Box( + modifier = Modifier.height(treeHeight.dp).width(treeWidth.dp), + contentAlignment = Alignment.Center + ) { tree.root?.let { Tree( - mutableStateOf(tree.root) + mutableStateOf(tree.root), + nodeSize, + xOffset, + yOffset ) } } diff --git a/lib/src/main/kotlin/bstrees/view/screens/ChosingTypesScreen.kt b/lib/src/main/kotlin/bstrees/view/screens/ChosingTypesScreen.kt new file mode 100644 index 0000000..e0acb39 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/view/screens/ChosingTypesScreen.kt @@ -0,0 +1,51 @@ +package bstrees.view.screens + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import bstrees.view.assets.Selector + +@Composable +fun ChosingTypesScreen( + keyType: State, + valueType: State, + onClickChangesKey: (String) -> Unit, + onClickChangesValue: (String) -> Unit, + approve: () -> Unit +) { + Column(modifier = Modifier.padding(16.dp)) { + + Selector( + keyType, + onClickChangesKey, + listOf("Int", "String") + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Selector( + valueType, + onClickChangesValue, + listOf("Int", "String") + ) + + Spacer(modifier = Modifier.height(16.dp)) + + if ( + keyType.value != "Choose the key type from the following options" && + valueType.value != "Choose the value type from the following options" + ) { + Button(onClick = approve) { + Text("Approve and create") + } + } + + } +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/view/screens/ScreenManager.kt b/lib/src/main/kotlin/bstrees/view/screens/ScreenManager.kt index 76ef0cf..44ccfaa 100644 --- a/lib/src/main/kotlin/bstrees/view/screens/ScreenManager.kt +++ b/lib/src/main/kotlin/bstrees/view/screens/ScreenManager.kt @@ -9,5 +9,8 @@ sealed class ScreenManager : Parcelable { object HomeScreen : ScreenManager() @Parcelize - object TreeSelector : ScreenManager() + object TreeScreen : ScreenManager() + + @Parcelize + object ChosingTypesScreen: ScreenManager() } diff --git a/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt b/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt index 57fc775..dc29158 100644 --- a/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt +++ b/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt @@ -16,45 +16,44 @@ import bstrees.view.assets.TreeView fun TreeActions( treePresenter: TreePresenter, treeName: State, - treeType: State + treeType: State, + createTreeMenu: () -> Unit, + keyType: State, + valueType: State, + ) { Column { - val isClickedAdd = remember { mutableStateOf(false) } - Button(onClick = { isClickedAdd.value = true }) { - Text("Create Tree") - } - - val isClickedLoad = remember { mutableStateOf(false) } - Button(onClick = { isClickedLoad.value = true }){ - Text("Load Tree") + Button(onClick = { + createTreeMenu() + treePresenter.createTree(treeName.value, treeType.value, keyType.value, valueType.value) } - - if(isClickedAdd.value){ - treePresenter.createTree(treeName.value, treeType.value, "", "") - TreeView(treePresenter) - //isClickedAdd.value = false + ) { + Text("Create Tree") } - if(isClickedLoad.value){ + Button(onClick = { treePresenter.loadTree(treeName.value, treeType.value) - TreeView(treePresenter) - //isClickedLoad.value = false } - + ) { + Text("Load Tree") + } } } @Composable -fun TreeSelector( +fun TreeSreen( treeType: State, onClickChanges: (String) -> Unit, treePresenter: TreePresenter, treeName: State, treeNameChange: (String) -> Unit, - back: () -> Unit + back: () -> Unit, + createTreeMenu: () -> Unit, + keyType: State, + valueType: State ) { Column(modifier = Modifier.padding(16.dp)) { Selector(treeType, onClickChanges, listOf("BS", "AVL", "RB")) @@ -62,10 +61,10 @@ fun TreeSelector( if (treeType.value != "Choose your tree") { Spacer(modifier = Modifier.height(16.dp)) OutlinedTextField(value = treeName.value, onValueChange = treeNameChange) - TreeActions(treePresenter, treeName, treeType) + TreeActions(treePresenter, treeName, treeType, createTreeMenu, keyType, valueType) } - Button(onClick = back){ + Button(onClick = back) { Text("Back") } } From 20c10465ff0366a89154c47d9bde261e655bacb9 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 1 May 2023 07:19:14 +0300 Subject: [PATCH 103/135] feat: Added the ability to add and delete a node from SerializableTree --- .../serialize/strategies/SerializeMethods.kt | 7 ++ .../kotlin/bstrees/presenter/TreePresenter.kt | 47 +++++++++++-- .../treesPresenters/AvlTreePresenter.kt | 70 +++++++++++++++++++ .../treesPresenters/BsTreePresenter.kt | 69 ++++++++++++++++++ .../treesPresenters/RbTreePresenter.kt | 69 ++++++++++++++++++ 5 files changed, 255 insertions(+), 7 deletions(-) create mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/SerializeMethods.kt create mode 100644 lib/src/main/kotlin/bstrees/presenter/treesPresenters/AvlTreePresenter.kt create mode 100644 lib/src/main/kotlin/bstrees/presenter/treesPresenters/BsTreePresenter.kt create mode 100644 lib/src/main/kotlin/bstrees/presenter/treesPresenters/RbTreePresenter.kt diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/SerializeMethods.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/SerializeMethods.kt new file mode 100644 index 0000000..da17e82 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/SerializeMethods.kt @@ -0,0 +1,7 @@ +package bstrees.model.dataBases.serialize.strategies + +fun intToString(a: Int): String = a.toString() + +fun stringToInt(a: String): Int = a.toInt() + +fun stringToString(a: String): String = a diff --git a/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt b/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt index 497ec51..105d806 100644 --- a/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt +++ b/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt @@ -2,25 +2,58 @@ package bstrees.presenter import bstrees.model.dataBases.reps.DBTreeRepo import bstrees.model.dataBases.serialize.types.SerializableTree +import bstrees.presenter.treesPresenters.AvlTreePresenter +import bstrees.presenter.treesPresenters.BsTreePresenter +import bstrees.presenter.treesPresenters.RbTreePresenter + class TreePresenter(private val db: DBTreeRepo) { - var tree: SerializableTree? = null + lateinit var tree: SerializableTree private set fun loadTree(treeName: String, treeType: String) { - tree = db.getTree(treeName, treeType) + val dbTreeResult: SerializableTree = + db.getTree(treeName, treeType) ?: throw Exception("There is no tree with that name") + tree = dbTreeResult } fun createTree(treeName: String, treeType: String, keyType: String, valueType: String) { tree = SerializableTree(treeName, treeType, keyType, valueType, null) - tree?.let { db.setTree(it) } + db.setTree(tree) } - fun addNode() { - TODO() + fun addNode(key: String, value: String) { + tree = when (tree.treeType) { + "AVL" -> { + AvlTreePresenter.addNode(tree, key, value) + } + "BS" -> { + BsTreePresenter.addNode(tree, key, value) + } + "RB" -> { + RbTreePresenter.addNode(tree, key, value) + } + else -> { + throw Exception("treeType error") + } + } } - fun deleteNode() { - TODO() + + fun deleteNode(key: String) { + tree = when (tree.treeType) { + "AVL" -> { + AvlTreePresenter.deleteNode(tree, key) + } + "BS" -> { + BsTreePresenter.deleteNode(tree, key) + } + "RB" -> { + RbTreePresenter.deleteNode(tree, key) + } + else -> { + throw Exception("treeType error") + } + } } } \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/presenter/treesPresenters/AvlTreePresenter.kt b/lib/src/main/kotlin/bstrees/presenter/treesPresenters/AvlTreePresenter.kt new file mode 100644 index 0000000..4f10bf6 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/presenter/treesPresenters/AvlTreePresenter.kt @@ -0,0 +1,70 @@ +package bstrees.presenter.treesPresenters + +import bstrees.model.dataBases.serialize.strategies.AvlStrategy +import bstrees.model.dataBases.serialize.strategies.intToString +import bstrees.model.dataBases.serialize.strategies.stringToInt +import bstrees.model.dataBases.serialize.strategies.stringToString +import bstrees.model.dataBases.serialize.types.SerializableTree + + +object AvlTreePresenter { + fun addNode(tree: SerializableTree, key: String, value: String): SerializableTree{ + return when(tree.keyType to tree.valueType){ + "String" to "String" -> { + val strategy = AvlStrategy(::stringToString, ::stringToString, ::stringToString, ::stringToString, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.insert(key, value) + strategy.serializeTree(bTree, tree.name) + } + "Int" to "Int" -> { + val strategy = AvlStrategy(::intToString, ::intToString, ::stringToInt, ::stringToInt, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.insert(key.toInt(), value.toInt()) + strategy.serializeTree(bTree, tree.name) + } + "String" to "Int" -> { + val strategy = AvlStrategy(::stringToString, ::intToString, ::stringToString, ::stringToInt, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.insert(key, value.toInt()) + strategy.serializeTree(bTree, tree.name) + } + "Int" to "String" -> { + val strategy = AvlStrategy(::intToString, ::stringToString, ::stringToInt, ::stringToString, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.insert(key.toInt(), value) + strategy.serializeTree(bTree, tree.name) + } + else -> { throw Exception("keyValue type error") } + } + } + + fun deleteNode(tree: SerializableTree, key: String): SerializableTree { + return when(tree.keyType to tree.valueType){ + "String" to "String" -> { + val strategy = AvlStrategy(::stringToString, ::stringToString, ::stringToString, ::stringToString, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.delete(key) + strategy.serializeTree(bTree, tree.name) + } + "Int" to "Int" -> { + val strategy = AvlStrategy(::intToString, ::intToString, ::stringToInt, ::stringToInt, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.delete(key.toInt()) + strategy.serializeTree(bTree, tree.name) + } + "String" to "Int" -> { + val strategy = AvlStrategy(::stringToString, ::intToString, ::stringToString, ::stringToInt, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.delete(key) + strategy.serializeTree(bTree, tree.name) + } + "Int" to "String" -> { + val strategy = AvlStrategy(::intToString, ::stringToString, ::stringToInt, ::stringToString, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.delete(key.toInt()) + strategy.serializeTree(bTree, tree.name) + } + else -> { throw Exception("keyValue type error") } + } + } +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/presenter/treesPresenters/BsTreePresenter.kt b/lib/src/main/kotlin/bstrees/presenter/treesPresenters/BsTreePresenter.kt new file mode 100644 index 0000000..a6f6b3d --- /dev/null +++ b/lib/src/main/kotlin/bstrees/presenter/treesPresenters/BsTreePresenter.kt @@ -0,0 +1,69 @@ +package bstrees.presenter.treesPresenters + +import bstrees.model.dataBases.serialize.strategies.BsStrategy +import bstrees.model.dataBases.serialize.strategies.intToString +import bstrees.model.dataBases.serialize.strategies.stringToInt +import bstrees.model.dataBases.serialize.strategies.stringToString +import bstrees.model.dataBases.serialize.types.SerializableTree + +object BsTreePresenter { + fun addNode(tree: SerializableTree, key: String, value: String): SerializableTree{ + return when(tree.keyType to tree.valueType){ + "String" to "String" -> { + val strategy = BsStrategy(::stringToString, ::stringToString, ::stringToString, ::stringToString, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.insert(key, value) + strategy.serializeTree(bTree, tree.name) + } + "Int" to "Int" -> { + val strategy = BsStrategy(::intToString, ::intToString, ::stringToInt, ::stringToInt, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.insert(key.toInt(), value.toInt()) + strategy.serializeTree(bTree, tree.name) + } + "String" to "Int" -> { + val strategy = BsStrategy(::stringToString, ::intToString, ::stringToString, ::stringToInt, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.insert(key, value.toInt()) + strategy.serializeTree(bTree, tree.name) + } + "Int" to "String" -> { + val strategy = BsStrategy(::intToString, ::stringToString, ::stringToInt, ::stringToString, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.insert(key.toInt(), value) + strategy.serializeTree(bTree, tree.name) + } + else -> { throw Exception("keyValue type error") } + } + } + + fun deleteNode(tree: SerializableTree, key: String): SerializableTree { + return when(tree.keyType to tree.valueType){ + "String" to "String" -> { + val strategy = BsStrategy(::stringToString, ::stringToString, ::stringToString, ::stringToString, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.delete(key) + strategy.serializeTree(bTree, tree.name) + } + "Int" to "Int" -> { + val strategy = BsStrategy(::intToString, ::intToString, ::stringToInt, ::stringToInt, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.delete(key.toInt()) + strategy.serializeTree(bTree, tree.name) + } + "String" to "Int" -> { + val strategy = BsStrategy(::stringToString, ::intToString, ::stringToString, ::stringToInt, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.delete(key) + strategy.serializeTree(bTree, tree.name) + } + "Int" to "String" -> { + val strategy = BsStrategy(::intToString, ::stringToString, ::stringToInt, ::stringToString, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.delete(key.toInt()) + strategy.serializeTree(bTree, tree.name) + } + else -> { throw Exception("keyValue type error") } + } + } +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/presenter/treesPresenters/RbTreePresenter.kt b/lib/src/main/kotlin/bstrees/presenter/treesPresenters/RbTreePresenter.kt new file mode 100644 index 0000000..0f7e6f7 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/presenter/treesPresenters/RbTreePresenter.kt @@ -0,0 +1,69 @@ +package bstrees.presenter.treesPresenters + +import bstrees.model.dataBases.serialize.strategies.RbStrategy +import bstrees.model.dataBases.serialize.strategies.intToString +import bstrees.model.dataBases.serialize.strategies.stringToInt +import bstrees.model.dataBases.serialize.strategies.stringToString +import bstrees.model.dataBases.serialize.types.SerializableTree + +object RbTreePresenter { + fun addNode(tree: SerializableTree, key: String, value: String): SerializableTree{ + return when(tree.keyType to tree.valueType){ + "String" to "String" -> { + val strategy = RbStrategy(::stringToString, ::stringToString, ::stringToString, ::stringToString, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.insert(key, value) + strategy.serializeTree(bTree, tree.name) + } + "Int" to "Int" -> { + val strategy = RbStrategy(::intToString, ::intToString, ::stringToInt, ::stringToInt, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.insert(key.toInt(), value.toInt()) + strategy.serializeTree(bTree, tree.name) + } + "String" to "Int" -> { + val strategy = RbStrategy(::stringToString, ::intToString, ::stringToString, ::stringToInt, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.insert(key, value.toInt()) + strategy.serializeTree(bTree, tree.name) + } + "Int" to "String" -> { + val strategy = RbStrategy(::intToString, ::stringToString, ::stringToInt, ::stringToString, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.insert(key.toInt(), value) + strategy.serializeTree(bTree, tree.name) + } + else -> { throw Exception("keyValue type error") } + } + } + + fun deleteNode(tree: SerializableTree, key: String): SerializableTree { + return when(tree.keyType to tree.valueType){ + "String" to "String" -> { + val strategy = RbStrategy(::stringToString, ::stringToString, ::stringToString, ::stringToString, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.delete(key) + strategy.serializeTree(bTree, tree.name) + } + "Int" to "Int" -> { + val strategy = RbStrategy(::intToString, ::intToString, ::stringToInt, ::stringToInt, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.delete(key.toInt()) + strategy.serializeTree(bTree, tree.name) + } + "String" to "Int" -> { + val strategy = RbStrategy(::stringToString, ::intToString, ::stringToString, ::stringToInt, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.delete(key) + strategy.serializeTree(bTree, tree.name) + } + "Int" to "String" -> { + val strategy = RbStrategy(::intToString, ::stringToString, ::stringToInt, ::stringToString, tree.keyType, tree.valueType) + val bTree = strategy.deserializeTree(tree) + bTree.delete(key.toInt()) + strategy.serializeTree(bTree, tree.name) + } + else -> { throw Exception("keyValue type error") } + } + } +} \ No newline at end of file From bf77f09c94155a5e9dd8e47a6e4f24f3d751028e Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 1 May 2023 08:24:41 +0300 Subject: [PATCH 104/135] fix: Fixed the error of searching and deleting the tree in Neo4j. --- .../model/dataBases/reps/Neo4jTreeRepo.kt | 44 ++++++++++++------- .../kotlin/bstrees/presenter/TreePresenter.kt | 4 +- .../kotlin/bstrees/view/assets/TreeView.kt | 6 +-- .../kotlin/bstrees/view/screens/TreeScreen.kt | 1 + 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt index eaaea42..bb527b8 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt @@ -18,22 +18,36 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl var serializableTree: SerializableTree? = null session.executeRead { tx -> + val resultTreeInfo = tx.run( + "MATCH (tree: Tree {name: \$name, type: \$type}) RETURN tree.keyType as keyType, tree.valueType as valueType", + mutableMapOf( + "name" to treeName, + "type" to treeType, + ) as Map? + ) val resultRootKey = tx.run( - "MATCH (tree:Tree {name: \$name, type: \$type})" + - "WITH tree MATCH (tree)-[:root]->(root) RETURN tree.keyType as keyType, tree.valueType as valueType, root.key AS rootKey", + "MATCH (tree: Tree {name: \$name, type: \$type}) " + + "WITH tree MATCH (tree)-[:root]->(root) RETURN root.key AS rootKey", mutableMapOf( "name" to treeName, "type" to treeType, ) as Map? ) + + var rootKey = "" if (resultRootKey.hasNext()) { val info: Map = resultRootKey.next().asMap() + rootKey = info["rootKey"].toString() + } + + if (resultTreeInfo.hasNext()) { + val info: Map = resultTreeInfo.next().asMap() serializableTree = SerializableTree( treeName, treeType, info["keyType"].toString(), info["valueType"].toString(), - getSerializedNodes(tx, info["rootKey"].toString()) + if (rootKey != "") getSerializedNodes(tx, rootKey) else null ) } } @@ -53,10 +67,10 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl "MATCH (node:Node {key: $nodeKey}) RETURN node.key AS key, node.value AS value, node.metadata AS metadata, node.posX AS posX, node.posY AS posY" ) val resultLeftSonKey = tx.run( - "MATCH (node:Node {key: $nodeKey}) MATCH (node)-[:leftSon]->(leftSon) RETURN leftSon.key as key " + "MATCH (node:Node {key: $nodeKey}) MATCH (node)-[:leftSon]->(leftSon) RETURN leftSon.key as key" ) val resultRightSonKey = tx.run( - "MATCH (node:Node {key: $nodeKey}) MATCH (node)-[:rightSon]->(rightSon) RETURN rightSon.key as key " + "MATCH (node:Node {key: $nodeKey}) MATCH (node)-[:rightSon]->(rightSon) RETURN rightSon.key as key" ) if (resultNodeData.hasNext()) { @@ -99,9 +113,9 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl serializableTree.root?.let { root -> setNeo4jNodes(tx, root) tx.run( - "MATCH (tree: Tree {name: \$name, type: \$type})" + - "MATCH (node: NewNode {key: ${root.key} })" + - "CREATE (tree)-[:root]->(node)" + + "MATCH (tree: Tree {name: \$name, type: \$type}) " + + "MATCH (node: NewNode {key: ${root.key} }) " + + "CREATE (tree)-[:root]->(node) " + "REMOVE node:NewNode", mutableMapOf( "name" to serializableTree.name, @@ -122,18 +136,18 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl node.leftNode?.let { leftNode -> setNeo4jNodes(tx, leftNode) tx.run( - "MATCH (node: NewNode {key: ${node.key}})" + - "MATCH (leftSon: NewNode {key: ${leftNode.key}})" + - "CREATE (node)-[:leftSon]->(leftSon)" + + "MATCH (node: NewNode {key: ${node.key}}) " + + "MATCH (leftSon: NewNode {key: ${leftNode.key}}) " + + "CREATE (node)-[:leftSon]->(leftSon) " + "REMOVE leftSon:NewNode" ) } node.rightNode?.let { rightNode -> setNeo4jNodes(tx, rightNode) tx.run( - "MATCH (node: NewNode {key: ${node.key}})" + - "MATCH (rightSon: NewNode {key: ${rightNode.key}})" + - "CREATE (node)-[:rightSon]->(rightSon)" + + "MATCH (node: NewNode {key: ${node.key}}) " + + "MATCH (rightSon: NewNode {key: ${rightNode.key}}) " + + "CREATE (node)-[:rightSon]->(rightSon) " + "REMOVE rightSon:NewNode" ) } @@ -142,7 +156,7 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl override fun deleteTree(treeName: String, treeType: String) { session.executeWrite { tx -> tx.run( - "MATCH (tree: Tree {name: \$name, type: \$type})" + + "MATCH (tree: Tree {name: \$name, type: \$type}) " + "MATCH (tree)-[*]->(node:Node) " + "DETACH DELETE tree, node", mutableMapOf( diff --git a/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt b/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt index 105d806..e4fb9b5 100644 --- a/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt +++ b/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt @@ -12,9 +12,7 @@ class TreePresenter(private val db: DBTreeRepo) { private set fun loadTree(treeName: String, treeType: String) { - val dbTreeResult: SerializableTree = - db.getTree(treeName, treeType) ?: throw Exception("There is no tree with that name") - tree = dbTreeResult + tree = db.getTree(treeName, treeType) ?: throw Exception("There is no tree with that name: $treeName") } fun createTree(treeName: String, treeType: String, keyType: String, valueType: String) { diff --git a/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt b/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt index 640bb40..77fe033 100644 --- a/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt +++ b/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt @@ -101,11 +101,11 @@ fun Node( fun TreeActionButtons(treePresenter: TreePresenter) { Column { - Button(onClick = { treePresenter.addNode() }) { + Button(onClick = { treePresenter.addNode("0", "0") }) { Text("Add Node") } - Button(onClick = { treePresenter.deleteNode() }) { + Button(onClick = { treePresenter.deleteNode("0") }) { Text(text = "Delete Node") } } @@ -121,7 +121,7 @@ fun TreeView( xOffset: Double = 0.0, yOffset: Double = 0.0 ) { - val tree = treePresenter.tree ?: return + val tree = treePresenter.tree Row { TreeActionButtons(treePresenter) Box( diff --git a/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt b/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt index dc29158..058e013 100644 --- a/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt +++ b/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt @@ -40,6 +40,7 @@ fun TreeActions( Text("Load Tree") } + //TODO(Add a call to the TreeView method) } } From da5d5f030be1015d7f9059167dc51e341acd4baf Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 1 May 2023 12:33:20 +0300 Subject: [PATCH 105/135] feat: Added new comments to the RBTree code --- .../bstrees/model/trees/redBlack/RBBalancer.kt | 16 +++++++++------- .../bstrees/model/trees/redBlack/RBTree.kt | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBBalancer.kt b/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBBalancer.kt index 34a71d5..a92fd91 100644 --- a/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBBalancer.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBBalancer.kt @@ -13,11 +13,12 @@ import bstrees.model.trees.redBlack.RBNode.Color open class RBBalancer, V> : Balancer>() { /** - * Balance the tree after deletion a red node - * TODO write more about the situations in which it is used + * Balance the tree after deletion a red node. Starting from some node, + * we perform balancing and recursively climb up until we meet a black node + * for balancing or reach the root of the tree * - * @param tree TODO - * @param node TODO + * @param tree the tree we are balancing + * @param node the node from which we start balancing */ internal fun balanceAfterDeletion(tree: RBTree, node: RBNode) { var curNode = node @@ -154,10 +155,11 @@ open class RBBalancer, V> : Balancer>() { } /** - * Balance the tree after adding a red node - * TODO write more about the situations in which it is used + * Balance the tree after adding a red node. Starting from some node, + * we perform balancing and recursively climb up until we meet a red parentNode + * for balancing or reach the root of the tree * - * @param node TODO + * @param node the node from which we start balancing */ internal fun balanceAfterAdding(node: RBNode): RBNode { var nodeParent = node.parent diff --git a/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBTree.kt b/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBTree.kt index 9956e2c..229080e 100644 --- a/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBTree.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBTree.kt @@ -144,7 +144,11 @@ class RBTree, V> : BTree>() { } /** - * TODO ?? + * After we have selected a node that will take the place of the deleted one, + * we must specify all the links for the selected node. + * + * @param curNode the node that we are deleting + * @param nodeForSwapping the node that will stand in place of the deleted one */ private fun setLinksWithNodeForSwapping(curNode: RBNode, nodeForSwapping: RBNode) { nodeForSwapping.leftNode = curNode.leftNode @@ -167,7 +171,13 @@ class RBTree, V> : BTree>() { } /** - * TODO ?? + * The node that we are moving to the place of the deleted one. + * Therefore, it is necessary to put one of the sons of this peak in its place + * and establish the necessary links. + * + * @param nodeForSwapping the node that we are deleting + * @param sonOfNodeForSwapping the node that will stand in place of the deleted one + * @param sonIsNilNode checking that the son of this vertex is imaginary */ private fun setLinksWithSonOfNodeForSwapping( nodeForSwapping: RBNode, From 2b0360cd007565e8efb6d5ed5f82e17c4dcd7516 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 1 May 2023 12:50:23 +0300 Subject: [PATCH 106/135] fix: TreesInvariants is divided into several parts: AVLTreeInvariants, BSTreeInvariants, RBTreeInvariants. --- .../test/kotlin/avlTree/AVLTreeInvariants.kt | 17 ++++ lib/src/test/kotlin/avlTree/AVLTreeTest.kt | 3 +- .../binarySearchTree/BSTreeInvariants.kt | 18 +++++ .../kotlin/binarySearchTree/BSTreeTest.kt | 3 +- .../kotlin/redBlackTree/RBTreeInvariants.kt | 53 +++++++++++++ .../test/kotlin/redBlackTree/RBTreeTest.kt | 3 +- .../kotlin/treeInvariants/TreesInvariants.kt | 79 ------------------- lib/src/test/kotlin/utils/TreesInvariants.kt | 12 +++ 8 files changed, 103 insertions(+), 85 deletions(-) create mode 100644 lib/src/test/kotlin/avlTree/AVLTreeInvariants.kt create mode 100644 lib/src/test/kotlin/binarySearchTree/BSTreeInvariants.kt create mode 100644 lib/src/test/kotlin/redBlackTree/RBTreeInvariants.kt delete mode 100644 lib/src/test/kotlin/treeInvariants/TreesInvariants.kt create mode 100644 lib/src/test/kotlin/utils/TreesInvariants.kt diff --git a/lib/src/test/kotlin/avlTree/AVLTreeInvariants.kt b/lib/src/test/kotlin/avlTree/AVLTreeInvariants.kt new file mode 100644 index 0000000..32b0a43 --- /dev/null +++ b/lib/src/test/kotlin/avlTree/AVLTreeInvariants.kt @@ -0,0 +1,17 @@ +package avlTree + +import bstrees.model.trees.Node +import bstrees.model.trees.avl.AvlNode +import utils.TreesInvariants + +@Suppress("UNCHECKED_CAST") +class AVLTreeInvariants, V, NODE_TYPE : Node> : TreesInvariants() { + fun checkAvlTreeInvariants(root: AvlNode?): Boolean = root == null || checkAvlHeightInvariants(root) + && checkNodeInvariants(root as NODE_TYPE) + + private fun checkAvlHeightInvariants(node: AvlNode): Boolean = + ((node.rightNode?.height ?: 0) - (node.leftNode?.height ?: 0) in -1..1) + && (node.leftNode == null || checkAvlHeightInvariants(node.leftNode!!)) + && (node.rightNode == null || checkAvlHeightInvariants(node.rightNode!!)) + +} \ No newline at end of file diff --git a/lib/src/test/kotlin/avlTree/AVLTreeTest.kt b/lib/src/test/kotlin/avlTree/AVLTreeTest.kt index 10641cc..a7ab4fc 100644 --- a/lib/src/test/kotlin/avlTree/AVLTreeTest.kt +++ b/lib/src/test/kotlin/avlTree/AVLTreeTest.kt @@ -3,7 +3,6 @@ package avlTree import org.junit.jupiter.api.* import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource -import treeInvariants.TreesInvariants import bstrees.model.trees.avl.AvlNode import bstrees.model.trees.avl.AvlTree import kotlin.random.Random @@ -15,7 +14,7 @@ class AVLTreeTest { private lateinit var keyValue: List> private lateinit var bigKeyValue: List> private val tree = AvlTree() - private val treeChecker = TreesInvariants>() + private val treeChecker = AVLTreeInvariants>() @BeforeAll fun prepareNodes() { diff --git a/lib/src/test/kotlin/binarySearchTree/BSTreeInvariants.kt b/lib/src/test/kotlin/binarySearchTree/BSTreeInvariants.kt new file mode 100644 index 0000000..2c4d896 --- /dev/null +++ b/lib/src/test/kotlin/binarySearchTree/BSTreeInvariants.kt @@ -0,0 +1,18 @@ +package binarySearchTree + +import bstrees.model.trees.Node +import bstrees.model.trees.binarySearch.BSNode +import utils.TreesInvariants + +@Suppress("UNCHECKED_CAST") +class BSTreeInvariants, V, NODE_TYPE : Node> : TreesInvariants() { + private fun checkBSSizeInvariant(node: BSNode?): Boolean { + return node == null || + node.size == (node.leftNode?.size ?: 0) + (node.rightNode?.size ?: 0) + 1 + && checkBSSizeInvariant(node.leftNode) && checkBSSizeInvariant(node.rightNode) + } + + fun checkBsTreeInvariants(root: BSNode?): Boolean { + return (root == null || checkNodeInvariants(root as NODE_TYPE)) && checkBSSizeInvariant(root) + } +} \ No newline at end of file diff --git a/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt index d01f595..1d86994 100644 --- a/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt +++ b/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt @@ -3,7 +3,6 @@ package binarySearchTree import org.junit.jupiter.api.* import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource -import treeInvariants.TreesInvariants import bstrees.model.trees.binarySearch.BSNode import bstrees.model.trees.binarySearch.BSTree import kotlin.random.Random @@ -15,7 +14,7 @@ class BSTreeTest { private lateinit var keyValue: List> private lateinit var bigKeyValue: List> private val tree = BSTree() - private val treeChecker = TreesInvariants>() + private val treeChecker = BSTreeInvariants>() @BeforeAll fun prepareNodes() { diff --git a/lib/src/test/kotlin/redBlackTree/RBTreeInvariants.kt b/lib/src/test/kotlin/redBlackTree/RBTreeInvariants.kt new file mode 100644 index 0000000..5510a36 --- /dev/null +++ b/lib/src/test/kotlin/redBlackTree/RBTreeInvariants.kt @@ -0,0 +1,53 @@ +package redBlackTree + +import bstrees.model.trees.Node +import bstrees.model.trees.redBlack.RBNode +import utils.TreesInvariants + +@Suppress("UNCHECKED_CAST") +class RBTreeInvariants, V, NODE_TYPE : Node> : TreesInvariants() { + fun checkRBTreeInvariants(root: RBNode?): Boolean { + return root == null || root.parent == null && checkNodeInvariants(root as NODE_TYPE) && root.color == RBNode.Color.BLACK && + checkRBNodeBlackHeightInvariant(root, 0, getBlackHeightExample(root)) && + checkRBNodeBlackParentForRedInvariant(root) + } + + private fun checkRBNodeBlackParentForRedInvariant(node: RBNode): Boolean { + return (node.color == RBNode.Color.BLACK || node.parent!!.color == RBNode.Color.BLACK) && + (node.leftNode == null || checkRBNodeBlackParentForRedInvariant(node.leftNode!!)) && + (node.rightNode == null || checkRBNodeBlackParentForRedInvariant(node.rightNode!!)) + } + + private fun checkRBNodeBlackHeightInvariant(node: RBNode, curHeight: Int, rightHeight: Int): Boolean { + val newCurHeight = curHeight + if (node.color == RBNode.Color.BLACK) 1 else 0 + if (node.leftNode == null && node.rightNode == null) { + return newCurHeight == rightHeight + } + return ((node.leftNode == null || checkRBNodeBlackHeightInvariant( + node.leftNode!!, + newCurHeight, + rightHeight + )) && + (node.rightNode == null || checkRBNodeBlackHeightInvariant( + node.rightNode!!, + newCurHeight, + rightHeight + ))) + } + + /** + * We take the height of the leftmost leaf in order to compare it + * with the heights to other leaves of the tree + */ + private fun getBlackHeightExample(root: RBNode): Int { + var curNode: RBNode? = root + var blackHeight = 0 + while (curNode != null) { + if (curNode.color == RBNode.Color.BLACK) { + ++blackHeight + } + curNode = curNode.leftNode + } + return blackHeight + } +} \ No newline at end of file diff --git a/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt b/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt index 8e9ac52..fa995cd 100644 --- a/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt +++ b/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt @@ -4,7 +4,6 @@ import org.junit.jupiter.api.* import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource -import treeInvariants.TreesInvariants import bstrees.model.trees.redBlack.RBNode import bstrees.model.trees.redBlack.RBTree import kotlin.random.Random @@ -19,7 +18,7 @@ class RBTreeTest { private lateinit var keyValue: List> private lateinit var bigKeyValue: List> private val tree = RBTree() - private val treeChecker = TreesInvariants>() + private val treeChecker = RBTreeInvariants>() @BeforeAll diff --git a/lib/src/test/kotlin/treeInvariants/TreesInvariants.kt b/lib/src/test/kotlin/treeInvariants/TreesInvariants.kt deleted file mode 100644 index 37d9f80..0000000 --- a/lib/src/test/kotlin/treeInvariants/TreesInvariants.kt +++ /dev/null @@ -1,79 +0,0 @@ -package treeInvariants - -import bstrees.model.trees.Node -import bstrees.model.trees.avl.AvlNode -import bstrees.model.trees.binarySearch.BSNode -import bstrees.model.trees.redBlack.RBNode -import bstrees.model.trees.redBlack.RBNode.Color - -@Suppress("UNCHECKED_CAST") -class TreesInvariants, V, NODE_TYPE : Node> { - - fun checkRBTreeInvariants(root: RBNode?): Boolean { - return root == null || root.parent == null && checkNodeInvariants(root as NODE_TYPE) && root.color == Color.BLACK && - checkRBNodeBlackHeightInvariant(root, 0, getSomeBlackHeight(root)) && - checkRBNodeBlackParentForRedInvariant(root) - } - - private fun checkRBNodeBlackParentForRedInvariant(node: RBNode): Boolean { - return (node.color == Color.BLACK || node.parent!!.color == Color.BLACK) && - (node.leftNode == null || checkRBNodeBlackParentForRedInvariant(node.leftNode!!)) && - (node.rightNode == null || checkRBNodeBlackParentForRedInvariant(node.rightNode!!)) - } - - private fun checkRBNodeBlackHeightInvariant(node: RBNode, curHeight: Int, rightHeight: Int): Boolean { - val newCurHeight = curHeight + if (node.color == Color.BLACK) 1 else 0 - if (node.leftNode == null && node.rightNode == null) { - return newCurHeight == rightHeight - } - return ((node.leftNode == null || checkRBNodeBlackHeightInvariant( - node.leftNode!!, - newCurHeight, - rightHeight - )) && - (node.rightNode == null || checkRBNodeBlackHeightInvariant( - node.rightNode!!, - newCurHeight, - rightHeight - ))) - } - - private fun getSomeBlackHeight(root: RBNode): Int { - var curNode: RBNode? = root - var blackHeight = 0 - while (curNode != null) { - if (curNode.color == Color.BLACK) { - ++blackHeight - } - curNode = curNode.leftNode - } - return blackHeight - } - - private fun checkNodeInvariants(node: NODE_TYPE): Boolean { - return (node.leftNode == null || node.leftNode!!.parent == node && - node.leftNode!!.key < node.key && checkNodeInvariants(node.leftNode!!)) && - (node.rightNode == null || node.rightNode!!.parent == node && - node.rightNode!!.key > node.key && checkNodeInvariants(node.rightNode!!)) - } - - fun checkAvlTreeInvariants(root: AvlNode?): Boolean = root == null || checkAvlHeightInvariants(root) - && checkNodeInvariants(root as NODE_TYPE) - - private fun checkAvlHeightInvariants(node: AvlNode): Boolean = - ((node.rightNode?.height ?: 0) - (node.leftNode?.height ?: 0) in -1..1) - && (node.leftNode == null || checkAvlHeightInvariants(node.leftNode!!)) - && (node.rightNode == null || checkAvlHeightInvariants(node.rightNode!!)) - - - private fun checkBSSizeInvariant(node: BSNode?): Boolean { - return node == null || - node.size == (node.leftNode?.size ?: 0) + (node.rightNode?.size ?: 0) + 1 - && checkBSSizeInvariant(node.leftNode) && checkBSSizeInvariant(node.rightNode) - } - - fun checkBsTreeInvariants(root: BSNode?): Boolean { - return (root == null || checkNodeInvariants(root as NODE_TYPE)) && checkBSSizeInvariant(root) - } - -} \ No newline at end of file diff --git a/lib/src/test/kotlin/utils/TreesInvariants.kt b/lib/src/test/kotlin/utils/TreesInvariants.kt new file mode 100644 index 0000000..68a6f5b --- /dev/null +++ b/lib/src/test/kotlin/utils/TreesInvariants.kt @@ -0,0 +1,12 @@ +package utils + +import bstrees.model.trees.Node + +open class TreesInvariants, V, NODE_TYPE : Node> { + protected fun checkNodeInvariants(node: NODE_TYPE): Boolean { + return (node.leftNode == null || node.leftNode!!.parent == node && + node.leftNode!!.key < node.key && checkNodeInvariants(node.leftNode!!)) && + (node.rightNode == null || node.rightNode!!.parent == node && + node.rightNode!!.key > node.key && checkNodeInvariants(node.rightNode!!)) + } +} \ No newline at end of file From 228dd5b185e6493e5e79917eeebeff3c753f583b Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 1 May 2023 13:02:55 +0300 Subject: [PATCH 107/135] fix: @ValueSource replaced with @MethodSource for parameterized tests --- lib/src/test/kotlin/avlTree/AVLTreeTest.kt | 14 ++++++++++++-- .../test/kotlin/binarySearchTree/BSTreeTest.kt | 14 ++++++++++++-- lib/src/test/kotlin/redBlackTree/RBTreeTest.kt | 15 +++++++++++++-- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/lib/src/test/kotlin/avlTree/AVLTreeTest.kt b/lib/src/test/kotlin/avlTree/AVLTreeTest.kt index a7ab4fc..62462c0 100644 --- a/lib/src/test/kotlin/avlTree/AVLTreeTest.kt +++ b/lib/src/test/kotlin/avlTree/AVLTreeTest.kt @@ -2,9 +2,10 @@ package avlTree import org.junit.jupiter.api.* import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource import bstrees.model.trees.avl.AvlNode import bstrees.model.trees.avl.AvlTree +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource import kotlin.random.Random @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -63,7 +64,7 @@ class AVLTreeTest { } @ParameterizedTest(name = "Function get returns correct value for key {0}") - @ValueSource(ints = [12, -121, 56, 1, 23728, 6464, 112]) + @MethodSource("keyProvider") fun `find return a correct value`(key: Int) { keyValue.forEach { tree.insert(it.first, it.second) } @@ -74,6 +75,15 @@ class AVLTreeTest { Assertions.assertEquals(null, tree.find(key)) } + companion object { + @JvmStatic + fun keyProvider(): List { + return (0..1000).map { + Arguments.of(Random.nextInt(5000)) + } + } + } + @Test fun `adding nodes with equal key`() { keyValue.forEach { tree.insert(it.first, it.second) } diff --git a/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt index 1d86994..6bf1032 100644 --- a/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt +++ b/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt @@ -2,9 +2,10 @@ package binarySearchTree import org.junit.jupiter.api.* import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource import bstrees.model.trees.binarySearch.BSNode import bstrees.model.trees.binarySearch.BSTree +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource import kotlin.random.Random @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -63,7 +64,7 @@ class BSTreeTest { } @ParameterizedTest(name = "Function get returns correct value for key {0}") - @ValueSource(ints = [12, -121, 56, 1, 23728, 6464, 112]) + @MethodSource("keyProvider") fun `find return a correct value`(key: Int) { keyValue.forEach { tree.insert(it.first, it.second) } @@ -74,6 +75,15 @@ class BSTreeTest { Assertions.assertEquals(null, tree.find(key)) } + companion object { + @JvmStatic + fun keyProvider(): List { + return (0..1000).map { + Arguments.of(Random.nextInt(5000)) + } + } + } + @Test fun `adding nodes with equal key`() { keyValue.forEach { tree.insert(it.first, it.second) } diff --git a/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt b/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt index fa995cd..cd5ff34 100644 --- a/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt +++ b/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt @@ -3,14 +3,16 @@ package redBlackTree import org.junit.jupiter.api.* import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.ValueSource import bstrees.model.trees.redBlack.RBNode import bstrees.model.trees.redBlack.RBTree +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource import kotlin.random.Random const val seed = 10 @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class RBTreeTest { private val randomizer = Random(seed) @@ -84,7 +86,7 @@ class RBTreeTest { } @ParameterizedTest(name = "Function get returns correct value for key {0}") - @ValueSource(ints = [12, -121, 56, 1, 23728, 6464, 112]) + @MethodSource("keyProvider") fun `find return a correct value`(key: Int) { keyValue.forEach { tree.insert(it.first, it.second) } @@ -95,6 +97,15 @@ class RBTreeTest { assertEquals(null, tree.find(key)) } + companion object { + @JvmStatic + fun keyProvider(): List { + return (0..1000).map { + Arguments.of(Random.nextInt(5000)) + } + } + } + @Test fun `deleting a node`() { tree.insert(keyValue[0].first, keyValue[0].second) From 8019e53256e0cee8f35a5c9efd0e95ce0cec2c28 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 1 May 2023 13:19:17 +0300 Subject: [PATCH 108/135] feat: Added a test checking that the tree is balanced and contains all nodes that have not been deleted --- lib/src/test/kotlin/avlTree/AVLTreeTest.kt | 17 +++++++++++++++++ .../test/kotlin/binarySearchTree/BSTreeTest.kt | 17 +++++++++++++++++ lib/src/test/kotlin/redBlackTree/RBTreeTest.kt | 17 +++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/lib/src/test/kotlin/avlTree/AVLTreeTest.kt b/lib/src/test/kotlin/avlTree/AVLTreeTest.kt index 62462c0..57ffb09 100644 --- a/lib/src/test/kotlin/avlTree/AVLTreeTest.kt +++ b/lib/src/test/kotlin/avlTree/AVLTreeTest.kt @@ -95,6 +95,23 @@ class AVLTreeTest { Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) { "Error adding nodes with equal keys" } } + @Test + fun `deleting a part of nodes`(){ + keyValue.forEach { tree.insert(it.first, it.second) } + + keyValue = keyValue.shuffled() + + for(i in 0 until keyValue.size){ + tree.delete(keyValue[i].first) + for(j in i + 1 until keyValue.size){ + assertAll("Error deleting a node. The tree must be balanced and must contain all nodes that are not deleted", + { Assertions.assertNotNull(tree.find(keyValue[j].first)) }, + { Assertions.assertTrue(treeChecker.checkAvlTreeInvariants(tree.root)) } + ) + } + } + } + @Test fun `deleting a node`() { tree.insert(keyValue[0].first, keyValue[0].second) diff --git a/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt index 6bf1032..0ff6033 100644 --- a/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt +++ b/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt @@ -95,6 +95,23 @@ class BSTreeTest { Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) { "Error adding nodes with equal keys" } } + @Test + fun `deleting a part of nodes`(){ + keyValue.forEach { tree.insert(it.first, it.second) } + + keyValue = keyValue.shuffled() + + for(i in 0 until keyValue.size){ + tree.delete(keyValue[i].first) + for(j in i + 1 until keyValue.size){ + assertAll("Error deleting a node. The tree must be balanced and must contain all nodes that are not deleted", + { Assertions.assertNotNull(tree.find(keyValue[j].first)) }, + { Assertions.assertTrue(treeChecker.checkBsTreeInvariants(tree.root)) } + ) + } + } + } + @Test fun `deleting a node`() { tree.insert(keyValue[0].first, keyValue[0].second) diff --git a/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt b/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt index cd5ff34..3675880 100644 --- a/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt +++ b/lib/src/test/kotlin/redBlackTree/RBTreeTest.kt @@ -67,6 +67,23 @@ class RBTreeTest { Assertions.assertTrue(treeChecker.checkRBTreeInvariants(tree.root)) { "Error adding nodes with equal keys" } } + @Test + fun `deleting a part of nodes`(){ + keyValue.forEach { tree.insert(it.first, it.second) } + + keyValue = keyValue.shuffled() + + for(i in 0 until keyValue.size){ + tree.delete(keyValue[i].first) + for(j in i + 1 until keyValue.size){ + assertAll("Error deleting a node. The tree must be balanced and must contain all nodes that are not deleted", + { Assertions.assertNotNull(tree.find(keyValue[j].first)) }, + { Assertions.assertTrue(treeChecker.checkRBTreeInvariants(tree.root)) } + ) + } + } + } + @Test fun `adding a lot of nodes`() { val bigTree = RBTree() From 7d2b08e8492ffc4f89cbf667633ff1c697475feb Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Mon, 1 May 2023 22:09:59 +0300 Subject: [PATCH 109/135] feat: Now the test coverage is considered only for model trees --- lib/build.gradle.kts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 7d6d9cf..97ca045 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -54,6 +54,13 @@ tasks.jacocoTestReport { csv.required.set(true) csv.outputLocation.set(layout.buildDirectory.file("jacoco/jacocoCsv")) } + classDirectories.setFrom( + files(classDirectories.files.map { + fileTree(it) { + include("**/model/trees/**") + } + }) + ) } application { From cf989f27907226e921b8cee25506ce0e7bd10376 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 2 May 2023 00:52:20 +0300 Subject: [PATCH 110/135] fix: GUI moved to the app directory --- app/build.gradle.kts | 17 +++++++---- app/src/main/kotlin/Main.kt | 3 -- .../app}/presenter/DataBasePresenter.kt | 8 +++--- .../kotlin/app}/presenter/LayoutPresenter.kt | 2 +- .../kotlin/app}/presenter/TreePresenter.kt | 8 +++--- .../treesPresenters/AvlTreePresenter.kt | 2 +- .../treesPresenters/BsTreePresenter.kt | 2 +- .../treesPresenters/RbTreePresenter.kt | 2 +- .../src/main/kotlin/app}/view/App.kt | 28 ++++++------------- .../app}/view/assets/DatabaseConnections.kt | 2 +- .../kotlin/app}/view/assets/Navigation.kt | 2 +- .../main/kotlin/app}/view/assets/Selector.kt | 2 +- .../main/kotlin/app}/view/assets/TreeView.kt | 7 ++--- .../app}/view/screens/ChosingTypesScreen.kt | 4 +-- .../kotlin/app}/view/screens/HomeScreen.kt | 10 +++---- .../kotlin/app}/view/screens/ScreenManager.kt | 2 +- .../kotlin/app}/view/screens/TreeScreen.kt | 9 +++--- gradle.properties | 3 +- lib/build.gradle.kts | 19 +++---------- 19 files changed, 56 insertions(+), 76 deletions(-) delete mode 100644 app/src/main/kotlin/Main.kt rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/presenter/DataBasePresenter.kt (73%) rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/presenter/LayoutPresenter.kt (96%) rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/presenter/TreePresenter.kt (88%) rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/presenter/treesPresenters/AvlTreePresenter.kt (98%) rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/presenter/treesPresenters/BsTreePresenter.kt (98%) rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/presenter/treesPresenters/RbTreePresenter.kt (98%) rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/view/App.kt (87%) rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/view/assets/DatabaseConnections.kt (98%) rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/view/assets/Navigation.kt (98%) rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/view/assets/Selector.kt (98%) rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/view/assets/TreeView.kt (96%) rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/view/screens/ChosingTypesScreen.kt (95%) rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/view/screens/HomeScreen.kt (84%) rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/view/screens/ScreenManager.kt (91%) rename {lib/src/main/kotlin/bstrees => app/src/main/kotlin/app}/view/screens/TreeScreen.kt (92%) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index cdccdd3..9fdfdd1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,5 +1,8 @@ +val composeVersion: String? by rootProject + plugins { - id("org.jetbrains.kotlin.jvm") version "1.8.10" + id("org.jetbrains.kotlin.jvm") version "1.8.20" + id("org.jetbrains.compose") version "1.4.0" application } @@ -9,15 +12,17 @@ repositories { } dependencies { - // Use the Kotlin test library. - testImplementation("org.jetbrains.kotlin:kotlin-test") + implementation(project(":lib")) - // Use the Kotlin JUnit integration. - testImplementation("org.jetbrains.kotlin:kotlin-test-junit") + implementation("com.arkivanov.decompose:extensions-compose-jetbrains:$composeVersion") + implementation("com.arkivanov.decompose:decompose:$composeVersion") + implementation(compose.desktop.currentOs) + implementation(compose.material3) } + application { // Define the main class for the application. - mainClass.set("MainKt") + mainClass.set("app/view/AppKt") } diff --git a/app/src/main/kotlin/Main.kt b/app/src/main/kotlin/Main.kt deleted file mode 100644 index 0c704e9..0000000 --- a/app/src/main/kotlin/Main.kt +++ /dev/null @@ -1,3 +0,0 @@ -fun main(){ - println("Test gradle") -} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/presenter/DataBasePresenter.kt b/app/src/main/kotlin/app/presenter/DataBasePresenter.kt similarity index 73% rename from lib/src/main/kotlin/bstrees/presenter/DataBasePresenter.kt rename to app/src/main/kotlin/app/presenter/DataBasePresenter.kt index f4e6d55..36ef6d5 100644 --- a/lib/src/main/kotlin/bstrees/presenter/DataBasePresenter.kt +++ b/app/src/main/kotlin/app/presenter/DataBasePresenter.kt @@ -1,19 +1,19 @@ -package bstrees.presenter +package app.presenter import bstrees.model.dataBases.reps.JsonTreeRepo import bstrees.model.dataBases.reps.Neo4jTreeRepo import bstrees.model.dataBases.reps.SQLTreeRepo object DataBasePresenter { - fun connectNeo4j(host: String, username: String, password: String): TreePresenter{ + fun connectNeo4j(host: String, username: String, password: String): TreePresenter { return TreePresenter(Neo4jTreeRepo(host, username, password)) } - fun connectSQL(bdName: String): TreePresenter{ + fun connectSQL(bdName: String): TreePresenter { return TreePresenter(SQLTreeRepo(bdName)) } - fun connectJson(dirName: String): TreePresenter{ + fun connectJson(dirName: String): TreePresenter { return TreePresenter(JsonTreeRepo(dirName)) } } \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/presenter/LayoutPresenter.kt b/app/src/main/kotlin/app/presenter/LayoutPresenter.kt similarity index 96% rename from lib/src/main/kotlin/bstrees/presenter/LayoutPresenter.kt rename to app/src/main/kotlin/app/presenter/LayoutPresenter.kt index 974e6f5..3594a33 100644 --- a/lib/src/main/kotlin/bstrees/presenter/LayoutPresenter.kt +++ b/app/src/main/kotlin/app/presenter/LayoutPresenter.kt @@ -1,4 +1,4 @@ -package bstrees.presenter +package app.presenter import bstrees.model.dataBases.serialize.types.SerializableNode import bstrees.model.dataBases.serialize.types.SerializableTree diff --git a/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt b/app/src/main/kotlin/app/presenter/TreePresenter.kt similarity index 88% rename from lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt rename to app/src/main/kotlin/app/presenter/TreePresenter.kt index e4fb9b5..4220f16 100644 --- a/lib/src/main/kotlin/bstrees/presenter/TreePresenter.kt +++ b/app/src/main/kotlin/app/presenter/TreePresenter.kt @@ -1,10 +1,10 @@ -package bstrees.presenter +package app.presenter import bstrees.model.dataBases.reps.DBTreeRepo import bstrees.model.dataBases.serialize.types.SerializableTree -import bstrees.presenter.treesPresenters.AvlTreePresenter -import bstrees.presenter.treesPresenters.BsTreePresenter -import bstrees.presenter.treesPresenters.RbTreePresenter +import app.presenter.treesPresenters.AvlTreePresenter +import app.presenter.treesPresenters.BsTreePresenter +import app.presenter.treesPresenters.RbTreePresenter class TreePresenter(private val db: DBTreeRepo) { diff --git a/lib/src/main/kotlin/bstrees/presenter/treesPresenters/AvlTreePresenter.kt b/app/src/main/kotlin/app/presenter/treesPresenters/AvlTreePresenter.kt similarity index 98% rename from lib/src/main/kotlin/bstrees/presenter/treesPresenters/AvlTreePresenter.kt rename to app/src/main/kotlin/app/presenter/treesPresenters/AvlTreePresenter.kt index 4f10bf6..6ae6dfb 100644 --- a/lib/src/main/kotlin/bstrees/presenter/treesPresenters/AvlTreePresenter.kt +++ b/app/src/main/kotlin/app/presenter/treesPresenters/AvlTreePresenter.kt @@ -1,4 +1,4 @@ -package bstrees.presenter.treesPresenters +package app.presenter.treesPresenters import bstrees.model.dataBases.serialize.strategies.AvlStrategy import bstrees.model.dataBases.serialize.strategies.intToString diff --git a/lib/src/main/kotlin/bstrees/presenter/treesPresenters/BsTreePresenter.kt b/app/src/main/kotlin/app/presenter/treesPresenters/BsTreePresenter.kt similarity index 98% rename from lib/src/main/kotlin/bstrees/presenter/treesPresenters/BsTreePresenter.kt rename to app/src/main/kotlin/app/presenter/treesPresenters/BsTreePresenter.kt index a6f6b3d..268505a 100644 --- a/lib/src/main/kotlin/bstrees/presenter/treesPresenters/BsTreePresenter.kt +++ b/app/src/main/kotlin/app/presenter/treesPresenters/BsTreePresenter.kt @@ -1,4 +1,4 @@ -package bstrees.presenter.treesPresenters +package app.presenter.treesPresenters import bstrees.model.dataBases.serialize.strategies.BsStrategy import bstrees.model.dataBases.serialize.strategies.intToString diff --git a/lib/src/main/kotlin/bstrees/presenter/treesPresenters/RbTreePresenter.kt b/app/src/main/kotlin/app/presenter/treesPresenters/RbTreePresenter.kt similarity index 98% rename from lib/src/main/kotlin/bstrees/presenter/treesPresenters/RbTreePresenter.kt rename to app/src/main/kotlin/app/presenter/treesPresenters/RbTreePresenter.kt index 0f7e6f7..2463910 100644 --- a/lib/src/main/kotlin/bstrees/presenter/treesPresenters/RbTreePresenter.kt +++ b/app/src/main/kotlin/app/presenter/treesPresenters/RbTreePresenter.kt @@ -1,4 +1,4 @@ -package bstrees.presenter.treesPresenters +package app.presenter.treesPresenters import bstrees.model.dataBases.serialize.strategies.RbStrategy import bstrees.model.dataBases.serialize.strategies.intToString diff --git a/lib/src/main/kotlin/bstrees/view/App.kt b/app/src/main/kotlin/app/view/App.kt similarity index 87% rename from lib/src/main/kotlin/bstrees/view/App.kt rename to app/src/main/kotlin/app/view/App.kt index ce8b0ab..7aef1eb 100644 --- a/lib/src/main/kotlin/bstrees/view/App.kt +++ b/app/src/main/kotlin/app/view/App.kt @@ -1,28 +1,18 @@ -package bstrees.view +package app.view -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.width import androidx.compose.runtime.* import androidx.compose.ui.unit.dp import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.DpSize import androidx.compose.ui.window.* -import bstrees.model.dataBases.serialize.types.SerializableNode -import bstrees.presenter.DataBasePresenter -import bstrees.presenter.TreePresenter -import bstrees.view.assets.ChildStack -import bstrees.view.assets.ProvideComponentContext -import bstrees.view.assets.Tree -import bstrees.view.assets.TreeView -import bstrees.view.screens.ChosingTypesScreen -import bstrees.view.screens.HomeScreen -import bstrees.view.screens.ScreenManager -import bstrees.view.screens.TreeSreen +import app.presenter.DataBasePresenter +import app.presenter.TreePresenter +import app.view.assets.ChildStack +import app.view.assets.ProvideComponentContext +import app.view.screens.ChosingTypesScreen +import app.view.screens.HomeScreen +import app.view.screens.ScreenManager +import app.view.screens.TreeSreen import com.arkivanov.decompose.DefaultComponentContext import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.fade import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.plus diff --git a/lib/src/main/kotlin/bstrees/view/assets/DatabaseConnections.kt b/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt similarity index 98% rename from lib/src/main/kotlin/bstrees/view/assets/DatabaseConnections.kt rename to app/src/main/kotlin/app/view/assets/DatabaseConnections.kt index ff3c231..8837d6f 100644 --- a/lib/src/main/kotlin/bstrees/view/assets/DatabaseConnections.kt +++ b/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt @@ -1,4 +1,4 @@ -package bstrees.view.assets +package app.view.assets import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding diff --git a/lib/src/main/kotlin/bstrees/view/assets/Navigation.kt b/app/src/main/kotlin/app/view/assets/Navigation.kt similarity index 98% rename from lib/src/main/kotlin/bstrees/view/assets/Navigation.kt rename to app/src/main/kotlin/app/view/assets/Navigation.kt index 122339d..ddf96cd 100644 --- a/lib/src/main/kotlin/bstrees/view/assets/Navigation.kt +++ b/app/src/main/kotlin/app/view/assets/Navigation.kt @@ -1,4 +1,4 @@ -package bstrees.view.assets +package app.view.assets import androidx.compose.runtime.* import androidx.compose.ui.Modifier diff --git a/lib/src/main/kotlin/bstrees/view/assets/Selector.kt b/app/src/main/kotlin/app/view/assets/Selector.kt similarity index 98% rename from lib/src/main/kotlin/bstrees/view/assets/Selector.kt rename to app/src/main/kotlin/app/view/assets/Selector.kt index d6990ab..999e4c5 100644 --- a/lib/src/main/kotlin/bstrees/view/assets/Selector.kt +++ b/app/src/main/kotlin/app/view/assets/Selector.kt @@ -1,4 +1,4 @@ -package bstrees.view.assets +package app.view.assets import androidx.compose.foundation.background import androidx.compose.foundation.border diff --git a/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt b/app/src/main/kotlin/app/view/assets/TreeView.kt similarity index 96% rename from lib/src/main/kotlin/bstrees/view/assets/TreeView.kt rename to app/src/main/kotlin/app/view/assets/TreeView.kt index 77fe033..5669d1d 100644 --- a/lib/src/main/kotlin/bstrees/view/assets/TreeView.kt +++ b/app/src/main/kotlin/app/view/assets/TreeView.kt @@ -1,4 +1,4 @@ -package bstrees.view.assets +package app.view.assets import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -11,11 +11,10 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import bstrees.model.dataBases.serialize.types.SerializableNode -import bstrees.presenter.TreePresenter +import app.presenter.TreePresenter @Composable fun Tree( @@ -130,7 +129,7 @@ fun TreeView( ) { tree.root?.let { Tree( - mutableStateOf(tree.root), + mutableStateOf(it), nodeSize, xOffset, yOffset diff --git a/lib/src/main/kotlin/bstrees/view/screens/ChosingTypesScreen.kt b/app/src/main/kotlin/app/view/screens/ChosingTypesScreen.kt similarity index 95% rename from lib/src/main/kotlin/bstrees/view/screens/ChosingTypesScreen.kt rename to app/src/main/kotlin/app/view/screens/ChosingTypesScreen.kt index e0acb39..d3d14d9 100644 --- a/lib/src/main/kotlin/bstrees/view/screens/ChosingTypesScreen.kt +++ b/app/src/main/kotlin/app/view/screens/ChosingTypesScreen.kt @@ -1,4 +1,4 @@ -package bstrees.view.screens +package app.view.screens import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -10,7 +10,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import bstrees.view.assets.Selector +import app.view.assets.Selector @Composable fun ChosingTypesScreen( diff --git a/lib/src/main/kotlin/bstrees/view/screens/HomeScreen.kt b/app/src/main/kotlin/app/view/screens/HomeScreen.kt similarity index 84% rename from lib/src/main/kotlin/bstrees/view/screens/HomeScreen.kt rename to app/src/main/kotlin/app/view/screens/HomeScreen.kt index 3f8197f..0f21d8f 100644 --- a/lib/src/main/kotlin/bstrees/view/screens/HomeScreen.kt +++ b/app/src/main/kotlin/app/view/screens/HomeScreen.kt @@ -1,13 +1,13 @@ -package bstrees.view.screens +package app.view.screens import androidx.compose.foundation.layout.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import bstrees.view.assets.Selector -import bstrees.view.assets.databaseConnectionJson -import bstrees.view.assets.databaseConnectionNeo4j -import bstrees.view.assets.databaseConnectionSQL +import app.view.assets.Selector +import app.view.assets.databaseConnectionJson +import app.view.assets.databaseConnectionNeo4j +import app.view.assets.databaseConnectionSQL @Composable fun HomeScreen( diff --git a/lib/src/main/kotlin/bstrees/view/screens/ScreenManager.kt b/app/src/main/kotlin/app/view/screens/ScreenManager.kt similarity index 91% rename from lib/src/main/kotlin/bstrees/view/screens/ScreenManager.kt rename to app/src/main/kotlin/app/view/screens/ScreenManager.kt index 44ccfaa..1467cf3 100644 --- a/lib/src/main/kotlin/bstrees/view/screens/ScreenManager.kt +++ b/app/src/main/kotlin/app/view/screens/ScreenManager.kt @@ -1,4 +1,4 @@ -package bstrees.view.screens +package app.view.screens import com.arkivanov.essenty.parcelable.Parcelable import com.arkivanov.essenty.parcelable.Parcelize diff --git a/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt b/app/src/main/kotlin/app/view/screens/TreeScreen.kt similarity index 92% rename from lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt rename to app/src/main/kotlin/app/view/screens/TreeScreen.kt index 058e013..e5ecd72 100644 --- a/lib/src/main/kotlin/bstrees/view/screens/TreeScreen.kt +++ b/app/src/main/kotlin/app/view/screens/TreeScreen.kt @@ -1,4 +1,4 @@ -package bstrees.view.screens +package app.view.screens import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -8,9 +8,8 @@ import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import bstrees.presenter.TreePresenter -import bstrees.view.assets.Selector -import bstrees.view.assets.TreeView +import app.presenter.TreePresenter +import app.view.assets.Selector @Composable fun TreeActions( @@ -21,7 +20,7 @@ fun TreeActions( keyType: State, valueType: State, -) { + ) { Column { diff --git a/gradle.properties b/gradle.properties index 945d0b3..2d52fe7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,4 +5,5 @@ kotlinxSerializationVersion=1.5.0 neo4jDriverVersion=5.6.0 sqliteJdbcVersion=3.34.0 kotlinLoggingVersion=2.0.6 -slf4jVersion=1.7.29 \ No newline at end of file +slf4jVersion=1.7.29 +composeVersion=2.0.0-alpha-02 \ No newline at end of file diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 97ca045..7d53e66 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -2,15 +2,14 @@ val jetbrainsExposedVersion: String? by rootProject val junit5Version: String? by rootProject val gsonVersion: String? by rootProject val kotlinxSerializationVersion: String? by rootProject -val neo4jDriverVersion: String? by project -val sqliteJdbcVersion: String? by project -val kotlinLoggingVersion: String? by project -val slf4jVersion: String? by project +val neo4jDriverVersion: String? by rootProject +val sqliteJdbcVersion: String? by rootProject +val kotlinLoggingVersion: String? by rootProject +val slf4jVersion: String? by rootProject plugins { id("org.jetbrains.kotlin.jvm") version "1.8.20" kotlin("plugin.serialization") version "1.8.20" - id("org.jetbrains.compose") version "1.4.0" jacoco application @@ -37,12 +36,6 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-engine:$junit5Version") testImplementation("org.junit.jupiter:junit-jupiter-params:$junit5Version") - - implementation("com.arkivanov.decompose:extensions-compose-jetbrains:2.0.0-alpha-02") - implementation("com.arkivanov.decompose:decompose:2.0.0-alpha-02") - - implementation(compose.desktop.currentOs) - implementation(compose.material3) } tasks.getByName("test") { @@ -63,7 +56,3 @@ tasks.jacocoTestReport { ) } -application { - // Define the main class for the application. - mainClass.set("bstrees/view/AppKt") -} From 638a24b1754540326abd7a678ca0ac9bf617f29b Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 2 May 2023 01:41:51 +0300 Subject: [PATCH 111/135] feat: Added LayoutPresenter implementation --- .../kotlin/app/presenter/LayoutPresenter.kt | 40 ++++++++++++++----- .../presenter/utils/TreeHeightPresenter.kt | 15 +++++++ 2 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 app/src/main/kotlin/app/presenter/utils/TreeHeightPresenter.kt diff --git a/app/src/main/kotlin/app/presenter/LayoutPresenter.kt b/app/src/main/kotlin/app/presenter/LayoutPresenter.kt index 3594a33..67c75f1 100644 --- a/app/src/main/kotlin/app/presenter/LayoutPresenter.kt +++ b/app/src/main/kotlin/app/presenter/LayoutPresenter.kt @@ -2,25 +2,43 @@ package app.presenter import bstrees.model.dataBases.serialize.types.SerializableNode import bstrees.model.dataBases.serialize.types.SerializableTree +import app.presenter.utils.TreeHeightPresenter object LayoutPresenter { - private val defaultNodeLength = 1 - private val windowHeight = 800 - private val windowWidth = 800 + private const val nodeRadius = 50 + private const val edgeLength = 50 - fun setTreeLayout(tree: SerializableTree, height: Int, width: Int){ - } + fun setTreeLayout(tree: SerializableTree, windowHeight: Int, windowWidth: Int){ - // This method will assign coordinates to the nodes of the tree - private fun setNodesLayout(node: SerializableNode){ - node.posX = 0 - node.posY = 0 + val treeHeight = TreeHeightPresenter.getTreeHeight(tree) - node.leftNode?.let { setNodesLayout(it) } - node.rightNode?.let { setNodesLayout(it) } + tree.root?.let {root-> + root.posX = 0 + root.posY = 0 + setNodesLayout(root, treeHeight) + } + } + + // This method will assign coordinates to the nodes of the tree + private fun setNodesLayout(node: SerializableNode, height: Int){ + val xDiff = (edgeLength + 2 * nodeRadius) * height + (height - 1) + val yDiff = (edgeLength + 2 * nodeRadius) + node.leftNode?.let {leftNode-> + leftNode.posX = node.posX - xDiff + leftNode.posY = node.posY + yDiff + + setNodesLayout(leftNode, height - 1) + } + + node.rightNode?.let { rightNode -> + rightNode.posX = node.posX + xDiff + rightNode.posY = node.posY + yDiff + + setNodesLayout(rightNode, height - 1) + } } } \ No newline at end of file diff --git a/app/src/main/kotlin/app/presenter/utils/TreeHeightPresenter.kt b/app/src/main/kotlin/app/presenter/utils/TreeHeightPresenter.kt new file mode 100644 index 0000000..e0a8d26 --- /dev/null +++ b/app/src/main/kotlin/app/presenter/utils/TreeHeightPresenter.kt @@ -0,0 +1,15 @@ +package app.presenter.utils + +import bstrees.model.dataBases.serialize.types.SerializableNode +import bstrees.model.dataBases.serialize.types.SerializableTree +import java.lang.Integer.max + +object TreeHeightPresenter { + + fun getTreeHeight(tree: SerializableTree): Int = getNodeHeight(tree.root) + + private fun getNodeHeight(node: SerializableNode?): Int { + return node?.let { 1 + max(getNodeHeight(node.leftNode), getNodeHeight(node.rightNode)) } ?: 0 + } + +} \ No newline at end of file From 679bc871b8fe6c10db5707302f32784d1e91a05f Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 2 May 2023 03:02:56 +0300 Subject: [PATCH 112/135] feat: Added a new treeToDataConverter and made some structural changes --- .../kotlin/app/presenter/LayoutPresenter.kt | 8 +- .../kotlin/app/presenter/TreePresenter.kt | 85 +++++++++++-------- .../treesPresenters/AvlTreePresenter.kt | 70 --------------- .../treesPresenters/BsTreePresenter.kt | 69 --------------- .../treesPresenters/RbTreePresenter.kt | 69 --------------- .../presenter/utils/TreeHeightPresenter.kt | 8 +- .../main/kotlin/app/view/assets/TreeView.kt | 6 +- .../bstrees/model/dataBases/NodeData.kt | 17 ++++ .../types/SerializableTree.kt => TreeData.kt} | 6 +- .../converters/TreeToDataConverter.kt | 28 ++++++ .../treesConverters/AvlToDataConverter.kt | 60 +++++++++++++ .../treesConverters/BsToDataConverter.kt | 61 +++++++++++++ .../treesConverters/RbToDataConverter.kt | 61 +++++++++++++ .../converters/utils/StringConverter.kt | 27 ++++++ .../model/dataBases/reps/DBTreeRepo.kt | 11 --- .../model/dataBases/reps/JsonTreeRepo.kt | 16 ++-- .../model/dataBases/reps/Neo4jTreeRepo.kt | 40 ++++----- .../model/dataBases/reps/SQLTreeRepo.kt | 36 ++++---- .../bstrees/model/dataBases/reps/TreeRepo.kt | 11 +++ .../dataBases/serialize/SerializeStrategy.kt | 39 --------- .../serialize/strategies/AvlStrategy.kt | 62 -------------- .../serialize/strategies/BsStrategy.kt | 63 -------------- .../serialize/strategies/RbStrategy.kt | 64 -------------- .../serialize/strategies/SerializeMethods.kt | 7 -- .../serialize/types/SerializableNode.kt | 17 ---- 25 files changed, 375 insertions(+), 566 deletions(-) delete mode 100644 app/src/main/kotlin/app/presenter/treesPresenters/AvlTreePresenter.kt delete mode 100644 app/src/main/kotlin/app/presenter/treesPresenters/BsTreePresenter.kt delete mode 100644 app/src/main/kotlin/app/presenter/treesPresenters/RbTreePresenter.kt create mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/NodeData.kt rename lib/src/main/kotlin/bstrees/model/dataBases/{serialize/types/SerializableTree.kt => TreeData.kt} (65%) create mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/converters/TreeToDataConverter.kt create mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/AvlToDataConverter.kt create mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/BsToDataConverter.kt create mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RbToDataConverter.kt create mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/converters/utils/StringConverter.kt delete mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/reps/DBTreeRepo.kt create mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/reps/TreeRepo.kt delete mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt delete mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/AvlStrategy.kt delete mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt delete mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt delete mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/SerializeMethods.kt delete mode 100644 lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt diff --git a/app/src/main/kotlin/app/presenter/LayoutPresenter.kt b/app/src/main/kotlin/app/presenter/LayoutPresenter.kt index 67c75f1..1e0d6f0 100644 --- a/app/src/main/kotlin/app/presenter/LayoutPresenter.kt +++ b/app/src/main/kotlin/app/presenter/LayoutPresenter.kt @@ -1,7 +1,7 @@ package app.presenter -import bstrees.model.dataBases.serialize.types.SerializableNode -import bstrees.model.dataBases.serialize.types.SerializableTree +import bstrees.model.dataBases.NodeData +import bstrees.model.dataBases.TreeData import app.presenter.utils.TreeHeightPresenter object LayoutPresenter { @@ -10,7 +10,7 @@ object LayoutPresenter { private const val edgeLength = 50 - fun setTreeLayout(tree: SerializableTree, windowHeight: Int, windowWidth: Int){ + fun setTreeLayout(tree: TreeData, windowHeight: Int, windowWidth: Int){ val treeHeight = TreeHeightPresenter.getTreeHeight(tree) @@ -23,7 +23,7 @@ object LayoutPresenter { } // This method will assign coordinates to the nodes of the tree - private fun setNodesLayout(node: SerializableNode, height: Int){ + private fun setNodesLayout(node: NodeData, height: Int){ val xDiff = (edgeLength + 2 * nodeRadius) * height + (height - 1) val yDiff = (edgeLength + 2 * nodeRadius) node.leftNode?.let {leftNode-> diff --git a/app/src/main/kotlin/app/presenter/TreePresenter.kt b/app/src/main/kotlin/app/presenter/TreePresenter.kt index 4220f16..2cad109 100644 --- a/app/src/main/kotlin/app/presenter/TreePresenter.kt +++ b/app/src/main/kotlin/app/presenter/TreePresenter.kt @@ -1,57 +1,72 @@ package app.presenter -import bstrees.model.dataBases.reps.DBTreeRepo -import bstrees.model.dataBases.serialize.types.SerializableTree -import app.presenter.treesPresenters.AvlTreePresenter -import app.presenter.treesPresenters.BsTreePresenter -import app.presenter.treesPresenters.RbTreePresenter +import bstrees.model.dataBases.reps.TreeRepo +import bstrees.model.dataBases.TreeData +import bstrees.model.dataBases.converters.TreeToDataConverter +import bstrees.model.dataBases.converters.treesConverters.AvlToDataConverter +import bstrees.model.dataBases.converters.treesConverters.BsToDataConverter +import bstrees.model.dataBases.converters.treesConverters.RbToDataConverter +import bstrees.model.dataBases.converters.utils.createStringConverter +import bstrees.model.trees.BTree -class TreePresenter(private val db: DBTreeRepo) { - lateinit var tree: SerializableTree +class TreePresenter(private val db: TreeRepo) { + lateinit var tree: TreeData private set fun loadTree(treeName: String, treeType: String) { - tree = db.getTree(treeName, treeType) ?: throw Exception("There is no tree with that name: $treeName") + tree = db.getTree(treeName, treeType) ?: throw IllegalArgumentException("There is no tree with that name: $treeName") } fun createTree(treeName: String, treeType: String, keyType: String, valueType: String) { - tree = SerializableTree(treeName, treeType, keyType, valueType, null) + tree = TreeData(treeName, treeType, keyType, valueType, null) db.setTree(tree) } + private fun createStrategy(): TreeToDataConverter<*, *, *, *, *> = when (tree.treeType) { + "AVL" -> AvlToDataConverter( + keyStringConverter = createStringConverter(tree.keyType), + valueStringConverter = createStringConverter(tree.valueType), + keyType = tree.keyType, + valueType = tree.valueType + ) + "RB" -> RbToDataConverter( + keyStringConverter = createStringConverter(tree.keyType), + valueStringConverter = createStringConverter(tree.valueType), + keyType = tree.keyType, + valueType = tree.valueType + ) + "BS" -> BsToDataConverter( + keyStringConverter = createStringConverter(tree.keyType), + valueStringConverter = createStringConverter(tree.valueType), + keyType = tree.keyType, + valueType = tree.valueType + ) + else -> throw IllegalArgumentException("Unknown tree type ${tree.treeType}") + } + + fun addNode(key: String, value: String) { - tree = when (tree.treeType) { - "AVL" -> { - AvlTreePresenter.addNode(tree, key, value) - } - "BS" -> { - BsTreePresenter.addNode(tree, key, value) - } - "RB" -> { - RbTreePresenter.addNode(tree, key, value) - } - else -> { - throw Exception("treeType error") - } + fun , V, TREE_TYPE : BTree> helper(strategy: TreeToDataConverter) { + val bTree = strategy.deserializeTree(tree) + bTree.insert( + strategy.keyStringConverter.fromString(key), + strategy.valueStringConverter.fromString(value) + ) + strategy.serializeTree(bTree, tree.name) } + helper(createStrategy()) } fun deleteNode(key: String) { - tree = when (tree.treeType) { - "AVL" -> { - AvlTreePresenter.deleteNode(tree, key) - } - "BS" -> { - BsTreePresenter.deleteNode(tree, key) - } - "RB" -> { - RbTreePresenter.deleteNode(tree, key) - } - else -> { - throw Exception("treeType error") - } + fun , V, TREE_TYPE : BTree> helper(strategy: TreeToDataConverter) { + val bTree = strategy.deserializeTree(tree) + bTree.delete( + strategy.keyStringConverter.fromString(key), + ) + strategy.serializeTree(bTree, tree.name) } + helper(createStrategy()) } } \ No newline at end of file diff --git a/app/src/main/kotlin/app/presenter/treesPresenters/AvlTreePresenter.kt b/app/src/main/kotlin/app/presenter/treesPresenters/AvlTreePresenter.kt deleted file mode 100644 index 6ae6dfb..0000000 --- a/app/src/main/kotlin/app/presenter/treesPresenters/AvlTreePresenter.kt +++ /dev/null @@ -1,70 +0,0 @@ -package app.presenter.treesPresenters - -import bstrees.model.dataBases.serialize.strategies.AvlStrategy -import bstrees.model.dataBases.serialize.strategies.intToString -import bstrees.model.dataBases.serialize.strategies.stringToInt -import bstrees.model.dataBases.serialize.strategies.stringToString -import bstrees.model.dataBases.serialize.types.SerializableTree - - -object AvlTreePresenter { - fun addNode(tree: SerializableTree, key: String, value: String): SerializableTree{ - return when(tree.keyType to tree.valueType){ - "String" to "String" -> { - val strategy = AvlStrategy(::stringToString, ::stringToString, ::stringToString, ::stringToString, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.insert(key, value) - strategy.serializeTree(bTree, tree.name) - } - "Int" to "Int" -> { - val strategy = AvlStrategy(::intToString, ::intToString, ::stringToInt, ::stringToInt, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.insert(key.toInt(), value.toInt()) - strategy.serializeTree(bTree, tree.name) - } - "String" to "Int" -> { - val strategy = AvlStrategy(::stringToString, ::intToString, ::stringToString, ::stringToInt, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.insert(key, value.toInt()) - strategy.serializeTree(bTree, tree.name) - } - "Int" to "String" -> { - val strategy = AvlStrategy(::intToString, ::stringToString, ::stringToInt, ::stringToString, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.insert(key.toInt(), value) - strategy.serializeTree(bTree, tree.name) - } - else -> { throw Exception("keyValue type error") } - } - } - - fun deleteNode(tree: SerializableTree, key: String): SerializableTree { - return when(tree.keyType to tree.valueType){ - "String" to "String" -> { - val strategy = AvlStrategy(::stringToString, ::stringToString, ::stringToString, ::stringToString, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.delete(key) - strategy.serializeTree(bTree, tree.name) - } - "Int" to "Int" -> { - val strategy = AvlStrategy(::intToString, ::intToString, ::stringToInt, ::stringToInt, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.delete(key.toInt()) - strategy.serializeTree(bTree, tree.name) - } - "String" to "Int" -> { - val strategy = AvlStrategy(::stringToString, ::intToString, ::stringToString, ::stringToInt, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.delete(key) - strategy.serializeTree(bTree, tree.name) - } - "Int" to "String" -> { - val strategy = AvlStrategy(::intToString, ::stringToString, ::stringToInt, ::stringToString, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.delete(key.toInt()) - strategy.serializeTree(bTree, tree.name) - } - else -> { throw Exception("keyValue type error") } - } - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/app/presenter/treesPresenters/BsTreePresenter.kt b/app/src/main/kotlin/app/presenter/treesPresenters/BsTreePresenter.kt deleted file mode 100644 index 268505a..0000000 --- a/app/src/main/kotlin/app/presenter/treesPresenters/BsTreePresenter.kt +++ /dev/null @@ -1,69 +0,0 @@ -package app.presenter.treesPresenters - -import bstrees.model.dataBases.serialize.strategies.BsStrategy -import bstrees.model.dataBases.serialize.strategies.intToString -import bstrees.model.dataBases.serialize.strategies.stringToInt -import bstrees.model.dataBases.serialize.strategies.stringToString -import bstrees.model.dataBases.serialize.types.SerializableTree - -object BsTreePresenter { - fun addNode(tree: SerializableTree, key: String, value: String): SerializableTree{ - return when(tree.keyType to tree.valueType){ - "String" to "String" -> { - val strategy = BsStrategy(::stringToString, ::stringToString, ::stringToString, ::stringToString, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.insert(key, value) - strategy.serializeTree(bTree, tree.name) - } - "Int" to "Int" -> { - val strategy = BsStrategy(::intToString, ::intToString, ::stringToInt, ::stringToInt, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.insert(key.toInt(), value.toInt()) - strategy.serializeTree(bTree, tree.name) - } - "String" to "Int" -> { - val strategy = BsStrategy(::stringToString, ::intToString, ::stringToString, ::stringToInt, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.insert(key, value.toInt()) - strategy.serializeTree(bTree, tree.name) - } - "Int" to "String" -> { - val strategy = BsStrategy(::intToString, ::stringToString, ::stringToInt, ::stringToString, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.insert(key.toInt(), value) - strategy.serializeTree(bTree, tree.name) - } - else -> { throw Exception("keyValue type error") } - } - } - - fun deleteNode(tree: SerializableTree, key: String): SerializableTree { - return when(tree.keyType to tree.valueType){ - "String" to "String" -> { - val strategy = BsStrategy(::stringToString, ::stringToString, ::stringToString, ::stringToString, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.delete(key) - strategy.serializeTree(bTree, tree.name) - } - "Int" to "Int" -> { - val strategy = BsStrategy(::intToString, ::intToString, ::stringToInt, ::stringToInt, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.delete(key.toInt()) - strategy.serializeTree(bTree, tree.name) - } - "String" to "Int" -> { - val strategy = BsStrategy(::stringToString, ::intToString, ::stringToString, ::stringToInt, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.delete(key) - strategy.serializeTree(bTree, tree.name) - } - "Int" to "String" -> { - val strategy = BsStrategy(::intToString, ::stringToString, ::stringToInt, ::stringToString, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.delete(key.toInt()) - strategy.serializeTree(bTree, tree.name) - } - else -> { throw Exception("keyValue type error") } - } - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/app/presenter/treesPresenters/RbTreePresenter.kt b/app/src/main/kotlin/app/presenter/treesPresenters/RbTreePresenter.kt deleted file mode 100644 index 2463910..0000000 --- a/app/src/main/kotlin/app/presenter/treesPresenters/RbTreePresenter.kt +++ /dev/null @@ -1,69 +0,0 @@ -package app.presenter.treesPresenters - -import bstrees.model.dataBases.serialize.strategies.RbStrategy -import bstrees.model.dataBases.serialize.strategies.intToString -import bstrees.model.dataBases.serialize.strategies.stringToInt -import bstrees.model.dataBases.serialize.strategies.stringToString -import bstrees.model.dataBases.serialize.types.SerializableTree - -object RbTreePresenter { - fun addNode(tree: SerializableTree, key: String, value: String): SerializableTree{ - return when(tree.keyType to tree.valueType){ - "String" to "String" -> { - val strategy = RbStrategy(::stringToString, ::stringToString, ::stringToString, ::stringToString, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.insert(key, value) - strategy.serializeTree(bTree, tree.name) - } - "Int" to "Int" -> { - val strategy = RbStrategy(::intToString, ::intToString, ::stringToInt, ::stringToInt, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.insert(key.toInt(), value.toInt()) - strategy.serializeTree(bTree, tree.name) - } - "String" to "Int" -> { - val strategy = RbStrategy(::stringToString, ::intToString, ::stringToString, ::stringToInt, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.insert(key, value.toInt()) - strategy.serializeTree(bTree, tree.name) - } - "Int" to "String" -> { - val strategy = RbStrategy(::intToString, ::stringToString, ::stringToInt, ::stringToString, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.insert(key.toInt(), value) - strategy.serializeTree(bTree, tree.name) - } - else -> { throw Exception("keyValue type error") } - } - } - - fun deleteNode(tree: SerializableTree, key: String): SerializableTree { - return when(tree.keyType to tree.valueType){ - "String" to "String" -> { - val strategy = RbStrategy(::stringToString, ::stringToString, ::stringToString, ::stringToString, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.delete(key) - strategy.serializeTree(bTree, tree.name) - } - "Int" to "Int" -> { - val strategy = RbStrategy(::intToString, ::intToString, ::stringToInt, ::stringToInt, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.delete(key.toInt()) - strategy.serializeTree(bTree, tree.name) - } - "String" to "Int" -> { - val strategy = RbStrategy(::stringToString, ::intToString, ::stringToString, ::stringToInt, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.delete(key) - strategy.serializeTree(bTree, tree.name) - } - "Int" to "String" -> { - val strategy = RbStrategy(::intToString, ::stringToString, ::stringToInt, ::stringToString, tree.keyType, tree.valueType) - val bTree = strategy.deserializeTree(tree) - bTree.delete(key.toInt()) - strategy.serializeTree(bTree, tree.name) - } - else -> { throw Exception("keyValue type error") } - } - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/app/presenter/utils/TreeHeightPresenter.kt b/app/src/main/kotlin/app/presenter/utils/TreeHeightPresenter.kt index e0a8d26..5c71dcb 100644 --- a/app/src/main/kotlin/app/presenter/utils/TreeHeightPresenter.kt +++ b/app/src/main/kotlin/app/presenter/utils/TreeHeightPresenter.kt @@ -1,14 +1,14 @@ package app.presenter.utils -import bstrees.model.dataBases.serialize.types.SerializableNode -import bstrees.model.dataBases.serialize.types.SerializableTree +import bstrees.model.dataBases.NodeData +import bstrees.model.dataBases.TreeData import java.lang.Integer.max object TreeHeightPresenter { - fun getTreeHeight(tree: SerializableTree): Int = getNodeHeight(tree.root) + fun getTreeHeight(tree: TreeData): Int = getNodeHeight(tree.root) - private fun getNodeHeight(node: SerializableNode?): Int { + private fun getNodeHeight(node: NodeData?): Int { return node?.let { 1 + max(getNodeHeight(node.leftNode), getNodeHeight(node.rightNode)) } ?: 0 } diff --git a/app/src/main/kotlin/app/view/assets/TreeView.kt b/app/src/main/kotlin/app/view/assets/TreeView.kt index 5669d1d..0587299 100644 --- a/app/src/main/kotlin/app/view/assets/TreeView.kt +++ b/app/src/main/kotlin/app/view/assets/TreeView.kt @@ -13,12 +13,12 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import bstrees.model.dataBases.serialize.types.SerializableNode +import bstrees.model.dataBases.NodeData import app.presenter.TreePresenter @Composable fun Tree( - root: State, + root: State, nodeSize: Double, xOffset: Double, yOffset: Double, @@ -55,7 +55,7 @@ fun Tree( @Composable fun Node( - node: State, + node: State, nodeSize: Double, ) { diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/NodeData.kt b/lib/src/main/kotlin/bstrees/model/dataBases/NodeData.kt new file mode 100644 index 0000000..66c7afe --- /dev/null +++ b/lib/src/main/kotlin/bstrees/model/dataBases/NodeData.kt @@ -0,0 +1,17 @@ +package bstrees.model.dataBases + +import kotlinx.serialization.Serializable + +@Serializable +class NodeData( + val key: String, + val value: String, + val metadata: String, //If RB meta is RED or BLACK in capital letters + + //layout + var posX: Int, + var posY: Int, + + val leftNode: NodeData? = null, + val rightNode: NodeData? = null, +) \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt b/lib/src/main/kotlin/bstrees/model/dataBases/TreeData.kt similarity index 65% rename from lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt rename to lib/src/main/kotlin/bstrees/model/dataBases/TreeData.kt index f3b4c71..077ef54 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableTree.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/TreeData.kt @@ -1,12 +1,12 @@ -package bstrees.model.dataBases.serialize.types +package bstrees.model.dataBases import kotlinx.serialization.Serializable @Serializable -class SerializableTree( +class TreeData( val name: String, val treeType: String, //RB, AVL or BS in capital letters!!! val keyType: String, val valueType: String, - val root: SerializableNode?, + val root: NodeData?, ) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/converters/TreeToDataConverter.kt b/lib/src/main/kotlin/bstrees/model/dataBases/converters/TreeToDataConverter.kt new file mode 100644 index 0000000..5c27691 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/model/dataBases/converters/TreeToDataConverter.kt @@ -0,0 +1,28 @@ +package bstrees.model.dataBases.converters + +import bstrees.model.dataBases.TreeData +import bstrees.model.dataBases.converters.utils.ComparableStringConverter +import bstrees.model.dataBases.converters.utils.StringConverter +import bstrees.model.trees.BTree +import bstrees.model.trees.Node + +abstract class TreeToDataConverter< + K : Comparable, V, M, + NODE_TYPE : Node, + TREE_TYPE : BTree>( + val keyStringConverter: ComparableStringConverter, + val valueStringConverter: StringConverter, + val keyType: String, + val valueType: String, +) { + abstract fun serializeTree(tree: TREE_TYPE, treeName: String): TreeData + + abstract fun deserializeTree(tree: TreeData): TREE_TYPE + + protected fun linkParents(node: NODE_TYPE) { + node.leftNode?.parent = node + node.rightNode?.parent = node + node.leftNode?.let { linkParents(it) } + node.rightNode?.let { linkParents(it) } + } +} diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/AvlToDataConverter.kt b/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/AvlToDataConverter.kt new file mode 100644 index 0000000..e29960d --- /dev/null +++ b/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/AvlToDataConverter.kt @@ -0,0 +1,60 @@ +package bstrees.model.dataBases.converters.treesConverters + +import bstrees.model.dataBases.NodeData +import bstrees.model.dataBases.TreeData +import bstrees.model.dataBases.converters.TreeToDataConverter +import bstrees.model.dataBases.converters.utils.ComparableStringConverter +import bstrees.model.dataBases.converters.utils.StringConverter +import bstrees.model.trees.avl.AvlNode +import bstrees.model.trees.avl.AvlTree + +class AvlToDataConverter, V>( + keyStringConverter: ComparableStringConverter, + valueStringConverter: StringConverter, + keyType: String, + valueType: String, +) : TreeToDataConverter, AvlTree>( + keyStringConverter, + valueStringConverter, + keyType, + valueType, +) { + private fun serializeNode(node: AvlNode): NodeData = NodeData( + keyStringConverter.toString(node.key), + valueStringConverter.toString(node.value), + serializeMetadata(node.height), + 0, + 0, + node.leftNode?.let { serializeNode(it) }, + node.rightNode?.let { serializeNode(it) } + ) + + private fun deserializeNode(node: NodeData): AvlNode { + val avlnode: AvlNode = AvlNode(keyStringConverter.fromString(node.key), valueStringConverter.fromString(node.value)) + if (node.metadata[0] != 'H') throw Exception("Wrong metadata. Impossible to deserialize") + avlnode.height = deserializeMetadata(node.metadata) + node.leftNode?.let { deserializeNode(it) } + node.rightNode?.let { deserializeNode(it) } + linkParents(avlnode) + return avlnode + } + + override fun serializeTree(tree: AvlTree, treeName: String) = TreeData( + name = treeName, + treeType = "AVL", + keyType = keyType, + valueType = valueType, + root = tree.root?.let { serializeNode(it) } + ) + + override fun deserializeTree(tree: TreeData): AvlTree { + if (tree.treeType != "AVL") throw Exception("Wrong tree type. Impossible to deserialize") + val avltree = AvlTree() + avltree.root = tree.root?.let { deserializeNode(it) } + return avltree + } + + private fun serializeMetadata(meta: Int) = "H$meta" + + private fun deserializeMetadata(meta: String) = meta.substring(1).toInt() +} diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/BsToDataConverter.kt b/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/BsToDataConverter.kt new file mode 100644 index 0000000..0bf9fbe --- /dev/null +++ b/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/BsToDataConverter.kt @@ -0,0 +1,61 @@ +package bstrees.model.dataBases.converters.treesConverters + +import bstrees.model.dataBases.NodeData +import bstrees.model.dataBases.TreeData +import bstrees.model.dataBases.converters.TreeToDataConverter +import bstrees.model.dataBases.converters.utils.ComparableStringConverter +import bstrees.model.dataBases.converters.utils.StringConverter +import bstrees.model.trees.binarySearch.BSNode +import bstrees.model.trees.binarySearch.BSTree + +class BsToDataConverter, V>( + keyStringConverter: ComparableStringConverter, + valueStringConverter: StringConverter, + keyType: String, + valueType: String, +) : TreeToDataConverter, BSTree>( + keyStringConverter, + valueStringConverter, + keyType, + valueType +) { + + private fun serializeNode(node: BSNode): NodeData = NodeData( + keyStringConverter.toString(node.key), + valueStringConverter.toString(node.value), + serializeMetadata(node.size), + 0, + 0, + node.leftNode?.let { serializeNode(it) }, + node.rightNode?.let { serializeNode(it) } + ) + + private fun deserializeNode(node: NodeData): BSNode { + val bsnode: BSNode = BSNode(keyStringConverter.fromString(node.key), valueStringConverter.fromString(node.value)) + if (node.metadata[0] != 'S') throw Exception("Wrong metadata. Impossible to deserialize") + bsnode.size = deserializeMetadata(node.metadata) + node.leftNode?.let { deserializeNode(it) } + node.rightNode?.let { deserializeNode(it) } + linkParents(bsnode) + return bsnode + } + + override fun serializeTree(tree: BSTree, treeName: String) = TreeData( + name = treeName, + treeType = "BS", + keyType = keyType, + valueType = valueType, + root = tree.root?.let { serializeNode(it) } + ) + + override fun deserializeTree(tree: TreeData): BSTree { + if (tree.treeType != "BS") throw Exception("Wrong tree type. Impossible to deserialize") + val bstree = BSTree() + bstree.root = tree.root?.let { deserializeNode(it) } + return bstree + } + + private fun serializeMetadata(meta: Int) = "S$meta" + + private fun deserializeMetadata(meta: String) = meta.substring(1).toInt() +} diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RbToDataConverter.kt b/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RbToDataConverter.kt new file mode 100644 index 0000000..f0e2e41 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RbToDataConverter.kt @@ -0,0 +1,61 @@ +package bstrees.model.dataBases.converters.treesConverters + +import bstrees.model.dataBases.NodeData +import bstrees.model.dataBases.TreeData +import bstrees.model.dataBases.converters.TreeToDataConverter +import bstrees.model.dataBases.converters.utils.ComparableStringConverter +import bstrees.model.dataBases.converters.utils.StringConverter +import bstrees.model.trees.redBlack.RBNode +import bstrees.model.trees.redBlack.RBTree +import bstrees.model.trees.redBlack.RBNode.Color + +class RbToDataConverter, V>( + keyStringConverter: ComparableStringConverter, + valueStringConverter: StringConverter, + keyType: String, + valueType: String, +) : TreeToDataConverter, RBTree>( + keyStringConverter, + valueStringConverter, + keyType, + valueType, +) { + private fun serializeNode(node: RBNode): NodeData = NodeData( + keyStringConverter.toString(node.key), + valueStringConverter.toString(node.value), + serializeMetadata(node.color), + 0, + 0, + node.leftNode?.let { serializeNode(it) }, + node.rightNode?.let { serializeNode(it) } + ) + + private fun deserializeNode(node: NodeData): RBNode { + val rbnode: RBNode = RBNode(keyStringConverter.fromString(node.key), valueStringConverter.fromString(node.value)) + if (node.metadata != "RED" && node.metadata != "BLACK") throw Exception("Wrong metadata. Impossible to deserialize") + rbnode.color = deserializeMetadata(node.metadata) + node.leftNode?.let { deserializeNode(it) } + node.rightNode?.let { deserializeNode(it) } + linkParents(rbnode) + return rbnode + } + + override fun serializeTree(tree: RBTree, treeName: String) = TreeData( + name = treeName, + treeType = "RB", + keyType = keyType, + valueType = valueType, + root = tree.root?.let { serializeNode(it) } + ) + + override fun deserializeTree(tree: TreeData): RBTree { + if (tree.treeType != "RB") throw Exception("Wrong tree type. Impossible to deserialize") + val rbtree = RBTree() + rbtree.root = tree.root?.let { deserializeNode(it) } + return rbtree + } + + private fun deserializeMetadata(meta: String): Color = if (meta == "RED") Color.RED else Color.BLACK + + private fun serializeMetadata(meta: Color): String = if (meta == Color.RED) "RED" else "BLACK" +} diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/converters/utils/StringConverter.kt b/lib/src/main/kotlin/bstrees/model/dataBases/converters/utils/StringConverter.kt new file mode 100644 index 0000000..0f44a11 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/model/dataBases/converters/utils/StringConverter.kt @@ -0,0 +1,27 @@ +package bstrees.model.dataBases.converters.utils + +interface StringConverter { + fun toString(value: T): String + fun fromString(value: String): T +} + +interface ComparableStringConverter>: StringConverter + +object StringStringConverter : ComparableStringConverter { + override fun toString(value: String): String = value + + override fun fromString(value: String): String = value +} + +object IntStringConverter : ComparableStringConverter { + override fun toString(value: Int): String = value.toString() + + override fun fromString(value: String): Int = value.toInt() +} + +fun createStringConverter(type: String): ComparableStringConverter<*> = when (type) { + "String" -> StringStringConverter + "Int" -> IntStringConverter + else -> throw IllegalArgumentException("Unsupported type $type") +} + diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/DBTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/DBTreeRepo.kt deleted file mode 100644 index 890c1c1..0000000 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/DBTreeRepo.kt +++ /dev/null @@ -1,11 +0,0 @@ -package bstrees.model.dataBases.reps - -import bstrees.model.dataBases.serialize.types.SerializableTree - -interface DBTreeRepo { - fun getTree(treeName: String, treeType: String): SerializableTree? - - fun setTree(serializableTree: SerializableTree) - - fun deleteTree(treeName: String, treeType: String) -} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt index b7e4dff..2585431 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt @@ -2,7 +2,7 @@ package bstrees.model.dataBases.reps import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json -import bstrees.model.dataBases.serialize.types.SerializableTree +import bstrees.model.dataBases.TreeData import kotlinx.serialization.encodeToString import mu.KotlinLogging import java.io.* @@ -12,7 +12,7 @@ import java.nio.file.FileAlreadyExistsException private val logger = KotlinLogging.logger { } -class JsonTreeRepo(private val dir: String) : DBTreeRepo { +class JsonTreeRepo(private val dir: String) : TreeRepo { init { makeDir(dir) @@ -30,7 +30,7 @@ class JsonTreeRepo(private val dir: String) : DBTreeRepo { return Path(dir, typeTree, "${treeName}.json").toString() } - override fun getTree(treeName: String, treeType: String): SerializableTree? { + override fun getTree(treeName: String, treeType: String): TreeData? { val filePath = getPathToFile(treeName, treeType) lateinit var file: FileReader var fileFound = true @@ -39,7 +39,7 @@ class JsonTreeRepo(private val dir: String) : DBTreeRepo { file = FileReader(filePath) val jsonText = file.readText() - Json.decodeFromString(jsonText) + Json.decodeFromString(jsonText) } catch (e: FileNotFoundException) { logger.warn { "[JSON] Tree file not found" } fileFound = false @@ -55,8 +55,8 @@ class JsonTreeRepo(private val dir: String) : DBTreeRepo { } } - override fun setTree(serializableTree: SerializableTree) { - val filePath = getPathToFile(serializableTree.name, serializableTree.treeType) + override fun setTree(treeData: TreeData) { + val filePath = getPathToFile(treeData.name, treeData.treeType) lateinit var file: FileWriter var fileAlreadyExists = false @@ -66,7 +66,7 @@ class JsonTreeRepo(private val dir: String) : DBTreeRepo { throw FileAlreadyExistsException("") } file = FileWriter(filePath) - file.write(Json.encodeToString(serializableTree)) + file.write(Json.encodeToString(treeData)) } catch (e: FileAlreadyExistsException) { logger.warn { "[JSON] A tree with that name already exists" } } catch (e: Exception) { @@ -78,7 +78,7 @@ class JsonTreeRepo(private val dir: String) : DBTreeRepo { file.close() } } - logger.info { "[JSON] Set tree - treeName: ${serializableTree.name}, treeType: ${serializableTree.treeType}" } + logger.info { "[JSON] Set tree - treeName: ${treeData.name}, treeType: ${treeData.treeType}" } } override fun deleteTree(treeName: String, treeType: String) { diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt index bb527b8..857a242 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt @@ -4,18 +4,18 @@ import mu.KotlinLogging import org.neo4j.driver.AuthTokens import org.neo4j.driver.GraphDatabase import org.neo4j.driver.TransactionContext -import bstrees.model.dataBases.serialize.types.SerializableNode -import bstrees.model.dataBases.serialize.types.SerializableTree +import bstrees.model.dataBases.NodeData +import bstrees.model.dataBases.TreeData import java.io.Closeable private val logger = KotlinLogging.logger { } -class Neo4jTreeRepo(host: String, username: String, password: String) : Closeable, DBTreeRepo { +class Neo4jTreeRepo(host: String, username: String, password: String) : Closeable, TreeRepo { private val driver = GraphDatabase.driver(host, AuthTokens.basic(username, password)) private val session = driver.session() - override fun getTree(treeName: String, treeType: String): SerializableTree? { - var serializableTree: SerializableTree? = null + override fun getTree(treeName: String, treeType: String): TreeData? { + var treeData: TreeData? = null session.executeRead { tx -> val resultTreeInfo = tx.run( @@ -42,7 +42,7 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl if (resultTreeInfo.hasNext()) { val info: Map = resultTreeInfo.next().asMap() - serializableTree = SerializableTree( + treeData = TreeData( treeName, treeType, info["keyType"].toString(), @@ -54,11 +54,11 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl logger.info { "[NEO4J] Got tree - treeName: $treeName, treeType: $treeType" } - return serializableTree + return treeData } - private fun getSerializedNodes(tx: TransactionContext, nodeKey: String): SerializableNode? { + private fun getSerializedNodes(tx: TransactionContext, nodeKey: String): NodeData? { var nodeData = mapOf() var leftSonKey = mapOf() var rightSonKey = mapOf() @@ -84,7 +84,7 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl } if (nodeData.isEmpty()) return null - return SerializableNode( + return NodeData( nodeData["key"].toString(), nodeData["value"].toString(), nodeData["metadata"].toString(), @@ -95,22 +95,22 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl ) } - override fun setTree(serializableTree: SerializableTree) { + override fun setTree(treeData: TreeData) { - deleteTree(serializableTree.name, serializableTree.treeType) + deleteTree(treeData.name, treeData.treeType) session.executeWrite { tx -> tx.run( "CREATE (:Tree {name: \$name, type: \$type, keyType: \$keyType, valueType: \$valueType})", mutableMapOf( - "name" to serializableTree.name, - "type" to serializableTree.treeType, - "keyType" to serializableTree.keyType, - "valueType" to serializableTree.valueType, + "name" to treeData.name, + "type" to treeData.treeType, + "keyType" to treeData.keyType, + "valueType" to treeData.valueType, ) as Map? ) - serializableTree.root?.let { root -> + treeData.root?.let { root -> setNeo4jNodes(tx, root) tx.run( "MATCH (tree: Tree {name: \$name, type: \$type}) " + @@ -118,17 +118,17 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl "CREATE (tree)-[:root]->(node) " + "REMOVE node:NewNode", mutableMapOf( - "name" to serializableTree.name, - "type" to serializableTree.treeType, + "name" to treeData.name, + "type" to treeData.treeType, ) as Map? ) } } - logger.info { "[NEO4J] Set tree - treeName: ${serializableTree.name}, treeType: ${serializableTree.treeType}" } + logger.info { "[NEO4J] Set tree - treeName: ${treeData.name}, treeType: ${treeData.treeType}" } } - private fun setNeo4jNodes(tx: TransactionContext, node: SerializableNode) { + private fun setNeo4jNodes(tx: TransactionContext, node: NodeData) { tx.run( "CREATE (:Node:NewNode {key: ${node.key}, value: ${node.value}, " + "metadata: ${node.metadata}, posX: ${node.posX}, posY: ${node.posY} })" diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt index d80cbd3..dbaf025 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/SQLTreeRepo.kt @@ -1,7 +1,7 @@ package bstrees.model.dataBases.reps -import bstrees.model.dataBases.serialize.types.SerializableNode -import bstrees.model.dataBases.serialize.types.SerializableTree +import bstrees.model.dataBases.NodeData +import bstrees.model.dataBases.TreeData import mu.KotlinLogging import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.SchemaUtils @@ -60,7 +60,7 @@ class NodeEntity(id: EntityID) : IntEntity(id) { var tree by TreeEntity referencedOn NodesTable.tree } -class SQLTreeRepo(dbName: String) : DBTreeRepo { +class SQLTreeRepo(dbName: String) : TreeRepo { init { connectDB(dbName) @@ -82,7 +82,7 @@ class SQLTreeRepo(dbName: String) : DBTreeRepo { logger.info { "[SQLite] Database tables have been created successfully" } } - override fun getTree(treeName: String, treeType: String): SerializableTree? { + override fun getTree(treeName: String, treeType: String): TreeData? { var treeEntity: TreeEntity? = null transaction { treeEntity = TreeEntity.find { (TreesTable.treeName eq treeName) and (TreesTable.treeType eq treeType) } @@ -94,10 +94,10 @@ class SQLTreeRepo(dbName: String) : DBTreeRepo { return null } - var serializableTree: SerializableTree? = null + var treeData: TreeData? = null transaction { treeEntity?.let { tree -> - serializableTree = SerializableTree( + treeData = TreeData( treeName, tree.treeType, tree.keyType, @@ -109,11 +109,11 @@ class SQLTreeRepo(dbName: String) : DBTreeRepo { logger.info { "[SQLite] Got tree - treeName: $treeName, treeType: $treeType" } - return serializableTree + return treeData } - private fun NodeEntity.toSerializableEntity(treeEntity: TreeEntity): SerializableNode { - return SerializableNode( + private fun NodeEntity.toSerializableEntity(treeEntity: TreeEntity): NodeData { + return NodeData( this@toSerializableEntity.key, this@toSerializableEntity.value, this@toSerializableEntity.metadata, @@ -124,24 +124,24 @@ class SQLTreeRepo(dbName: String) : DBTreeRepo { ) } - override fun setTree(serializableTree: SerializableTree) { - deleteTree(serializableTree.name, serializableTree.treeType) + override fun setTree(treeData: TreeData) { + deleteTree(treeData.name, treeData.treeType) transaction { val newTree = TreeEntity.new { - treeName = serializableTree.name - treeType = serializableTree.treeType - keyType = serializableTree.keyType - valueType = serializableTree.valueType + treeName = treeData.name + treeType = treeData.treeType + keyType = treeData.keyType + valueType = treeData.valueType } - newTree.root = serializableTree.root?.toNodeEntity(newTree) + newTree.root = treeData.root?.toNodeEntity(newTree) } - logger.info { "[SQLite] Set tree - treeName: ${serializableTree.name}, treeType: ${serializableTree.treeType}" } + logger.info { "[SQLite] Set tree - treeName: ${treeData.name}, treeType: ${treeData.treeType}" } } - private fun SerializableNode.toNodeEntity(treeEntity: TreeEntity): NodeEntity { + private fun NodeData.toNodeEntity(treeEntity: TreeEntity): NodeEntity { return NodeEntity.new { key = this@toNodeEntity.key value = this@toNodeEntity.value diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/TreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/TreeRepo.kt new file mode 100644 index 0000000..041acb2 --- /dev/null +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/TreeRepo.kt @@ -0,0 +1,11 @@ +package bstrees.model.dataBases.reps + +import bstrees.model.dataBases.TreeData + +interface TreeRepo { + fun getTree(treeName: String, treeType: String): TreeData? + + fun setTree(treeData: TreeData) + + fun deleteTree(treeName: String, treeType: String) +} \ No newline at end of file diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt deleted file mode 100644 index 5e03742..0000000 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/SerializeStrategy.kt +++ /dev/null @@ -1,39 +0,0 @@ -package bstrees.model.dataBases.serialize - -import bstrees.model.dataBases.serialize.types.SerializableNode -import bstrees.model.dataBases.serialize.types.SerializableTree -import bstrees.model.trees.BTree -import bstrees.model.trees.Node - -abstract class SerializeStrategy< - K : Comparable, V, M, - NODE_TYPE : Node, - TREE_TYPE : BTree>( - val serializeKey: (K) -> String, - val serializeValue: (V) -> String, - val deserializeKey: (String) -> K, - val deserializeValue: (String) -> V, - val keyType: String, - val valueType: String, -) { - - abstract fun serializeNode(node: NODE_TYPE): SerializableNode - - abstract fun deserializeNode(node: SerializableNode): NODE_TYPE - - abstract fun serializeTree(tree: TREE_TYPE, treeName: String): SerializableTree - - abstract fun deserializeTree(tree: SerializableTree): TREE_TYPE - - protected fun linkParents(node: NODE_TYPE) { - node.leftNode?.parent = node - node.rightNode?.parent = node - node.leftNode?.let { linkParents(it) } - node.rightNode?.let { linkParents(it) } - } - - abstract fun serializeMetadata(meta: M): String - - abstract fun deserializeMetadata(meta: String): M - -} diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/AvlStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/AvlStrategy.kt deleted file mode 100644 index ca58816..0000000 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/AvlStrategy.kt +++ /dev/null @@ -1,62 +0,0 @@ -package bstrees.model.dataBases.serialize.strategies - -import bstrees.model.dataBases.serialize.SerializeStrategy -import bstrees.model.dataBases.serialize.types.SerializableNode -import bstrees.model.dataBases.serialize.types.SerializableTree -import bstrees.model.trees.avl.AvlNode -import bstrees.model.trees.avl.AvlTree - -class AvlStrategy, V>( - serializeKey: (K) -> String, - serializeValue: (V) -> String, - deserializeKey: (String) -> K, - deserializeValue: (String) -> V, - keyType: String, - valueType: String, -) : SerializeStrategy, AvlTree>( - serializeKey, - serializeValue, - deserializeKey, - deserializeValue, - keyType, - valueType, -) { - override fun serializeNode(node: AvlNode): SerializableNode = SerializableNode( - serializeKey(node.key), - serializeValue(node.value), - serializeMetadata(node.height), - 0, - 0, - node.leftNode?.let { serializeNode(it) }, - node.rightNode?.let { serializeNode(it) } - ) - - override fun deserializeNode(node: SerializableNode): AvlNode { - val avlnode: AvlNode = AvlNode(deserializeKey(node.key), deserializeValue(node.value)) - if (node.metadata[0] != 'H') throw Exception("Wrong metadata. Impossible to deserialize") - avlnode.height = deserializeMetadata(node.metadata) - node.leftNode?.let { deserializeNode(it) } - node.rightNode?.let { deserializeNode(it) } - linkParents(avlnode) - return avlnode - } - - override fun serializeTree(tree: AvlTree, treeName: String) = SerializableTree( - name = treeName, - treeType = "AVL", - keyType = keyType, - valueType = valueType, - root = tree.root?.let { serializeNode(it) } - ) - - override fun deserializeTree(tree: SerializableTree): AvlTree { - if (tree.treeType != "AVL") throw Exception("Wrong tree type. Impossible to deserialize") - val avltree = AvlTree() - avltree.root = tree.root?.let { deserializeNode(it) } - return avltree - } - - override fun serializeMetadata(meta: Int) = "H$meta" - - override fun deserializeMetadata(meta: String) = meta.substring(1).toInt() -} diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt deleted file mode 100644 index e0ea457..0000000 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/BsStrategy.kt +++ /dev/null @@ -1,63 +0,0 @@ -package bstrees.model.dataBases.serialize.strategies - -import bstrees.model.dataBases.serialize.types.SerializableNode -import bstrees.model.dataBases.serialize.types.SerializableTree -import bstrees.model.dataBases.serialize.SerializeStrategy -import bstrees.model.trees.binarySearch.BSNode -import bstrees.model.trees.binarySearch.BSTree - -class BsStrategy, V>( - serializeKey: (K) -> String, - serializeValue: (V) -> String, - deserializeKey: (String) -> K, - deserializeValue: (String) -> V, - keyType: String, - valueType: String, -) : SerializeStrategy, BSTree>( - serializeKey, - serializeValue, - deserializeKey, - deserializeValue, - keyType, - valueType -) { - - override fun serializeNode(node: BSNode): SerializableNode = SerializableNode( - serializeKey(node.key), - serializeValue(node.value), - serializeMetadata(node.size), - 0, - 0, - node.leftNode?.let { serializeNode(it) }, - node.rightNode?.let { serializeNode(it) } - ) - - override fun deserializeNode(node: SerializableNode): BSNode { - val bsnode: BSNode = BSNode(deserializeKey(node.key), deserializeValue(node.value)) - if (node.metadata[0] != 'S') throw Exception("Wrong metadata. Impossible to deserialize") - bsnode.size = deserializeMetadata(node.metadata) - node.leftNode?.let { deserializeNode(it) } - node.rightNode?.let { deserializeNode(it) } - linkParents(bsnode) - return bsnode - } - - override fun serializeTree(tree: BSTree, treeName: String) = SerializableTree( - name = treeName, - treeType = "BS", - keyType = keyType, - valueType = valueType, - root = tree.root?.let { serializeNode(it) } - ) - - override fun deserializeTree(tree: SerializableTree): BSTree { - if (tree.treeType != "BS") throw Exception("Wrong tree type. Impossible to deserialize") - val bstree = BSTree() - bstree.root = tree.root?.let { deserializeNode(it) } - return bstree - } - - override fun serializeMetadata(meta: Int) = "S$meta" - - override fun deserializeMetadata(meta: String) = meta.substring(1).toInt() -} diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt deleted file mode 100644 index 3a0aa7c..0000000 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/RbStrategy.kt +++ /dev/null @@ -1,64 +0,0 @@ -package bstrees.model.dataBases.serialize.strategies - -import bstrees.model.dataBases.serialize.SerializeStrategy -import bstrees.model.dataBases.serialize.types.SerializableNode -import bstrees.model.dataBases.serialize.types.SerializableTree -import bstrees.model.trees.redBlack.RBNode -import bstrees.model.trees.redBlack.RBTree -import bstrees.model.trees.redBlack.RBNode.Color - -class RbStrategy, V>( - serializeKey: (K) -> String, - serializeValue: (V) -> String, - deserializeKey: (String) -> K, - deserializeValue: (String) -> V, - keyType: String, - valueType: String, -) : SerializeStrategy, RBTree>( - serializeKey, - serializeValue, - deserializeKey, - deserializeValue, - keyType, - valueType, -) { - override fun serializeNode(node: RBNode): SerializableNode = SerializableNode( - serializeKey(node.key), - serializeValue(node.value), - serializeMetadata(node.color), - 0, - 0, - node.leftNode?.let { serializeNode(it) }, - node.rightNode?.let { serializeNode(it) } - ) - - override fun deserializeNode(node: SerializableNode): RBNode { - val rbnode: RBNode = RBNode(deserializeKey(node.key), deserializeValue(node.value)) - if (node.metadata != "RED" && node.metadata != "BLACK") throw Exception("Wrong metadata. Impossible to deserialize") - rbnode.color = deserializeMetadata(node.metadata) - node.leftNode?.let { deserializeNode(it) } - node.rightNode?.let { deserializeNode(it) } - linkParents(rbnode) - return rbnode - } - - override fun serializeTree(tree: RBTree, treeName: String) = SerializableTree( - name = treeName, - treeType = "RB", - keyType = keyType, - valueType = valueType, - root = tree.root?.let { serializeNode(it) } - ) - - override fun deserializeTree(tree: SerializableTree): RBTree { - if (tree.treeType != "RB") throw Exception("Wrong tree type. Impossible to deserialize") - val rbtree = RBTree() - rbtree.root = tree.root?.let { deserializeNode(it) } - return rbtree - } - - override fun deserializeMetadata(meta: String): Color = if (meta == "RED") Color.RED else Color.BLACK - - override fun serializeMetadata(meta: Color): String = if (meta == Color.RED) "RED" else "BLACK" - -} diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/SerializeMethods.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/SerializeMethods.kt deleted file mode 100644 index da17e82..0000000 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/strategies/SerializeMethods.kt +++ /dev/null @@ -1,7 +0,0 @@ -package bstrees.model.dataBases.serialize.strategies - -fun intToString(a: Int): String = a.toString() - -fun stringToInt(a: String): Int = a.toInt() - -fun stringToString(a: String): String = a diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt b/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt deleted file mode 100644 index 7f6d86a..0000000 --- a/lib/src/main/kotlin/bstrees/model/dataBases/serialize/types/SerializableNode.kt +++ /dev/null @@ -1,17 +0,0 @@ -package bstrees.model.dataBases.serialize.types - -import kotlinx.serialization.Serializable - -@Serializable -class SerializableNode( - val key: String, - val value: String, - val metadata: String, //If Rb meta is RED or BLACK in capital letters - - //layout - var posX: Int, - var posY: Int, - - val leftNode: SerializableNode? = null, - val rightNode: SerializableNode? = null, -) \ No newline at end of file From c10747ab834ca53e93f758d6245a2fa74af6510e Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 2 May 2023 03:47:25 +0300 Subject: [PATCH 113/135] fix: The names of some model files have been changed --- .../kotlin/app/presenter/TreePresenter.kt | 10 +-- .../converters/TreeToDataConverter.kt | 8 +- ...onverter.kt => RandomBsToDataConverter.kt} | 20 ++--- .../model/trees/{Node.kt => BSNode.kt} | 2 +- .../model/trees/{BTree.kt => BSTree.kt} | 2 +- .../kotlin/bstrees/model/trees/Balancer.kt | 2 +- .../kotlin/bstrees/model/trees/avl/AvlNode.kt | 4 +- .../kotlin/bstrees/model/trees/avl/AvlTree.kt | 4 +- .../RandomBSBalancer.kt} | 8 +- .../RandomBSNode.kt} | 6 +- .../RandomBSTree.kt} | 24 ++--- .../bstrees/model/trees/redBlack/RBNode.kt | 4 +- .../bstrees/model/trees/redBlack/RBTree.kt | 4 +- .../test/kotlin/avlTree/AVLTreeInvariants.kt | 4 +- lib/src/test/kotlin/balancers/BalancerTest.kt | 18 ++-- .../binarySearchTree/BSTreeInvariants.kt | 10 +-- .../{BSTreeTest.kt => RandomBSTreeTest.kt} | 12 +-- .../kotlin/redBlackTree/RBTreeInvariants.kt | 4 +- lib/src/test/kotlin/utils/BSTreeUtil.kt | 88 +++++++++---------- lib/src/test/kotlin/utils/TreesInvariants.kt | 4 +- 20 files changed, 119 insertions(+), 119 deletions(-) rename lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/{BsToDataConverter.kt => RandomBsToDataConverter.kt} (69%) rename lib/src/main/kotlin/bstrees/model/trees/{Node.kt => BSNode.kt} (86%) rename lib/src/main/kotlin/bstrees/model/trees/{BTree.kt => BSTree.kt} (93%) rename lib/src/main/kotlin/bstrees/model/trees/{binarySearch/BSBalancer.kt => randomBinarySearch/RandomBSBalancer.kt} (75%) rename lib/src/main/kotlin/bstrees/model/trees/{binarySearch/BSNode.kt => randomBinarySearch/RandomBSNode.kt} (80%) rename lib/src/main/kotlin/bstrees/model/trees/{binarySearch/BSTree.kt => randomBinarySearch/RandomBSTree.kt} (88%) rename lib/src/test/kotlin/binarySearchTree/{BSTreeTest.kt => RandomBSTreeTest.kt} (95%) diff --git a/app/src/main/kotlin/app/presenter/TreePresenter.kt b/app/src/main/kotlin/app/presenter/TreePresenter.kt index 2cad109..9457fe3 100644 --- a/app/src/main/kotlin/app/presenter/TreePresenter.kt +++ b/app/src/main/kotlin/app/presenter/TreePresenter.kt @@ -4,10 +4,10 @@ import bstrees.model.dataBases.reps.TreeRepo import bstrees.model.dataBases.TreeData import bstrees.model.dataBases.converters.TreeToDataConverter import bstrees.model.dataBases.converters.treesConverters.AvlToDataConverter -import bstrees.model.dataBases.converters.treesConverters.BsToDataConverter +import bstrees.model.dataBases.converters.treesConverters.RandomBsToDataConverter import bstrees.model.dataBases.converters.treesConverters.RbToDataConverter import bstrees.model.dataBases.converters.utils.createStringConverter -import bstrees.model.trees.BTree +import bstrees.model.trees.BSTree class TreePresenter(private val db: TreeRepo) { @@ -36,7 +36,7 @@ class TreePresenter(private val db: TreeRepo) { keyType = tree.keyType, valueType = tree.valueType ) - "BS" -> BsToDataConverter( + "BS" -> RandomBsToDataConverter( keyStringConverter = createStringConverter(tree.keyType), valueStringConverter = createStringConverter(tree.valueType), keyType = tree.keyType, @@ -47,7 +47,7 @@ class TreePresenter(private val db: TreeRepo) { fun addNode(key: String, value: String) { - fun , V, TREE_TYPE : BTree> helper(strategy: TreeToDataConverter) { + fun , V, TREE_TYPE : BSTree> helper(strategy: TreeToDataConverter) { val bTree = strategy.deserializeTree(tree) bTree.insert( strategy.keyStringConverter.fromString(key), @@ -60,7 +60,7 @@ class TreePresenter(private val db: TreeRepo) { fun deleteNode(key: String) { - fun , V, TREE_TYPE : BTree> helper(strategy: TreeToDataConverter) { + fun , V, TREE_TYPE : BSTree> helper(strategy: TreeToDataConverter) { val bTree = strategy.deserializeTree(tree) bTree.delete( strategy.keyStringConverter.fromString(key), diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/converters/TreeToDataConverter.kt b/lib/src/main/kotlin/bstrees/model/dataBases/converters/TreeToDataConverter.kt index 5c27691..1fe161f 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/converters/TreeToDataConverter.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/converters/TreeToDataConverter.kt @@ -3,13 +3,13 @@ package bstrees.model.dataBases.converters import bstrees.model.dataBases.TreeData import bstrees.model.dataBases.converters.utils.ComparableStringConverter import bstrees.model.dataBases.converters.utils.StringConverter -import bstrees.model.trees.BTree -import bstrees.model.trees.Node +import bstrees.model.trees.BSTree +import bstrees.model.trees.BSNode abstract class TreeToDataConverter< K : Comparable, V, M, - NODE_TYPE : Node, - TREE_TYPE : BTree>( + NODE_TYPE : BSNode, + TREE_TYPE : BSTree>( val keyStringConverter: ComparableStringConverter, val valueStringConverter: StringConverter, val keyType: String, diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/BsToDataConverter.kt b/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RandomBsToDataConverter.kt similarity index 69% rename from lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/BsToDataConverter.kt rename to lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RandomBsToDataConverter.kt index 0bf9fbe..a157ac0 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/BsToDataConverter.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RandomBsToDataConverter.kt @@ -5,22 +5,22 @@ import bstrees.model.dataBases.TreeData import bstrees.model.dataBases.converters.TreeToDataConverter import bstrees.model.dataBases.converters.utils.ComparableStringConverter import bstrees.model.dataBases.converters.utils.StringConverter -import bstrees.model.trees.binarySearch.BSNode -import bstrees.model.trees.binarySearch.BSTree +import bstrees.model.trees.randomBinarySearch.RandomBSNode +import bstrees.model.trees.randomBinarySearch.RandomBSTree -class BsToDataConverter, V>( +class RandomBsToDataConverter, V>( keyStringConverter: ComparableStringConverter, valueStringConverter: StringConverter, keyType: String, valueType: String, -) : TreeToDataConverter, BSTree>( +) : TreeToDataConverter, RandomBSTree>( keyStringConverter, valueStringConverter, keyType, valueType ) { - private fun serializeNode(node: BSNode): NodeData = NodeData( + private fun serializeNode(node: RandomBSNode): NodeData = NodeData( keyStringConverter.toString(node.key), valueStringConverter.toString(node.value), serializeMetadata(node.size), @@ -30,8 +30,8 @@ class BsToDataConverter, V>( node.rightNode?.let { serializeNode(it) } ) - private fun deserializeNode(node: NodeData): BSNode { - val bsnode: BSNode = BSNode(keyStringConverter.fromString(node.key), valueStringConverter.fromString(node.value)) + private fun deserializeNode(node: NodeData): RandomBSNode { + val bsnode: RandomBSNode = RandomBSNode(keyStringConverter.fromString(node.key), valueStringConverter.fromString(node.value)) if (node.metadata[0] != 'S') throw Exception("Wrong metadata. Impossible to deserialize") bsnode.size = deserializeMetadata(node.metadata) node.leftNode?.let { deserializeNode(it) } @@ -40,7 +40,7 @@ class BsToDataConverter, V>( return bsnode } - override fun serializeTree(tree: BSTree, treeName: String) = TreeData( + override fun serializeTree(tree: RandomBSTree, treeName: String) = TreeData( name = treeName, treeType = "BS", keyType = keyType, @@ -48,9 +48,9 @@ class BsToDataConverter, V>( root = tree.root?.let { serializeNode(it) } ) - override fun deserializeTree(tree: TreeData): BSTree { + override fun deserializeTree(tree: TreeData): RandomBSTree { if (tree.treeType != "BS") throw Exception("Wrong tree type. Impossible to deserialize") - val bstree = BSTree() + val bstree = RandomBSTree() bstree.root = tree.root?.let { deserializeNode(it) } return bstree } diff --git a/lib/src/main/kotlin/bstrees/model/trees/Node.kt b/lib/src/main/kotlin/bstrees/model/trees/BSNode.kt similarity index 86% rename from lib/src/main/kotlin/bstrees/model/trees/Node.kt rename to lib/src/main/kotlin/bstrees/model/trees/BSNode.kt index 18a5908..6e8b4c7 100644 --- a/lib/src/main/kotlin/bstrees/model/trees/Node.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/BSNode.kt @@ -8,7 +8,7 @@ package bstrees.model.trees * @generic the type of value stored in the tree * @generic the type of node used in the tree */ -abstract class Node, V, NODE_TYPE : Node>(val key: K, var value: V) { +abstract class BSNode, V, NODE_TYPE : BSNode>(val key: K, var value: V) { /** * The parent of the node */ diff --git a/lib/src/main/kotlin/bstrees/model/trees/BTree.kt b/lib/src/main/kotlin/bstrees/model/trees/BSTree.kt similarity index 93% rename from lib/src/main/kotlin/bstrees/model/trees/BTree.kt rename to lib/src/main/kotlin/bstrees/model/trees/BSTree.kt index 964c57a..7a0ef5f 100644 --- a/lib/src/main/kotlin/bstrees/model/trees/BTree.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/BSTree.kt @@ -7,7 +7,7 @@ package bstrees.model.trees * @generic the type of value stored in the tree * @generic the type of node used in the tree */ -abstract class BTree, V, NODE_TYPE : Node> { +abstract class BSTree, V, NODE_TYPE : BSNode> { /** * The root node of the tree. */ diff --git a/lib/src/main/kotlin/bstrees/model/trees/Balancer.kt b/lib/src/main/kotlin/bstrees/model/trees/Balancer.kt index c4f6b9f..f6345ef 100644 --- a/lib/src/main/kotlin/bstrees/model/trees/Balancer.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/Balancer.kt @@ -7,7 +7,7 @@ package bstrees.model.trees * @generic the type of value stored in the tree * @generic the type of node used in the tree */ -abstract class Balancer, V, NODE_TYPE : Node> { +abstract class Balancer, V, NODE_TYPE : BSNode> { /** * Do a left rotate around this node * diff --git a/lib/src/main/kotlin/bstrees/model/trees/avl/AvlNode.kt b/lib/src/main/kotlin/bstrees/model/trees/avl/AvlNode.kt index ae3b9ab..2ec188c 100644 --- a/lib/src/main/kotlin/bstrees/model/trees/avl/AvlNode.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/avl/AvlNode.kt @@ -1,6 +1,6 @@ package bstrees.model.trees.avl -import bstrees.model.trees.Node +import bstrees.model.trees.BSNode import kotlin.math.max /** @@ -10,7 +10,7 @@ import kotlin.math.max * @generic the type of key stored in the tree. It must be comparable * @generic the type of value stored in the tree */ -class AvlNode, V>(key: K, value: V) : Node>(key, value) { +class AvlNode, V>(key: K, value: V) : BSNode>(key, value) { /** * The variable that contains a height of the tree diff --git a/lib/src/main/kotlin/bstrees/model/trees/avl/AvlTree.kt b/lib/src/main/kotlin/bstrees/model/trees/avl/AvlTree.kt index 78d5202..2591669 100644 --- a/lib/src/main/kotlin/bstrees/model/trees/avl/AvlTree.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/avl/AvlTree.kt @@ -1,6 +1,6 @@ package bstrees.model.trees.avl -import bstrees.model.trees.BTree +import bstrees.model.trees.BSTree /** * A class representing an AVL binary search tree. @@ -9,7 +9,7 @@ import bstrees.model.trees.BTree * @generic the type of key stored in the tree. It must be comparable * @generic the type of value stored in the tree */ -class AvlTree, V> : BTree>() { +class AvlTree, V> : BSTree>() { /** * A balancer class providing balancing of the current node of the tree diff --git a/lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSBalancer.kt b/lib/src/main/kotlin/bstrees/model/trees/randomBinarySearch/RandomBSBalancer.kt similarity index 75% rename from lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSBalancer.kt rename to lib/src/main/kotlin/bstrees/model/trees/randomBinarySearch/RandomBSBalancer.kt index f52ffda..e044635 100644 --- a/lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSBalancer.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/randomBinarySearch/RandomBSBalancer.kt @@ -1,4 +1,4 @@ -package bstrees.model.trees.binarySearch +package bstrees.model.trees.randomBinarySearch import bstrees.model.trees.Balancer @@ -9,14 +9,14 @@ import bstrees.model.trees.Balancer * @generic the type of key stored in the tree. It must be comparable * @generic the type of value stored in the tree */ -internal class BSBalancer, V> : Balancer>() { +internal class RandomBSBalancer, V> : Balancer>() { /** * Do a right rotate around this node with updating size * * @param node the node around which the rotation is done */ - internal fun bsRightRotate(node: BSNode): BSNode { + internal fun bsRightRotate(node: RandomBSNode): RandomBSNode { val temp = rightRotate(node) temp.leftNode?.updateSize() temp.rightNode?.updateSize() @@ -29,7 +29,7 @@ internal class BSBalancer, V> : Balancer>() * * @param node the node around which the rotation is done */ - internal fun bsLeftRotate(node: BSNode): BSNode { + internal fun bsLeftRotate(node: RandomBSNode): RandomBSNode { val temp = leftRotate(node) temp.leftNode?.updateSize() temp.rightNode?.updateSize() diff --git a/lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSNode.kt b/lib/src/main/kotlin/bstrees/model/trees/randomBinarySearch/RandomBSNode.kt similarity index 80% rename from lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSNode.kt rename to lib/src/main/kotlin/bstrees/model/trees/randomBinarySearch/RandomBSNode.kt index 6570778..c717c4d 100644 --- a/lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSNode.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/randomBinarySearch/RandomBSNode.kt @@ -1,6 +1,6 @@ -package bstrees.model.trees.binarySearch +package bstrees.model.trees.randomBinarySearch -import bstrees.model.trees.Node +import bstrees.model.trees.BSNode /** * A class representing a randomized binary search tree node. @@ -9,7 +9,7 @@ import bstrees.model.trees.Node * @generic the type of key stored in the tree. It must be comparable * @generic the type of value stored in the tree */ -class BSNode, V>(key: K, value: V) : Node>(key, value) { +class RandomBSNode, V>(key: K, value: V) : BSNode>(key, value) { /** * The variable that contains size of the tree diff --git a/lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSTree.kt b/lib/src/main/kotlin/bstrees/model/trees/randomBinarySearch/RandomBSTree.kt similarity index 88% rename from lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSTree.kt rename to lib/src/main/kotlin/bstrees/model/trees/randomBinarySearch/RandomBSTree.kt index 5dbd674..6593ec6 100644 --- a/lib/src/main/kotlin/bstrees/model/trees/binarySearch/BSTree.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/randomBinarySearch/RandomBSTree.kt @@ -1,6 +1,6 @@ -package bstrees.model.trees.binarySearch +package bstrees.model.trees.randomBinarySearch -import bstrees.model.trees.BTree +import bstrees.model.trees.BSTree import kotlin.random.Random /** @@ -10,12 +10,12 @@ import kotlin.random.Random * @generic the type of key stored in the tree. It must be comparable * @generic the type of value stored in the tree */ -class BSTree, V> : BTree>() { +class RandomBSTree, V> : BSTree>() { /** * A balancer class providing rotations of the tree with updating the size */ - private val balancer = BSBalancer() + private val balancer = RandomBSBalancer() /** * Insert a node to the tree. @@ -25,7 +25,7 @@ class BSTree, V> : BTree>() { * @param key the key under which the value is stored */ override fun insert(key: K, value: V) { - add(BSNode(key, value)) + add(RandomBSNode(key, value)) } /** @@ -34,7 +34,7 @@ class BSTree, V> : BTree>() { * * @param node the node to add */ - private fun addRoot(node: BSNode): BSNode { + private fun addRoot(node: RandomBSNode): RandomBSNode { //temp is needed to avoid possibility of changing the root val temp = this.root return if (temp == null) node @@ -47,7 +47,7 @@ class BSTree, V> : BTree>() { * Creating subtree to execute add function again * Then we return the node to the desired son */ - val subTree = BSTree() + val subTree = RandomBSTree() //We make the usual adding, then we put the node in the root by rotation it tom the top if (node.key < temp.key) { subTree.root = temp.leftNode @@ -67,7 +67,7 @@ class BSTree, V> : BTree>() { * * @param node the node to add */ - private fun add(node: BSNode) { + private fun add(node: RandomBSNode) { //temp is needed to avoid possibility of changing the root val temp = this.root if (temp == null) this.root = node @@ -90,7 +90,7 @@ class BSTree, V> : BTree>() { * Creating subtree to execute add function again * Then we return the node to the desired son */ - val subTree = BSTree() + val subTree = RandomBSTree() if (temp.key > node.key) { subTree.root = temp.leftNode subTree.add(node) @@ -118,7 +118,7 @@ class BSTree, V> : BTree>() { * @param right * The nodes to merge */ - private fun join(left: BSNode?, right: BSNode?): BSNode? { + private fun join(left: RandomBSNode?, right: RandomBSNode?): RandomBSNode? { //If one of the nodes is null then we can just return the second one if (left == null) return right @@ -152,13 +152,13 @@ class BSTree, V> : BTree>() { if (temp.key == key) this.root = join(temp.leftNode, temp.rightNode) else if (key < temp.key) { - val subTree = BSTree() + val subTree = RandomBSTree() subTree.root = temp.leftNode subTree.delete(key) subTree.root?.parent = this.root this.root?.leftNode = subTree.root } else { - val subTree = BSTree() + val subTree = RandomBSTree() subTree.root = temp.rightNode subTree.delete(key) subTree.root?.parent = this.root diff --git a/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBNode.kt b/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBNode.kt index 8367ca2..d0100cc 100644 --- a/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBNode.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBNode.kt @@ -1,6 +1,6 @@ package bstrees.model.trees.redBlack -import bstrees.model.trees.Node +import bstrees.model.trees.BSNode /** * A class representing an AVL binary search tree node. @@ -9,7 +9,7 @@ import bstrees.model.trees.Node * @generic the type of key stored in the tree. It must be comparable * @generic the type of value stored in the tree */ -class RBNode, V>(key: K, value: V) : Node>(key, value) { +class RBNode, V>(key: K, value: V) : BSNode>(key, value) { /** * An auxiliary enum class that contains the color of the node diff --git a/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBTree.kt b/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBTree.kt index 229080e..1f4a578 100644 --- a/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBTree.kt +++ b/lib/src/main/kotlin/bstrees/model/trees/redBlack/RBTree.kt @@ -1,6 +1,6 @@ package bstrees.model.trees.redBlack -import bstrees.model.trees.BTree +import bstrees.model.trees.BSTree import bstrees.model.trees.redBlack.RBNode.Color /** @@ -11,7 +11,7 @@ import bstrees.model.trees.redBlack.RBNode.Color * @generic the type of key stored in the tree. It must be comparable * @generic the type of value stored in the tree */ -class RBTree, V> : BTree>() { +class RBTree, V> : BSTree>() { /** * A balancer class providing balancing the tree when adding or deleting nodes */ diff --git a/lib/src/test/kotlin/avlTree/AVLTreeInvariants.kt b/lib/src/test/kotlin/avlTree/AVLTreeInvariants.kt index 32b0a43..6ef031d 100644 --- a/lib/src/test/kotlin/avlTree/AVLTreeInvariants.kt +++ b/lib/src/test/kotlin/avlTree/AVLTreeInvariants.kt @@ -1,11 +1,11 @@ package avlTree -import bstrees.model.trees.Node +import bstrees.model.trees.BSNode import bstrees.model.trees.avl.AvlNode import utils.TreesInvariants @Suppress("UNCHECKED_CAST") -class AVLTreeInvariants, V, NODE_TYPE : Node> : TreesInvariants() { +class AVLTreeInvariants, V, NODE_TYPE : BSNode> : TreesInvariants() { fun checkAvlTreeInvariants(root: AvlNode?): Boolean = root == null || checkAvlHeightInvariants(root) && checkNodeInvariants(root as NODE_TYPE) diff --git a/lib/src/test/kotlin/balancers/BalancerTest.kt b/lib/src/test/kotlin/balancers/BalancerTest.kt index 184bee3..6cd3e01 100644 --- a/lib/src/test/kotlin/balancers/BalancerTest.kt +++ b/lib/src/test/kotlin/balancers/BalancerTest.kt @@ -1,9 +1,9 @@ package balancers import bstrees.model.trees.Balancer -import bstrees.model.trees.Node -import bstrees.model.trees.binarySearch.BSBalancer -import bstrees.model.trees.binarySearch.BSNode +import bstrees.model.trees.BSNode +import bstrees.model.trees.randomBinarySearch.RandomBSBalancer +import bstrees.model.trees.randomBinarySearch.RandomBSNode import org.junit.jupiter.api.Test import utils.BSTreeUtil @@ -13,22 +13,22 @@ class BalancerTest { @Test fun `left rotate`() { - val balancer = BSBalancer() + val balancer = RandomBSBalancer() - val privateLeftRotateField = Balancer::class.java.getDeclaredMethod("leftRotate", Node::class.java) + val privateLeftRotateField = Balancer::class.java.getDeclaredMethod("leftRotate", BSNode::class.java) privateLeftRotateField.isAccessible = true - val newNode = privateLeftRotateField.invoke(balancer, BSTreeUtil.createBSTree().root) as BSNode + val newNode = privateLeftRotateField.invoke(balancer, BSTreeUtil.createBSTree().root) as RandomBSNode assert(BSTreeUtil.checkNodeEquals(newNode, BSTreeUtil.createLeftRotatedBSTree().root)) } @Test fun `right rotate`() { - val balancer = BSBalancer() + val balancer = RandomBSBalancer() - val privateRightRotateField = Balancer::class.java.getDeclaredMethod("rightRotate", Node::class.java) + val privateRightRotateField = Balancer::class.java.getDeclaredMethod("rightRotate", BSNode::class.java) privateRightRotateField.isAccessible = true - val newNode = privateRightRotateField.invoke(balancer, BSTreeUtil.createBSTree().root) as BSNode + val newNode = privateRightRotateField.invoke(balancer, BSTreeUtil.createBSTree().root) as RandomBSNode assert(BSTreeUtil.checkNodeEquals(newNode, BSTreeUtil.createRightRotatedBSTree().root)) } diff --git a/lib/src/test/kotlin/binarySearchTree/BSTreeInvariants.kt b/lib/src/test/kotlin/binarySearchTree/BSTreeInvariants.kt index 2c4d896..e06435c 100644 --- a/lib/src/test/kotlin/binarySearchTree/BSTreeInvariants.kt +++ b/lib/src/test/kotlin/binarySearchTree/BSTreeInvariants.kt @@ -1,18 +1,18 @@ package binarySearchTree -import bstrees.model.trees.Node -import bstrees.model.trees.binarySearch.BSNode +import bstrees.model.trees.BSNode +import bstrees.model.trees.randomBinarySearch.RandomBSNode import utils.TreesInvariants @Suppress("UNCHECKED_CAST") -class BSTreeInvariants, V, NODE_TYPE : Node> : TreesInvariants() { - private fun checkBSSizeInvariant(node: BSNode?): Boolean { +class BSTreeInvariants, V, NODE_TYPE : BSNode> : TreesInvariants() { + private fun checkBSSizeInvariant(node: RandomBSNode?): Boolean { return node == null || node.size == (node.leftNode?.size ?: 0) + (node.rightNode?.size ?: 0) + 1 && checkBSSizeInvariant(node.leftNode) && checkBSSizeInvariant(node.rightNode) } - fun checkBsTreeInvariants(root: BSNode?): Boolean { + fun checkBsTreeInvariants(root: RandomBSNode?): Boolean { return (root == null || checkNodeInvariants(root as NODE_TYPE)) && checkBSSizeInvariant(root) } } \ No newline at end of file diff --git a/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt b/lib/src/test/kotlin/binarySearchTree/RandomBSTreeTest.kt similarity index 95% rename from lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt rename to lib/src/test/kotlin/binarySearchTree/RandomBSTreeTest.kt index 0ff6033..b2b141f 100644 --- a/lib/src/test/kotlin/binarySearchTree/BSTreeTest.kt +++ b/lib/src/test/kotlin/binarySearchTree/RandomBSTreeTest.kt @@ -2,20 +2,20 @@ package binarySearchTree import org.junit.jupiter.api.* import org.junit.jupiter.params.ParameterizedTest -import bstrees.model.trees.binarySearch.BSNode -import bstrees.model.trees.binarySearch.BSTree +import bstrees.model.trees.randomBinarySearch.RandomBSNode +import bstrees.model.trees.randomBinarySearch.RandomBSTree import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.MethodSource import kotlin.random.Random @TestInstance(TestInstance.Lifecycle.PER_CLASS) -class BSTreeTest { +class RandomBSTreeTest { private lateinit var keyValue: List> private lateinit var bigKeyValue: List> - private val tree = BSTree() - private val treeChecker = BSTreeInvariants>() + private val tree = RandomBSTree() + private val treeChecker = BSTreeInvariants>() @BeforeAll fun prepareNodes() { @@ -30,7 +30,7 @@ class BSTreeTest { @Test fun `init null tree`() { - val tree = BSTree() + val tree = RandomBSTree() Assertions.assertNull(tree.root) { "After initialization, the tree must have NULL root" } } diff --git a/lib/src/test/kotlin/redBlackTree/RBTreeInvariants.kt b/lib/src/test/kotlin/redBlackTree/RBTreeInvariants.kt index 5510a36..b8f51c5 100644 --- a/lib/src/test/kotlin/redBlackTree/RBTreeInvariants.kt +++ b/lib/src/test/kotlin/redBlackTree/RBTreeInvariants.kt @@ -1,11 +1,11 @@ package redBlackTree -import bstrees.model.trees.Node +import bstrees.model.trees.BSNode import bstrees.model.trees.redBlack.RBNode import utils.TreesInvariants @Suppress("UNCHECKED_CAST") -class RBTreeInvariants, V, NODE_TYPE : Node> : TreesInvariants() { +class RBTreeInvariants, V, NODE_TYPE : BSNode> : TreesInvariants() { fun checkRBTreeInvariants(root: RBNode?): Boolean { return root == null || root.parent == null && checkNodeInvariants(root as NODE_TYPE) && root.color == RBNode.Color.BLACK && checkRBNodeBlackHeightInvariant(root, 0, getBlackHeightExample(root)) && diff --git a/lib/src/test/kotlin/utils/BSTreeUtil.kt b/lib/src/test/kotlin/utils/BSTreeUtil.kt index a741b1f..0db0a54 100644 --- a/lib/src/test/kotlin/utils/BSTreeUtil.kt +++ b/lib/src/test/kotlin/utils/BSTreeUtil.kt @@ -1,7 +1,7 @@ package utils -import bstrees.model.trees.binarySearch.BSNode -import bstrees.model.trees.binarySearch.BSTree +import bstrees.model.trees.randomBinarySearch.RandomBSNode +import bstrees.model.trees.randomBinarySearch.RandomBSTree /** @@ -9,7 +9,7 @@ import bstrees.model.trees.binarySearch.BSTree */ object BSTreeUtil { - fun checkNodeEquals(root1: BSNode<*, *>?, root2: BSNode<*, *>?): Boolean { + fun checkNodeEquals(root1: RandomBSNode<*, *>?, root2: RandomBSNode<*, *>?): Boolean { if (root1 == null || root2 == null) { return root1 == null && root2 == null } @@ -20,67 +20,67 @@ object BSTreeUtil { // This will be rewritten when the BSTree implementation is added - fun createBSTree(): BSTree { - val testBSTree: BSTree = BSTree() - testBSTree.root = BSNode(0, 0) - val testBSTreeRoot = testBSTree.root!! + fun createBSTree(): RandomBSTree { + val testRandomBSTree: RandomBSTree = RandomBSTree() + testRandomBSTree.root = RandomBSNode(0, 0) + val testBSTreeRoot = testRandomBSTree.root!! - val leftSubTestBSTree: BSTree = BSTree() - leftSubTestBSTree.root = BSNode(-2, 2) - val leftSubTestBSTreeRoot = leftSubTestBSTree.root!! - leftSubTestBSTreeRoot.leftNode = BSNode(-3, 5) - leftSubTestBSTreeRoot.rightNode = BSNode(-1, 6) + val leftSubTestRandomBSTree: RandomBSTree = RandomBSTree() + leftSubTestRandomBSTree.root = RandomBSNode(-2, 2) + val leftSubTestBSTreeRoot = leftSubTestRandomBSTree.root!! + leftSubTestBSTreeRoot.leftNode = RandomBSNode(-3, 5) + leftSubTestBSTreeRoot.rightNode = RandomBSNode(-1, 6) - val rightSubTestBSTree: BSTree = BSTree() - rightSubTestBSTree.root = BSNode(2, 3) - val rightSubTestBSTreeRoot = rightSubTestBSTree.root!! - rightSubTestBSTreeRoot.leftNode = BSNode(1, 7) - rightSubTestBSTreeRoot.rightNode = BSNode(3, 8) + val rightSubTestRandomBSTree: RandomBSTree = RandomBSTree() + rightSubTestRandomBSTree.root = RandomBSNode(2, 3) + val rightSubTestBSTreeRoot = rightSubTestRandomBSTree.root!! + rightSubTestBSTreeRoot.leftNode = RandomBSNode(1, 7) + rightSubTestBSTreeRoot.rightNode = RandomBSNode(3, 8) testBSTreeRoot.leftNode = leftSubTestBSTreeRoot testBSTreeRoot.rightNode = rightSubTestBSTreeRoot - return testBSTree + return testRandomBSTree } - fun createLeftRotatedBSTree(): BSTree { - val leftRotatedTestBSTree: BSTree = BSTree() - leftRotatedTestBSTree.root = BSNode(2, 3) - val leftRotatedTestBSTreeRoot = leftRotatedTestBSTree.root!! + fun createLeftRotatedBSTree(): RandomBSTree { + val leftRotatedTestRandomBSTree: RandomBSTree = RandomBSTree() + leftRotatedTestRandomBSTree.root = RandomBSNode(2, 3) + val leftRotatedTestBSTreeRoot = leftRotatedTestRandomBSTree.root!! - leftRotatedTestBSTreeRoot.rightNode = BSNode(3, 8) - leftRotatedTestBSTreeRoot.leftNode = BSNode(0, 0) + leftRotatedTestBSTreeRoot.rightNode = RandomBSNode(3, 8) + leftRotatedTestBSTreeRoot.leftNode = RandomBSNode(0, 0) - val leftRotatedSubTestBSTree: BSTree = BSTree() - leftRotatedSubTestBSTree.root = BSNode(-2, 2) - val leftRotatedSubTestBSTreeRoot = leftRotatedSubTestBSTree.root!! - leftRotatedSubTestBSTreeRoot.leftNode = BSNode(-3, 5) - leftRotatedSubTestBSTreeRoot.rightNode = BSNode(-1, 6) + val leftRotatedSubTestRandomBSTree: RandomBSTree = RandomBSTree() + leftRotatedSubTestRandomBSTree.root = RandomBSNode(-2, 2) + val leftRotatedSubTestBSTreeRoot = leftRotatedSubTestRandomBSTree.root!! + leftRotatedSubTestBSTreeRoot.leftNode = RandomBSNode(-3, 5) + leftRotatedSubTestBSTreeRoot.rightNode = RandomBSNode(-1, 6) - leftRotatedTestBSTreeRoot.leftNode?.rightNode = BSNode(1, 7) + leftRotatedTestBSTreeRoot.leftNode?.rightNode = RandomBSNode(1, 7) leftRotatedTestBSTreeRoot.leftNode?.leftNode = leftRotatedSubTestBSTreeRoot - return leftRotatedTestBSTree + return leftRotatedTestRandomBSTree } - fun createRightRotatedBSTree(): BSTree { - val rightRotatedTestBSTree: BSTree = BSTree() - rightRotatedTestBSTree.root = BSNode(-2, 2) - val rightRotatedTestBSTreeRoot = rightRotatedTestBSTree.root!! + fun createRightRotatedBSTree(): RandomBSTree { + val rightRotatedTestRandomBSTree: RandomBSTree = RandomBSTree() + rightRotatedTestRandomBSTree.root = RandomBSNode(-2, 2) + val rightRotatedTestBSTreeRoot = rightRotatedTestRandomBSTree.root!! - rightRotatedTestBSTreeRoot.leftNode = BSNode(-3, 5) - rightRotatedTestBSTreeRoot.rightNode = BSNode(0, 0) + rightRotatedTestBSTreeRoot.leftNode = RandomBSNode(-3, 5) + rightRotatedTestBSTreeRoot.rightNode = RandomBSNode(0, 0) - val rightRotatedSubTestBSTree: BSTree = BSTree() - rightRotatedSubTestBSTree.root = BSNode(2, 3) - val rightRotatedSubTestBSTreeRoot = rightRotatedSubTestBSTree.root!! - rightRotatedSubTestBSTreeRoot.leftNode = BSNode(1, 7) - rightRotatedSubTestBSTreeRoot.rightNode = BSNode(3, 8) + val rightRotatedSubTestRandomBSTree: RandomBSTree = RandomBSTree() + rightRotatedSubTestRandomBSTree.root = RandomBSNode(2, 3) + val rightRotatedSubTestBSTreeRoot = rightRotatedSubTestRandomBSTree.root!! + rightRotatedSubTestBSTreeRoot.leftNode = RandomBSNode(1, 7) + rightRotatedSubTestBSTreeRoot.rightNode = RandomBSNode(3, 8) - rightRotatedTestBSTreeRoot.rightNode?.leftNode = BSNode(-1, 6) + rightRotatedTestBSTreeRoot.rightNode?.leftNode = RandomBSNode(-1, 6) rightRotatedTestBSTreeRoot.rightNode?.rightNode = rightRotatedSubTestBSTreeRoot - return rightRotatedTestBSTree + return rightRotatedTestRandomBSTree } } \ No newline at end of file diff --git a/lib/src/test/kotlin/utils/TreesInvariants.kt b/lib/src/test/kotlin/utils/TreesInvariants.kt index 68a6f5b..457ff31 100644 --- a/lib/src/test/kotlin/utils/TreesInvariants.kt +++ b/lib/src/test/kotlin/utils/TreesInvariants.kt @@ -1,8 +1,8 @@ package utils -import bstrees.model.trees.Node +import bstrees.model.trees.BSNode -open class TreesInvariants, V, NODE_TYPE : Node> { +open class TreesInvariants, V, NODE_TYPE : BSNode> { protected fun checkNodeInvariants(node: NODE_TYPE): Boolean { return (node.leftNode == null || node.leftNode!!.parent == node && node.leftNode!!.key < node.key && checkNodeInvariants(node.leftNode!!)) && From 3d5fa3af09087a2d668716524412175c350510cc Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 2 May 2023 15:27:44 +0300 Subject: [PATCH 114/135] feat: Added tests for the database and converters --- lib/build.gradle.kts | 5 +- .../treesConverters/AvlToDataConverter.kt | 4 +- .../RandomBsToDataConverter.kt | 4 +- .../treesConverters/RbToDataConverter.kt | 4 +- .../model/dataBases/reps/JsonTreeRepo.kt | 14 +- lib/src/test/kotlin/balancers/BalancerTest.kt | 41 ++-- .../converters/TreeToDataConverterTest.kt | 79 +++++++ .../test/kotlin/dataBases/JsonTreeRepoTest.kt | 111 +++++++++ .../test/kotlin/dataBases/SQLTreeRepoTest.kt | 109 +++++++++ lib/src/test/kotlin/utils/BSTreeUtil.kt | 218 ++++++++++++++---- lib/src/test/kotlin/utils/TreeDataUtil.kt | 90 ++++++++ 11 files changed, 599 insertions(+), 80 deletions(-) create mode 100644 lib/src/test/kotlin/converters/TreeToDataConverterTest.kt create mode 100644 lib/src/test/kotlin/dataBases/JsonTreeRepoTest.kt create mode 100644 lib/src/test/kotlin/dataBases/SQLTreeRepoTest.kt create mode 100644 lib/src/test/kotlin/utils/TreeDataUtil.kt diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 7d53e66..423e737 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -50,7 +50,10 @@ tasks.jacocoTestReport { classDirectories.setFrom( files(classDirectories.files.map { fileTree(it) { - include("**/model/trees/**") + include("**/model/**") + exclude("**/**/*Neo4jTreeRepo*.*") + exclude("**/**/*TreeData*.*") + exclude("**/**/*NodeData*.*") } }) ) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/AvlToDataConverter.kt b/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/AvlToDataConverter.kt index e29960d..cb576dd 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/AvlToDataConverter.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/AvlToDataConverter.kt @@ -33,8 +33,8 @@ class AvlToDataConverter, V>( val avlnode: AvlNode = AvlNode(keyStringConverter.fromString(node.key), valueStringConverter.fromString(node.value)) if (node.metadata[0] != 'H') throw Exception("Wrong metadata. Impossible to deserialize") avlnode.height = deserializeMetadata(node.metadata) - node.leftNode?.let { deserializeNode(it) } - node.rightNode?.let { deserializeNode(it) } + avlnode.leftNode = node.leftNode?.let { deserializeNode(it) } + avlnode.rightNode = node.rightNode?.let { deserializeNode(it) } linkParents(avlnode) return avlnode } diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RandomBsToDataConverter.kt b/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RandomBsToDataConverter.kt index a157ac0..663e350 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RandomBsToDataConverter.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RandomBsToDataConverter.kt @@ -34,8 +34,8 @@ class RandomBsToDataConverter, V>( val bsnode: RandomBSNode = RandomBSNode(keyStringConverter.fromString(node.key), valueStringConverter.fromString(node.value)) if (node.metadata[0] != 'S') throw Exception("Wrong metadata. Impossible to deserialize") bsnode.size = deserializeMetadata(node.metadata) - node.leftNode?.let { deserializeNode(it) } - node.rightNode?.let { deserializeNode(it) } + bsnode.leftNode = node.leftNode?.let { deserializeNode(it) } + bsnode.rightNode = node.rightNode?.let { deserializeNode(it) } linkParents(bsnode) return bsnode } diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RbToDataConverter.kt b/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RbToDataConverter.kt index f0e2e41..089bb8e 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RbToDataConverter.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/converters/treesConverters/RbToDataConverter.kt @@ -34,8 +34,8 @@ class RbToDataConverter, V>( val rbnode: RBNode = RBNode(keyStringConverter.fromString(node.key), valueStringConverter.fromString(node.value)) if (node.metadata != "RED" && node.metadata != "BLACK") throw Exception("Wrong metadata. Impossible to deserialize") rbnode.color = deserializeMetadata(node.metadata) - node.leftNode?.let { deserializeNode(it) } - node.rightNode?.let { deserializeNode(it) } + rbnode.leftNode = node.leftNode?.let { deserializeNode(it) } + rbnode.rightNode = node.rightNode?.let { deserializeNode(it) } linkParents(rbnode) return rbnode } diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt index 2585431..21e4869 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/JsonTreeRepo.kt @@ -7,7 +7,6 @@ import kotlinx.serialization.encodeToString import mu.KotlinLogging import java.io.* import kotlin.io.path.Path -import java.nio.file.FileAlreadyExistsException private val logger = KotlinLogging.logger { } @@ -58,25 +57,16 @@ class JsonTreeRepo(private val dir: String) : TreeRepo { override fun setTree(treeData: TreeData) { val filePath = getPathToFile(treeData.name, treeData.treeType) lateinit var file: FileWriter - var fileAlreadyExists = false try { - if (File(filePath).exists()) { - fileAlreadyExists = true - throw FileAlreadyExistsException("") - } file = FileWriter(filePath) file.write(Json.encodeToString(treeData)) - } catch (e: FileAlreadyExistsException) { - logger.warn { "[JSON] A tree with that name already exists" } } catch (e: Exception) { logger.error { "[JSON] Error getting the tree: $e" } throw e } finally { - if (!fileAlreadyExists) { - file.flush() - file.close() - } + file.flush() + file.close() } logger.info { "[JSON] Set tree - treeName: ${treeData.name}, treeType: ${treeData.treeType}" } } diff --git a/lib/src/test/kotlin/balancers/BalancerTest.kt b/lib/src/test/kotlin/balancers/BalancerTest.kt index 6cd3e01..f8571ac 100644 --- a/lib/src/test/kotlin/balancers/BalancerTest.kt +++ b/lib/src/test/kotlin/balancers/BalancerTest.kt @@ -1,9 +1,10 @@ package balancers -import bstrees.model.trees.Balancer -import bstrees.model.trees.BSNode +import bstrees.model.dataBases.converters.utils.ComparableStringConverter +import bstrees.model.dataBases.converters.utils.StringConverter +import bstrees.model.dataBases.converters.utils.createStringConverter import bstrees.model.trees.randomBinarySearch.RandomBSBalancer -import bstrees.model.trees.randomBinarySearch.RandomBSNode +import bstrees.model.trees.randomBinarySearch.RandomBSTree import org.junit.jupiter.api.Test import utils.BSTreeUtil @@ -13,23 +14,37 @@ class BalancerTest { @Test fun `left rotate`() { - val balancer = RandomBSBalancer() + fun , V> helper(keyStringConverter: ComparableStringConverter, valueStringConverter: StringConverter) { + val balancer = RandomBSBalancer() - val privateLeftRotateField = Balancer::class.java.getDeclaredMethod("leftRotate", BSNode::class.java) - privateLeftRotateField.isAccessible = true - val newNode = privateLeftRotateField.invoke(balancer, BSTreeUtil.createBSTree().root) as RandomBSNode + val tree: RandomBSTree = BSTreeUtil.createTree(keyStringConverter, valueStringConverter, "BS") + val newNode = balancer.bsLeftRotate(tree.root!!) - assert(BSTreeUtil.checkNodeEquals(newNode, BSTreeUtil.createLeftRotatedBSTree().root)) + val leftRotatedTree: RandomBSTree = BSTreeUtil.createLeftRotatedTree(keyStringConverter, valueStringConverter, "BS") + + assert(BSTreeUtil.checkNodeEquals(newNode, leftRotatedTree.root)) + } + helper( + keyStringConverter = createStringConverter("Int"), + valueStringConverter = createStringConverter("Int"), + ) } @Test fun `right rotate`() { - val balancer = RandomBSBalancer() + fun , V> helper(keyStringConverter: ComparableStringConverter, valueStringConverter: StringConverter) { + val balancer = RandomBSBalancer() + + val tree: RandomBSTree = BSTreeUtil.createTree(keyStringConverter, valueStringConverter, "BS") + val newNode = balancer.bsRightRotate(tree.root!!) - val privateRightRotateField = Balancer::class.java.getDeclaredMethod("rightRotate", BSNode::class.java) - privateRightRotateField.isAccessible = true - val newNode = privateRightRotateField.invoke(balancer, BSTreeUtil.createBSTree().root) as RandomBSNode + val rightRotatedTree: RandomBSTree = BSTreeUtil.createRightRotatedTree(keyStringConverter, valueStringConverter, "BS") - assert(BSTreeUtil.checkNodeEquals(newNode, BSTreeUtil.createRightRotatedBSTree().root)) + assert(BSTreeUtil.checkNodeEquals(newNode, rightRotatedTree.root)) + } + helper( + keyStringConverter = createStringConverter("Int"), + valueStringConverter = createStringConverter("Int"), + ) } } \ No newline at end of file diff --git a/lib/src/test/kotlin/converters/TreeToDataConverterTest.kt b/lib/src/test/kotlin/converters/TreeToDataConverterTest.kt new file mode 100644 index 0000000..97f689e --- /dev/null +++ b/lib/src/test/kotlin/converters/TreeToDataConverterTest.kt @@ -0,0 +1,79 @@ +package converters + +import bstrees.model.dataBases.converters.TreeToDataConverter +import bstrees.model.dataBases.converters.treesConverters.AvlToDataConverter +import bstrees.model.dataBases.converters.treesConverters.RandomBsToDataConverter +import bstrees.model.dataBases.converters.treesConverters.RbToDataConverter +import bstrees.model.dataBases.converters.utils.createStringConverter +import bstrees.model.trees.BSNode +import bstrees.model.trees.BSTree +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource +import utils.BSTreeUtil +import java.util.stream.Stream + + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class TreeToDataConverterTest { + + @ParameterizedTest(name = "serialize deserialize ({0}, {1}) {2}tree") + @MethodSource("keyValueTypeProvider") + fun `serialize deserialize ({0}, {1}) tree`(keyType: String, valueType: String, treeType: String){ + fun , V, NODE_TYPE: BSNode, TREE_TYPE : BSTree> helper(strategy: TreeToDataConverter) { + val tree: TREE_TYPE = BSTreeUtil.createTree(strategy.keyStringConverter, strategy.valueStringConverter, treeType) + + val dataTree = strategy.serializeTree(tree, "") + + val resultTree = strategy.deserializeTree(dataTree) + + Assertions.assertTrue(BSTreeUtil.checkNodeEquals(tree.root, resultTree.root), "Serialize deserialize (${keyType}, ${valueType}) ${treeType}tree test error") + } + helper(createStrategy(treeType, keyType, valueType)) + } + + + companion object { + @JvmStatic + fun keyValueTypeProvider(): Stream { + return Stream.of( + Arguments.of("String", "String", "BS"), + Arguments.of("String", "Int", "BS"), + Arguments.of("Int", "String", "BS"), + Arguments.of("String", "String", "BS"), + Arguments.of("String", "String", "AVL"), + Arguments.of("String", "Int", "AVL"), + Arguments.of("Int", "String", "AVL"), + Arguments.of("String", "String", "AVL"), + Arguments.of("String", "String", "RB"), + Arguments.of("String", "Int", "RB"), + Arguments.of("Int", "String", "RB"), + Arguments.of("String", "String", "RB") + ) + } + } + + private fun createStrategy(treeType: String, keyType: String, valueType: String): TreeToDataConverter<*, *, *, *, *> = when (treeType) { + "AVL" -> AvlToDataConverter( + keyStringConverter = createStringConverter(keyType), + valueStringConverter = createStringConverter(valueType), + keyType = keyType, + valueType = valueType + ) + "RB" -> RbToDataConverter( + keyStringConverter = createStringConverter(keyType), + valueStringConverter = createStringConverter(valueType), + keyType = keyType, + valueType = valueType + ) + "BS" -> RandomBsToDataConverter( + keyStringConverter = createStringConverter(keyType), + valueStringConverter = createStringConverter(valueType), + keyType = keyType, + valueType = valueType + ) + else -> throw IllegalArgumentException("Unknown tree type $treeType") + } +} \ No newline at end of file diff --git a/lib/src/test/kotlin/dataBases/JsonTreeRepoTest.kt b/lib/src/test/kotlin/dataBases/JsonTreeRepoTest.kt new file mode 100644 index 0000000..d65bf65 --- /dev/null +++ b/lib/src/test/kotlin/dataBases/JsonTreeRepoTest.kt @@ -0,0 +1,111 @@ +package dataBases + + +import bstrees.model.dataBases.reps.JsonTreeRepo +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import utils.TreeDataUtil +import java.nio.file.Files +import kotlin.io.path.Path + +const val DIR = "JsonTreeRepo" + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class JsonTreeRepoTest { + + private val repo = JsonTreeRepo(DIR) + + @Test + fun `setting and getting unique tree`(){ + val dataTree = TreeDataUtil.getTreeData("first", "BS") + repo.setTree(dataTree) + + val resultDataTree = repo.getTree("first", "BS") + + Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree, resultDataTree), "error setting unique tree") + } + + @Test + fun `setting and getting trees with the same names and types`(){ + val dataTree1 = TreeDataUtil.getTreeData("name", "RB") + val dataTree2 = TreeDataUtil.getTreeData("name", "RB") + + repo.setTree(dataTree1) + val resultDataTree1 = repo.getTree("name", "RB") + + repo.setTree(dataTree2) + val resultDataTree2 = repo.getTree("name", "RB") + + Assertions.assertAll("Error setting trees with the same name", + { Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree1, resultDataTree1)) }, + { Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree2, resultDataTree2)) } + ) + } + + @Test + fun `setting and getting trees with the same names but different types`(){ + val dataTree1 = TreeDataUtil.getTreeData("name2", "BS") + val dataTree2 = TreeDataUtil.getTreeData("name2", "RB") + + repo.setTree(dataTree1) + repo.setTree(dataTree2) + + val resultDataTree1 = repo.getTree("name2", "BS") + val resultDataTree2 = repo.getTree("name2", "RB") + + Assertions.assertAll("Error setting trees with the same name but different types", + { Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree1, resultDataTree1)) }, + { Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree2, resultDataTree2)) } + ) + } + + @Test + fun `setting and getting trees with different names but the same types`(){ + val dataTree1 = TreeDataUtil.getTreeData("name3", "AVL") + val dataTree2 = TreeDataUtil.getTreeData("name4", "AVL") + + repo.setTree(dataTree1) + repo.setTree(dataTree2) + + val resultDataTree1 = repo.getTree("name3", "AVL") + val resultDataTree2 = repo.getTree("name4", "AVL") + + Assertions.assertAll("Error setting trees with different names but the same types", + { Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree1, resultDataTree1)) }, + { Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree2, resultDataTree2)) } + ) + } + + @Test + fun `getting non-existent tree`(){ + val resultDataTree = repo.getTree("name5", "RB") + + Assertions.assertNull(resultDataTree, "error getting non-existent tree") + } + + @Test + fun `deleting tree`(){ + val dataTree1 = TreeDataUtil.getTreeData("name6", "RB") + + repo.setTree(dataTree1) + val resultDataTree1 = repo.getTree("name6", "RB") + + repo.deleteTree("name6", "RB") + val resultDataTree2 = repo.getTree("name6", "RB") + + Assertions.assertAll("Error deleting tree", + { Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree1, resultDataTree1)) }, + { Assertions.assertNull(resultDataTree2) } + ) + } + + @AfterAll + fun `delete dir`(){ + Files.walk(Path(DIR)) + .sorted(Comparator.reverseOrder()) + .map { it.toFile() } + .forEach { it.delete() } + } +} \ No newline at end of file diff --git a/lib/src/test/kotlin/dataBases/SQLTreeRepoTest.kt b/lib/src/test/kotlin/dataBases/SQLTreeRepoTest.kt new file mode 100644 index 0000000..920c179 --- /dev/null +++ b/lib/src/test/kotlin/dataBases/SQLTreeRepoTest.kt @@ -0,0 +1,109 @@ +package dataBases + +import bstrees.model.dataBases.reps.SQLTreeRepo +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import utils.TreeDataUtil +import java.nio.file.Files +import kotlin.io.path.Path + +const val DB_NAME = "SQLTreeRepo" + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class SQLTreeRepoTest { + private val repo = SQLTreeRepo(DB_NAME) + + @Test + fun `setting and getting unique tree`(){ + val dataTree = TreeDataUtil.getTreeData("first", "BS") + repo.setTree(dataTree) + + val resultDataTree = repo.getTree("first", "BS") + + Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree, resultDataTree), "error setting unique tree") + } + + @Test + fun `setting and getting trees with the same names and types`(){ + val dataTree1 = TreeDataUtil.getTreeData("name", "RB") + val dataTree2 = TreeDataUtil.getTreeData("name", "RB") + + repo.setTree(dataTree1) + val resultDataTree1 = repo.getTree("name", "RB") + + repo.setTree(dataTree2) + val resultDataTree2 = repo.getTree("name", "RB") + + Assertions.assertAll("Error setting trees with the same name", + { Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree1, resultDataTree1)) }, + { Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree2, resultDataTree2)) } + ) + } + + @Test + fun `setting and getting trees with the same names but different types`(){ + val dataTree1 = TreeDataUtil.getTreeData("name2", "BS") + val dataTree2 = TreeDataUtil.getTreeData("name2", "RB") + + repo.setTree(dataTree1) + repo.setTree(dataTree2) + + val resultDataTree1 = repo.getTree("name2", "BS") + val resultDataTree2 = repo.getTree("name2", "RB") + + Assertions.assertAll("Error setting trees with the same name but different types", + { Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree1, resultDataTree1)) }, + { Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree2, resultDataTree2)) } + ) + } + + @Test + fun `setting and getting trees with different names but the same types`(){ + val dataTree1 = TreeDataUtil.getTreeData("name3", "AVL") + val dataTree2 = TreeDataUtil.getTreeData("name4", "AVL") + + repo.setTree(dataTree1) + repo.setTree(dataTree2) + + val resultDataTree1 = repo.getTree("name3", "AVL") + val resultDataTree2 = repo.getTree("name4", "AVL") + + Assertions.assertAll("Error setting trees with different names but the same types", + { Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree1, resultDataTree1)) }, + { Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree2, resultDataTree2)) } + ) + } + + @Test + fun `getting non-existent tree`(){ + val resultDataTree = repo.getTree("name5", "RB") + + Assertions.assertNull(resultDataTree, "error getting non-existent tree") + } + + @Test + fun `deleting tree`(){ + val dataTree1 = TreeDataUtil.getTreeData("name6", "RB") + + repo.setTree(dataTree1) + val resultDataTree1 = repo.getTree("name6", "RB") + + repo.deleteTree("name6", "RB") + val resultDataTree2 = repo.getTree("name6", "RB") + + Assertions.assertAll("Error deleting tree", + { Assertions.assertTrue(TreeDataUtil.isEqualsTrees(dataTree1, resultDataTree1)) }, + { Assertions.assertNull(resultDataTree2) } + ) + } + + @AfterAll + fun `delete DB`(){ + Files.walk(Path(DB_NAME)) + .sorted(Comparator.reverseOrder()) + .map { it.toFile() } + .forEach { it.delete() } + } +} \ No newline at end of file diff --git a/lib/src/test/kotlin/utils/BSTreeUtil.kt b/lib/src/test/kotlin/utils/BSTreeUtil.kt index 0db0a54..bff7834 100644 --- a/lib/src/test/kotlin/utils/BSTreeUtil.kt +++ b/lib/src/test/kotlin/utils/BSTreeUtil.kt @@ -1,15 +1,26 @@ package utils +import bstrees.model.dataBases.converters.utils.ComparableStringConverter +import bstrees.model.dataBases.converters.utils.StringConverter +import bstrees.model.trees.BSNode +import bstrees.model.trees.BSTree +import bstrees.model.trees.avl.AvlNode +import bstrees.model.trees.avl.AvlTree import bstrees.model.trees.randomBinarySearch.RandomBSNode import bstrees.model.trees.randomBinarySearch.RandomBSTree - +import bstrees.model.trees.redBlack.RBNode +import bstrees.model.trees.redBlack.RBTree /** * BSTreeUtil performs the BSTree handler function for test classes */ +@Suppress("UNCHECKED_CAST") object BSTreeUtil { - fun checkNodeEquals(root1: RandomBSNode<*, *>?, root2: RandomBSNode<*, *>?): Boolean { + fun , V, NODE_TYPE : BSNode> checkNodeEquals( + root1: NODE_TYPE?, + root2: NODE_TYPE? + ): Boolean { if (root1 == null || root2 == null) { return root1 == null && root2 == null } @@ -18,67 +29,178 @@ object BSTreeUtil { checkNodeEquals(root1.rightNode, root2.rightNode) } + private fun , V, TREE_TYPE : BSTree> getTreeInstance(treeType: String): TREE_TYPE { + return when (treeType) { + "AVL" -> AvlTree() as TREE_TYPE + "RB" -> RBTree() as TREE_TYPE + "BS" -> RandomBSTree() as TREE_TYPE + else -> throw IllegalArgumentException("Unknown tree type $treeType") + } + } - // This will be rewritten when the BSTree implementation is added - fun createBSTree(): RandomBSTree { - val testRandomBSTree: RandomBSTree = RandomBSTree() - testRandomBSTree.root = RandomBSNode(0, 0) - val testBSTreeRoot = testRandomBSTree.root!! - - val leftSubTestRandomBSTree: RandomBSTree = RandomBSTree() - leftSubTestRandomBSTree.root = RandomBSNode(-2, 2) - val leftSubTestBSTreeRoot = leftSubTestRandomBSTree.root!! - leftSubTestBSTreeRoot.leftNode = RandomBSNode(-3, 5) - leftSubTestBSTreeRoot.rightNode = RandomBSNode(-1, 6) - - val rightSubTestRandomBSTree: RandomBSTree = RandomBSTree() - rightSubTestRandomBSTree.root = RandomBSNode(2, 3) - val rightSubTestBSTreeRoot = rightSubTestRandomBSTree.root!! - rightSubTestBSTreeRoot.leftNode = RandomBSNode(1, 7) - rightSubTestBSTreeRoot.rightNode = RandomBSNode(3, 8) - - - testBSTreeRoot.leftNode = leftSubTestBSTreeRoot - testBSTreeRoot.rightNode = rightSubTestBSTreeRoot + private fun , V, NODE_TYPE> getNodeInstance(treeType: String, key: K, value: V): NODE_TYPE { + return when (treeType) { + "AVL" -> AvlNode(key, value) as NODE_TYPE + "RB" -> RBNode(key, value) as NODE_TYPE + "BS" -> RandomBSNode(key, value) as NODE_TYPE + else -> throw IllegalArgumentException("Unknown tree type $treeType") + } + } - return testRandomBSTree + fun , V, NODE_TYPE : BSNode, TREE_TYPE : BSTree> createTree( + keyStringConverter: ComparableStringConverter, + valueStringConverter: StringConverter, + treeType: String + ): TREE_TYPE { + val tree: TREE_TYPE = getTreeInstance(treeType) + tree.root = getNodeInstance( + treeType, + keyStringConverter.fromString("0"), + valueStringConverter.fromString("0") + ) + val testRBTreeRoot = tree.root!! + + val leftSubTestRBTree: TREE_TYPE = getTreeInstance(treeType) + leftSubTestRBTree.root = getNodeInstance( + treeType, + keyStringConverter.fromString("-2"), + valueStringConverter.fromString("2") + ) + val leftSubTestRBTreeRoot = leftSubTestRBTree.root!! + leftSubTestRBTreeRoot.leftNode = getNodeInstance( + treeType, + keyStringConverter.fromString("-3"), + valueStringConverter.fromString("5") + ) + leftSubTestRBTreeRoot.rightNode = getNodeInstance( + treeType, + keyStringConverter.fromString("-1"), + valueStringConverter.fromString("6") + ) + + val rightSubTestRBTree: TREE_TYPE = getTreeInstance(treeType) + rightSubTestRBTree.root = getNodeInstance( + treeType, + keyStringConverter.fromString("2"), + valueStringConverter.fromString("3") + ) + val rightSubTestRBTreeRoot = rightSubTestRBTree.root!! + rightSubTestRBTreeRoot.leftNode = getNodeInstance( + treeType, + keyStringConverter.fromString("1"), + valueStringConverter.fromString("7") + ) + rightSubTestRBTreeRoot.rightNode = getNodeInstance( + treeType, + keyStringConverter.fromString("3"), + valueStringConverter.fromString("8") + ) + + testRBTreeRoot.leftNode = leftSubTestRBTreeRoot + testRBTreeRoot.rightNode = rightSubTestRBTreeRoot + + return tree } - fun createLeftRotatedBSTree(): RandomBSTree { - val leftRotatedTestRandomBSTree: RandomBSTree = RandomBSTree() - leftRotatedTestRandomBSTree.root = RandomBSNode(2, 3) + fun , V, NODE_TYPE : BSNode, TREE_TYPE : BSTree> createLeftRotatedTree( + keyStringConverter: ComparableStringConverter, + valueStringConverter: StringConverter, + treeType: String + ): TREE_TYPE { + val leftRotatedTestRandomBSTree: TREE_TYPE = getTreeInstance(treeType) + leftRotatedTestRandomBSTree.root = getNodeInstance( + treeType, + keyStringConverter.fromString("2"), + valueStringConverter.fromString("3") + ) val leftRotatedTestBSTreeRoot = leftRotatedTestRandomBSTree.root!! - leftRotatedTestBSTreeRoot.rightNode = RandomBSNode(3, 8) - leftRotatedTestBSTreeRoot.leftNode = RandomBSNode(0, 0) - - val leftRotatedSubTestRandomBSTree: RandomBSTree = RandomBSTree() - leftRotatedSubTestRandomBSTree.root = RandomBSNode(-2, 2) + leftRotatedTestBSTreeRoot.rightNode = getNodeInstance( + treeType, + keyStringConverter.fromString("3"), + valueStringConverter.fromString("8") + ) + leftRotatedTestBSTreeRoot.leftNode = getNodeInstance( + treeType, + keyStringConverter.fromString("0"), + valueStringConverter.fromString("0") + ) + + val leftRotatedSubTestRandomBSTree: TREE_TYPE = getTreeInstance(treeType) + leftRotatedSubTestRandomBSTree.root = getNodeInstance( + treeType, + keyStringConverter.fromString("-2"), + valueStringConverter.fromString("2") + ) val leftRotatedSubTestBSTreeRoot = leftRotatedSubTestRandomBSTree.root!! - leftRotatedSubTestBSTreeRoot.leftNode = RandomBSNode(-3, 5) - leftRotatedSubTestBSTreeRoot.rightNode = RandomBSNode(-1, 6) - - leftRotatedTestBSTreeRoot.leftNode?.rightNode = RandomBSNode(1, 7) + leftRotatedSubTestBSTreeRoot.leftNode = getNodeInstance( + treeType, + keyStringConverter.fromString("-3"), + valueStringConverter.fromString("5") + ) + leftRotatedSubTestBSTreeRoot.rightNode = getNodeInstance( + treeType, + keyStringConverter.fromString("-1"), + valueStringConverter.fromString("6") + ) + + leftRotatedTestBSTreeRoot.leftNode?.rightNode = getNodeInstance( + treeType, + keyStringConverter.fromString("1"), + valueStringConverter.fromString("7") + ) leftRotatedTestBSTreeRoot.leftNode?.leftNode = leftRotatedSubTestBSTreeRoot return leftRotatedTestRandomBSTree } - fun createRightRotatedBSTree(): RandomBSTree { - val rightRotatedTestRandomBSTree: RandomBSTree = RandomBSTree() - rightRotatedTestRandomBSTree.root = RandomBSNode(-2, 2) + fun , V, NODE_TYPE : BSNode, TREE_TYPE : BSTree> createRightRotatedTree( + keyStringConverter: ComparableStringConverter, + valueStringConverter: StringConverter, + treeType: String + ): TREE_TYPE { + val rightRotatedTestRandomBSTree: TREE_TYPE = getTreeInstance(treeType) + rightRotatedTestRandomBSTree.root = getNodeInstance( + treeType, + keyStringConverter.fromString("-2"), + valueStringConverter.fromString("2") + ) val rightRotatedTestBSTreeRoot = rightRotatedTestRandomBSTree.root!! - rightRotatedTestBSTreeRoot.leftNode = RandomBSNode(-3, 5) - rightRotatedTestBSTreeRoot.rightNode = RandomBSNode(0, 0) - - val rightRotatedSubTestRandomBSTree: RandomBSTree = RandomBSTree() - rightRotatedSubTestRandomBSTree.root = RandomBSNode(2, 3) + rightRotatedTestBSTreeRoot.leftNode = getNodeInstance( + treeType, + keyStringConverter.fromString("-3"), + valueStringConverter.fromString("5") + ) + rightRotatedTestBSTreeRoot.rightNode = getNodeInstance( + treeType, + keyStringConverter.fromString("0"), + valueStringConverter.fromString("0") + ) + + val rightRotatedSubTestRandomBSTree: TREE_TYPE = getTreeInstance(treeType) + rightRotatedSubTestRandomBSTree.root = getNodeInstance( + treeType, + keyStringConverter.fromString("2"), + valueStringConverter.fromString("3") + ) val rightRotatedSubTestBSTreeRoot = rightRotatedSubTestRandomBSTree.root!! - rightRotatedSubTestBSTreeRoot.leftNode = RandomBSNode(1, 7) - rightRotatedSubTestBSTreeRoot.rightNode = RandomBSNode(3, 8) - - rightRotatedTestBSTreeRoot.rightNode?.leftNode = RandomBSNode(-1, 6) + rightRotatedSubTestBSTreeRoot.leftNode = getNodeInstance( + treeType, + keyStringConverter.fromString("1"), + valueStringConverter.fromString("7") + ) + rightRotatedSubTestBSTreeRoot.rightNode = getNodeInstance( + treeType, + keyStringConverter.fromString("3"), + valueStringConverter.fromString("8") + ) + + rightRotatedTestBSTreeRoot.rightNode?.leftNode = getNodeInstance( + treeType, + keyStringConverter.fromString("-1"), + valueStringConverter.fromString("6") + ) rightRotatedTestBSTreeRoot.rightNode?.rightNode = rightRotatedSubTestBSTreeRoot return rightRotatedTestRandomBSTree diff --git a/lib/src/test/kotlin/utils/TreeDataUtil.kt b/lib/src/test/kotlin/utils/TreeDataUtil.kt new file mode 100644 index 0000000..392fdf9 --- /dev/null +++ b/lib/src/test/kotlin/utils/TreeDataUtil.kt @@ -0,0 +1,90 @@ +package utils + +import bstrees.model.dataBases.NodeData +import bstrees.model.dataBases.TreeData + +object TreeDataUtil { + fun getTreeData(name: String, treeType: String): TreeData { + return TreeData( + name = name, + treeType = treeType, + keyType = "", + valueType = "", + NodeData( + "1", + "", + "", + 0, + 0, + NodeData( + "2", + "", + "", + 0, + 0, + NodeData( + "3", + "", + "", + 0, + 0, + null, + null + ), + NodeData( + "4", + "", + "", + 0, + 0, + null, + null + ) + ), + NodeData( + "5", + "", + "", + 0, + 0, + NodeData( + "6", + "", + "", + 0, + 0, + null, + null + ), + NodeData( + "7", + "", + "", + 0, + 0, + null, + null + ) + ) + ) + ) + } + + fun isEqualsTrees(tree1: TreeData?, tree2: TreeData?): Boolean{ + if(tree1 == null && tree2 == null)return true + if(tree1 == null || tree2 == null)return false + return tree1.name == tree2.name && tree1.treeType == tree2.treeType && + tree1.keyType == tree2.keyType && tree1.valueType == tree2.valueType && + isEqualsNodes(tree1.root, tree2.root) + } + + private fun isEqualsNodes(node1: NodeData?, node2: NodeData?): Boolean{ + if(node1 == null && node2 == null)return true + if(node1 == null || node2 == null)return false + return node1.key == node2.key && node1.value == node2.value && + node1.metadata == node2.metadata && + node1.posX == node2.posX && node1.posY == node2.posY && + isEqualsNodes(node1.leftNode, node2.leftNode) && + isEqualsNodes(node1.rightNode, node2.rightNode) + } +} \ No newline at end of file From ccb6e38e2c210f0d3f4a21751f7b50ac778d7ce9 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 2 May 2023 17:40:10 +0300 Subject: [PATCH 115/135] fix: Small changes in the code before starting work on tree output --- app/src/main/kotlin/app/view/App.kt | 60 +++++++++++-------- .../app/view/assets/DatabaseConnections.kt | 4 ++ .../app/view/screens/ChosingTypesScreen.kt | 13 +++- .../kotlin/app/view/screens/ScreenManager.kt | 3 + .../kotlin/app/view/screens/TreeScreen.kt | 2 - 5 files changed, 55 insertions(+), 27 deletions(-) diff --git a/app/src/main/kotlin/app/view/App.kt b/app/src/main/kotlin/app/view/App.kt index 7aef1eb..c923f22 100644 --- a/app/src/main/kotlin/app/view/App.kt +++ b/app/src/main/kotlin/app/view/App.kt @@ -51,14 +51,14 @@ fun main() { remember { mutableStateOf("Choose the key type from the following options") } val valueType = remember { mutableStateOf("Choose the value type from the following options") } - var treePresenter: TreePresenter + var treePresenter: TreePresenter? = null ChildStack( source = navigation, initialStack = { listOf(ScreenManager.HomeScreen) }, handleBackButton = true, animation = stackAnimation(fade() + scale()), - ) { screen -> + ) { screen -> when (screen) { is ScreenManager.HomeScreen -> { @@ -89,44 +89,56 @@ fun main() { is ScreenManager.TreeScreen -> { - when (header.value) { + treePresenter = when (header.value) { - "Neo4j" -> treePresenter = DataBasePresenter.connectNeo4j( + "Neo4j" -> DataBasePresenter.connectNeo4j( databaseMetadata.value, username.value, password.value ) - "Json" -> treePresenter = DataBasePresenter.connectJson(databaseMetadata.value) + "Json" -> DataBasePresenter.connectJson(databaseMetadata.value) - "SQLite" -> treePresenter = DataBasePresenter.connectSQL(databaseMetadata.value) + "SQLite" -> DataBasePresenter.connectSQL(databaseMetadata.value) else -> throw Exception("Incorrect database") } - TreeSreen( - treeType, - { newHeader -> treeType.value = newHeader }, - treePresenter, - treeName = treeName, - { newName -> treeName.value = newName }, - back = navigation::pop, - { navigation.push(ScreenManager.ChosingTypesScreen) }, - keyType, - valueType - ) + treePresenter?.let { treePresenter -> + TreeSreen( + treeType, + { newHeader -> treeType.value = newHeader }, + treePresenter, + treeName = treeName, + { newName -> treeName.value = newName }, + back = navigation::pop, + { navigation.push(ScreenManager.ChosingTypesScreen) }, + keyType, + valueType + ) + } } is ScreenManager.ChosingTypesScreen -> { - ChosingTypesScreen( - keyType, - valueType, - { newKeyType -> keyType.value = newKeyType }, - { newValueType -> valueType.value = newValueType }, - approve = navigation::pop - ) + treePresenter?.let { treePresenter -> + ChosingTypesScreen( + treePresenter, + treeName, + treeType, + keyType, + valueType, + { newKeyType -> keyType.value = newKeyType }, + { newValueType -> valueType.value = newValueType }, + back = navigation::pop, + approve= { navigation.push(ScreenManager.TreeView) } + ) + } + } + + is ScreenManager.TreeView -> { + } } } diff --git a/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt b/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt index 8837d6f..2a929d2 100644 --- a/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt +++ b/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt @@ -17,7 +17,9 @@ fun databaseConnectionJson( approveChange: () -> Unit ) { Column(modifier = Modifier.padding(vertical = 16.dp)) { + OutlinedTextField(value = host.value, onValueChange = hostChange) + Button(onClick = approveChange){ Text("Approve") } @@ -31,7 +33,9 @@ fun databaseConnectionSQL( approveChange: () -> Unit ) { Column(modifier = Modifier.padding(vertical = 16.dp)) { + OutlinedTextField(value = host.value, onValueChange = hostChange) + Button(onClick = approveChange){ Text("Approve") } diff --git a/app/src/main/kotlin/app/view/screens/ChosingTypesScreen.kt b/app/src/main/kotlin/app/view/screens/ChosingTypesScreen.kt index d3d14d9..9e5b020 100644 --- a/app/src/main/kotlin/app/view/screens/ChosingTypesScreen.kt +++ b/app/src/main/kotlin/app/view/screens/ChosingTypesScreen.kt @@ -10,14 +10,19 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import app.presenter.TreePresenter import app.view.assets.Selector @Composable fun ChosingTypesScreen( + treePresenter: TreePresenter, + treeName: State, + treeType: State, keyType: State, valueType: State, onClickChangesKey: (String) -> Unit, onClickChangesValue: (String) -> Unit, + back: () -> Unit, approve: () -> Unit ) { Column(modifier = Modifier.padding(16.dp)) { @@ -42,10 +47,16 @@ fun ChosingTypesScreen( keyType.value != "Choose the key type from the following options" && valueType.value != "Choose the value type from the following options" ) { - Button(onClick = approve) { + Button(onClick = { + treePresenter.createTree(treeName.value, treeType.value, keyType.value, valueType.value) + approve() + }) { Text("Approve and create") } } + Button(onClick = back){ + Text("back") + } } } \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/screens/ScreenManager.kt b/app/src/main/kotlin/app/view/screens/ScreenManager.kt index 1467cf3..6462d6e 100644 --- a/app/src/main/kotlin/app/view/screens/ScreenManager.kt +++ b/app/src/main/kotlin/app/view/screens/ScreenManager.kt @@ -13,4 +13,7 @@ sealed class ScreenManager : Parcelable { @Parcelize object ChosingTypesScreen: ScreenManager() + + @Parcelize + object TreeView: ScreenManager() } diff --git a/app/src/main/kotlin/app/view/screens/TreeScreen.kt b/app/src/main/kotlin/app/view/screens/TreeScreen.kt index e5ecd72..2565096 100644 --- a/app/src/main/kotlin/app/view/screens/TreeScreen.kt +++ b/app/src/main/kotlin/app/view/screens/TreeScreen.kt @@ -19,14 +19,12 @@ fun TreeActions( createTreeMenu: () -> Unit, keyType: State, valueType: State, - ) { Column { Button(onClick = { createTreeMenu() - treePresenter.createTree(treeName.value, treeType.value, keyType.value, valueType.value) } ) { Text("Create Tree") From 6ed657156483258a6f2b9d5144d807b58509f59c Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 2 May 2023 18:39:28 +0300 Subject: [PATCH 116/135] feat: UI add node implementation --- .../kotlin/app/presenter/TreePresenter.kt | 4 +- app/src/main/kotlin/app/view/App.kt | 36 ++++++++++--- .../main/kotlin/app/view/assets/TreeView.kt | 35 ++++++------ .../kotlin/app/view/screens/AddNodeScreen.kt | 53 +++++++++++++++++++ .../kotlin/app/view/screens/ScreenManager.kt | 3 ++ .../kotlin/app/view/screens/TreeScreen.kt | 11 ++-- 6 files changed, 110 insertions(+), 32 deletions(-) create mode 100644 app/src/main/kotlin/app/view/screens/AddNodeScreen.kt diff --git a/app/src/main/kotlin/app/presenter/TreePresenter.kt b/app/src/main/kotlin/app/presenter/TreePresenter.kt index 9457fe3..2897c2e 100644 --- a/app/src/main/kotlin/app/presenter/TreePresenter.kt +++ b/app/src/main/kotlin/app/presenter/TreePresenter.kt @@ -53,7 +53,7 @@ class TreePresenter(private val db: TreeRepo) { strategy.keyStringConverter.fromString(key), strategy.valueStringConverter.fromString(value) ) - strategy.serializeTree(bTree, tree.name) + tree = strategy.serializeTree(bTree, tree.name) } helper(createStrategy()) } @@ -65,7 +65,7 @@ class TreePresenter(private val db: TreeRepo) { bTree.delete( strategy.keyStringConverter.fromString(key), ) - strategy.serializeTree(bTree, tree.name) + tree = strategy.serializeTree(bTree, tree.name) } helper(createStrategy()) } diff --git a/app/src/main/kotlin/app/view/App.kt b/app/src/main/kotlin/app/view/App.kt index c923f22..9210928 100644 --- a/app/src/main/kotlin/app/view/App.kt +++ b/app/src/main/kotlin/app/view/App.kt @@ -9,10 +9,8 @@ import app.presenter.DataBasePresenter import app.presenter.TreePresenter import app.view.assets.ChildStack import app.view.assets.ProvideComponentContext -import app.view.screens.ChosingTypesScreen -import app.view.screens.HomeScreen -import app.view.screens.ScreenManager -import app.view.screens.TreeSreen +import app.view.assets.TreeView +import app.view.screens.* import com.arkivanov.decompose.DefaultComponentContext import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.fade import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.plus @@ -53,12 +51,16 @@ fun main() { remember { mutableStateOf("Choose the value type from the following options") } var treePresenter: TreePresenter? = null + // for tree adding and deleting + val key = remember { mutableStateOf("Enter key") } + val value = remember { mutableStateOf("Enter value") } + ChildStack( source = navigation, initialStack = { listOf(ScreenManager.HomeScreen) }, handleBackButton = true, animation = stackAnimation(fade() + scale()), - ) { screen -> + ) { screen -> when (screen) { is ScreenManager.HomeScreen -> { @@ -114,8 +116,7 @@ fun main() { { newName -> treeName.value = newName }, back = navigation::pop, { navigation.push(ScreenManager.ChosingTypesScreen) }, - keyType, - valueType + { navigation.push(ScreenManager.TreeView) } ) } @@ -132,13 +133,32 @@ fun main() { { newKeyType -> keyType.value = newKeyType }, { newValueType -> valueType.value = newValueType }, back = navigation::pop, - approve= { navigation.push(ScreenManager.TreeView) } + approve = { navigation.push(ScreenManager.TreeView) } ) } } is ScreenManager.TreeView -> { + treePresenter?.let { treePresenter -> + TreeView( + treePresenter, + addNode = { navigation.push(ScreenManager.AddNodeScreen)} + ) + } + } + is ScreenManager.AddNodeScreen -> { + treePresenter?.let {treePresenter -> + AddNodeScreen( + treePresenter, + key, + value, + { newKey -> key.value = newKey }, + { newValue -> value.value = newValue }, + back = { navigation.pop() }, + approve = { navigation.pop() } + ) + } } } } diff --git a/app/src/main/kotlin/app/view/assets/TreeView.kt b/app/src/main/kotlin/app/view/assets/TreeView.kt index 0587299..1b91bbd 100644 --- a/app/src/main/kotlin/app/view/assets/TreeView.kt +++ b/app/src/main/kotlin/app/view/assets/TreeView.kt @@ -13,6 +13,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import app.presenter.LayoutPresenter import bstrees.model.dataBases.NodeData import app.presenter.TreePresenter @@ -97,14 +98,21 @@ fun Node( } @Composable -fun TreeActionButtons(treePresenter: TreePresenter) { +fun TreeActionButtons( + treePresenter: TreePresenter, + addNode: () -> Unit +) { Column { - Button(onClick = { treePresenter.addNode("0", "0") }) { + Button(onClick = { + addNode() + }) { Text("Add Node") } - Button(onClick = { treePresenter.deleteNode("0") }) { + Button(onClick = { + treePresenter.deleteNode("0") + }) { Text(text = "Delete Node") } } @@ -114,25 +122,22 @@ fun TreeActionButtons(treePresenter: TreePresenter) { @Composable fun TreeView( treePresenter: TreePresenter, - treeWidth: Double, - treeHeight: Double, - nodeSize: Double, - xOffset: Double = 0.0, - yOffset: Double = 0.0 + addNode: () -> Unit, ) { val tree = treePresenter.tree + LayoutPresenter.setTreeLayout(tree, 800, 800) Row { - TreeActionButtons(treePresenter) + TreeActionButtons(treePresenter, addNode) Box( - modifier = Modifier.height(treeHeight.dp).width(treeWidth.dp), + modifier = Modifier.height(800.dp).width(800.dp), contentAlignment = Alignment.Center ) { - tree.root?.let { + tree.root?.let { root -> Tree( - mutableStateOf(it), - nodeSize, - xOffset, - yOffset + mutableStateOf(root), + 50.0, + 0.0, + 0.0, ) } } diff --git a/app/src/main/kotlin/app/view/screens/AddNodeScreen.kt b/app/src/main/kotlin/app/view/screens/AddNodeScreen.kt new file mode 100644 index 0000000..e2b12d5 --- /dev/null +++ b/app/src/main/kotlin/app/view/screens/AddNodeScreen.kt @@ -0,0 +1,53 @@ +package app.view.screens + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Button +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import app.presenter.TreePresenter +import app.view.assets.Selector + +@Composable +fun AddNodeScreen( + treePresenter: TreePresenter, + key: State, + value: State, + ChangesKey: (String) -> Unit, + ChangesValue: (String) -> Unit, + back: () -> Unit, + approve: () -> Unit +) { + Column(modifier = Modifier.padding(16.dp)) { + + OutlinedTextField(value = key.value, onValueChange = ChangesKey) + + Spacer(modifier = Modifier.height(16.dp)) + + OutlinedTextField(value = value.value, onValueChange = ChangesValue) + + Spacer(modifier = Modifier.height(16.dp)) + + if ( + key.value != "Enter key" && + value.value != "Enter value" + ) { + Button(onClick = { + treePresenter.addNode(key.value, value.value) + approve() + }) { + Text("add node") + } + } + + Button(onClick = back) { + Text("back") + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/screens/ScreenManager.kt b/app/src/main/kotlin/app/view/screens/ScreenManager.kt index 6462d6e..e0987d4 100644 --- a/app/src/main/kotlin/app/view/screens/ScreenManager.kt +++ b/app/src/main/kotlin/app/view/screens/ScreenManager.kt @@ -16,4 +16,7 @@ sealed class ScreenManager : Parcelable { @Parcelize object TreeView: ScreenManager() + + @Parcelize + object AddNodeScreen: ScreenManager() } diff --git a/app/src/main/kotlin/app/view/screens/TreeScreen.kt b/app/src/main/kotlin/app/view/screens/TreeScreen.kt index 2565096..f039962 100644 --- a/app/src/main/kotlin/app/view/screens/TreeScreen.kt +++ b/app/src/main/kotlin/app/view/screens/TreeScreen.kt @@ -17,8 +17,7 @@ fun TreeActions( treeName: State, treeType: State, createTreeMenu: () -> Unit, - keyType: State, - valueType: State, + treeView: () -> Unit, ) { Column { @@ -32,12 +31,11 @@ fun TreeActions( Button(onClick = { treePresenter.loadTree(treeName.value, treeType.value) + treeView() } ) { Text("Load Tree") } - - //TODO(Add a call to the TreeView method) } } @@ -50,8 +48,7 @@ fun TreeSreen( treeNameChange: (String) -> Unit, back: () -> Unit, createTreeMenu: () -> Unit, - keyType: State, - valueType: State + treeView: () -> Unit ) { Column(modifier = Modifier.padding(16.dp)) { Selector(treeType, onClickChanges, listOf("BS", "AVL", "RB")) @@ -59,7 +56,7 @@ fun TreeSreen( if (treeType.value != "Choose your tree") { Spacer(modifier = Modifier.height(16.dp)) OutlinedTextField(value = treeName.value, onValueChange = treeNameChange) - TreeActions(treePresenter, treeName, treeType, createTreeMenu, keyType, valueType) + TreeActions(treePresenter, treeName, treeType, createTreeMenu, treeView) } Button(onClick = back) { From 9e9959eaca98bea3a9ea21feb7b125e0fa3fa247 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 2 May 2023 18:52:01 +0300 Subject: [PATCH 117/135] feat: UI delete node implementation --- app/src/main/kotlin/app/view/App.kt | 15 +++++- .../main/kotlin/app/view/assets/TreeView.kt | 15 ++++-- .../app/view/screens/DeleteNodeScreen.kt | 46 +++++++++++++++++++ .../kotlin/app/view/screens/ScreenManager.kt | 3 ++ 4 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 app/src/main/kotlin/app/view/screens/DeleteNodeScreen.kt diff --git a/app/src/main/kotlin/app/view/App.kt b/app/src/main/kotlin/app/view/App.kt index 9210928..240429b 100644 --- a/app/src/main/kotlin/app/view/App.kt +++ b/app/src/main/kotlin/app/view/App.kt @@ -142,7 +142,8 @@ fun main() { treePresenter?.let { treePresenter -> TreeView( treePresenter, - addNode = { navigation.push(ScreenManager.AddNodeScreen)} + addNode = { navigation.push(ScreenManager.AddNodeScreen) }, + deleteNode = { navigation.push(ScreenManager.DeleteNodeScreen) }, ) } } @@ -160,6 +161,18 @@ fun main() { ) } } + + is ScreenManager.DeleteNodeScreen -> { + treePresenter?.let { treePresenter -> + DeleteNodeScreen( + treePresenter, + key, + { newKey -> key.value = newKey }, + back = { navigation.pop() }, + approve = { navigation.pop() } + ) + } + } } } } diff --git a/app/src/main/kotlin/app/view/assets/TreeView.kt b/app/src/main/kotlin/app/view/assets/TreeView.kt index 1b91bbd..1223278 100644 --- a/app/src/main/kotlin/app/view/assets/TreeView.kt +++ b/app/src/main/kotlin/app/view/assets/TreeView.kt @@ -100,18 +100,21 @@ fun Node( @Composable fun TreeActionButtons( treePresenter: TreePresenter, - addNode: () -> Unit + addNode: () -> Unit, + deleteNode: () -> Unit, ) { - Column { + Row { Button(onClick = { addNode() }) { Text("Add Node") } + Spacer(modifier = Modifier.width(30.dp)) + Button(onClick = { - treePresenter.deleteNode("0") + deleteNode() }) { Text(text = "Delete Node") } @@ -123,11 +126,13 @@ fun TreeActionButtons( fun TreeView( treePresenter: TreePresenter, addNode: () -> Unit, + deleteNode: () -> Unit, ) { val tree = treePresenter.tree LayoutPresenter.setTreeLayout(tree, 800, 800) - Row { - TreeActionButtons(treePresenter, addNode) + Column { + TreeActionButtons(treePresenter, addNode, deleteNode) + Box( modifier = Modifier.height(800.dp).width(800.dp), contentAlignment = Alignment.Center diff --git a/app/src/main/kotlin/app/view/screens/DeleteNodeScreen.kt b/app/src/main/kotlin/app/view/screens/DeleteNodeScreen.kt new file mode 100644 index 0000000..8898f44 --- /dev/null +++ b/app/src/main/kotlin/app/view/screens/DeleteNodeScreen.kt @@ -0,0 +1,46 @@ +package app.view.screens + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Button +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import app.presenter.TreePresenter +import app.view.assets.Selector + +@Composable +fun DeleteNodeScreen( + treePresenter: TreePresenter, + key: State, + ChangesKey: (String) -> Unit, + back: () -> Unit, + approve: () -> Unit +) { + Column(modifier = Modifier.padding(16.dp)) { + + OutlinedTextField(value = key.value, onValueChange = ChangesKey) + + Spacer(modifier = Modifier.height(16.dp)) + + if ( + key.value != "Enter key" + ) { + Button(onClick = { + treePresenter.deleteNode(key.value) + approve() + }) { + Text("delete node") + } + } + + Button(onClick = back) { + Text("back") + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/screens/ScreenManager.kt b/app/src/main/kotlin/app/view/screens/ScreenManager.kt index e0987d4..1a31f50 100644 --- a/app/src/main/kotlin/app/view/screens/ScreenManager.kt +++ b/app/src/main/kotlin/app/view/screens/ScreenManager.kt @@ -19,4 +19,7 @@ sealed class ScreenManager : Parcelable { @Parcelize object AddNodeScreen: ScreenManager() + + @Parcelize + object DeleteNodeScreen: ScreenManager() } From 6580b6417fd227b5eb3f5cf243ad202c762e0ea4 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 2 May 2023 19:10:32 +0300 Subject: [PATCH 118/135] fix: Updating `key` and `value` to the default value before adding and removing a node --- app/src/main/kotlin/app/view/App.kt | 3 +++ app/src/main/kotlin/app/view/assets/TreeView.kt | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/app/view/App.kt b/app/src/main/kotlin/app/view/App.kt index 240429b..248554c 100644 --- a/app/src/main/kotlin/app/view/App.kt +++ b/app/src/main/kotlin/app/view/App.kt @@ -149,6 +149,8 @@ fun main() { } is ScreenManager.AddNodeScreen -> { + key.value = "Enter key" + value.value = "Enter value" treePresenter?.let {treePresenter -> AddNodeScreen( treePresenter, @@ -163,6 +165,7 @@ fun main() { } is ScreenManager.DeleteNodeScreen -> { + key.value = "Enter key" treePresenter?.let { treePresenter -> DeleteNodeScreen( treePresenter, diff --git a/app/src/main/kotlin/app/view/assets/TreeView.kt b/app/src/main/kotlin/app/view/assets/TreeView.kt index 1223278..ad7a399 100644 --- a/app/src/main/kotlin/app/view/assets/TreeView.kt +++ b/app/src/main/kotlin/app/view/assets/TreeView.kt @@ -99,7 +99,6 @@ fun Node( @Composable fun TreeActionButtons( - treePresenter: TreePresenter, addNode: () -> Unit, deleteNode: () -> Unit, ) { @@ -131,7 +130,7 @@ fun TreeView( val tree = treePresenter.tree LayoutPresenter.setTreeLayout(tree, 800, 800) Column { - TreeActionButtons(treePresenter, addNode, deleteNode) + TreeActionButtons(addNode, deleteNode) Box( modifier = Modifier.height(800.dp).width(800.dp), From 22c311707f7e5865c0f28db08bd3788cf376d894 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 2 May 2023 19:20:37 +0300 Subject: [PATCH 119/135] feat: Fixed app size added --- app/src/main/kotlin/app/view/App.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/app/view/App.kt b/app/src/main/kotlin/app/view/App.kt index 248554c..32e1637 100644 --- a/app/src/main/kotlin/app/view/App.kt +++ b/app/src/main/kotlin/app/view/App.kt @@ -20,6 +20,7 @@ import com.arkivanov.decompose.router.stack.StackNavigation import com.arkivanov.decompose.router.stack.pop import com.arkivanov.decompose.router.stack.push import com.arkivanov.essenty.lifecycle.LifecycleRegistry +import java.awt.Dimension fun main() { @@ -32,9 +33,11 @@ fun main() { title = "graph", state = rememberWindowState( position = WindowPosition(alignment = Alignment.Center), - size = DpSize(800.dp, 800.dp) ), + ) { + window.minimumSize = Dimension(800, 800) + window.maximumSize = Dimension(800, 800) ProvideComponentContext(rootComponentContext) { From 77b53a0d9a815de899f257c6cf49227bc2ef8a4f Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 2 May 2023 19:29:18 +0300 Subject: [PATCH 120/135] feat: Added tree saving to the database --- app/src/main/kotlin/app/presenter/LayoutPresenter.kt | 3 +++ app/src/main/kotlin/app/presenter/TreePresenter.kt | 4 ++++ app/src/main/kotlin/app/view/assets/TreeView.kt | 12 ++++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/app/presenter/LayoutPresenter.kt b/app/src/main/kotlin/app/presenter/LayoutPresenter.kt index 1e0d6f0..3e5199a 100644 --- a/app/src/main/kotlin/app/presenter/LayoutPresenter.kt +++ b/app/src/main/kotlin/app/presenter/LayoutPresenter.kt @@ -1,11 +1,14 @@ package app.presenter +import androidx.compose.ui.unit.dp import bstrees.model.dataBases.NodeData import bstrees.model.dataBases.TreeData import app.presenter.utils.TreeHeightPresenter object LayoutPresenter { + private const val windowHeight = 800 + private const val windowWidth = 800 private const val nodeRadius = 50 private const val edgeLength = 50 diff --git a/app/src/main/kotlin/app/presenter/TreePresenter.kt b/app/src/main/kotlin/app/presenter/TreePresenter.kt index 2897c2e..a091b45 100644 --- a/app/src/main/kotlin/app/presenter/TreePresenter.kt +++ b/app/src/main/kotlin/app/presenter/TreePresenter.kt @@ -18,6 +18,10 @@ class TreePresenter(private val db: TreeRepo) { tree = db.getTree(treeName, treeType) ?: throw IllegalArgumentException("There is no tree with that name: $treeName") } + fun saveTree(){ + db.setTree(tree) + } + fun createTree(treeName: String, treeType: String, keyType: String, valueType: String) { tree = TreeData(treeName, treeType, keyType, valueType, null) db.setTree(tree) diff --git a/app/src/main/kotlin/app/view/assets/TreeView.kt b/app/src/main/kotlin/app/view/assets/TreeView.kt index ad7a399..b576f1e 100644 --- a/app/src/main/kotlin/app/view/assets/TreeView.kt +++ b/app/src/main/kotlin/app/view/assets/TreeView.kt @@ -99,6 +99,7 @@ fun Node( @Composable fun TreeActionButtons( + treePresenter: TreePresenter, addNode: () -> Unit, deleteNode: () -> Unit, ) { @@ -117,8 +118,15 @@ fun TreeActionButtons( }) { Text(text = "Delete Node") } - } + Spacer(modifier = Modifier.width(30.dp)) + + Button(onClick = { + treePresenter.saveTree() + }) { + Text(text = "Save tree") + } + } } @Composable @@ -130,7 +138,7 @@ fun TreeView( val tree = treePresenter.tree LayoutPresenter.setTreeLayout(tree, 800, 800) Column { - TreeActionButtons(addNode, deleteNode) + TreeActionButtons(treePresenter, addNode, deleteNode) Box( modifier = Modifier.height(800.dp).width(800.dp), From d2b6de4b4927ecb0d25c1d0a5b163015cf1d7f29 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 2 May 2023 21:44:02 +0300 Subject: [PATCH 121/135] feat: Added the first version of the tree with moving vertices --- .../main/kotlin/app/view/assets/TreeView.kt | 138 +++++++++--------- 1 file changed, 65 insertions(+), 73 deletions(-) diff --git a/app/src/main/kotlin/app/view/assets/TreeView.kt b/app/src/main/kotlin/app/view/assets/TreeView.kt index b576f1e..3013fd9 100644 --- a/app/src/main/kotlin/app/view/assets/TreeView.kt +++ b/app/src/main/kotlin/app/view/assets/TreeView.kt @@ -1,7 +1,8 @@ package app.view.assets +import androidx.compose.foundation.Canvas import androidx.compose.foundation.background -import androidx.compose.foundation.border +import androidx.compose.foundation.gestures.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.Button @@ -9,92 +10,84 @@ import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.input.pointer.positionChange +import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import app.presenter.LayoutPresenter -import bstrees.model.dataBases.NodeData import app.presenter.TreePresenter +import bstrees.model.dataBases.NodeData @Composable fun Tree( - root: State, - nodeSize: Double, - xOffset: Double, - yOffset: Double, - modifier: Modifier = Modifier + node: State, ) { - Box(modifier = modifier) { - Node(root, nodeSize) - - val checkLeftSon = root.value.leftNode - checkLeftSon?.let { leftSon -> - val temp = remember { mutableStateOf(leftSon) } - Tree( - temp, - nodeSize, - xOffset - nodeSize / 2, - yOffset + nodeSize, - modifier = Modifier.absoluteOffset(x = (xOffset - nodeSize / 1.5).dp, y = (yOffset + nodeSize).dp) - ) - } - val checkRightSon = root.value.rightNode - checkRightSon?.let { rightSon -> - val temp = remember { mutableStateOf(rightSon) } - Tree( - temp, - nodeSize, - xOffset + nodeSize / 2, - yOffset + nodeSize, - modifier = Modifier.absoluteOffset(x = (xOffset + nodeSize / 1.5).dp, y = (yOffset + nodeSize).dp) - ) + val nodeCoords = remember { mutableStateOf(Pair(node.value.posX.toFloat(), node.value.posY.toFloat())) } + + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Row( + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + node.value.leftNode?.let { leftNode-> + Tree(mutableStateOf(leftNode)) + } + node.value.rightNode?.let { rightNode-> + Tree(mutableStateOf(rightNode)) + } } + TreeNode(node, nodeCoords) } } -@Composable -fun Node( - node: State, - nodeSize: Double, -) { +@Composable +fun TreeNode(node: State, nodeCoords: MutableState>) { + node.value.posX = nodeCoords.value.first.toInt() + node.value.posY = nodeCoords.value.second.toInt() Box( - contentAlignment = Alignment.Center, modifier = Modifier - .background( - color = if (node.value.metadata == "RED") Color.Red - else if (node.value.metadata == "BLACK") Color.Black - else Color.Magenta, - shape = CircleShape - ) - .width(nodeSize.dp) - .height(nodeSize.dp) - .border( - width = 1.dp, - color = Color.Blue, - shape = CircleShape - ) - ) { - Column( - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text( - text = "Key: ${node.value.key}", - textAlign = TextAlign.Center, - color = Color.White, - fontSize = if (((nodeSize / 4).toInt()) > 20) 20.sp else (nodeSize / 4).toInt().sp - ) - Text( - text = "Value: ${node.value.value}", - textAlign = TextAlign.Center, - color = Color.White, - fontSize = if (((nodeSize / 4).toInt()) > 20) 20.sp else (nodeSize / 4).toInt().sp + .offset { IntOffset(nodeCoords.value.first.toInt(), nodeCoords.value.second.toInt()) } + .background(Color.Red, CircleShape) + .size(50.dp) + .pointerInput(Unit) { + // Обработчик перемещения узла + detectDragGestures { change, dragAmount -> + nodeCoords.value = Pair( + nodeCoords.value.first + dragAmount.x, + nodeCoords.value.second + dragAmount.y + ) + if (change.positionChange() != Offset.Zero) change.consume() + } + } + + ) +} + + +@Composable +fun Edge( + node1: State, + node2: State, + modifier: Modifier = Modifier +) { + Canvas( + modifier = modifier.size(800.dp), + onDraw = { + drawLine( + start = Offset(x = node1.value.posX.toFloat() + 800, y = node1.value.posY.toFloat() + 100), + end = Offset(x = node2.value.posX.toFloat() + 800, y = node2.value.posY.toFloat() + 100), + color = Color.Black, + strokeWidth = 5F ) } - } - + ) } @Composable @@ -146,12 +139,11 @@ fun TreeView( ) { tree.root?.let { root -> Tree( - mutableStateOf(root), - 50.0, - 0.0, - 0.0, + mutableStateOf(root) ) } } } } + + From 40831ebb13137765bf14edb6ce6abf4911abf344 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Tue, 2 May 2023 21:49:28 +0300 Subject: [PATCH 122/135] feat: Now the screen with the tree can be moved --- .../main/kotlin/app/view/assets/TreeView.kt | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/app/src/main/kotlin/app/view/assets/TreeView.kt b/app/src/main/kotlin/app/view/assets/TreeView.kt index 3013fd9..4785a57 100644 --- a/app/src/main/kotlin/app/view/assets/TreeView.kt +++ b/app/src/main/kotlin/app/view/assets/TreeView.kt @@ -12,6 +12,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.positionChange import androidx.compose.ui.unit.IntOffset @@ -19,6 +20,7 @@ import androidx.compose.ui.unit.dp import app.presenter.LayoutPresenter import app.presenter.TreePresenter import bstrees.model.dataBases.NodeData +import bstrees.model.dataBases.TreeData @Composable fun Tree( @@ -137,13 +139,46 @@ fun TreeView( modifier = Modifier.height(800.dp).width(800.dp), contentAlignment = Alignment.Center ) { - tree.root?.let { root -> - Tree( - mutableStateOf(root) - ) - } + TransformableSample(tree) + } + } +} + + +@Composable +private fun TransformableSample(tree: TreeData) { + // set up all transformation states + var scale by remember { mutableStateOf(1f) } + var rotation by remember { mutableStateOf(0f) } + var offset by remember { mutableStateOf(Offset.Zero) } + val state = rememberTransformableState { zoomChange, offsetChange, rotationChange -> + scale *= zoomChange + rotation += rotationChange + offset += offsetChange + } + Box( + Modifier + // apply other transformations like rotation and zoom + // on the pizza slice emoji + .graphicsLayer( + scaleX = scale, + scaleY = scale, + rotationZ = rotation, + translationX = offset.x, + translationY = offset.y + ) + // add transformable to listen to multitouch transformation events + // after offset + .transformable(state = state) + .fillMaxSize() + ){ + tree.root?.let { root -> + Tree( + mutableStateOf(root) + ) } } + } From af8d375417ecf1dfbfc09392261d118b9b1254cd Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Tue, 2 May 2023 22:51:49 +0300 Subject: [PATCH 123/135] Updated README --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c37efda..0334ff4 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ val bsTree = BSTree() // instantiate empty simple tree The first type parameter is a comparable key. \ The second type parameter is a stored value. It can be anything -Each tree supports 3 basic operations: `insert`, `search`, `delete`. +Each tree supports 3 basic operations: `insert`, `find`, `delete`. ```kotlin val bsTree = BSTree() @@ -26,9 +26,15 @@ bsTree.delete("bruh") ``` ## Storing BSTs -Currently, only storage in SQLite is supported \ -(WIP) storing in JSON, neo4j - +You can store any tree in any of the three databases presented. These are `Neo4j`, `SQLite` and `Json`. You can choose the types of key and value on wich the tree is built, but supported only string and int if you want to store it + +To use `Neo4j`, you need to install the desktop application `Neo4j` and `Doсker` and perform the necessary manipulations in the console + +# User Interface + +You can interact with the trees directly using the provided user interface. It allows you to choose the database, the types of keys and values on which the tree is built, as well as save and unload trees from databases. Again, you can create and load any trees to any data bases. + + ## License Distributed under the Apache 2.0 License. See [LICENSE](https://github.com/spbu-coding-2022/trees-6/blob/main/LICENSE) for more information. From 61de148d5172e95927cc6e8d5d73408859e12f1f Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Wed, 3 May 2023 00:16:09 +0300 Subject: [PATCH 124/135] feat: Added an adequate mapping for small graphs --- .../kotlin/app/presenter/LayoutPresenter.kt | 10 +- .../main/kotlin/app/view/assets/TreeView.kt | 129 ++++++++++-------- 2 files changed, 74 insertions(+), 65 deletions(-) diff --git a/app/src/main/kotlin/app/presenter/LayoutPresenter.kt b/app/src/main/kotlin/app/presenter/LayoutPresenter.kt index 3e5199a..f2f4f24 100644 --- a/app/src/main/kotlin/app/presenter/LayoutPresenter.kt +++ b/app/src/main/kotlin/app/presenter/LayoutPresenter.kt @@ -1,6 +1,5 @@ package app.presenter -import androidx.compose.ui.unit.dp import bstrees.model.dataBases.NodeData import bstrees.model.dataBases.TreeData import app.presenter.utils.TreeHeightPresenter @@ -9,8 +8,8 @@ object LayoutPresenter { private const val windowHeight = 800 private const val windowWidth = 800 - private const val nodeRadius = 50 - private const val edgeLength = 50 + private const val nodeRadius = 30 + private const val edgeLength = 10 fun setTreeLayout(tree: TreeData, windowHeight: Int, windowWidth: Int){ @@ -18,17 +17,18 @@ object LayoutPresenter { val treeHeight = TreeHeightPresenter.getTreeHeight(tree) tree.root?.let {root-> - root.posX = 0 + root.posX = 800 root.posY = 0 setNodesLayout(root, treeHeight) } + } // This method will assign coordinates to the nodes of the tree private fun setNodesLayout(node: NodeData, height: Int){ val xDiff = (edgeLength + 2 * nodeRadius) * height + (height - 1) - val yDiff = (edgeLength + 2 * nodeRadius) + val yDiff = (edgeLength + 2 * nodeRadius) * 3 node.leftNode?.let {leftNode-> leftNode.posX = node.posX - xDiff leftNode.posY = node.posY + yDiff diff --git a/app/src/main/kotlin/app/view/assets/TreeView.kt b/app/src/main/kotlin/app/view/assets/TreeView.kt index 4785a57..f5ca3a5 100644 --- a/app/src/main/kotlin/app/view/assets/TreeView.kt +++ b/app/src/main/kotlin/app/view/assets/TreeView.kt @@ -2,6 +2,7 @@ package app.view.assets import androidx.compose.foundation.Canvas import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.gestures.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape @@ -21,6 +22,21 @@ import app.presenter.LayoutPresenter import app.presenter.TreePresenter import bstrees.model.dataBases.NodeData import bstrees.model.dataBases.TreeData +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.sp + + +const val NODE_SIZE = 30 + + +@Composable +fun Dp.dpToPx() = with(LocalDensity.current) { this@dpToPx.toPx() } + + +@Composable +fun Int.pxToDp() = with(LocalDensity.current) { this@pxToDp.toDp() } @Composable fun Tree( @@ -29,23 +45,20 @@ fun Tree( val nodeCoords = remember { mutableStateOf(Pair(node.value.posX.toFloat(), node.value.posY.toFloat())) } - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center - ) { - Row( - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically - ) { - node.value.leftNode?.let { leftNode-> - Tree(mutableStateOf(leftNode)) - } - node.value.rightNode?.let { rightNode-> - Tree(mutableStateOf(rightNode)) - } - } - TreeNode(node, nodeCoords) + node.value.leftNode?.let { it -> + Edge(node, mutableStateOf(it)) + } + node.value.rightNode?.let { it -> + Edge(node, mutableStateOf(it)) + } + node.value.leftNode?.let { leftNode -> + Tree(mutableStateOf(leftNode)) } + node.value.rightNode?.let { rightNode -> + Tree(mutableStateOf(rightNode)) + } + + TreeNode(node, nodeCoords) } @@ -54,10 +67,11 @@ fun TreeNode(node: State, nodeCoords: MutableState> node.value.posX = nodeCoords.value.first.toInt() node.value.posY = nodeCoords.value.second.toInt() Box( + contentAlignment = Alignment.Center, modifier = Modifier .offset { IntOffset(nodeCoords.value.first.toInt(), nodeCoords.value.second.toInt()) } .background(Color.Red, CircleShape) - .size(50.dp) + .size(NODE_SIZE.dp) .pointerInput(Unit) { // Обработчик перемещения узла detectDragGestures { change, dragAmount -> @@ -68,8 +82,38 @@ fun TreeNode(node: State, nodeCoords: MutableState> if (change.positionChange() != Offset.Zero) change.consume() } } + .background( + color = if (node.value.metadata == "RED") Color.Red + else if (node.value.metadata == "BLACK") Color.Black + else Color.Magenta, + shape = CircleShape + ) + .width(NODE_SIZE.dp) + .height(NODE_SIZE.dp) + .border( + width = 1.dp, + color = Color.Blue, + shape = CircleShape + ) - ) + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "Key: ${node.value.key}", + textAlign = TextAlign.Center, + color = Color.White, + fontSize = if (((NODE_SIZE / 4)) > 20) 20.sp else (NODE_SIZE / 4).sp + ) + Text( + text = "Value: ${node.value.value}", + textAlign = TextAlign.Center, + color = Color.White, + fontSize = if (((NODE_SIZE / 4)) > 20) 20.sp else (NODE_SIZE / 4).sp + ) + } + } } @@ -83,8 +127,8 @@ fun Edge( modifier = modifier.size(800.dp), onDraw = { drawLine( - start = Offset(x = node1.value.posX.toFloat() + 800, y = node1.value.posY.toFloat() + 100), - end = Offset(x = node2.value.posX.toFloat() + 800, y = node2.value.posY.toFloat() + 100), + start = Offset(x = node1.value.posX.toFloat() + NODE_SIZE, y = node1.value.posY.toFloat() + NODE_SIZE), + end = Offset(x = node2.value.posX.toFloat() + NODE_SIZE, y = node2.value.posY.toFloat() + NODE_SIZE), color = Color.Black, strokeWidth = 5F ) @@ -137,48 +181,13 @@ fun TreeView( Box( modifier = Modifier.height(800.dp).width(800.dp), - contentAlignment = Alignment.Center ) { - TransformableSample(tree) - } - } -} - - -@Composable -private fun TransformableSample(tree: TreeData) { - // set up all transformation states - var scale by remember { mutableStateOf(1f) } - var rotation by remember { mutableStateOf(0f) } - var offset by remember { mutableStateOf(Offset.Zero) } - val state = rememberTransformableState { zoomChange, offsetChange, rotationChange -> - scale *= zoomChange - rotation += rotationChange - offset += offsetChange - } - Box( - Modifier - // apply other transformations like rotation and zoom - // on the pizza slice emoji - .graphicsLayer( - scaleX = scale, - scaleY = scale, - rotationZ = rotation, - translationX = offset.x, - translationY = offset.y - ) - // add transformable to listen to multitouch transformation events - // after offset - .transformable(state = state) - .fillMaxSize() - ){ - tree.root?.let { root -> - Tree( - mutableStateOf(root) - ) + tree.root?.let { root -> + Tree( + mutableStateOf(root) + ) + } } } - } - From d0f13a6d49ab89d3348c172ab4297cf6f231d0d7 Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Wed, 3 May 2023 00:25:56 +0300 Subject: [PATCH 125/135] fix: A lot of appearance changes --- app/src/main/kotlin/app/view/App.kt | 30 ++++---- .../app/view/assets/DatabaseConnections.kt | 68 ++++++++++++++++--- .../main/kotlin/app/view/assets/Selector.kt | 22 ++++-- .../app/view/screens/ChosingTypesScreen.kt | 41 ++++++----- .../kotlin/app/view/screens/HomeScreen.kt | 13 +++- .../kotlin/app/view/screens/TreeScreen.kt | 52 +++++++++----- 6 files changed, 155 insertions(+), 71 deletions(-) diff --git a/app/src/main/kotlin/app/view/App.kt b/app/src/main/kotlin/app/view/App.kt index 32e1637..3214919 100644 --- a/app/src/main/kotlin/app/view/App.kt +++ b/app/src/main/kotlin/app/view/App.kt @@ -1,9 +1,7 @@ package app.view import androidx.compose.runtime.* -import androidx.compose.ui.unit.dp import androidx.compose.ui.Alignment -import androidx.compose.ui.unit.DpSize import androidx.compose.ui.window.* import app.presenter.DataBasePresenter import app.presenter.TreePresenter @@ -35,23 +33,21 @@ fun main() { position = WindowPosition(alignment = Alignment.Center), ), - ) { + ) { window.minimumSize = Dimension(800, 800) window.maximumSize = Dimension(800, 800) ProvideComponentContext(rootComponentContext) { - val header = remember { mutableStateOf("Choose your database") } + val databaseChoice = remember { mutableStateOf("▾") } val databaseMetadata = remember { mutableStateOf("") } val username = remember { mutableStateOf("Enter username") } val password = remember { mutableStateOf("Enter password") } val navigation = remember { StackNavigation() } - val treeType = remember { mutableStateOf("Choose your tree") } + val treeType = remember { mutableStateOf("▾") } val treeName = remember { mutableStateOf("Enter tree name") } - val keyType = - remember { mutableStateOf("Choose the key type from the following options") } - val valueType = - remember { mutableStateOf("Choose the value type from the following options") } + val keyType = remember { mutableStateOf("▾") } + val valueType = remember { mutableStateOf("▾") } var treePresenter: TreePresenter? = null // for tree adding and deleting @@ -68,7 +64,7 @@ fun main() { is ScreenManager.HomeScreen -> { - when (header.value) { + when (databaseChoice.value) { "Neo4j" -> databaseMetadata.value = "Enter host" @@ -79,8 +75,8 @@ fun main() { } HomeScreen( - header, - { newHeader -> header.value = newHeader }, + databaseChoice, + { newHeader -> databaseChoice.value = newHeader }, databaseMetadata, username, password, @@ -94,7 +90,7 @@ fun main() { is ScreenManager.TreeScreen -> { - treePresenter = when (header.value) { + treePresenter = when (databaseChoice.value) { "Neo4j" -> DataBasePresenter.connectNeo4j( databaseMetadata.value, @@ -152,9 +148,9 @@ fun main() { } is ScreenManager.AddNodeScreen -> { - key.value = "Enter key" - value.value = "Enter value" - treePresenter?.let {treePresenter -> + key.value = "Enter key" + value.value = "Enter value" + treePresenter?.let { treePresenter -> AddNodeScreen( treePresenter, key, @@ -168,7 +164,7 @@ fun main() { } is ScreenManager.DeleteNodeScreen -> { - key.value = "Enter key" + key.value = "Enter key" treePresenter?.let { treePresenter -> DeleteNodeScreen( treePresenter, diff --git a/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt b/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt index 2a929d2..81b6afd 100644 --- a/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt +++ b/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt @@ -1,13 +1,14 @@ package app.view.assets import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.material.Button -import androidx.compose.material.OutlinedTextField -import androidx.compose.material.Text +import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp @Composable @@ -18,9 +19,18 @@ fun databaseConnectionJson( ) { Column(modifier = Modifier.padding(vertical = 16.dp)) { - OutlinedTextField(value = host.value, onValueChange = hostChange) + OutlinedTextField( + value = host.value, + onValueChange = hostChange, + colors = TextFieldDefaults.textFieldColors( + textColor = if (host.value == "Enter the directory name") Color.Gray else Color.Black, + backgroundColor = Color.White, + ) + ) - Button(onClick = approveChange){ + Spacer(modifier = Modifier.height(15.dp)) + + Button(onClick = approveChange) { Text("Approve") } } @@ -34,9 +44,18 @@ fun databaseConnectionSQL( ) { Column(modifier = Modifier.padding(vertical = 16.dp)) { - OutlinedTextField(value = host.value, onValueChange = hostChange) + OutlinedTextField( + value = host.value, + onValueChange = hostChange, + colors = TextFieldDefaults.textFieldColors( + textColor = if (host.value == "Enter the database name") Color.Gray else Color.Black, + backgroundColor = Color.White, + ) + ) + + Spacer(modifier = Modifier.height(15.dp)) - Button(onClick = approveChange){ + Button(onClick = approveChange) { Text("Approve") } } @@ -54,13 +73,40 @@ fun databaseConnectionNeo4j( ) { Column(modifier = Modifier.padding(vertical = 16.dp)) { - OutlinedTextField(value = host.value, onValueChange = hostChange) + OutlinedTextField( + value = host.value, + onValueChange = hostChange, + colors = TextFieldDefaults.textFieldColors( + textColor = if (host.value == "Enter host") Color.Gray else Color.Black, + backgroundColor = Color.White, + ) + ) + + Spacer(modifier = Modifier.height(10.dp)) + + OutlinedTextField( + value = username.value, + onValueChange = usernameChange, + colors = TextFieldDefaults.textFieldColors( + textColor = if (username.value == "Enter username") Color.Gray else Color.Black, + backgroundColor = Color.White, + ) + ) + + Spacer(modifier = Modifier.height(10.dp)) - OutlinedTextField(value = username.value, onValueChange = usernameChange) + OutlinedTextField( + value = password.value, + onValueChange = passwordChange, + colors = TextFieldDefaults.textFieldColors( + textColor = if (password.value == "Enter password") Color.Gray else Color.Black, + backgroundColor = Color.White, + ) + ) - OutlinedTextField(value = password.value, onValueChange = passwordChange) + Spacer(modifier = Modifier.height(15.dp)) - Button(onClick = approveChange){ + Button(onClick = approveChange) { Text("Approve") } diff --git a/app/src/main/kotlin/app/view/assets/Selector.kt b/app/src/main/kotlin/app/view/assets/Selector.kt index 999e4c5..d4e2cd6 100644 --- a/app/src/main/kotlin/app/view/assets/Selector.kt +++ b/app/src/main/kotlin/app/view/assets/Selector.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.AbsoluteRoundedCornerShape import androidx.compose.material.DropdownMenu import androidx.compose.material.DropdownMenuItem import androidx.compose.material.Text @@ -11,7 +12,6 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -19,16 +19,24 @@ import androidx.compose.ui.unit.sp fun Selector(header: State, onClickChanges: (String) -> Unit, items: List) { var expanded by remember { mutableStateOf(false) } var selectedIndex by remember { mutableStateOf(0) } - Column(horizontalAlignment = Alignment.CenterHorizontally) { + Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) { - Text( - header.value, - fontSize = 30.sp, + Row( + horizontalArrangement = if (header.value != "▾") Arrangement.Center else Arrangement.End, + verticalAlignment = Alignment.CenterVertically, modifier = Modifier .clickable(onClick = { expanded = true }) .background(Color.White) - .border(width = 1.dp, shape = RectangleShape, color = Color.Blue) - ) + .border(width = 1.dp, shape = AbsoluteRoundedCornerShape(10.dp), color = Color.Blue) + .width(300.dp) + .height(40.dp) + .absoluteOffset(if (header.value == "▾") -12.dp else 0.dp) + ) { + Text( + header.value, + fontSize = 25.sp, + ) + } DropdownMenu( expanded = expanded, diff --git a/app/src/main/kotlin/app/view/screens/ChosingTypesScreen.kt b/app/src/main/kotlin/app/view/screens/ChosingTypesScreen.kt index 9e5b020..df3ee0f 100644 --- a/app/src/main/kotlin/app/view/screens/ChosingTypesScreen.kt +++ b/app/src/main/kotlin/app/view/screens/ChosingTypesScreen.kt @@ -1,13 +1,11 @@ package app.view.screens -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.State +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import app.presenter.TreePresenter @@ -27,25 +25,34 @@ fun ChosingTypesScreen( ) { Column(modifier = Modifier.padding(16.dp)) { - Selector( - keyType, - onClickChangesKey, - listOf("Int", "String") - ) + Row(verticalAlignment = Alignment.CenterVertically) { + Text("Choose the key type from the following options:") + Spacer(modifier = Modifier.width(10.dp)) + Selector( + keyType, + onClickChangesKey, + listOf("Int", "String") + ) + } + Spacer(modifier = Modifier.height(16.dp)) - Selector( - valueType, - onClickChangesValue, - listOf("Int", "String") - ) + Row(verticalAlignment = Alignment.CenterVertically) { + Text("Choose the value type from the following options:") + Spacer(modifier = Modifier.width(10.dp)) + Selector( + valueType, + onClickChangesValue, + listOf("Int", "String") + ) + } Spacer(modifier = Modifier.height(16.dp)) if ( - keyType.value != "Choose the key type from the following options" && - valueType.value != "Choose the value type from the following options" + keyType.value != "▾" && + valueType.value != "▾" ) { Button(onClick = { treePresenter.createTree(treeName.value, treeType.value, keyType.value, valueType.value) @@ -55,7 +62,7 @@ fun ChosingTypesScreen( } } - Button(onClick = back){ + Button(onClick = back) { Text("back") } } diff --git a/app/src/main/kotlin/app/view/screens/HomeScreen.kt b/app/src/main/kotlin/app/view/screens/HomeScreen.kt index 0f21d8f..127011c 100644 --- a/app/src/main/kotlin/app/view/screens/HomeScreen.kt +++ b/app/src/main/kotlin/app/view/screens/HomeScreen.kt @@ -1,7 +1,9 @@ package app.view.screens import androidx.compose.foundation.layout.* +import androidx.compose.material.Text import androidx.compose.runtime.* +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import app.view.assets.Selector @@ -11,7 +13,7 @@ import app.view.assets.databaseConnectionSQL @Composable fun HomeScreen( - header: State, + databaseName: State, onClickChanges: (String) -> Unit, host: State, username: State, @@ -22,8 +24,13 @@ fun HomeScreen( approveChange: () -> Unit ) { Column(modifier = Modifier.padding(16.dp)) { - Selector(header, onClickChanges, listOf("Neo4j", "Json", "SQLite")) - when (header.value) { + Row(verticalAlignment = Alignment.CenterVertically) { + Text("Choose your database:") + Spacer(modifier = Modifier.width(10.dp)) + Selector(databaseName, onClickChanges, listOf("Neo4j", "Json", "SQLite")) + } + + when (databaseName.value) { "Neo4j" -> databaseConnectionNeo4j( host, username, diff --git a/app/src/main/kotlin/app/view/screens/TreeScreen.kt b/app/src/main/kotlin/app/view/screens/TreeScreen.kt index f039962..7927e7f 100644 --- a/app/src/main/kotlin/app/view/screens/TreeScreen.kt +++ b/app/src/main/kotlin/app/view/screens/TreeScreen.kt @@ -1,12 +1,11 @@ package app.view.screens -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.material.* import androidx.compose.runtime.* +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import app.presenter.TreePresenter import app.view.assets.Selector @@ -18,24 +17,32 @@ fun TreeActions( treeType: State, createTreeMenu: () -> Unit, treeView: () -> Unit, - ) { +) { Column { - Button(onClick = { - createTreeMenu() - } + Spacer(modifier = Modifier.height(8.dp)) + + Button( + onClick = { createTreeMenu() }, + modifier = Modifier.width(150.dp) ) { Text("Create Tree") } - Button(onClick = { - treePresenter.loadTree(treeName.value, treeType.value) - treeView() - } + Spacer(modifier = Modifier.height(8.dp)) + + Button( + onClick = { + treePresenter.loadTree(treeName.value, treeType.value) + treeView() + }, + modifier = Modifier.width(150.dp) ) { Text("Load Tree") } + + Spacer(modifier = Modifier.height(8.dp)) } } @@ -51,15 +58,28 @@ fun TreeSreen( treeView: () -> Unit ) { Column(modifier = Modifier.padding(16.dp)) { - Selector(treeType, onClickChanges, listOf("BS", "AVL", "RB")) - if (treeType.value != "Choose your tree") { + Row(verticalAlignment = Alignment.CenterVertically) { + Text("Choose your tree:") + Spacer(modifier = Modifier.width(10.dp)) + Selector(treeType, onClickChanges, listOf("BS", "AVL", "RB")) + } + + if (treeType.value != "▾") { Spacer(modifier = Modifier.height(16.dp)) - OutlinedTextField(value = treeName.value, onValueChange = treeNameChange) + OutlinedTextField( + value = treeName.value, + onValueChange = treeNameChange, + colors = TextFieldDefaults.textFieldColors( + textColor = if (treeName.value == "Enter tree name") Color.Gray else Color.Black, + backgroundColor = Color.White, + ) + ) + Spacer(modifier = Modifier.height(8.dp)) TreeActions(treePresenter, treeName, treeType, createTreeMenu, treeView) } - Button(onClick = back) { + Button(onClick = back, modifier = Modifier.width(150.dp)) { Text("Back") } } From 52b1b2cdee5892069477e82adc02d24b2bc06c58 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Wed, 3 May 2023 01:11:31 +0300 Subject: [PATCH 126/135] feat: Small code refactoring --- .../kotlin/app/presenter/LayoutPresenter.kt | 6 +-- .../main/kotlin/app/view/assets/TreeView.kt | 38 ++++++++----------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/app/src/main/kotlin/app/presenter/LayoutPresenter.kt b/app/src/main/kotlin/app/presenter/LayoutPresenter.kt index f2f4f24..67fa20d 100644 --- a/app/src/main/kotlin/app/presenter/LayoutPresenter.kt +++ b/app/src/main/kotlin/app/presenter/LayoutPresenter.kt @@ -8,7 +8,7 @@ object LayoutPresenter { private const val windowHeight = 800 private const val windowWidth = 800 - private const val nodeRadius = 30 + private const val nodeSize = 30 private const val edgeLength = 10 @@ -27,8 +27,8 @@ object LayoutPresenter { // This method will assign coordinates to the nodes of the tree private fun setNodesLayout(node: NodeData, height: Int){ - val xDiff = (edgeLength + 2 * nodeRadius) * height + (height - 1) - val yDiff = (edgeLength + 2 * nodeRadius) * 3 + val xDiff = (edgeLength + 2 * nodeSize) * height + (height - 1) + val yDiff = (edgeLength + 2 * nodeSize) * 3 node.leftNode?.let {leftNode-> leftNode.posX = node.posX - xDiff leftNode.posY = node.posY + yDiff diff --git a/app/src/main/kotlin/app/view/assets/TreeView.kt b/app/src/main/kotlin/app/view/assets/TreeView.kt index f5ca3a5..ac7e513 100644 --- a/app/src/main/kotlin/app/view/assets/TreeView.kt +++ b/app/src/main/kotlin/app/view/assets/TreeView.kt @@ -13,7 +13,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.positionChange import androidx.compose.ui.unit.IntOffset @@ -21,35 +20,27 @@ import androidx.compose.ui.unit.dp import app.presenter.LayoutPresenter import app.presenter.TreePresenter import bstrees.model.dataBases.NodeData -import bstrees.model.dataBases.TreeData -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.sp const val NODE_SIZE = 30 +const val WINDOW_SIZE = 800 -@Composable -fun Dp.dpToPx() = with(LocalDensity.current) { this@dpToPx.toPx() } - - -@Composable -fun Int.pxToDp() = with(LocalDensity.current) { this@pxToDp.toDp() } - @Composable fun Tree( node: State, ) { - val nodeCoords = remember { mutableStateOf(Pair(node.value.posX.toFloat(), node.value.posY.toFloat())) } + val nodeCoords = remember { mutableStateOf(Pair( + node.value.posX.toFloat(), node.value.posY.toFloat())) } - node.value.leftNode?.let { it -> - Edge(node, mutableStateOf(it)) + node.value.leftNode?.let { leftNode -> + Edge(node, mutableStateOf(leftNode)) } - node.value.rightNode?.let { it -> - Edge(node, mutableStateOf(it)) + node.value.rightNode?.let { rightNode -> + Edge(node, mutableStateOf(rightNode)) } node.value.leftNode?.let { leftNode -> Tree(mutableStateOf(leftNode)) @@ -73,7 +64,6 @@ fun TreeNode(node: State, nodeCoords: MutableState> .background(Color.Red, CircleShape) .size(NODE_SIZE.dp) .pointerInput(Unit) { - // Обработчик перемещения узла detectDragGestures { change, dragAmount -> nodeCoords.value = Pair( nodeCoords.value.first + dragAmount.x, @@ -124,13 +114,13 @@ fun Edge( modifier: Modifier = Modifier ) { Canvas( - modifier = modifier.size(800.dp), + modifier = modifier.size(WINDOW_SIZE.dp), onDraw = { drawLine( start = Offset(x = node1.value.posX.toFloat() + NODE_SIZE, y = node1.value.posY.toFloat() + NODE_SIZE), end = Offset(x = node2.value.posX.toFloat() + NODE_SIZE, y = node2.value.posY.toFloat() + NODE_SIZE), color = Color.Black, - strokeWidth = 5F + strokeWidth = 3F ) } ) @@ -150,7 +140,7 @@ fun TreeActionButtons( Text("Add Node") } - Spacer(modifier = Modifier.width(30.dp)) + Spacer(modifier = Modifier.width(NODE_SIZE.dp)) Button(onClick = { deleteNode() @@ -158,7 +148,7 @@ fun TreeActionButtons( Text(text = "Delete Node") } - Spacer(modifier = Modifier.width(30.dp)) + Spacer(modifier = Modifier.width(NODE_SIZE.dp)) Button(onClick = { treePresenter.saveTree() @@ -175,13 +165,15 @@ fun TreeView( deleteNode: () -> Unit, ) { val tree = treePresenter.tree - LayoutPresenter.setTreeLayout(tree, 800, 800) + LayoutPresenter.setTreeLayout(tree, WINDOW_SIZE, WINDOW_SIZE) Column { TreeActionButtons(treePresenter, addNode, deleteNode) Box( - modifier = Modifier.height(800.dp).width(800.dp), + modifier = Modifier.height(WINDOW_SIZE.dp).width(WINDOW_SIZE.dp), + ) { + tree.root?.let { root -> Tree( mutableStateOf(root) From f1d6669c8afa34552463584ee0b6dfe6b66006ef Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Wed, 3 May 2023 01:50:00 +0300 Subject: [PATCH 127/135] fix: Some appearance changes. Added enum classes for databases names and trees names --- app/src/main/kotlin/app/view/App.kt | 35 +++++++++---------- .../app/view/assets/DatabaseConnections.kt | 26 +++++++------- .../kotlin/app/view/screens/HomeScreen.kt | 19 +++++----- .../{TreeScreen.kt => TreeChosingScreen.kt} | 5 +-- .../main/kotlin/app/view/utils/Databases.kt | 7 ++++ app/src/main/kotlin/app/view/utils/Trees.kt | 7 ++++ 6 files changed, 59 insertions(+), 40 deletions(-) rename app/src/main/kotlin/app/view/screens/{TreeScreen.kt => TreeChosingScreen.kt} (93%) create mode 100644 app/src/main/kotlin/app/view/utils/Databases.kt create mode 100644 app/src/main/kotlin/app/view/utils/Trees.kt diff --git a/app/src/main/kotlin/app/view/App.kt b/app/src/main/kotlin/app/view/App.kt index 3214919..d6a6efc 100644 --- a/app/src/main/kotlin/app/view/App.kt +++ b/app/src/main/kotlin/app/view/App.kt @@ -6,6 +6,7 @@ import androidx.compose.ui.window.* import app.presenter.DataBasePresenter import app.presenter.TreePresenter import app.view.assets.ChildStack +import app.view.utils.Databases import app.view.assets.ProvideComponentContext import app.view.assets.TreeView import app.view.screens.* @@ -41,13 +42,14 @@ fun main() { val databaseChoice = remember { mutableStateOf("▾") } val databaseMetadata = remember { mutableStateOf("") } - val username = remember { mutableStateOf("Enter username") } - val password = remember { mutableStateOf("Enter password") } + val username = remember { mutableStateOf("") } + val password = remember { mutableStateOf("") } val navigation = remember { StackNavigation() } val treeType = remember { mutableStateOf("▾") } val treeName = remember { mutableStateOf("Enter tree name") } val keyType = remember { mutableStateOf("▾") } val valueType = remember { mutableStateOf("▾") } + var isDirectoryNameWritten = true var treePresenter: TreePresenter? = null // for tree adding and deleting @@ -64,26 +66,23 @@ fun main() { is ScreenManager.HomeScreen -> { - when (databaseChoice.value) { - - "Neo4j" -> databaseMetadata.value = "Enter host" - - "Json" -> databaseMetadata.value = "Enter the directory name" - - "SQLite" -> databaseMetadata.value = "Enter the database name" - - } - HomeScreen( databaseChoice, { newHeader -> databaseChoice.value = newHeader }, databaseMetadata, username, password, - { newMeta -> databaseMetadata.value = newMeta }, + { newMeta -> + databaseMetadata.value = + if (databaseMetadata.value == "" && databaseChoice.value == "Json" && !isDirectoryNameWritten) "JsonDir" + else newMeta + }, { newUsername -> username.value = newUsername }, { newPassword -> password.value = newPassword }, - { navigation.push(ScreenManager.TreeScreen) } + { + navigation.push(ScreenManager.TreeScreen) + if (databaseMetadata.value == "") isDirectoryNameWritten = false + } ) } @@ -92,22 +91,22 @@ fun main() { treePresenter = when (databaseChoice.value) { - "Neo4j" -> DataBasePresenter.connectNeo4j( + Databases.Neo4j.toString() -> DataBasePresenter.connectNeo4j( databaseMetadata.value, username.value, password.value ) - "Json" -> DataBasePresenter.connectJson(databaseMetadata.value) + Databases.Json.toString() -> DataBasePresenter.connectJson(databaseMetadata.value) - "SQLite" -> DataBasePresenter.connectSQL(databaseMetadata.value) + Databases.SQLite.toString() -> DataBasePresenter.connectSQL(databaseMetadata.value) else -> throw Exception("Incorrect database") } treePresenter?.let { treePresenter -> - TreeSreen( + TreeChoosingScreen( treeType, { newHeader -> treeType.value = newHeader }, treePresenter, diff --git a/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt b/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt index 81b6afd..8ae4b41 100644 --- a/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt +++ b/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt @@ -13,19 +13,17 @@ import androidx.compose.ui.unit.dp @Composable fun databaseConnectionJson( - host: State, + directory: State, hostChange: (String) -> Unit, approveChange: () -> Unit ) { Column(modifier = Modifier.padding(vertical = 16.dp)) { OutlinedTextField( - value = host.value, + value = directory.value, onValueChange = hostChange, - colors = TextFieldDefaults.textFieldColors( - textColor = if (host.value == "Enter the directory name") Color.Gray else Color.Black, - backgroundColor = Color.White, - ) + label = { Text("Enter the directory name") }, + placeholder = { Text("JsonDir") } ) Spacer(modifier = Modifier.height(15.dp)) @@ -38,17 +36,18 @@ fun databaseConnectionJson( @Composable fun databaseConnectionSQL( - host: State, + name: State, hostChange: (String) -> Unit, approveChange: () -> Unit ) { Column(modifier = Modifier.padding(vertical = 16.dp)) { OutlinedTextField( - value = host.value, + value = name.value, onValueChange = hostChange, + label = { Text("Enter the database name") }, colors = TextFieldDefaults.textFieldColors( - textColor = if (host.value == "Enter the database name") Color.Gray else Color.Black, + textColor = if (name.value == "Enter the database name") Color.Gray else Color.Black, backgroundColor = Color.White, ) ) @@ -63,7 +62,7 @@ fun databaseConnectionSQL( @Composable fun databaseConnectionNeo4j( - host: State, + databaseMetadata: State, username: State, password: State, hostChange: (String) -> Unit, @@ -74,10 +73,11 @@ fun databaseConnectionNeo4j( Column(modifier = Modifier.padding(vertical = 16.dp)) { OutlinedTextField( - value = host.value, + value = databaseMetadata.value, onValueChange = hostChange, + label = { Text("Enter host") }, colors = TextFieldDefaults.textFieldColors( - textColor = if (host.value == "Enter host") Color.Gray else Color.Black, + textColor = if (databaseMetadata.value == "Enter host") Color.Gray else Color.Black, backgroundColor = Color.White, ) ) @@ -87,6 +87,7 @@ fun databaseConnectionNeo4j( OutlinedTextField( value = username.value, onValueChange = usernameChange, + label = { Text("Enter username") }, colors = TextFieldDefaults.textFieldColors( textColor = if (username.value == "Enter username") Color.Gray else Color.Black, backgroundColor = Color.White, @@ -98,6 +99,7 @@ fun databaseConnectionNeo4j( OutlinedTextField( value = password.value, onValueChange = passwordChange, + label = { Text("Enter password") }, colors = TextFieldDefaults.textFieldColors( textColor = if (password.value == "Enter password") Color.Gray else Color.Black, backgroundColor = Color.White, diff --git a/app/src/main/kotlin/app/view/screens/HomeScreen.kt b/app/src/main/kotlin/app/view/screens/HomeScreen.kt index 127011c..270852d 100644 --- a/app/src/main/kotlin/app/view/screens/HomeScreen.kt +++ b/app/src/main/kotlin/app/view/screens/HomeScreen.kt @@ -6,10 +6,8 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import app.view.assets.Selector -import app.view.assets.databaseConnectionJson -import app.view.assets.databaseConnectionNeo4j -import app.view.assets.databaseConnectionSQL +import app.view.assets.* +import app.view.utils.Databases @Composable fun HomeScreen( @@ -27,11 +25,16 @@ fun HomeScreen( Row(verticalAlignment = Alignment.CenterVertically) { Text("Choose your database:") Spacer(modifier = Modifier.width(10.dp)) - Selector(databaseName, onClickChanges, listOf("Neo4j", "Json", "SQLite")) + Selector( + databaseName, + onClickChanges, + listOf(Databases.Neo4j.toString(), Databases.Json.toString(), Databases.SQLite.toString()) + ) } when (databaseName.value) { - "Neo4j" -> databaseConnectionNeo4j( + + Databases.Neo4j.toString() -> databaseConnectionNeo4j( host, username, password, @@ -41,13 +44,13 @@ fun HomeScreen( approveChange ) - "Json" -> databaseConnectionJson( + Databases.Json.toString() -> databaseConnectionJson( host, hostChange, approveChange ) - "SQLite" -> databaseConnectionSQL( + Databases.SQLite.toString() -> databaseConnectionSQL( host, hostChange, approveChange diff --git a/app/src/main/kotlin/app/view/screens/TreeScreen.kt b/app/src/main/kotlin/app/view/screens/TreeChosingScreen.kt similarity index 93% rename from app/src/main/kotlin/app/view/screens/TreeScreen.kt rename to app/src/main/kotlin/app/view/screens/TreeChosingScreen.kt index 7927e7f..f5f80a2 100644 --- a/app/src/main/kotlin/app/view/screens/TreeScreen.kt +++ b/app/src/main/kotlin/app/view/screens/TreeChosingScreen.kt @@ -9,6 +9,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import app.presenter.TreePresenter import app.view.assets.Selector +import app.view.utils.Trees @Composable fun TreeActions( @@ -47,7 +48,7 @@ fun TreeActions( } @Composable -fun TreeSreen( +fun TreeChoosingScreen( treeType: State, onClickChanges: (String) -> Unit, treePresenter: TreePresenter, @@ -62,7 +63,7 @@ fun TreeSreen( Row(verticalAlignment = Alignment.CenterVertically) { Text("Choose your tree:") Spacer(modifier = Modifier.width(10.dp)) - Selector(treeType, onClickChanges, listOf("BS", "AVL", "RB")) + Selector(treeType, onClickChanges, listOf(Trees.BS.toString(), Trees.RB.toString(), Trees.AVL.toString())) } if (treeType.value != "▾") { diff --git a/app/src/main/kotlin/app/view/utils/Databases.kt b/app/src/main/kotlin/app/view/utils/Databases.kt new file mode 100644 index 0000000..a4e301e --- /dev/null +++ b/app/src/main/kotlin/app/view/utils/Databases.kt @@ -0,0 +1,7 @@ +package app.view.utils + +enum class Databases { + Neo4j, + Json, + SQLite +} diff --git a/app/src/main/kotlin/app/view/utils/Trees.kt b/app/src/main/kotlin/app/view/utils/Trees.kt new file mode 100644 index 0000000..86b2985 --- /dev/null +++ b/app/src/main/kotlin/app/view/utils/Trees.kt @@ -0,0 +1,7 @@ +package app.view.utils + +enum class Trees { + RB, + AVL, + BS +} \ No newline at end of file From 28db69461f9cf69b79bf455082ceb85d6151c7ad Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Wed, 3 May 2023 02:27:34 +0300 Subject: [PATCH 128/135] fix: Changed directories --- app/src/main/kotlin/app/view/App.kt | 13 +- .../app/view/assets/DatabaseConnections.kt | 2 +- .../main/kotlin/app/view/assets/TreeView.kt | 185 ------------------ .../app/view/screens/TreeChosingScreen.kt | 6 +- .../kotlin/app/view/screens/TreeScreen.kt | 71 +++++++ app/src/main/kotlin/app/view/treeView/Edge.kt | 32 +++ app/src/main/kotlin/app/view/treeView/Node.kt | 76 +++++++ app/src/main/kotlin/app/view/treeView/Tree.kt | 31 +++ 8 files changed, 221 insertions(+), 195 deletions(-) delete mode 100644 app/src/main/kotlin/app/view/assets/TreeView.kt create mode 100644 app/src/main/kotlin/app/view/screens/TreeScreen.kt create mode 100644 app/src/main/kotlin/app/view/treeView/Edge.kt create mode 100644 app/src/main/kotlin/app/view/treeView/Node.kt create mode 100644 app/src/main/kotlin/app/view/treeView/Tree.kt diff --git a/app/src/main/kotlin/app/view/App.kt b/app/src/main/kotlin/app/view/App.kt index d6a6efc..07039b8 100644 --- a/app/src/main/kotlin/app/view/App.kt +++ b/app/src/main/kotlin/app/view/App.kt @@ -8,7 +8,7 @@ import app.presenter.TreePresenter import app.view.assets.ChildStack import app.view.utils.Databases import app.view.assets.ProvideComponentContext -import app.view.assets.TreeView +import app.view.screens.TreeView import app.view.screens.* import com.arkivanov.decompose.DefaultComponentContext import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.fade @@ -46,7 +46,7 @@ fun main() { val password = remember { mutableStateOf("") } val navigation = remember { StackNavigation() } val treeType = remember { mutableStateOf("▾") } - val treeName = remember { mutableStateOf("Enter tree name") } + val treeName = remember { mutableStateOf("") } val keyType = remember { mutableStateOf("▾") } val valueType = remember { mutableStateOf("▾") } var isDirectoryNameWritten = true @@ -74,14 +74,19 @@ fun main() { password, { newMeta -> databaseMetadata.value = - if (databaseMetadata.value == "" && databaseChoice.value == "Json" && !isDirectoryNameWritten) "JsonDir" + if ( + databaseMetadata.value == "" && + databaseChoice.value == Databases.Json.toString() && + !isDirectoryNameWritten + ) + "jsondir" else newMeta }, { newUsername -> username.value = newUsername }, { newPassword -> password.value = newPassword }, { - navigation.push(ScreenManager.TreeScreen) if (databaseMetadata.value == "") isDirectoryNameWritten = false + navigation.push(ScreenManager.TreeScreen) } ) diff --git a/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt b/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt index 8ae4b41..6c9469c 100644 --- a/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt +++ b/app/src/main/kotlin/app/view/assets/DatabaseConnections.kt @@ -23,7 +23,7 @@ fun databaseConnectionJson( value = directory.value, onValueChange = hostChange, label = { Text("Enter the directory name") }, - placeholder = { Text("JsonDir") } + placeholder = { Text("jsondir") } ) Spacer(modifier = Modifier.height(15.dp)) diff --git a/app/src/main/kotlin/app/view/assets/TreeView.kt b/app/src/main/kotlin/app/view/assets/TreeView.kt deleted file mode 100644 index ac7e513..0000000 --- a/app/src/main/kotlin/app/view/assets/TreeView.kt +++ /dev/null @@ -1,185 +0,0 @@ -package app.view.assets - -import androidx.compose.foundation.Canvas -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.gestures.* -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material.Button -import androidx.compose.material.Text -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.pointer.pointerInput -import androidx.compose.ui.input.pointer.positionChange -import androidx.compose.ui.unit.IntOffset -import androidx.compose.ui.unit.dp -import app.presenter.LayoutPresenter -import app.presenter.TreePresenter -import bstrees.model.dataBases.NodeData -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.sp - - -const val NODE_SIZE = 30 -const val WINDOW_SIZE = 800 - - -@Composable -fun Tree( - node: State, -) { - - val nodeCoords = remember { mutableStateOf(Pair( - node.value.posX.toFloat(), node.value.posY.toFloat())) } - - node.value.leftNode?.let { leftNode -> - Edge(node, mutableStateOf(leftNode)) - } - node.value.rightNode?.let { rightNode -> - Edge(node, mutableStateOf(rightNode)) - } - node.value.leftNode?.let { leftNode -> - Tree(mutableStateOf(leftNode)) - } - node.value.rightNode?.let { rightNode -> - Tree(mutableStateOf(rightNode)) - } - - TreeNode(node, nodeCoords) -} - - -@Composable -fun TreeNode(node: State, nodeCoords: MutableState>) { - node.value.posX = nodeCoords.value.first.toInt() - node.value.posY = nodeCoords.value.second.toInt() - Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .offset { IntOffset(nodeCoords.value.first.toInt(), nodeCoords.value.second.toInt()) } - .background(Color.Red, CircleShape) - .size(NODE_SIZE.dp) - .pointerInput(Unit) { - detectDragGestures { change, dragAmount -> - nodeCoords.value = Pair( - nodeCoords.value.first + dragAmount.x, - nodeCoords.value.second + dragAmount.y - ) - if (change.positionChange() != Offset.Zero) change.consume() - } - } - .background( - color = if (node.value.metadata == "RED") Color.Red - else if (node.value.metadata == "BLACK") Color.Black - else Color.Magenta, - shape = CircleShape - ) - .width(NODE_SIZE.dp) - .height(NODE_SIZE.dp) - .border( - width = 1.dp, - color = Color.Blue, - shape = CircleShape - ) - - ) { - Column( - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text( - text = "Key: ${node.value.key}", - textAlign = TextAlign.Center, - color = Color.White, - fontSize = if (((NODE_SIZE / 4)) > 20) 20.sp else (NODE_SIZE / 4).sp - ) - Text( - text = "Value: ${node.value.value}", - textAlign = TextAlign.Center, - color = Color.White, - fontSize = if (((NODE_SIZE / 4)) > 20) 20.sp else (NODE_SIZE / 4).sp - ) - } - } -} - - -@Composable -fun Edge( - node1: State, - node2: State, - modifier: Modifier = Modifier -) { - Canvas( - modifier = modifier.size(WINDOW_SIZE.dp), - onDraw = { - drawLine( - start = Offset(x = node1.value.posX.toFloat() + NODE_SIZE, y = node1.value.posY.toFloat() + NODE_SIZE), - end = Offset(x = node2.value.posX.toFloat() + NODE_SIZE, y = node2.value.posY.toFloat() + NODE_SIZE), - color = Color.Black, - strokeWidth = 3F - ) - } - ) -} - -@Composable -fun TreeActionButtons( - treePresenter: TreePresenter, - addNode: () -> Unit, - deleteNode: () -> Unit, -) { - - Row { - Button(onClick = { - addNode() - }) { - Text("Add Node") - } - - Spacer(modifier = Modifier.width(NODE_SIZE.dp)) - - Button(onClick = { - deleteNode() - }) { - Text(text = "Delete Node") - } - - Spacer(modifier = Modifier.width(NODE_SIZE.dp)) - - Button(onClick = { - treePresenter.saveTree() - }) { - Text(text = "Save tree") - } - } -} - -@Composable -fun TreeView( - treePresenter: TreePresenter, - addNode: () -> Unit, - deleteNode: () -> Unit, -) { - val tree = treePresenter.tree - LayoutPresenter.setTreeLayout(tree, WINDOW_SIZE, WINDOW_SIZE) - Column { - TreeActionButtons(treePresenter, addNode, deleteNode) - - Box( - modifier = Modifier.height(WINDOW_SIZE.dp).width(WINDOW_SIZE.dp), - - ) { - - tree.root?.let { root -> - Tree( - mutableStateOf(root) - ) - } - } - } -} - diff --git a/app/src/main/kotlin/app/view/screens/TreeChosingScreen.kt b/app/src/main/kotlin/app/view/screens/TreeChosingScreen.kt index f5f80a2..19a438e 100644 --- a/app/src/main/kotlin/app/view/screens/TreeChosingScreen.kt +++ b/app/src/main/kotlin/app/view/screens/TreeChosingScreen.kt @@ -5,7 +5,6 @@ import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import app.presenter.TreePresenter import app.view.assets.Selector @@ -71,10 +70,7 @@ fun TreeChoosingScreen( OutlinedTextField( value = treeName.value, onValueChange = treeNameChange, - colors = TextFieldDefaults.textFieldColors( - textColor = if (treeName.value == "Enter tree name") Color.Gray else Color.Black, - backgroundColor = Color.White, - ) + label = { Text("Enter the tree name") }, ) Spacer(modifier = Modifier.height(8.dp)) TreeActions(treePresenter, treeName, treeType, createTreeMenu, treeView) diff --git a/app/src/main/kotlin/app/view/screens/TreeScreen.kt b/app/src/main/kotlin/app/view/screens/TreeScreen.kt new file mode 100644 index 0000000..cf66d62 --- /dev/null +++ b/app/src/main/kotlin/app/view/screens/TreeScreen.kt @@ -0,0 +1,71 @@ +package app.view.screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import app.presenter.LayoutPresenter +import app.presenter.TreePresenter +import app.view.treeView.Tree + + +const val NODE_SIZE = 30 +const val WINDOW_SIZE = 800 + +@Composable +fun TreeActionButtons( + treePresenter: TreePresenter, + addNode: () -> Unit, + deleteNode: () -> Unit, +) { + + Row(modifier = Modifier.background(Color.Cyan).fillMaxWidth(), horizontalArrangement = Arrangement.Center) { + Button(onClick = addNode) { + Text("Add Node") + } + + Spacer(modifier = Modifier.width(NODE_SIZE.dp)) + + Button(onClick = deleteNode) { + Text(text = "Delete Node") + } + + Spacer(modifier = Modifier.width(NODE_SIZE.dp)) + + Button(onClick = { + treePresenter.saveTree() + }) { + Text(text = "Save tree") + } + } +} + +@Composable +fun TreeView( + treePresenter: TreePresenter, + addNode: () -> Unit, + deleteNode: () -> Unit, +) { + val tree = treePresenter.tree + LayoutPresenter.setTreeLayout(tree, WINDOW_SIZE, WINDOW_SIZE) + Column { + TreeActionButtons(treePresenter, addNode, deleteNode) + + Box( + modifier = Modifier.height(WINDOW_SIZE.dp).width(WINDOW_SIZE.dp), + + ) { + + tree.root?.let { root -> + Tree( + mutableStateOf(root) + ) + } + } + } +} + diff --git a/app/src/main/kotlin/app/view/treeView/Edge.kt b/app/src/main/kotlin/app/view/treeView/Edge.kt new file mode 100644 index 0000000..1f9155c --- /dev/null +++ b/app/src/main/kotlin/app/view/treeView/Edge.kt @@ -0,0 +1,32 @@ +package app.view.treeView + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import app.view.screens.NODE_SIZE +import app.view.screens.WINDOW_SIZE +import bstrees.model.dataBases.NodeData + +@Composable +fun Edge( + node1: State, + node2: State, + modifier: Modifier = Modifier +) { + Canvas( + modifier = modifier.size(WINDOW_SIZE.dp), + onDraw = { + drawLine( + start = Offset(x = node1.value.posX.toFloat() + NODE_SIZE, y = node1.value.posY.toFloat() + NODE_SIZE), + end = Offset(x = node2.value.posX.toFloat() + NODE_SIZE, y = node2.value.posY.toFloat() + NODE_SIZE), + color = Color.Black, + strokeWidth = 3F + ) + } + ) +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/treeView/Node.kt b/app/src/main/kotlin/app/view/treeView/Node.kt new file mode 100644 index 0000000..c410683 --- /dev/null +++ b/app/src/main/kotlin/app/view/treeView/Node.kt @@ -0,0 +1,76 @@ +package app.view.treeView + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.gestures.detectDragGestures +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.State +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.input.pointer.positionChange +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import app.view.screens.NODE_SIZE +import bstrees.model.dataBases.NodeData + +@Composable +fun Node(node: State, nodeCoords: MutableState>) { + node.value.posX = nodeCoords.value.first.toInt() + node.value.posY = nodeCoords.value.second.toInt() + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .offset { IntOffset(nodeCoords.value.first.toInt(), nodeCoords.value.second.toInt()) } + .background(Color.Red, CircleShape) + .size(NODE_SIZE.dp) + .pointerInput(Unit) { + detectDragGestures { change, dragAmount -> + nodeCoords.value = Pair( + nodeCoords.value.first + dragAmount.x, + nodeCoords.value.second + dragAmount.y + ) + if (change.positionChange() != Offset.Zero) change.consume() + } + } + .background( + color = if (node.value.metadata == "RED") Color.Red + else if (node.value.metadata == "BLACK") Color.Black + else Color.Magenta, + shape = CircleShape + ) + .width(NODE_SIZE.dp) + .height(NODE_SIZE.dp) + .border( + width = 1.dp, + color = Color.Blue, + shape = CircleShape + ) + + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "Key: ${node.value.key}", + textAlign = TextAlign.Center, + color = Color.White, + fontSize = if (((NODE_SIZE / 4)) > 20) 20.sp else (NODE_SIZE / 4).sp + ) + Text( + text = "Value: ${node.value.value}", + textAlign = TextAlign.Center, + color = Color.White, + fontSize = if (((NODE_SIZE / 4)) > 20) 20.sp else (NODE_SIZE / 4).sp + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/treeView/Tree.kt b/app/src/main/kotlin/app/view/treeView/Tree.kt new file mode 100644 index 0000000..cc7ebba --- /dev/null +++ b/app/src/main/kotlin/app/view/treeView/Tree.kt @@ -0,0 +1,31 @@ +package app.view.treeView + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import bstrees.model.dataBases.NodeData + +@Composable +fun Tree( + node: State, +) { + + val nodeCoords = remember { mutableStateOf(Pair( + node.value.posX.toFloat(), node.value.posY.toFloat())) } + + node.value.leftNode?.let { leftNode -> + Edge(node, mutableStateOf(leftNode)) + } + node.value.rightNode?.let { rightNode -> + Edge(node, mutableStateOf(rightNode)) + } + node.value.leftNode?.let { leftNode -> + Tree(mutableStateOf(leftNode)) + } + node.value.rightNode?.let { rightNode -> + Tree(mutableStateOf(rightNode)) + } + + Node(node, nodeCoords) +} From 9bb834c3f4ae7fe55035cea6e99f3038437404f7 Mon Sep 17 00:00:00 2001 From: LeonidElkin <113133848+LeonidElkin@users.noreply.github.com> Date: Wed, 3 May 2023 02:31:52 +0300 Subject: [PATCH 129/135] fix: Renamed files --- app/src/main/kotlin/app/view/App.kt | 16 ++++++++-------- .../kotlin/app/view/screens/ScreenManager.kt | 6 +++--- ...singTypesScreen.kt => TypesChoosingScreen.kt} | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) rename app/src/main/kotlin/app/view/screens/{ChosingTypesScreen.kt => TypesChoosingScreen.kt} (98%) diff --git a/app/src/main/kotlin/app/view/App.kt b/app/src/main/kotlin/app/view/App.kt index 07039b8..3934634 100644 --- a/app/src/main/kotlin/app/view/App.kt +++ b/app/src/main/kotlin/app/view/App.kt @@ -86,13 +86,13 @@ fun main() { { newPassword -> password.value = newPassword }, { if (databaseMetadata.value == "") isDirectoryNameWritten = false - navigation.push(ScreenManager.TreeScreen) + navigation.push(ScreenManager.TreeChoosingScreen) } ) } - is ScreenManager.TreeScreen -> { + is ScreenManager.TreeChoosingScreen -> { treePresenter = when (databaseChoice.value) { @@ -118,16 +118,16 @@ fun main() { treeName = treeName, { newName -> treeName.value = newName }, back = navigation::pop, - { navigation.push(ScreenManager.ChosingTypesScreen) }, - { navigation.push(ScreenManager.TreeView) } + { navigation.push(ScreenManager.TypesChoosingScreen) }, + { navigation.push(ScreenManager.TreeScreen) } ) } } - is ScreenManager.ChosingTypesScreen -> { + is ScreenManager.TypesChoosingScreen -> { treePresenter?.let { treePresenter -> - ChosingTypesScreen( + TypesChoosingScreen( treePresenter, treeName, treeType, @@ -136,12 +136,12 @@ fun main() { { newKeyType -> keyType.value = newKeyType }, { newValueType -> valueType.value = newValueType }, back = navigation::pop, - approve = { navigation.push(ScreenManager.TreeView) } + approve = { navigation.push(ScreenManager.TreeScreen) } ) } } - is ScreenManager.TreeView -> { + is ScreenManager.TreeScreen -> { treePresenter?.let { treePresenter -> TreeView( treePresenter, diff --git a/app/src/main/kotlin/app/view/screens/ScreenManager.kt b/app/src/main/kotlin/app/view/screens/ScreenManager.kt index 1a31f50..360d4d1 100644 --- a/app/src/main/kotlin/app/view/screens/ScreenManager.kt +++ b/app/src/main/kotlin/app/view/screens/ScreenManager.kt @@ -9,13 +9,13 @@ sealed class ScreenManager : Parcelable { object HomeScreen : ScreenManager() @Parcelize - object TreeScreen : ScreenManager() + object TreeChoosingScreen : ScreenManager() @Parcelize - object ChosingTypesScreen: ScreenManager() + object TypesChoosingScreen: ScreenManager() @Parcelize - object TreeView: ScreenManager() + object TreeScreen: ScreenManager() @Parcelize object AddNodeScreen: ScreenManager() diff --git a/app/src/main/kotlin/app/view/screens/ChosingTypesScreen.kt b/app/src/main/kotlin/app/view/screens/TypesChoosingScreen.kt similarity index 98% rename from app/src/main/kotlin/app/view/screens/ChosingTypesScreen.kt rename to app/src/main/kotlin/app/view/screens/TypesChoosingScreen.kt index df3ee0f..6399609 100644 --- a/app/src/main/kotlin/app/view/screens/ChosingTypesScreen.kt +++ b/app/src/main/kotlin/app/view/screens/TypesChoosingScreen.kt @@ -12,7 +12,7 @@ import app.presenter.TreePresenter import app.view.assets.Selector @Composable -fun ChosingTypesScreen( +fun TypesChoosingScreen( treePresenter: TreePresenter, treeName: State, treeType: State, From 915b0aab444d8a2f8d7b34f2b0ab8a523aa61da8 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Wed, 3 May 2023 02:51:11 +0300 Subject: [PATCH 130/135] feat: Added an algorithm for drawing a tree --- .../kotlin/app/presenter/LayoutPresenter.kt | 32 +++++++++++-------- .../kotlin/app/view/screens/TreeScreen.kt | 22 +++++++------ app/src/main/kotlin/app/view/treeView/Edge.kt | 6 ++-- app/src/main/kotlin/app/view/treeView/Node.kt | 12 +++---- 4 files changed, 41 insertions(+), 31 deletions(-) diff --git a/app/src/main/kotlin/app/presenter/LayoutPresenter.kt b/app/src/main/kotlin/app/presenter/LayoutPresenter.kt index 67fa20d..e6acfad 100644 --- a/app/src/main/kotlin/app/presenter/LayoutPresenter.kt +++ b/app/src/main/kotlin/app/presenter/LayoutPresenter.kt @@ -3,45 +3,51 @@ package app.presenter import bstrees.model.dataBases.NodeData import bstrees.model.dataBases.TreeData import app.presenter.utils.TreeHeightPresenter +import kotlin.math.pow object LayoutPresenter { private const val windowHeight = 800 private const val windowWidth = 800 - private const val nodeSize = 30 - private const val edgeLength = 10 + private var edgeLengthY = 10 - fun setTreeLayout(tree: TreeData, windowHeight: Int, windowWidth: Int){ + fun getNodeSize(tree: TreeData): Int{ + val treeHeight = TreeHeightPresenter.getTreeHeight(tree) + return windowHeight / 5 / (treeHeight + 1) + } + + fun setTreeLayout(tree: TreeData){ val treeHeight = TreeHeightPresenter.getTreeHeight(tree) + edgeLengthY = windowHeight / (treeHeight + 1) + tree.root?.let {root-> root.posX = 800 root.posY = 0 - setNodesLayout(root, treeHeight) + setNodesLayout(root, 0) } } // This method will assign coordinates to the nodes of the tree private fun setNodesLayout(node: NodeData, height: Int){ - val xDiff = (edgeLength + 2 * nodeSize) * height + (height - 1) - val yDiff = (edgeLength + 2 * nodeSize) * 3 + val edgeLengthX = windowWidth / 2.0.pow(height + 1).toInt() + node.leftNode?.let {leftNode-> - leftNode.posX = node.posX - xDiff - leftNode.posY = node.posY + yDiff + leftNode.posX = node.posX - edgeLengthX + leftNode.posY = node.posY + edgeLengthY - setNodesLayout(leftNode, height - 1) + setNodesLayout(leftNode, height + 1) } node.rightNode?.let { rightNode -> - rightNode.posX = node.posX + xDiff - rightNode.posY = node.posY + yDiff + rightNode.posX = node.posX + edgeLengthX + rightNode.posY = node.posY + edgeLengthY - setNodesLayout(rightNode, height - 1) + setNodesLayout(rightNode, height + 1) } } - } \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/screens/TreeScreen.kt b/app/src/main/kotlin/app/view/screens/TreeScreen.kt index cf66d62..7ba076f 100644 --- a/app/src/main/kotlin/app/view/screens/TreeScreen.kt +++ b/app/src/main/kotlin/app/view/screens/TreeScreen.kt @@ -12,10 +12,10 @@ import app.presenter.LayoutPresenter import app.presenter.TreePresenter import app.view.treeView.Tree - -const val NODE_SIZE = 30 const val WINDOW_SIZE = 800 +var nodeSize = 30 + @Composable fun TreeActionButtons( treePresenter: TreePresenter, @@ -24,17 +24,22 @@ fun TreeActionButtons( ) { Row(modifier = Modifier.background(Color.Cyan).fillMaxWidth(), horizontalArrangement = Arrangement.Center) { - Button(onClick = addNode) { + Button(onClick = { + addNode() + }) { Text("Add Node") } - Spacer(modifier = Modifier.width(NODE_SIZE.dp)) + Spacer(modifier = Modifier.width(nodeSize.dp)) - Button(onClick = deleteNode) { + Button(onClick = + { + deleteNode() + }){ Text(text = "Delete Node") } - Spacer(modifier = Modifier.width(NODE_SIZE.dp)) + Spacer(modifier = Modifier.width(nodeSize.dp)) Button(onClick = { treePresenter.saveTree() @@ -51,13 +56,12 @@ fun TreeView( deleteNode: () -> Unit, ) { val tree = treePresenter.tree - LayoutPresenter.setTreeLayout(tree, WINDOW_SIZE, WINDOW_SIZE) Column { TreeActionButtons(treePresenter, addNode, deleteNode) - + LayoutPresenter.setTreeLayout(tree) + nodeSize = LayoutPresenter.getNodeSize(tree) Box( modifier = Modifier.height(WINDOW_SIZE.dp).width(WINDOW_SIZE.dp), - ) { tree.root?.let { root -> diff --git a/app/src/main/kotlin/app/view/treeView/Edge.kt b/app/src/main/kotlin/app/view/treeView/Edge.kt index 1f9155c..477ce60 100644 --- a/app/src/main/kotlin/app/view/treeView/Edge.kt +++ b/app/src/main/kotlin/app/view/treeView/Edge.kt @@ -8,7 +8,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp -import app.view.screens.NODE_SIZE +import app.view.screens.nodeSize import app.view.screens.WINDOW_SIZE import bstrees.model.dataBases.NodeData @@ -22,8 +22,8 @@ fun Edge( modifier = modifier.size(WINDOW_SIZE.dp), onDraw = { drawLine( - start = Offset(x = node1.value.posX.toFloat() + NODE_SIZE, y = node1.value.posY.toFloat() + NODE_SIZE), - end = Offset(x = node2.value.posX.toFloat() + NODE_SIZE, y = node2.value.posY.toFloat() + NODE_SIZE), + start = Offset(x = node1.value.posX.toFloat() + nodeSize, y = node1.value.posY.toFloat() + nodeSize), + end = Offset(x = node2.value.posX.toFloat() + nodeSize, y = node2.value.posY.toFloat() + nodeSize), color = Color.Black, strokeWidth = 3F ) diff --git a/app/src/main/kotlin/app/view/treeView/Node.kt b/app/src/main/kotlin/app/view/treeView/Node.kt index c410683..d439212 100644 --- a/app/src/main/kotlin/app/view/treeView/Node.kt +++ b/app/src/main/kotlin/app/view/treeView/Node.kt @@ -19,7 +19,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import app.view.screens.NODE_SIZE +import app.view.screens.nodeSize import bstrees.model.dataBases.NodeData @Composable @@ -31,7 +31,7 @@ fun Node(node: State, nodeCoords: MutableState>) { modifier = Modifier .offset { IntOffset(nodeCoords.value.first.toInt(), nodeCoords.value.second.toInt()) } .background(Color.Red, CircleShape) - .size(NODE_SIZE.dp) + .size(nodeSize.dp) .pointerInput(Unit) { detectDragGestures { change, dragAmount -> nodeCoords.value = Pair( @@ -47,8 +47,8 @@ fun Node(node: State, nodeCoords: MutableState>) { else Color.Magenta, shape = CircleShape ) - .width(NODE_SIZE.dp) - .height(NODE_SIZE.dp) + .width(nodeSize.dp) + .height(nodeSize.dp) .border( width = 1.dp, color = Color.Blue, @@ -63,13 +63,13 @@ fun Node(node: State, nodeCoords: MutableState>) { text = "Key: ${node.value.key}", textAlign = TextAlign.Center, color = Color.White, - fontSize = if (((NODE_SIZE / 4)) > 20) 20.sp else (NODE_SIZE / 4).sp + fontSize = if (((nodeSize / 4)) > 20) 20.sp else (nodeSize / 4).sp ) Text( text = "Value: ${node.value.value}", textAlign = TextAlign.Center, color = Color.White, - fontSize = if (((NODE_SIZE / 4)) > 20) 20.sp else (NODE_SIZE / 4).sp + fontSize = if (((nodeSize / 4)) > 20) 20.sp else (nodeSize / 4).sp ) } } From 0dde14d8ce0d2fa112e742a53a20e77397394dda Mon Sep 17 00:00:00 2001 From: Kirill Shishin <73890886+tepa46@users.noreply.github.com> Date: Wed, 3 May 2023 02:59:22 +0300 Subject: [PATCH 131/135] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0334ff4..8711ffd 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ bsTree.delete("bruh") ## Storing BSTs You can store any tree in any of the three databases presented. These are `Neo4j`, `SQLite` and `Json`. You can choose the types of key and value on wich the tree is built, but supported only string and int if you want to store it -To use `Neo4j`, you need to install the desktop application `Neo4j` and `Doсker` and perform the necessary manipulations in the console +To use `Neo4j`, you need to install the desktop application `Doсker`, open it and perform `neo4j_up.sh` with with the necessary configurations, which are in the `CONTAINER.conf` file # User Interface From 12b651ecf4a374585eb47e08faf27e80c03eb303 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Thu, 4 May 2023 03:03:08 +0300 Subject: [PATCH 132/135] feat: Added a coordinate check that allows you not to move the node beyond the edges of the screen --- app/src/main/kotlin/app/view/treeView/Node.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/app/view/treeView/Node.kt b/app/src/main/kotlin/app/view/treeView/Node.kt index d439212..6aa874a 100644 --- a/app/src/main/kotlin/app/view/treeView/Node.kt +++ b/app/src/main/kotlin/app/view/treeView/Node.kt @@ -21,6 +21,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import app.view.screens.nodeSize import bstrees.model.dataBases.NodeData +import java.lang.Float.max +import java.lang.Float.min @Composable fun Node(node: State, nodeCoords: MutableState>) { @@ -34,9 +36,12 @@ fun Node(node: State, nodeCoords: MutableState>) { .size(nodeSize.dp) .pointerInput(Unit) { detectDragGestures { change, dragAmount -> + val newXPos = max(0f, min(1550f, nodeCoords.value.first + dragAmount.x)) + val newYPos = max(0f, min(1400f, nodeCoords.value.second + dragAmount.y)) + nodeCoords.value = Pair( - nodeCoords.value.first + dragAmount.x, - nodeCoords.value.second + dragAmount.y + newXPos, + newYPos ) if (change.positionChange() != Offset.Zero) change.consume() } From e1bf25816d6596d2b2cc2e10775700da7d30ae70 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Thu, 4 May 2023 03:33:15 +0300 Subject: [PATCH 133/135] feat: Added tree display with coordinates from the database when opening --- app/src/main/kotlin/app/view/App.kt | 8 +++++++- .../kotlin/app/view/screens/TreeChosingScreen.kt | 4 +++- app/src/main/kotlin/app/view/screens/TreeScreen.kt | 12 ++++++++++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/app/src/main/kotlin/app/view/App.kt b/app/src/main/kotlin/app/view/App.kt index 3934634..9aa71fc 100644 --- a/app/src/main/kotlin/app/view/App.kt +++ b/app/src/main/kotlin/app/view/App.kt @@ -51,6 +51,7 @@ fun main() { val valueType = remember { mutableStateOf("▾") } var isDirectoryNameWritten = true var treePresenter: TreePresenter? = null + val isUpdatedTree = remember { mutableStateOf(false) } // for tree adding and deleting val key = remember { mutableStateOf("Enter key") } @@ -119,7 +120,8 @@ fun main() { { newName -> treeName.value = newName }, back = navigation::pop, { navigation.push(ScreenManager.TypesChoosingScreen) }, - { navigation.push(ScreenManager.TreeScreen) } + { navigation.push(ScreenManager.TreeScreen) }, + { newValue -> isUpdatedTree.value = newValue} ) } @@ -142,11 +144,15 @@ fun main() { } is ScreenManager.TreeScreen -> { + + treePresenter?.let { treePresenter -> TreeView( treePresenter, addNode = { navigation.push(ScreenManager.AddNodeScreen) }, deleteNode = { navigation.push(ScreenManager.DeleteNodeScreen) }, + isUpdatedTree, + { newValue -> isUpdatedTree.value = newValue} ) } } diff --git a/app/src/main/kotlin/app/view/screens/TreeChosingScreen.kt b/app/src/main/kotlin/app/view/screens/TreeChosingScreen.kt index 19a438e..2a943b3 100644 --- a/app/src/main/kotlin/app/view/screens/TreeChosingScreen.kt +++ b/app/src/main/kotlin/app/view/screens/TreeChosingScreen.kt @@ -55,7 +55,8 @@ fun TreeChoosingScreen( treeNameChange: (String) -> Unit, back: () -> Unit, createTreeMenu: () -> Unit, - treeView: () -> Unit + treeView: () -> Unit, + isLoadedTreeChange: (Boolean) -> Unit, ) { Column(modifier = Modifier.padding(16.dp)) { @@ -74,6 +75,7 @@ fun TreeChoosingScreen( ) Spacer(modifier = Modifier.height(8.dp)) TreeActions(treePresenter, treeName, treeType, createTreeMenu, treeView) + isLoadedTreeChange(false) } Button(onClick = back, modifier = Modifier.width(150.dp)) { diff --git a/app/src/main/kotlin/app/view/screens/TreeScreen.kt b/app/src/main/kotlin/app/view/screens/TreeScreen.kt index 7ba076f..258f41b 100644 --- a/app/src/main/kotlin/app/view/screens/TreeScreen.kt +++ b/app/src/main/kotlin/app/view/screens/TreeScreen.kt @@ -54,11 +54,19 @@ fun TreeView( treePresenter: TreePresenter, addNode: () -> Unit, deleteNode: () -> Unit, + isUpdatedTree: State, + isUpdatedTreeChanges: (Boolean) -> Unit, ) { - val tree = treePresenter.tree + Column { + val tree = treePresenter.tree + if(isUpdatedTree.value){ + LayoutPresenter.setTreeLayout(tree) + } + else{ + isUpdatedTreeChanges(true) + } TreeActionButtons(treePresenter, addNode, deleteNode) - LayoutPresenter.setTreeLayout(tree) nodeSize = LayoutPresenter.getNodeSize(tree) Box( modifier = Modifier.height(WINDOW_SIZE.dp).width(WINDOW_SIZE.dp), From e9aac734992b17453c13d130b626fc6ab817ee2a Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Thu, 4 May 2023 15:32:48 +0300 Subject: [PATCH 134/135] fix: Fixed a tree saving bug in Neo4j --- .../model/dataBases/reps/Neo4jTreeRepo.kt | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt index 857a242..cd360cb 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt @@ -114,12 +114,13 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl setNeo4jNodes(tx, root) tx.run( "MATCH (tree: Tree {name: \$name, type: \$type}) " + - "MATCH (node: NewNode {key: ${root.key} }) " + + "MATCH (node: NewNode {key: \$rootKey }) " + "CREATE (tree)-[:root]->(node) " + "REMOVE node:NewNode", mutableMapOf( "name" to treeData.name, "type" to treeData.treeType, + "rootKey" to root.key, ) as Map? ) } @@ -130,25 +131,38 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl private fun setNeo4jNodes(tx: TransactionContext, node: NodeData) { tx.run( - "CREATE (:Node:NewNode {key: ${node.key}, value: ${node.value}, " + - "metadata: ${node.metadata}, posX: ${node.posX}, posY: ${node.posY} })" + "CREATE (:Node:NewNode {key: \$nodeKey, value: \$nodeValue, " + + "metadata: \$nodeMetadata, posX: ${node.posX}, posY: ${node.posY} })", + mutableMapOf( + "nodeKey" to node.key, + "nodeValue" to node.value, + "nodeMetadata" to node.metadata, + ) as Map? ) node.leftNode?.let { leftNode -> setNeo4jNodes(tx, leftNode) tx.run( - "MATCH (node: NewNode {key: ${node.key}}) " + - "MATCH (leftSon: NewNode {key: ${leftNode.key}}) " + + "MATCH (node: NewNode {key: \$nodeKey}) " + + "MATCH (leftSon: NewNode {key: \$leftNodeKey}) " + "CREATE (node)-[:leftSon]->(leftSon) " + - "REMOVE leftSon:NewNode" + "REMOVE leftSon:NewNode", + mutableMapOf( + "nodeKey" to node.key, + "leftNodeKey" to leftNode.key, + ) as Map? ) } node.rightNode?.let { rightNode -> setNeo4jNodes(tx, rightNode) tx.run( - "MATCH (node: NewNode {key: ${node.key}}) " + - "MATCH (rightSon: NewNode {key: ${rightNode.key}}) " + + "MATCH (node: NewNode {key: \$nodeKey}) " + + "MATCH (rightSon: NewNode {key: \$rightNodeKey}) " + "CREATE (node)-[:rightSon]->(rightSon) " + - "REMOVE rightSon:NewNode" + "REMOVE rightSon:NewNode", + mutableMapOf( + "nodeKey" to node.key, + "rightNodeKey" to rightNode.key, + ) as Map? ) } } From 4a20ea5790bf0981a0336792b117508721fbb084 Mon Sep 17 00:00:00 2001 From: Kirill Shishin Date: Thu, 4 May 2023 15:38:31 +0300 Subject: [PATCH 135/135] fix: Another small fix for saving the tree in neo4j --- .../bstrees/model/dataBases/reps/Neo4jTreeRepo.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt index cd360cb..0344b42 100644 --- a/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt +++ b/lib/src/main/kotlin/bstrees/model/dataBases/reps/Neo4jTreeRepo.kt @@ -64,13 +64,22 @@ class Neo4jTreeRepo(host: String, username: String, password: String) : Closeabl var rightSonKey = mapOf() val resultNodeData = tx.run( - "MATCH (node:Node {key: $nodeKey}) RETURN node.key AS key, node.value AS value, node.metadata AS metadata, node.posX AS posX, node.posY AS posY" + "MATCH (node:Node {key: \$nodeKey}) RETURN node.key AS key, node.value AS value, node.metadata AS metadata, node.posX AS posX, node.posY AS posY", + mutableMapOf( + "nodeKey" to nodeKey, + ) as Map? ) val resultLeftSonKey = tx.run( - "MATCH (node:Node {key: $nodeKey}) MATCH (node)-[:leftSon]->(leftSon) RETURN leftSon.key as key" + "MATCH (node:Node {key: \$nodeKey}) MATCH (node)-[:leftSon]->(leftSon) RETURN leftSon.key as key", + mutableMapOf( + "nodeKey" to nodeKey, + ) as Map? ) val resultRightSonKey = tx.run( - "MATCH (node:Node {key: $nodeKey}) MATCH (node)-[:rightSon]->(rightSon) RETURN rightSon.key as key" + "MATCH (node:Node {key: \$nodeKey}) MATCH (node)-[:rightSon]->(rightSon) RETURN rightSon.key as key", + mutableMapOf( + "nodeKey" to nodeKey, + ) as Map? ) if (resultNodeData.hasNext()) {