From 16d61cff9dfe2a8057bee1d77215745f504ed92f Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 09:23:04 +0000 Subject: [PATCH 001/125] Setting up GitHub Classroom Feedback From b353bfdb20caae5ed9afa7dcd9c491492736b246 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Thu, 23 Mar 2023 00:58:55 +0300 Subject: [PATCH 002/125] struct: Add MIT licence --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9771046 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023-present Yakshigulov Vadim, Dyachkov Vitaliy, Perevalov Efim + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file From 8b49e81aa96d3058d27dd5dff71f75cb0c68a68a Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Thu, 23 Mar 2023 01:03:57 +0300 Subject: [PATCH 003/125] struct: Remove useless .keep file --- .github/.keep | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .github/.keep diff --git a/.github/.keep b/.github/.keep deleted file mode 100644 index e69de29..0000000 From cbd0f4f1d6cbc31e08f5db2074d1cc60a19a3f2c Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Thu, 23 Mar 2023 01:06:25 +0300 Subject: [PATCH 004/125] struct: Add .gitignore for garbage from java, idea and gradle --- .gitignore | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cdfbcda --- /dev/null +++ b/.gitignore @@ -0,0 +1,85 @@ +.gradle +**/build/ +!src/**/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Avoid ignore Gradle wrappper properties +!gradle-wrapper.properties + +# Cache of project +.gradletasknamecache + +# Eclipse Gradle plugin generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +.idea + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties \ No newline at end of file From c7f0b7ad10ce64a756801d9eee4c4cea0308cb4a Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Thu, 23 Mar 2023 11:28:29 +0300 Subject: [PATCH 005/125] struct: Init default gradle structure --- .gitattributes | 6 + app/build.gradle.kts | 39 ++++ app/src/main/kotlin/app/App.kt | 5 + gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 234 +++++++++++++++++++++++ gradlew.bat | 89 +++++++++ settings.gradle.kts | 11 ++ 7 files changed, 389 insertions(+) create mode 100644 .gitattributes create mode 100644 app/build.gradle.kts create mode 100644 app/src/main/kotlin/app/App.kt create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle.kts diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..00a51af --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..18b9967 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,39 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Kotlin application project to get you started. + * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle + * User Manual available at https://docs.gradle.org/7.2/userguide/building_java_projects.html + */ + +plugins { + // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. + id("org.jetbrains.kotlin.jvm") version "1.5.0" + + // Apply the application plugin to add support for building a CLI application in Java. + application +} + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() +} + +dependencies { + // Align versions of all Kotlin components + implementation(platform("org.jetbrains.kotlin:kotlin-bom")) + + // Use the Kotlin JDK 8 standard library. + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + + // 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("app:AppKt") +} diff --git a/app/src/main/kotlin/app/App.kt b/app/src/main/kotlin/app/App.kt new file mode 100644 index 0000000..192a445 --- /dev/null +++ b/app/src/main/kotlin/app/App.kt @@ -0,0 +1,5 @@ +package app + +fun main() { + println("Hello kotlin") +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..ffed3a2 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..1b6c787 --- /dev/null +++ b/gradlew @@ -0,0 +1,234 @@ +#!/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/master/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 + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..373a435 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,11 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user manual at https://docs.gradle.org/7.2/userguide/multi_project_builds.html + */ + +rootProject.name = "trees-4" +include("app") From 7fd60bc26b2e2d9edac34f8e571453e9ba98147c Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Thu, 23 Mar 2023 18:16:04 +0300 Subject: [PATCH 006/125] struct: Add module for future BST implementations --- app/build.gradle.kts | 1 + binary-search-trees/build.gradle.kts | 31 ++++++++++++++++++++++++++++ settings.gradle.kts | 1 + 3 files changed, 33 insertions(+) create mode 100644 binary-search-trees/build.gradle.kts diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 18b9967..4a294b6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { // Use the Kotlin JUnit integration. testImplementation("org.jetbrains.kotlin:kotlin-test-junit") + implementation(project(":binary-search-trees")) } application { diff --git a/binary-search-trees/build.gradle.kts b/binary-search-trees/build.gradle.kts new file mode 100644 index 0000000..d99edda --- /dev/null +++ b/binary-search-trees/build.gradle.kts @@ -0,0 +1,31 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Kotlin application project to get you started. + * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle + * User Manual available at https://docs.gradle.org/7.2/userguide/building_java_projects.html + */ + +plugins { + // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. + id("org.jetbrains.kotlin.jvm") version "1.5.0" +} + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() +} + +dependencies { + // Align versions of all Kotlin components + implementation(platform("org.jetbrains.kotlin:kotlin-bom")) + + // Use the Kotlin JDK 8 standard library. + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + + // Use the Kotlin test library. + testImplementation("org.jetbrains.kotlin:kotlin-test") + + // Use the Kotlin JUnit integration. + testImplementation("org.jetbrains.kotlin:kotlin-test-junit") +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 373a435..25a4981 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -9,3 +9,4 @@ rootProject.name = "trees-4" include("app") +include("binary-search-trees") From ade6a9c4a86edaffefbf4baeed35d974ee6ef310 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Thu, 23 Mar 2023 20:42:12 +0300 Subject: [PATCH 007/125] feat: Add contributing guidelines for newcomers fix: Fix typos --- CONTRIBUTING.md | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..27cc111 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,70 @@ +# Внесение правок + +## Основные советы + +1. Никогда не используйте merge, только rebase для сохранения линейной истории коммитов +2. **Осторожно** с изменениями в чужих ветках. Придется больно и мучительно делать rebase. Лучше не трогайте чужие + ветки. +3. Перепроверьте историю коммитов перед созданием пулл реквеста. +4. Каждый коммит должен быть осознанным и быть одним логическим элементом +5. Каждый пулл реквест должен быть осознанным и быть одним логическим элементом +6. **Перероверьте, что вы в правильной ветке**, никогда не коммитьте напрямую в main + +## Правила добавления коммитов + +Коммиты добавляются в соответствии с conventional commits. Т.е +`(): `. + +Поле `` должно принимать одно из этих значений: + +* `feat` для добавления новой функциональности +* `fix` для исправления бага в программе +* `refactor` для рефакторинга кода, например, переименования переменной +* `test` для добавления тестов, их рефакторинга +* `struct` для изменений связанных с изменением структуры проекта (НО НЕ КОДА), например изменение + расположения папок +* `ci` для различных задач ci/cd + +Поле `` опционально и показывает к какому модулю, классу, методу функции и т.п применены изменения + +Поле `` содержит суть изменений в повелительном наклонении настоящего времени на английском языке без точки в +конце, первое слово - глагол с большой буквы. Текст сообщения должен включать мотивацию к изменению и контрасты с +предыдущим поведением. + +Примеры: + +* Хорошо: "Add module for future BST implementations" +* Плохо: "Added module for future BST implementations." +* Плохо: "Adds module". +* Очень плохо: "new bug." + +## Правила именования и создания веток + +Ветка под одно (большое) логическое изменение. Формат для веток `/`. Тип аналогичен тому же в +коммитах, +а `` представляет собой короткое описание назначения ветки в kebab-case стиле. + +Примеры хороших названий: + +* `feat/add-avl-tree` +* `ci/add-klint` + +После одобрения пулл реквеста, ветка удаляется. А новая функциональность разрабатывается в новой ветке. + +## Правила для пулл реквестов + +Пулл реквесты оформляются на любом удобном языке. Но должны четко отвечать на 3 вопроса. + +1. Что? +2. Зачем? +3. Почему? + +Ответ на вопрос что должен содержаться в заголовке пулл реквеста. На остальные вопросы ответ должен быть в описании. + +**НЕ ТЫКАТЬ НА ЗЕЛЕНУЮ КНОПОЧКУ `REBASE AND MERGE` БЕЗ РЕВЬЮ** + +**Запрещено** сливать свой пулл реквест в ветку самостоятельно. + +Если тыкаете на зеленую кнопочку, то **убедитесь**, что на ней написано `REBASE AND MERGE` + +Ревью происходит в виде комметариев к пулл реквестов, обсуждения в чате команды и личном общении. From 091365f14df16a84355e8d8cba8b791a38bbc8ec Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Thu, 23 Mar 2023 20:54:49 +0300 Subject: [PATCH 008/125] feat: Add contributing header to README --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..efed1ee --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# trees + +## Внесение изменений + +Внимательно прочитайте раздел [CONTRIBUTING](./CONTRIBUTING.md). + +Быстрый способ начать вносить правки: + +1. Создате новую ветку (`git checkout -b feat/add-amazing-feature`) +2. Сделайте коммит изменений (`git commit -m "feat: Add some amazing feature"`) +3. Запушьте ветку в origin (`git push origin feat/add-amazing-feature`) +4. Откройте пулл реквест From 1f0bf4f1e8aee8c997959cae473cdce0efac1e4a Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Thu, 23 Mar 2023 21:08:22 +0300 Subject: [PATCH 009/125] feat: Add header about used license --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index efed1ee..1ad076d 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,7 @@ 2. Сделайте коммит изменений (`git commit -m "feat: Add some amazing feature"`) 3. Запушьте ветку в origin (`git push origin feat/add-amazing-feature`) 4. Откройте пулл реквест + +## Лицензия + +Этот проект используeт лицензию MIT. Подробнее в [LICENSE](./LICENSE) \ No newline at end of file From 8663dcdfcc6a8089ea5d330afd6ae88a3c5319ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Fri, 24 Mar 2023 19:50:15 +0300 Subject: [PATCH 010/125] fix: Fix several typos and beautify structure of the text --- CONTRIBUTING.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 27cc111..9653d28 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,11 +4,11 @@ 1. Никогда не используйте merge, только rebase для сохранения линейной истории коммитов 2. **Осторожно** с изменениями в чужих ветках. Придется больно и мучительно делать rebase. Лучше не трогайте чужие - ветки. -3. Перепроверьте историю коммитов перед созданием пулл реквеста. + ветки +3. Перепроверьте историю коммитов перед созданием пулл реквеста 4. Каждый коммит должен быть осознанным и быть одним логическим элементом 5. Каждый пулл реквест должен быть осознанным и быть одним логическим элементом -6. **Перероверьте, что вы в правильной ветке**, никогда не коммитьте напрямую в main +6. **Перепроверьте, что вы в правильной ветке**, никогда не коммитьте напрямую в main ## Правила добавления коммитов @@ -25,7 +25,7 @@ расположения папок * `ci` для различных задач ci/cd -Поле `` опционально и показывает к какому модулю, классу, методу функции и т.п применены изменения +Поле `` опционально и показывает к какому модулю, классу, методу функции и т.п применены изменения. Поле `` содержит суть изменений в повелительном наклонении настоящего времени на английском языке без точки в конце, первое слово - глагол с большой буквы. Текст сообщения должен включать мотивацию к изменению и контрасты с @@ -53,7 +53,7 @@ ## Правила для пулл реквестов -Пулл реквесты оформляются на любом удобном языке. Но должны четко отвечать на 3 вопроса. +Пулл реквесты оформляются на любом удобном языке. Но должны четко отвечать на 3 вопроса: 1. Что? 2. Зачем? @@ -67,4 +67,4 @@ Если тыкаете на зеленую кнопочку, то **убедитесь**, что на ней написано `REBASE AND MERGE` -Ревью происходит в виде комметариев к пулл реквестов, обсуждения в чате команды и личном общении. +Ревью происходит в виде комметариев к пулл реквестам, обсуждения в чате команды и личном общении. From e24f59d14b075da9325dba238f0efbcbdd89551d Mon Sep 17 00:00:00 2001 From: Vadim <88928096+toadharvard@users.noreply.github.com> Date: Sat, 25 Mar 2023 01:01:35 +0300 Subject: [PATCH 011/125] feat: Add template as reminder for contributors --- .github/pull_request_template.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..0cc7b37 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,6 @@ +Пожалуйста, убедитесь, что ваш пулл реквест соответствует [CONTRIBUTING](./CONTRIBUTING.md) +- [ ] Соответствует + +Прежде чем нажимать зеленую кнопочку убедитесь, что +* Пулл реквест проверен и одобрен хотя бы одним членом команды +* Используется `REBASE AND MERGE` для слияния в main ветку From 56d338e668eaa4179b43ebe3be650f4c803ecd73 Mon Sep 17 00:00:00 2001 From: Vadim <88928096+toadharvard@users.noreply.github.com> Date: Sat, 25 Mar 2023 12:58:29 +0300 Subject: [PATCH 012/125] feat: Add mergeable as contrib guidlines checker --- .github/mergeable.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/mergeable.yml diff --git a/.github/mergeable.yml b/.github/mergeable.yml new file mode 100644 index 0000000..52ad4d0 --- /dev/null +++ b/.github/mergeable.yml @@ -0,0 +1,13 @@ +version: 2 +mergeable: + - when: pull_request.*, pull_request_review.* + validate: + - do: description + no_empty: + enabled: true + message: Description matter and should not be empty. Provide detail with **what** was changed, **why** it was changed, and **how** it was changed. + - do: approvals + min: + count: 1 + required: + assignees: true From f12030bb507bc22f91a3643208d706edf68e00e3 Mon Sep 17 00:00:00 2001 From: Vadim <88928096+toadharvard@users.noreply.github.com> Date: Sat, 25 Mar 2023 13:10:01 +0300 Subject: [PATCH 013/125] refactor: Replace template with mergable config Mergeable action is preferred way to do this task --- .github/pull_request_template.md | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 0cc7b37..0000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,6 +0,0 @@ -Пожалуйста, убедитесь, что ваш пулл реквест соответствует [CONTRIBUTING](./CONTRIBUTING.md) -- [ ] Соответствует - -Прежде чем нажимать зеленую кнопочку убедитесь, что -* Пулл реквест проверен и одобрен хотя бы одним членом команды -* Используется `REBASE AND MERGE` для слияния в main ветку From 4dd15fbdb842e779bcc39df7363a30ba397da8d1 Mon Sep 17 00:00:00 2001 From: Vadim <88928096+toadharvard@users.noreply.github.com> Date: Sat, 25 Mar 2023 13:16:28 +0300 Subject: [PATCH 014/125] feat: Add comment with contributing guidlines --- .github/mergeable.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/mergeable.yml b/.github/mergeable.yml index 52ad4d0..9f44e22 100644 --- a/.github/mergeable.yml +++ b/.github/mergeable.yml @@ -5,9 +5,12 @@ mergeable: - do: description no_empty: enabled: true - message: Description matter and should not be empty. Provide detail with **what** was changed, **why** it was changed, and **how** it was changed. + message: "Description matter and should not be empty. Provide detail with **what** was changed, **why** it was changed, and **how** it was changed." - do: approvals min: count: 1 required: assignees: true + - do: comment + payload: + body: "Check that your pull request meets the [CONTRIBUTING](./CONTRIBUTING.md) requirements" From 71fb6efe5ad0593fc269f2ea2e3436e4358d9a45 Mon Sep 17 00:00:00 2001 From: Vadim <88928096+toadharvard@users.noreply.github.com> Date: Sat, 25 Mar 2023 13:20:38 +0300 Subject: [PATCH 015/125] fix: Fix invalid tabs/spaces mixture --- .github/mergeable.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/mergeable.yml b/.github/mergeable.yml index 9f44e22..52e1cb4 100644 --- a/.github/mergeable.yml +++ b/.github/mergeable.yml @@ -11,6 +11,12 @@ mergeable: count: 1 required: assignees: true - - do: comment + + - when: pull_request.opened + name: "Remind about contributing guidelines" + validate: [ ] + pass: + - do: comment payload: - body: "Check that your pull request meets the [CONTRIBUTING](./CONTRIBUTING.md) requirements" + body: > + Thanks for creating a pull request! Please, check that your pull request meets the [CONTRIBUTING](./CONTRIBUTING.md) requirements. From ae06618e6c6a64cf7744a30386533122427701dd Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sat, 25 Mar 2023 11:26:57 +0300 Subject: [PATCH 016/125] feat: Add abstract binary search tree feat: Add stubs for AVL, RB, BS balancers feat: Add tree nodes implementation feat: Add tree iterators feat: Add interfaces for future tree implementations --- .../src/main/kotlin/bst/BinarySearchTree.kt | 53 +++++++++++++++++++ .../main/kotlin/bst/balancer/AVLBalancer.kt | 13 +++++ .../main/kotlin/bst/balancer/BSBalancer.kt | 13 +++++ .../kotlin/bst/balancer/BinTreeBalancer.kt | 15 ++++++ .../main/kotlin/bst/balancer/RBBalancer.kt | 13 +++++ .../kotlin/bst/iterator/InOrderIterator.kt | 33 ++++++++++++ .../kotlin/bst/iterator/LevelOrderIterator.kt | 23 ++++++++ .../kotlin/bst/iterator/PreOrderIterator.kt | 23 ++++++++ .../src/main/kotlin/bst/node/AVLNode.kt | 8 +++ .../src/main/kotlin/bst/node/AVLTreeNode.kt | 5 ++ .../src/main/kotlin/bst/node/BSNode.kt | 7 +++ .../main/kotlin/bst/node/BinSearchTreeNode.kt | 3 ++ .../src/main/kotlin/bst/node/BinTreeNode.kt | 7 +++ .../src/main/kotlin/bst/node/RBNode.kt | 24 +++++++++ .../main/kotlin/bst/node/RedBlackTreeNode.kt | 9 ++++ 15 files changed, 249 insertions(+) create mode 100644 binary-search-trees/src/main/kotlin/bst/BinarySearchTree.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/balancer/BSBalancer.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/balancer/BinTreeBalancer.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/iterator/InOrderIterator.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/iterator/LevelOrderIterator.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/iterator/PreOrderIterator.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/node/AVLTreeNode.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/node/BSNode.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/node/BinSearchTreeNode.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/node/BinTreeNode.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/node/RBNode.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt diff --git a/binary-search-trees/src/main/kotlin/bst/BinarySearchTree.kt b/binary-search-trees/src/main/kotlin/bst/BinarySearchTree.kt new file mode 100644 index 0000000..1cdd51a --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/BinarySearchTree.kt @@ -0,0 +1,53 @@ +package bst + +import bst.balancer.BinTreeBalancer +import bst.iterator.InOrderIterator +import bst.iterator.LevelOrderIterator +import bst.iterator.PreOrderIterator +import bst.node.BinTreeNode + +abstract class BinarySearchTree, NodeType : BinTreeNode, WrappedType>( + protected val balancer: BinTreeBalancer, + protected val wrap: (NodeType) -> WrappedType +) { + protected var root: NodeType? = null + + open val wrappedRoot: WrappedType? + get() = root?.let { wrap(it) } + + open fun add(value: E, unique: Boolean = false) { + root = balancer.add(root, value, unique) + } + + open fun remove(value: E) { + root = balancer.remove(root, value) + } + + operator fun contains(value: E): Boolean { + return search(root, value) + } + + operator fun iterator(): Iterator { + return InOrderIterator(root) + } + + fun preOrderIterator(): Iterator { + return PreOrderIterator(root) + } + + fun levelOrderIterator(): Iterator { + return LevelOrderIterator(root) + } + + private tailrec fun search(node: NodeType?, value: E): Boolean { + if (node == null) { + return false + } + + if (value == node.value) { + return true + } + + return search((if (value < node.value) node.left else node.right), value) + } +} diff --git a/binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt b/binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt new file mode 100644 index 0000000..14edcfd --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt @@ -0,0 +1,13 @@ +package bst.balancer + +import bst.node.AVLTreeNode + +internal class AVLBalancer> : BinTreeBalancer> { + override fun add(root: AVLTreeNode?, value: E, unique: Boolean): AVLTreeNode { + TODO("Not yet implemented") + } + + override fun remove(root: AVLTreeNode?, value: E): AVLTreeNode? { + TODO("Not yet implemented") + } +} diff --git a/binary-search-trees/src/main/kotlin/bst/balancer/BSBalancer.kt b/binary-search-trees/src/main/kotlin/bst/balancer/BSBalancer.kt new file mode 100644 index 0000000..d83728d --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/balancer/BSBalancer.kt @@ -0,0 +1,13 @@ +package bst.balancer + +import bst.node.BinSearchTreeNode + +internal class BSBalancer> : BinTreeBalancer> { + override fun add(root: BinSearchTreeNode?, value: E, unique: Boolean): BinSearchTreeNode { + TODO("Not yet implemented") + } + + override fun remove(root: BinSearchTreeNode?, value: E): BinSearchTreeNode? { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/balancer/BinTreeBalancer.kt b/binary-search-trees/src/main/kotlin/bst/balancer/BinTreeBalancer.kt new file mode 100644 index 0000000..6cd319b --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/balancer/BinTreeBalancer.kt @@ -0,0 +1,15 @@ +package bst.balancer + +import bst.node.BinTreeNode + +interface BinTreeBalancer, NodeType : BinTreeNode> { + /** + * Adds a new node with a value to the root's subtree, and rebalances it if necessary. + */ + fun add(root: NodeType?, value: E, unique: Boolean): NodeType + + /** + * Removes a node with a value from the root's subtree, and rebalances it if necessary. + */ + fun remove(root: NodeType?, value: E): NodeType? +} \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt b/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt new file mode 100644 index 0000000..4bf20b5 --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt @@ -0,0 +1,13 @@ +package bst.balancer + +import bst.node.RedBlackTreeNode + +internal class RBBalancer> : BinTreeBalancer> { + override fun add(root: RedBlackTreeNode?, value: E, unique: Boolean): RedBlackTreeNode { + TODO("Not yet implemented") + } + + override fun remove(root: RedBlackTreeNode?, value: E): RedBlackTreeNode? { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/iterator/InOrderIterator.kt b/binary-search-trees/src/main/kotlin/bst/iterator/InOrderIterator.kt new file mode 100644 index 0000000..bdc31f9 --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/iterator/InOrderIterator.kt @@ -0,0 +1,33 @@ +package bst.iterator + +import bst.node.BinTreeNode +import java.util.* + +internal class InOrderIterator, NodeType : BinTreeNode>(root: NodeType?) : Iterator { + private val stack = LinkedList() + + init { + var node = root + while (node != null) { + stack.push(node) + node = node.left + } + } + + override fun hasNext(): Boolean { + return stack.isNotEmpty() + } + + override fun next(): E { + val node = stack.pop() + var nextNode = node.right + while (nextNode != null) { + stack.push(nextNode) + nextNode = nextNode.left + } + return node.value + } +} + + + diff --git a/binary-search-trees/src/main/kotlin/bst/iterator/LevelOrderIterator.kt b/binary-search-trees/src/main/kotlin/bst/iterator/LevelOrderIterator.kt new file mode 100644 index 0000000..bc949d4 --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/iterator/LevelOrderIterator.kt @@ -0,0 +1,23 @@ +package bst.iterator + +import bst.node.BinTreeNode +import java.util.* + +internal class LevelOrderIterator, NodeType : BinTreeNode>(root: NodeType?) : Iterator { + private val queue = LinkedList() + + init { + root?.let { queue.offer(it) } + } + + override fun hasNext(): Boolean { + return queue.isNotEmpty() + } + + override fun next(): E { + val node = queue.poll() + node.left?.let { queue.offer(it) } + node.right?.let { queue.offer(it) } + return node.value + } +} \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/iterator/PreOrderIterator.kt b/binary-search-trees/src/main/kotlin/bst/iterator/PreOrderIterator.kt new file mode 100644 index 0000000..957591a --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/iterator/PreOrderIterator.kt @@ -0,0 +1,23 @@ +package bst.iterator + +import bst.node.BinTreeNode +import java.util.* + +internal class PreOrderIterator, NodeType : BinTreeNode>(root: NodeType?) : Iterator { + private val stack = LinkedList() + + init { + root?.let { stack.push(it) } + } + + override fun hasNext(): Boolean { + return stack.isNotEmpty() + } + + override fun next(): E { + val node = stack.pop() + node.right?.let { stack.push(it) } + node.left?.let { stack.push(it) } + return node.value + } +} \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt b/binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt new file mode 100644 index 0000000..485d85e --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt @@ -0,0 +1,8 @@ +package bst.node + +internal data class AVLNode>( + override var value: E, + override var height: Int = 1, + override var left: AVLTreeNode? = null, + override var right: AVLTreeNode? = null, +) : AVLTreeNode \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/node/AVLTreeNode.kt b/binary-search-trees/src/main/kotlin/bst/node/AVLTreeNode.kt new file mode 100644 index 0000000..bdec5c3 --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/node/AVLTreeNode.kt @@ -0,0 +1,5 @@ +package bst.node + +interface AVLTreeNode> : BinTreeNode> { + var height: Int +} \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/node/BSNode.kt b/binary-search-trees/src/main/kotlin/bst/node/BSNode.kt new file mode 100644 index 0000000..760bc27 --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/node/BSNode.kt @@ -0,0 +1,7 @@ +package bst.node + +internal data class BSNode>( + override var value: E, + override var left: BinSearchTreeNode? = null, + override var right: BinSearchTreeNode? = null, +) : BinSearchTreeNode \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/node/BinSearchTreeNode.kt b/binary-search-trees/src/main/kotlin/bst/node/BinSearchTreeNode.kt new file mode 100644 index 0000000..19d7f1e --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/node/BinSearchTreeNode.kt @@ -0,0 +1,3 @@ +package bst.node + +interface BinSearchTreeNode> : BinTreeNode> diff --git a/binary-search-trees/src/main/kotlin/bst/node/BinTreeNode.kt b/binary-search-trees/src/main/kotlin/bst/node/BinTreeNode.kt new file mode 100644 index 0000000..ebcbc9f --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/node/BinTreeNode.kt @@ -0,0 +1,7 @@ +package bst.node + +interface BinTreeNode, Subtype : BinTreeNode> { + var value: E + var left: Subtype? + var right: Subtype? +} \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt b/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt new file mode 100644 index 0000000..5119c40 --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt @@ -0,0 +1,24 @@ +package bst.node + +internal data class RBNode>( + override var value: E, + override var color: RedBlackTreeNode.Color = RedBlackTreeNode.Color.RED, + override var left: RedBlackTreeNode? = null, + override var right: RedBlackTreeNode? = null, +) : RedBlackTreeNode { + override fun flipColor() { + color = when (color) { + RedBlackTreeNode.Color.BLACK -> RedBlackTreeNode.Color.RED + else -> RedBlackTreeNode.Color.BLACK + } + } +} + +internal fun > RedBlackTreeNode?.isBlack(): Boolean { + if (this == null) return true + return this.color == RedBlackTreeNode.Color.BLACK +} + +internal fun > RedBlackTreeNode?.isRed(): Boolean { + return !this.isBlack() +} diff --git a/binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt b/binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt new file mode 100644 index 0000000..ea4e96e --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt @@ -0,0 +1,9 @@ +package bst.node + +interface RedBlackTreeNode> : BinTreeNode> { + var color: Color + fun flipColor() + enum class Color { + RED, BLACK + } +} From dff298d51f505c4518312342825d22bf20b76af9 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sat, 25 Mar 2023 11:59:19 +0300 Subject: [PATCH 017/125] feat: Add node wrappers for easy access to root property --- .../main/kotlin/bst/wrapper/WrappedAVLNode.kt | 18 +++++++++++++++++ .../main/kotlin/bst/wrapper/WrappedBSNode.kt | 15 ++++++++++++++ .../main/kotlin/bst/wrapper/WrappedBinNode.kt | 7 +++++++ .../main/kotlin/bst/wrapper/WrappedRBNode.kt | 20 +++++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 binary-search-trees/src/main/kotlin/bst/wrapper/WrappedAVLNode.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBSNode.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBinNode.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/wrapper/WrappedRBNode.kt diff --git a/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedAVLNode.kt b/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedAVLNode.kt new file mode 100644 index 0000000..3a925d5 --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedAVLNode.kt @@ -0,0 +1,18 @@ +package bst.wrapper + +import bst.node.AVLTreeNode + +class WrappedAVLNode>(private val node: AVLTreeNode) : + WrappedBinNode> { + override val value: E + get() = node.value + override val left: WrappedAVLNode? + get() = node.left?.let { WrappedAVLNode(it) } + override val right: WrappedAVLNode? + get() = node.right?.let { WrappedAVLNode(it) } + + val height: Int + get() = node.height + + override fun toString() = "$value($height)" +} \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBSNode.kt b/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBSNode.kt new file mode 100644 index 0000000..cfe87b3 --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBSNode.kt @@ -0,0 +1,15 @@ +package bst.wrapper + +import bst.node.BinSearchTreeNode + +class WrappedBSNode>(private val node: BinSearchTreeNode) : + WrappedBinNode> { + override val value: E + get() = node.value + override val left: WrappedBSNode? + get() = node.left?.let { WrappedBSNode(it) } + override val right: WrappedBSNode? + get() = node.right?.let { WrappedBSNode(it) } + + override fun toString() = "$value" +} \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBinNode.kt b/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBinNode.kt new file mode 100644 index 0000000..ed3aa1f --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBinNode.kt @@ -0,0 +1,7 @@ +package bst.wrapper + +interface WrappedBinNode> { + val value: E + val left: Node? + val right: Node? +} \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedRBNode.kt b/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedRBNode.kt new file mode 100644 index 0000000..e0b5ed6 --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedRBNode.kt @@ -0,0 +1,20 @@ +package bst.wrapper + +import bst.node.RedBlackTreeNode + +class WrappedRBNode>(private val node: RedBlackTreeNode) : + WrappedBinNode> { + val color: RedBlackTreeNode.Color + get() = node.color + + override val value: E + get() = node.value + + override val left: WrappedRBNode? + get() = node.left?.let { WrappedRBNode(it) } + + override val right: WrappedRBNode? + get() = node.right?.let { WrappedRBNode(it) } + + override fun toString() = "$value($color)" +} From e5d78cf09fbfae44407442bffecf2e4b9c5ae044 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sat, 25 Mar 2023 12:01:10 +0300 Subject: [PATCH 018/125] feat: Add binary search tree facade pattern implementation --- binary-search-trees/src/main/kotlin/bst/AVLTree.kt | 11 +++++++++++ binary-search-trees/src/main/kotlin/bst/BSTree.kt | 11 +++++++++++ binary-search-trees/src/main/kotlin/bst/RBTree.kt | 11 +++++++++++ 3 files changed, 33 insertions(+) create mode 100644 binary-search-trees/src/main/kotlin/bst/AVLTree.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/BSTree.kt create mode 100644 binary-search-trees/src/main/kotlin/bst/RBTree.kt diff --git a/binary-search-trees/src/main/kotlin/bst/AVLTree.kt b/binary-search-trees/src/main/kotlin/bst/AVLTree.kt new file mode 100644 index 0000000..9531043 --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/AVLTree.kt @@ -0,0 +1,11 @@ +package bst + +import bst.balancer.AVLBalancer +import bst.node.AVLTreeNode +import bst.wrapper.WrappedAVLNode + +class AVLTree> : + BinarySearchTree, WrappedAVLNode>( + balancer = AVLBalancer(), + wrap = ::WrappedAVLNode + ) diff --git a/binary-search-trees/src/main/kotlin/bst/BSTree.kt b/binary-search-trees/src/main/kotlin/bst/BSTree.kt new file mode 100644 index 0000000..1e53112 --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/BSTree.kt @@ -0,0 +1,11 @@ +package bst + +import bst.balancer.BSBalancer +import bst.node.BinSearchTreeNode +import bst.wrapper.WrappedBSNode + +class BSTree> : + BinarySearchTree, WrappedBSNode>( + balancer = BSBalancer(), + wrap = ::WrappedBSNode + ) \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/RBTree.kt b/binary-search-trees/src/main/kotlin/bst/RBTree.kt new file mode 100644 index 0000000..0855efd --- /dev/null +++ b/binary-search-trees/src/main/kotlin/bst/RBTree.kt @@ -0,0 +1,11 @@ +package bst + +import bst.balancer.RBBalancer +import bst.node.RedBlackTreeNode +import bst.wrapper.WrappedRBNode + +class RBTree> : + BinarySearchTree, WrappedRBNode>( + balancer = RBBalancer(), + wrap = ::WrappedRBNode + ) From 1b502cc5599accaf421390fc3f76f43c234046bd Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sat, 25 Mar 2023 19:02:00 +0300 Subject: [PATCH 019/125] fix: Bump kotlin version to fix grandle run task --- app/build.gradle.kts | 7 +++++-- binary-search-trees/build.gradle.kts | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4a294b6..a105571 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -5,10 +5,13 @@ * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle * User Manual available at https://docs.gradle.org/7.2/userguide/building_java_projects.html */ +kotlin { + jvmToolchain(8) +} plugins { // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. - id("org.jetbrains.kotlin.jvm") version "1.5.0" + id("org.jetbrains.kotlin.jvm") version "1.8.10" // Apply the application plugin to add support for building a CLI application in Java. application @@ -36,5 +39,5 @@ dependencies { application { // Define the main class for the application. - mainClass.set("app:AppKt") + mainClass.set("app.AppKt") } diff --git a/binary-search-trees/build.gradle.kts b/binary-search-trees/build.gradle.kts index d99edda..ab19139 100644 --- a/binary-search-trees/build.gradle.kts +++ b/binary-search-trees/build.gradle.kts @@ -5,10 +5,13 @@ * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle * User Manual available at https://docs.gradle.org/7.2/userguide/building_java_projects.html */ +kotlin { + jvmToolchain(8) +} plugins { // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. - id("org.jetbrains.kotlin.jvm") version "1.5.0" + id("org.jetbrains.kotlin.jvm") version "1.8.10" } repositories { From 90b533081bbb53a57ea8ff98d01ffdec07c1c575 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sat, 25 Mar 2023 20:07:18 +0300 Subject: [PATCH 020/125] ci: Add actions on push and PRs --- .github/workflows/run-on-push-to-main.yml | 20 ++++++++++++++++++++ .github/workflows/run-tests.yml | 14 ++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 .github/workflows/run-on-push-to-main.yml create mode 100644 .github/workflows/run-tests.yml diff --git a/.github/workflows/run-on-push-to-main.yml b/.github/workflows/run-on-push-to-main.yml new file mode 100644 index 0000000..fcfa71d --- /dev/null +++ b/.github/workflows/run-on-push-to-main.yml @@ -0,0 +1,20 @@ +name: Run full build + +on: + push: + branches: + - main +jobs: + build-gradle-project: + runs-on: ubuntu-latest + steps: + - name: Checkout project sources + uses: actions/checkout@v2 + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + - name: Run build with Gradle Wrapper + run: ./gradlew build + - uses: actions/upload-artifact@v3 + with: + name: Package + path: build/libs \ No newline at end of file diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml new file mode 100644 index 0000000..9cc1855 --- /dev/null +++ b/.github/workflows/run-tests.yml @@ -0,0 +1,14 @@ +name: Run tests + +on: [ pull_request, push ] + +jobs: + build-gradle-project: + runs-on: ubuntu-latest + steps: + - name: Checkout project sources + uses: actions/checkout@v2 + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + - name: Run build with Gradle Wrapper + run: ./gradlew test From 16770f0c30857c59742f831080ea89d1b9cdc1c5 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sat, 25 Mar 2023 20:10:08 +0300 Subject: [PATCH 021/125] fix: Add executable permission to gradlew script --- gradlew | 0 gradlew.bat | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 gradlew mode change 100644 => 100755 gradlew.bat diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/gradlew.bat b/gradlew.bat old mode 100644 new mode 100755 From 54da724b85c432145ef63c89991860f80089a2b0 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sat, 25 Mar 2023 20:19:33 +0300 Subject: [PATCH 022/125] refactor: Allow gradlew-wrapper.jar in project --- .gitignore | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index cdfbcda..84d24ee 100644 --- a/.gitignore +++ b/.gitignore @@ -5,12 +5,6 @@ # Ignore Gradle GUI config gradle-app.setting -# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) -!gradle-wrapper.jar - -# Avoid ignore Gradle wrappper properties -!gradle-wrapper.properties - # Cache of project .gradletasknamecache @@ -82,4 +76,10 @@ atlassian-ide-plugin.xml com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties -fabric.properties \ No newline at end of file +fabric.properties + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Avoid ignore Gradle wrappper properties +!gradle-wrapper.properties \ No newline at end of file From 919ddebd8cd527613f02477ae443303004b5317d Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sat, 25 Mar 2023 20:19:59 +0300 Subject: [PATCH 023/125] fix: Add missing gradlew-wrapper.jar --- gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59536 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 gradle/wrapper/gradle-wrapper.jar diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7454180f2ae8848c63b8b4dea2cb829da983f2fa GIT binary patch literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 0 HcmV?d00001 From 53aaa1b8c016a4c47012bd8ffa582fadf3cfcb8b Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Sun, 26 Mar 2023 15:43:26 +0300 Subject: [PATCH 024/125] feat: Add AVL tree balancer implementation --- .../main/kotlin/bst/balancer/AVLBalancer.kt | 108 +++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt b/binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt index 14edcfd..9d21689 100644 --- a/binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt +++ b/binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt @@ -1,13 +1,117 @@ package bst.balancer +import kotlin.math.max import bst.node.AVLTreeNode +import bst.node.AVLNode internal class AVLBalancer> : BinTreeBalancer> { override fun add(root: AVLTreeNode?, value: E, unique: Boolean): AVLTreeNode { - TODO("Not yet implemented") + fun insertToSubtree(subtree: AVLTreeNode?): AVLTreeNode { + if (subtree == null) { + return AVLNode(value) + } + + if (value < subtree.value) { + subtree.left = insertToSubtree(subtree.left) + } else if (value > subtree.value) { + subtree.right = insertToSubtree(subtree.right) + } else { + if (unique) return subtree + else subtree.right = insertToSubtree(subtree.right) + } + + return rebalance(subtree) ?: throw Exception("Rebalance must return not null value") + } + return insertToSubtree(root) + } + + private fun rebalance(subtree: AVLTreeNode): AVLTreeNode? { + subtree.height = 1 + max(height(subtree.left), height(subtree.right)) + + val balance = getBalance(subtree) + + if (balance > 1 && getBalance(subtree.left) >= 0) { + return rotateRight(subtree) + } + + if (balance > 1 && getBalance(subtree.left) < 0) { + subtree.left = rotateLeft(subtree.left) + return rotateRight(subtree) + } + + if (balance < -1 && getBalance(subtree.right) <= 0) { + return rotateLeft(subtree) + } + + if (balance < -1 && getBalance(subtree.right) > 0) { + subtree.right = rotateRight(subtree.right) + return rotateLeft(subtree) + } + + return subtree + } + + private fun height(node: AVLTreeNode?): Int { + return node?.height ?: 0 + } + + private fun getBalance(node: AVLTreeNode?): Int { + return if (node == null) 0 else height(node.left) - height(node.right) + } + + private fun rotateRight(y: AVLTreeNode?): AVLTreeNode? { + val x = y?.left + val child = x?.right + + x?.right = y + y?.left = child + + y?.height = max(height(y?.left), height(y?.right)) + 1 + x?.height = 1 + max(height(x?.left), height(x?.right)) + + return x + } + + private fun rotateLeft(x: AVLTreeNode?): AVLTreeNode? { + val y = x?.right + val child = y?.left + + y?.left = x + x?.right = child + + x?.height = 1 + max(height(x?.left), height(x?.right)) + y?.height = 1 + max(height(y?.left), height(y?.right)) + + return y + } + + private fun minValueNode(node: AVLTreeNode): AVLTreeNode { + var current = node + while (true) { + current = current.left ?: break + } + return current } override fun remove(root: AVLTreeNode?, value: E): AVLTreeNode? { - TODO("Not yet implemented") + if (root == null) { + return null + } + + if (value < root.value) { + root.left = remove(root.left, value) + } else if (value > root.value) { + root.right = remove(root.right, value) + } else { + if (root.left == null || root.right == null) { + return root.left ?: root.right + } else { + val temp = + minValueNode(root.right ?: throw Exception("root.right must be not null")) + root.value = temp.value + root.right = remove(root.right, temp.value) + } + } + return rebalance(root) } } From 9b44ff454b3b09c6ad498d621cb929ed5739250e Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sun, 26 Mar 2023 12:05:53 +0300 Subject: [PATCH 025/125] fix: Add Main-Class to app.jar manifest --- app/build.gradle.kts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a105571..d61863c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -9,6 +9,10 @@ kotlin { jvmToolchain(8) } +tasks.jar { + manifest.attributes["Main-Class"] = "app.AppKt" +} + plugins { // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. id("org.jetbrains.kotlin.jvm") version "1.8.10" From 6e6b4c1f257b067c88de352931b999cf75bd4f7e Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sun, 26 Mar 2023 12:06:29 +0300 Subject: [PATCH 026/125] ci: Change artifact folder location --- .github/workflows/run-on-push-to-main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-on-push-to-main.yml b/.github/workflows/run-on-push-to-main.yml index fcfa71d..ee33f55 100644 --- a/.github/workflows/run-on-push-to-main.yml +++ b/.github/workflows/run-on-push-to-main.yml @@ -17,4 +17,6 @@ jobs: - uses: actions/upload-artifact@v3 with: name: Package - path: build/libs \ No newline at end of file + path: | + app/build/libs + binary-search-trees/build/libs \ No newline at end of file From 762199c66b94fa53d435a4a4e9c0318d78a00c20 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sun, 26 Mar 2023 19:42:28 +0300 Subject: [PATCH 027/125] ci: Fix runnig same actions on push to main --- .../workflows/{run-on-push-to-main.yml => ci.yml} | 11 +++++++---- .github/workflows/run-tests.yml | 14 -------------- 2 files changed, 7 insertions(+), 18 deletions(-) rename .github/workflows/{run-on-push-to-main.yml => ci.yml} (58%) delete mode 100644 .github/workflows/run-tests.yml diff --git a/.github/workflows/run-on-push-to-main.yml b/.github/workflows/ci.yml similarity index 58% rename from .github/workflows/run-on-push-to-main.yml rename to .github/workflows/ci.yml index ee33f55..28de474 100644 --- a/.github/workflows/run-on-push-to-main.yml +++ b/.github/workflows/ci.yml @@ -2,8 +2,6 @@ name: Run full build on: push: - branches: - - main jobs: build-gradle-project: runs-on: ubuntu-latest @@ -14,9 +12,14 @@ jobs: uses: gradle/gradle-build-action@v2 - name: Run build with Gradle Wrapper run: ./gradlew build + - name: Create fat .jar file on main + if: ${{ github.ref == 'refs/heads/main' }} + run: ./gradlew app:buildFatJar + - uses: actions/upload-artifact@v3 + if: ${{ github.ref == 'refs/heads/main' }} with: name: Package path: | - app/build/libs - binary-search-trees/build/libs \ No newline at end of file + app/build/libs/app-all.jar + binary-search-trees/build/libs/binary-search-trees.jar \ No newline at end of file diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml deleted file mode 100644 index 9cc1855..0000000 --- a/.github/workflows/run-tests.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Run tests - -on: [ pull_request, push ] - -jobs: - build-gradle-project: - runs-on: ubuntu-latest - steps: - - name: Checkout project sources - uses: actions/checkout@v2 - - name: Setup Gradle - uses: gradle/gradle-build-action@v2 - - name: Run build with Gradle Wrapper - run: ./gradlew test From 515147810a31d0c67c901f736e329b4628ac9684 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sun, 26 Mar 2023 19:43:24 +0300 Subject: [PATCH 028/125] feat: Add ktor for fat jar building --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d61863c..53c981c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -16,7 +16,7 @@ tasks.jar { plugins { // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. id("org.jetbrains.kotlin.jvm") version "1.8.10" - + id("io.ktor.plugin") version "2.2.4" // Apply the application plugin to add support for building a CLI application in Java. application } From ae2b3829cd05e93440a12c8b8232a53cc8a16807 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sun, 26 Mar 2023 20:00:41 +0300 Subject: [PATCH 029/125] ci: Upload artifacts separately --- .github/workflows/ci.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 28de474..f0c8ff2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,11 @@ jobs: - uses: actions/upload-artifact@v3 if: ${{ github.ref == 'refs/heads/main' }} with: - name: Package - path: | - app/build/libs/app-all.jar - binary-search-trees/build/libs/binary-search-trees.jar \ No newline at end of file + name: All in one jar + path: app/build/libs/app-all.jar + + - uses: actions/upload-artifact@v3 + if: ${{ github.ref == 'refs/heads/main' }} + with: + name: Binary search trees lib jar + path: binary-search-trees/build/libs/binary-search-trees.jar \ No newline at end of file From fea817d61064d725876740ce2e62d2273b3bfd26 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Thu, 30 Mar 2023 13:10:13 +0300 Subject: [PATCH 030/125] ci: Bump checkout version --- .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 f0c8ff2..eda67c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout project sources - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup Gradle uses: gradle/gradle-build-action@v2 - name: Run build with Gradle Wrapper From 866e988c60d7b09480ac90ba16995123c7ba09ef Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Thu, 30 Mar 2023 13:19:00 +0300 Subject: [PATCH 031/125] ci: Add filter for Feedback PR --- .github/mergeable.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/mergeable.yml b/.github/mergeable.yml index 52e1cb4..27ceb8f 100644 --- a/.github/mergeable.yml +++ b/.github/mergeable.yml @@ -1,6 +1,14 @@ version: 2 mergeable: - when: pull_request.*, pull_request_review.* + filter: + # ignore 'Feedback' PR + - do: payload + pull_request: + title: + must_exclude: + regex: ^Feedback$ + regex_flag: none validate: - do: description no_empty: From 240b4273c8e3529dd8bb03d25ced50aad710e206 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Mon, 3 Apr 2023 17:43:56 +0300 Subject: [PATCH 032/125] test: Add junit5 dependency --- app/build.gradle.kts | 41 ++++++++-------------------- binary-search-trees/build.gradle.kts | 33 +++++++--------------- 2 files changed, 22 insertions(+), 52 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 53c981c..b72db1d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,46 +1,29 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * This generated file contains a sample Kotlin application project to get you started. - * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle - * User Manual available at https://docs.gradle.org/7.2/userguide/building_java_projects.html - */ -kotlin { - jvmToolchain(8) -} - -tasks.jar { - manifest.attributes["Main-Class"] = "app.AppKt" -} - plugins { - // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. id("org.jetbrains.kotlin.jvm") version "1.8.10" id("io.ktor.plugin") version "2.2.4" - // Apply the application plugin to add support for building a CLI application in Java. application } repositories { - // Use Maven Central for resolving dependencies. mavenCentral() } dependencies { - // Align versions of all Kotlin components - implementation(platform("org.jetbrains.kotlin:kotlin-bom")) - - // Use the Kotlin JDK 8 standard library. - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - - // Use the Kotlin test library. - testImplementation("org.jetbrains.kotlin:kotlin-test") - - // Use the Kotlin JUnit integration. - testImplementation("org.jetbrains.kotlin:kotlin-test-junit") + testImplementation(kotlin("test")) + testImplementation(platform("org.junit:junit-bom:5.9.2")) + testImplementation("org.junit.jupiter:junit-jupiter") implementation(project(":binary-search-trees")) } +tasks.test { + useJUnitPlatform() +} +tasks.jar { + manifest.attributes["Main-Class"] = "app.AppKt" +} +kotlin { + jvmToolchain(8) +} application { // Define the main class for the application. mainClass.set("app.AppKt") diff --git a/binary-search-trees/build.gradle.kts b/binary-search-trees/build.gradle.kts index ab19139..3a4bc02 100644 --- a/binary-search-trees/build.gradle.kts +++ b/binary-search-trees/build.gradle.kts @@ -1,34 +1,21 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * This generated file contains a sample Kotlin application project to get you started. - * For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle - * User Manual available at https://docs.gradle.org/7.2/userguide/building_java_projects.html - */ -kotlin { - jvmToolchain(8) -} - plugins { - // Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin. id("org.jetbrains.kotlin.jvm") version "1.8.10" } repositories { - // Use Maven Central for resolving dependencies. mavenCentral() } dependencies { - // Align versions of all Kotlin components - implementation(platform("org.jetbrains.kotlin:kotlin-bom")) - - // Use the Kotlin JDK 8 standard library. - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - - // Use the Kotlin test library. - testImplementation("org.jetbrains.kotlin:kotlin-test") + testImplementation(kotlin("test")) + testImplementation(platform("org.junit:junit-bom:5.9.2")) + testImplementation("org.junit.jupiter:junit-jupiter") +} - // Use the Kotlin JUnit integration. - testImplementation("org.jetbrains.kotlin:kotlin-test-junit") +tasks.test { + useJUnitPlatform() } + +kotlin { + jvmToolchain(8) +} \ No newline at end of file From 982e7d81bde111c42190c3c58ee8f9fad2b9e67b Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Mon, 3 Apr 2023 17:44:54 +0300 Subject: [PATCH 033/125] feat: Add balancer for common binary search tree --- .../main/kotlin/bst/balancer/BSBalancer.kt | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/binary-search-trees/src/main/kotlin/bst/balancer/BSBalancer.kt b/binary-search-trees/src/main/kotlin/bst/balancer/BSBalancer.kt index d83728d..71c8925 100644 --- a/binary-search-trees/src/main/kotlin/bst/balancer/BSBalancer.kt +++ b/binary-search-trees/src/main/kotlin/bst/balancer/BSBalancer.kt @@ -1,13 +1,52 @@ package bst.balancer +import bst.node.BSNode import bst.node.BinSearchTreeNode internal class BSBalancer> : BinTreeBalancer> { override fun add(root: BinSearchTreeNode?, value: E, unique: Boolean): BinSearchTreeNode { - TODO("Not yet implemented") + if (root == null) { + return BSNode(value) + } + + if (value < root.value) { + root.left = add(root.left, value, unique) + } else if (value > root.value) { + root.right = add(root.right, value, unique) + } else { + if (unique) return root + else root.right = add(root.right, value, false) + } + return root } override fun remove(root: BinSearchTreeNode?, value: E): BinSearchTreeNode? { - TODO("Not yet implemented") + if (root == null) { + return null + } + + if (value < root.value) { + root.left = remove(root.left, value) + } else if (value > root.value) { + root.right = remove(root.right, value) + } else { + if (root.left == null || root.right == null) { + return root.left ?: root.right + } else { + val temp = + minValueNode(root.right ?: throw Exception("root.right must be not null")) + root.value = temp.value + root.right = remove(root.right, temp.value) + } + } + return root + } + + private fun minValueNode(node: BinSearchTreeNode): BinSearchTreeNode { + var current = node + while (true) { + current = current.left ?: break + } + return current } } \ No newline at end of file From be022fec611db30494a786f450645c1fa44f816c Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Mon, 3 Apr 2023 17:45:55 +0300 Subject: [PATCH 034/125] test: Add invariant checks for BSTree --- .../src/test/kotlin/bst/BSTreeTest.kt | 70 +++++++++++++++++++ .../src/test/kotlin/utils/InvariantChecker.kt | 34 +++++++++ 2 files changed, 104 insertions(+) create mode 100644 binary-search-trees/src/test/kotlin/bst/BSTreeTest.kt create mode 100644 binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt diff --git a/binary-search-trees/src/test/kotlin/bst/BSTreeTest.kt b/binary-search-trees/src/test/kotlin/bst/BSTreeTest.kt new file mode 100644 index 0000000..450b423 --- /dev/null +++ b/binary-search-trees/src/test/kotlin/bst/BSTreeTest.kt @@ -0,0 +1,70 @@ +package bst + +import utils.InvariantChecker +import kotlin.random.Random +import kotlin.test.* +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +class BSTreeTest { + companion object { + const val defaultSeed = 42 + } + + private lateinit var tree: BSTree + private lateinit var values: Array + private val randomizer = Random(defaultSeed) + + @BeforeTest + fun init() { + values = Array(1000) { randomizer.nextInt(10) } + tree = BSTree() + } + + @ParameterizedTest(name = "Are unique elements added: {0}") + @ValueSource(booleans = [true, false]) + fun `test values addition invariant`(unique: Boolean) { + for (v in values) { + tree.add(v, unique) + assertTrue(InvariantChecker.isBinarySearchTree(tree)) + } + } + + @Test + fun `test all added values are unique`() { + for (v in values) { + tree.add(v, unique = true) + } + assertEquals(values.sorted().distinct(), tree.iterator().asSequence().toList()) + // Don't use toSet in `actual` part of assertEquals because of false-positive effect + } + + @ParameterizedTest(name = "Are unique elements added: {0}") + @ValueSource(booleans = [true, false]) + fun `test values deletion invariant`(unique: Boolean) { + values.forEach { tree.add(it, unique) } + values.shuffle() + for (v in values) { + tree.remove(v) + assertTrue(InvariantChecker.isBinarySearchTree(tree)) + } + + assertEquals(null, tree.wrappedRoot) // Tree is empty + } + + @Test + fun `test values are being removed gradually`() { + val uniqueValues = values.toSet() + var countOfUniqueValues = uniqueValues.size + values.forEach { tree.add(it, unique = true) } + + for (v in uniqueValues) { + assertEquals(countOfUniqueValues, tree.iterator().asSequence().toList().size) + tree.remove(v) + countOfUniqueValues-- + } + + assertEquals(0, tree.iterator().asSequence().toList().size) + } +} \ No newline at end of file diff --git a/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt b/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt new file mode 100644 index 0000000..ff585a1 --- /dev/null +++ b/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt @@ -0,0 +1,34 @@ +package utils + +import bst.BinarySearchTree +import bst.node.BinTreeNode +import bst.wrapper.WrappedBinNode +import java.util.* + +object InvariantChecker { + fun , NodeType : BinTreeNode, WrappedType : WrappedBinNode> // python actually is better + isBinarySearchTree( + bst: BinarySearchTree + ): Boolean { + var currentNode = bst.wrappedRoot + var prevNode: WrappedType? = null + val stack = Stack() + + while (currentNode != null || stack.isNotEmpty()) { + while (currentNode != null) { + stack.push(currentNode) + currentNode = currentNode.left + } + + currentNode = stack.pop() + if (prevNode != null && currentNode.value < prevNode.value) { + return false + } + prevNode = currentNode + + currentNode = currentNode.right + } + + return true + } +} \ No newline at end of file From 9ed7e6e5add03da315b47419510e1dbd14c8214c Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Sun, 2 Apr 2023 23:34:57 +0300 Subject: [PATCH 035/125] test: Add test implementation for avl tree --- .../src/test/kotlin/bst/AVLTreeTest.kt | 51 +++++++++++++++++++ .../kotlin/bst/balancer/AVLBalancerTest.kt | 46 +++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt create mode 100644 binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt diff --git a/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt b/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt new file mode 100644 index 0000000..bd8ba72 --- /dev/null +++ b/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt @@ -0,0 +1,51 @@ +import bst.AVLTree +import org.junit.Assert.assertEquals +import org.junit.Test + +class AVLTreeTest { + @Test + fun `test adding elements to the tree`() { + val tree = AVLTree() + tree.add(5) + tree.add(3) + tree.add(7) + tree.add(2) + tree.add(4) + tree.add(6) + tree.add(8) + + assertEquals(tree.wrappedRoot?.value, 5) + assertEquals(tree.wrappedRoot?.left?.value, 3) + assertEquals(tree.wrappedRoot?.right?.value, 7) + assertEquals(tree.wrappedRoot?.left?.left?.value, 2) + assertEquals(tree.wrappedRoot?.left?.right?.value, 4) + assertEquals(tree.wrappedRoot?.right?.left?.value, 6) + assertEquals(tree.wrappedRoot?.right?.right?.value, 8) + } + + @Test + fun `test removing elements from the tree`() { + val tree = AVLTree() + tree.add(5) + tree.add(3) + tree.add(7) + tree.add(2) + tree.add(4) + tree.add(6) + tree.add(8) + + tree.remove(2) + tree.remove(4) + tree.remove(6) + + assertEquals(tree.wrappedRoot?.value, 5) + assertEquals(tree.wrappedRoot?.left?.value, 3) + assertEquals(tree.wrappedRoot?.right?.value, 7) + assertEquals(tree.wrappedRoot?.left?.left, null) + assertEquals(tree.wrappedRoot?.left?.right, null) + assertEquals(tree.wrappedRoot?.right?.left, null) + assertEquals(tree.wrappedRoot?.right?.right?.value, 8) + } +} + + diff --git a/binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt b/binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt new file mode 100644 index 0000000..278bc9e --- /dev/null +++ b/binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt @@ -0,0 +1,46 @@ +package bst.balancer + +import bst.node.AVLNode +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test + +class AVLBalancerTest { + private val balancer = AVLBalancer() + @Test + fun `test add`() { + val root = AVLNode(5) + balancer.add(root, 3, true) + balancer.add(root, 7, true) + balancer.add(root, 2, true) + balancer.add(root, 4, true) + balancer.add(root, 6, true) + balancer.add(root, 8, true) + assertEquals(5, root.value) + assertEquals(3, root.left?.value) + assertEquals(2, root.left?.left?.value) + assertEquals(4, root.left?.right?.value) + assertEquals(7, root.right?.value) + assertEquals(6, root.right?.left?.value) + assertEquals(8, root.right?.right?.value) + } + + @Test + fun `test remove`() { + val root = AVLNode(5) + balancer.add(root, 3, true) + balancer.add(root, 7, true) + balancer.add(root, 2, true) + balancer.add(root, 4, true) + balancer.add(root, 6, true) + balancer.add(root, 8, true) + balancer.remove(root, 2) + assertEquals(5, root.value) + assertEquals(3, root.left?.value) + assertNull(root.left?.left) + assertEquals(4, root.left?.right?.value) + assertEquals(7, root.right?.value) + assertEquals(6, root.right?.left?.value) + assertEquals(8, root.right?.right?.value) + } +} From 96b31168c035d8350d3a5b9ba6420c56b5950d47 Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Tue, 4 Apr 2023 20:44:52 +0300 Subject: [PATCH 036/125] refactor: Add comments with a drawn tree structure --- .../kotlin/bst/balancer/AVLBalancerTest.kt | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt b/binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt index 278bc9e..dc08be6 100644 --- a/binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt +++ b/binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt @@ -8,7 +8,7 @@ import org.junit.Test class AVLBalancerTest { private val balancer = AVLBalancer() @Test - fun `test add`() { + fun `test method 'add' in avl tree balancer`() { val root = AVLNode(5) balancer.add(root, 3, true) balancer.add(root, 7, true) @@ -16,6 +16,16 @@ class AVLBalancerTest { balancer.add(root, 4, true) balancer.add(root, 6, true) balancer.add(root, 8, true) + + /* + constructed tree: + 5 + / \ + 3 7 + / \ / \ + 2 4 6 8 + */ + assertEquals(5, root.value) assertEquals(3, root.left?.value) assertEquals(2, root.left?.left?.value) @@ -26,7 +36,7 @@ class AVLBalancerTest { } @Test - fun `test remove`() { + fun `test method 'remove' in avl tree balancer`() { val root = AVLNode(5) balancer.add(root, 3, true) balancer.add(root, 7, true) @@ -34,7 +44,27 @@ class AVLBalancerTest { balancer.add(root, 4, true) balancer.add(root, 6, true) balancer.add(root, 8, true) + + /* + constructed tree: + 5 + / \ + 3 7 + / \ / \ + 2 4 6 8 + */ + balancer.remove(root, 2) + + /* + constructed tree: + 5 + / \ + 3 7 + \ / \ + 4 6 8 + */ + assertEquals(5, root.value) assertEquals(3, root.left?.value) assertNull(root.left?.left) From 1c1b2594d5d77b7996d7b8422e2468f4b25d1a60 Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Tue, 4 Apr 2023 23:17:14 +0300 Subject: [PATCH 037/125] test: Add tree invariant validation tests --- .../src/test/kotlin/bst/AVLTreeTest.kt | 114 +++++++++++------- .../kotlin/bst/balancer/AVLBalancerTest.kt | 4 +- .../src/test/kotlin/utils/InvariantChecker.kt | 26 ++++ 3 files changed, 98 insertions(+), 46 deletions(-) diff --git a/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt b/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt index bd8ba72..9545445 100644 --- a/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt +++ b/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt @@ -1,51 +1,79 @@ -import bst.AVLTree -import org.junit.Assert.assertEquals -import org.junit.Test +package bst + +import utils.InvariantChecker +import kotlin.random.Random +import kotlin.test.* + +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource class AVLTreeTest { - @Test - fun `test adding elements to the tree`() { - val tree = AVLTree() - tree.add(5) - tree.add(3) - tree.add(7) - tree.add(2) - tree.add(4) - tree.add(6) - tree.add(8) - - assertEquals(tree.wrappedRoot?.value, 5) - assertEquals(tree.wrappedRoot?.left?.value, 3) - assertEquals(tree.wrappedRoot?.right?.value, 7) - assertEquals(tree.wrappedRoot?.left?.left?.value, 2) - assertEquals(tree.wrappedRoot?.left?.right?.value, 4) - assertEquals(tree.wrappedRoot?.right?.left?.value, 6) - assertEquals(tree.wrappedRoot?.right?.right?.value, 8) + companion object { + const val defaultSeed = 42 + } + + private lateinit var tree: AVLTree + private lateinit var values: Array + private val randomizer = Random(defaultSeed) + + @BeforeTest + fun init() { + values = Array(1000) { randomizer.nextInt(10) } + tree = AVLTree() + } + + @ParameterizedTest(name = "Are unique elements added: {0}") + @ValueSource(booleans = [true, false]) + fun `test values addition invariant`(unique: Boolean) { + for (v in values) { + tree.add(v, unique) + assertTrue(InvariantChecker.isBinarySearchTree(tree)) + assertTrue(InvariantChecker.checkNeighborHeights(tree.wrappedRoot)) + + } } @Test - fun `test removing elements from the tree`() { - val tree = AVLTree() - tree.add(5) - tree.add(3) - tree.add(7) - tree.add(2) - tree.add(4) - tree.add(6) - tree.add(8) - - tree.remove(2) - tree.remove(4) - tree.remove(6) - - assertEquals(tree.wrappedRoot?.value, 5) - assertEquals(tree.wrappedRoot?.left?.value, 3) - assertEquals(tree.wrappedRoot?.right?.value, 7) - assertEquals(tree.wrappedRoot?.left?.left, null) - assertEquals(tree.wrappedRoot?.left?.right, null) - assertEquals(tree.wrappedRoot?.right?.left, null) - assertEquals(tree.wrappedRoot?.right?.right?.value, 8) + fun `test all added values are unique`() { + for (v in values) { + tree.add(v, unique = true) + } + assertEquals(values.sorted().distinct(), tree.iterator().asSequence().toList()) + // Don't use toSet in `actual` part of assertEquals because of false-positive effect } -} + @ParameterizedTest(name = "Are unique elements added: {0}") + @ValueSource(booleans = [true, false]) + fun `test values deletion invariant`(unique: Boolean) { + values.forEach { tree.add(it, unique) } + values.shuffle() + for (v in values) { + tree.remove(v) + assertTrue(InvariantChecker.isBinarySearchTree(tree)) + } + assertEquals(null, tree.wrappedRoot) // Tree is empty + } + + @Test + fun `test values are being removed gradually`() { + val uniqueValues = values.toSet() + var countOfUniqueValues = uniqueValues.size + values.forEach { tree.add(it, unique = true) } + + for (v in uniqueValues) { + assertEquals(countOfUniqueValues, tree.iterator().asSequence().toList().size) + tree.remove(v) + countOfUniqueValues-- + } + + assertEquals(0, tree.iterator().asSequence().toList().size) + } + + @Test + fun `test value heights`() { + for (v in values) { + tree.add(v) + } + } +} \ No newline at end of file diff --git a/binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt b/binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt index dc08be6..31d3fca 100644 --- a/binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt +++ b/binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt @@ -1,9 +1,7 @@ package bst.balancer import bst.node.AVLNode -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNull -import org.junit.Test +import kotlin.test.* class AVLBalancerTest { private val balancer = AVLBalancer() diff --git a/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt b/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt index ff585a1..41fe554 100644 --- a/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt +++ b/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt @@ -2,8 +2,10 @@ package utils import bst.BinarySearchTree import bst.node.BinTreeNode +import bst.wrapper.WrappedAVLNode import bst.wrapper.WrappedBinNode import java.util.* +import kotlin.math.abs object InvariantChecker { fun , NodeType : BinTreeNode, WrappedType : WrappedBinNode> // python actually is better @@ -31,4 +33,28 @@ object InvariantChecker { return true } + + fun > checkNeighborHeights(node: WrappedAVLNode?): Boolean { + if (node == null) { + return true + } + + val leftHeight = calculateHeight(node.left) + val rightHeight = calculateHeight(node.right) + + if (abs(leftHeight - rightHeight) > 1) { + return false + } + + return checkNeighborHeights(node.left) && checkNeighborHeights(node.right) + } + + private fun > calculateHeight(node: WrappedAVLNode?): Int { + if (node == null) { + return 0 + } + val leftHeight = calculateHeight(node.left) + val rightHeight = calculateHeight(node.right) + return 1 + maxOf(leftHeight, rightHeight) + } } \ No newline at end of file From a8494c20474cf2ba956588dfacd5777fb472865d Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Tue, 4 Apr 2023 23:32:38 +0300 Subject: [PATCH 038/125] test: Add height check after removing elements --- binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt b/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt index 9545445..047f8ad 100644 --- a/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt +++ b/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt @@ -29,7 +29,6 @@ class AVLTreeTest { tree.add(v, unique) assertTrue(InvariantChecker.isBinarySearchTree(tree)) assertTrue(InvariantChecker.checkNeighborHeights(tree.wrappedRoot)) - } } @@ -50,6 +49,7 @@ class AVLTreeTest { for (v in values) { tree.remove(v) assertTrue(InvariantChecker.isBinarySearchTree(tree)) + assertTrue(InvariantChecker.checkNeighborHeights(tree.wrappedRoot)) } assertEquals(null, tree.wrappedRoot) // Tree is empty @@ -69,11 +69,4 @@ class AVLTreeTest { assertEquals(0, tree.iterator().asSequence().toList().size) } - - @Test - fun `test value heights`() { - for (v in values) { - tree.add(v) - } - } } \ No newline at end of file From 4ccc4891a3db35c7099a9bb3be6573a856d4d770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Sun, 2 Apr 2023 12:44:14 +0300 Subject: [PATCH 039/125] feat: Add red black tree balancer --- .../main/kotlin/bst/balancer/RBBalancer.kt | 212 +++++++++++++++++- .../src/main/kotlin/bst/node/RBNode.kt | 19 +- .../main/kotlin/bst/node/RedBlackTreeNode.kt | 2 +- 3 files changed, 212 insertions(+), 21 deletions(-) diff --git a/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt b/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt index 4bf20b5..d70e5f9 100644 --- a/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt +++ b/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt @@ -1,13 +1,219 @@ package bst.balancer +import bst.node.RBNode import bst.node.RedBlackTreeNode -internal class RBBalancer> : BinTreeBalancer> { +class RBBalancer> : BinTreeBalancer> { + private fun rotateLeft(node: RedBlackTreeNode?, root: RedBlackTreeNode?): RedBlackTreeNode? { + val child = node?.right ?: return root + var newRoot = root + + node.right = child.left + child.left?.parent = node + child.parent = node.parent + + if (node.parent == null) newRoot = child + else { + if (node == node.parent?.left) node.parent?.left = child + else node.parent?.right = child + } + child.left = node + node.parent = child + + + + return newRoot + } + + private fun rotateRight(node: RedBlackTreeNode?, root: RedBlackTreeNode?): RedBlackTreeNode? { + val child = node?.left ?: return root + var newRoot = root + + node.left = child.right + child.right?.parent = node + child.parent = node.parent + + if (node.parent == null) newRoot = child + else { + if (node == node.parent?.left) node.parent?.left + else node.parent?.right = child + } + + child.right = node + node.parent = child + return newRoot + } + + private fun fixAfterInsertion(node: RedBlackTreeNode, root: RedBlackTreeNode): RedBlackTreeNode? { + if (node.parent == null) return root + var current: RedBlackTreeNode? = node + var newRoot: RedBlackTreeNode? = root + + while (current?.parent?.color == RedBlackTreeNode.Color.RED) { + if (current.parent == current.parent?.parent?.left) { + val uncle = current.parent?.parent?.right + if (uncle?.color == RedBlackTreeNode.Color.RED) { + current.parent?.color = RedBlackTreeNode.Color.BLACK + uncle.color = RedBlackTreeNode.Color.BLACK + current.parent?.parent?.color = RedBlackTreeNode.Color.RED + current = current.parent?.parent + } else { + if (current == current.parent?.right) { + current = current.parent + newRoot = rotateLeft(current, newRoot) + } + current?.parent?.color = RedBlackTreeNode.Color.BLACK + current?.parent?.parent?.color = RedBlackTreeNode.Color.RED + newRoot = rotateRight(current?.parent?.parent, newRoot) + } + + } else { + val uncle = current.parent?.parent?.left + if (uncle?.color == RedBlackTreeNode.Color.RED) { + current.parent?.color = RedBlackTreeNode.Color.BLACK + uncle.color = RedBlackTreeNode.Color.BLACK + current.parent?.parent?.color = RedBlackTreeNode.Color.RED + current = current.parent?.parent + } else { + if (current == current.parent?.left) { + current = current.parent + newRoot = rotateRight(current, newRoot) + } + current?.parent?.color = RedBlackTreeNode.Color.BLACK + current?.parent?.parent?.color = RedBlackTreeNode.Color.RED + newRoot = rotateLeft(current?.parent?.parent, newRoot) + } + } + } + newRoot?.color = RedBlackTreeNode.Color.BLACK + + return newRoot + } + override fun add(root: RedBlackTreeNode?, value: E, unique: Boolean): RedBlackTreeNode { - TODO("Not yet implemented") + val newNode = RBNode(value) + + fun addToSubtree(subtree: RedBlackTreeNode?): RedBlackTreeNode { + val node = subtree ?: return newNode + + if (value < node.value) node.left = addToSubtree(node.left).also { it.parent = node } + else if (value > node.value) node.right = addToSubtree(node.right).also { it.parent = node } + else { + if (unique) node.value = value + else node.right = addToSubtree(node.right).also { it.parent = node } + } + + return node + } + + return fixAfterInsertion(newNode, addToSubtree(root)) + ?: throw Exception("after insertion root must be not null") + } + + private fun findNode(node: RedBlackTreeNode?, value: E): RedBlackTreeNode? { + node ?: return null + if (value == node.value) { + return node + } + return findNode(if (value < node.value) node.left else node.right, value) + } + + private fun minValueNode(node: RedBlackTreeNode): RedBlackTreeNode { + var current = node + while (true) { + current = current.left ?: break + } + return current + } + + private fun fixAfterDeletion(node: RedBlackTreeNode?, root: RedBlackTreeNode?): RedBlackTreeNode? { + var newRoot = root + var current = node + var sibling: RedBlackTreeNode? + + while (current != newRoot && current?.color == RedBlackTreeNode.Color.BLACK) { + if (current == current.parent?.left) { + sibling = current.parent?.right + if (sibling?.color == RedBlackTreeNode.Color.RED) { + sibling.color = RedBlackTreeNode.Color.BLACK + current.parent?.color = RedBlackTreeNode.Color.RED + newRoot = rotateLeft(current.parent, newRoot) + sibling = current.parent?.right + } + if (sibling?.left?.color == RedBlackTreeNode.Color.BLACK && sibling.right?.color == RedBlackTreeNode.Color.BLACK) { + sibling.color = RedBlackTreeNode.Color.RED + current = current.parent + } else { + if (sibling?.right?.color == RedBlackTreeNode.Color.BLACK) { + sibling.left?.color = RedBlackTreeNode.Color.BLACK + sibling.color = RedBlackTreeNode.Color.RED + newRoot = rotateRight(sibling, newRoot) + sibling = current.parent?.right + } + sibling?.color = current.parent?.color ?: RedBlackTreeNode.Color.BLACK + current.parent?.color = RedBlackTreeNode.Color.BLACK + sibling?.right?.color = RedBlackTreeNode.Color.BLACK + newRoot = rotateLeft(current.parent, newRoot) + current = newRoot + } + } else { + sibling = current.parent?.left + if (sibling?.color == RedBlackTreeNode.Color.RED) { + sibling.color = RedBlackTreeNode.Color.BLACK + current.parent?.color = RedBlackTreeNode.Color.RED + newRoot = rotateRight(current.parent, newRoot) + sibling = current.parent?.left + } + if (sibling?.right?.color == RedBlackTreeNode.Color.BLACK && sibling.left?.color == RedBlackTreeNode.Color.BLACK) { + sibling.color = RedBlackTreeNode.Color.RED + current = current.parent + } else { + if (sibling?.left?.color == RedBlackTreeNode.Color.BLACK) { + sibling.right?.color = RedBlackTreeNode.Color.BLACK + sibling.color = RedBlackTreeNode.Color.RED + newRoot = rotateLeft(sibling, newRoot) + sibling = current.parent?.left + } + sibling?.color = current.parent?.color ?: RedBlackTreeNode.Color.BLACK + current.parent?.color = RedBlackTreeNode.Color.BLACK + sibling?.left?.color = RedBlackTreeNode.Color.BLACK + newRoot = rotateRight(current.parent, newRoot) + current = newRoot + } + } + } + current?.color = RedBlackTreeNode.Color.BLACK + + return newRoot } override fun remove(root: RedBlackTreeNode?, value: E): RedBlackTreeNode? { - TODO("Not yet implemented") + val node = findNode(root, value) ?: return root + val successor: RedBlackTreeNode + + if (node.left == null || node.right == null) + successor = node + else { + successor = minValueNode(node.right ?: throw Exception("node.right must be not null")) + node.value = successor.value + } + + val child = successor.left ?: successor.right + + child?.parent = successor.parent + var newRoot = if (successor.parent == null) child else root + + if (successor == successor.parent?.left) { + successor.parent?.left = child + } else { + successor.parent?.right = child + } + + if (successor.color == RedBlackTreeNode.Color.BLACK) { + newRoot = fixAfterDeletion(child, newRoot) + } + + return newRoot } + } \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt b/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt index 5119c40..87bf917 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt +++ b/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt @@ -2,23 +2,8 @@ package bst.node internal data class RBNode>( override var value: E, + override var parent: RedBlackTreeNode? = null, override var color: RedBlackTreeNode.Color = RedBlackTreeNode.Color.RED, override var left: RedBlackTreeNode? = null, override var right: RedBlackTreeNode? = null, -) : RedBlackTreeNode { - override fun flipColor() { - color = when (color) { - RedBlackTreeNode.Color.BLACK -> RedBlackTreeNode.Color.RED - else -> RedBlackTreeNode.Color.BLACK - } - } -} - -internal fun > RedBlackTreeNode?.isBlack(): Boolean { - if (this == null) return true - return this.color == RedBlackTreeNode.Color.BLACK -} - -internal fun > RedBlackTreeNode?.isRed(): Boolean { - return !this.isBlack() -} +) : RedBlackTreeNode \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt b/binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt index ea4e96e..bfa8e70 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt +++ b/binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt @@ -2,7 +2,7 @@ package bst.node interface RedBlackTreeNode> : BinTreeNode> { var color: Color - fun flipColor() + var parent: RedBlackTreeNode? enum class Color { RED, BLACK } From cf694286575d9c4c30a92daade84af0d38c95b9c Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Mon, 3 Apr 2023 23:36:03 +0300 Subject: [PATCH 040/125] fix: Remove `data` in nodes because of comparation stackoverflow --- binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt | 2 +- binary-search-trees/src/main/kotlin/bst/node/BSNode.kt | 2 +- binary-search-trees/src/main/kotlin/bst/node/RBNode.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt b/binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt index 485d85e..44ce6e8 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt +++ b/binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt @@ -1,6 +1,6 @@ package bst.node -internal data class AVLNode>( +internal class AVLNode>( override var value: E, override var height: Int = 1, override var left: AVLTreeNode? = null, diff --git a/binary-search-trees/src/main/kotlin/bst/node/BSNode.kt b/binary-search-trees/src/main/kotlin/bst/node/BSNode.kt index 760bc27..ff0ed02 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/BSNode.kt +++ b/binary-search-trees/src/main/kotlin/bst/node/BSNode.kt @@ -1,6 +1,6 @@ package bst.node -internal data class BSNode>( +internal class BSNode>( override var value: E, override var left: BinSearchTreeNode? = null, override var right: BinSearchTreeNode? = null, diff --git a/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt b/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt index 87bf917..540a960 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt +++ b/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt @@ -1,6 +1,6 @@ package bst.node -internal data class RBNode>( +internal class RBNode>( override var value: E, override var parent: RedBlackTreeNode? = null, override var color: RedBlackTreeNode.Color = RedBlackTreeNode.Color.RED, From dfc61191f0dd9f624610b8a6cc7d27f1e916a050 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Mon, 3 Apr 2023 23:36:57 +0300 Subject: [PATCH 041/125] feat: Add parent property to wrapped red black node --- .../src/main/kotlin/bst/wrapper/WrappedRBNode.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedRBNode.kt b/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedRBNode.kt index e0b5ed6..6b8100e 100644 --- a/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedRBNode.kt +++ b/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedRBNode.kt @@ -10,6 +10,9 @@ class WrappedRBNode>(private val node: RedBlackTreeNode) : override val value: E get() = node.value + val parent: WrappedRBNode? + get() = node.parent?.let { WrappedRBNode(it) } + override val left: WrappedRBNode? get() = node.left?.let { WrappedRBNode(it) } From 2142110dc5c61f5a720699b5495cb2d8f229059d Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Wed, 5 Apr 2023 17:51:00 +0300 Subject: [PATCH 042/125] test: Add invariant checks for RBTree --- .../src/test/kotlin/bst/RBTreeTest.kt | 74 +++++++++++++++++++ .../src/test/kotlin/utils/InvariantChecker.kt | 55 +++++++++++++- 2 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt diff --git a/binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt b/binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt new file mode 100644 index 0000000..da19a39 --- /dev/null +++ b/binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt @@ -0,0 +1,74 @@ +package bst + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource +import utils.InvariantChecker +import kotlin.random.Random +import kotlin.test.* + +class RBTreeTest { + companion object { + const val defaultSeed = 42 + } + + private lateinit var tree: RBTree + private lateinit var values: Array + private val randomizer = Random(defaultSeed) + + @BeforeTest + fun init() { + values = Array(1000) { randomizer.nextInt(10) } + tree = RBTree() + } + + @ParameterizedTest(name = "Are unique elements added: {0}") + @ValueSource(booleans = [true, false]) + fun `test values addition invariant`(unique: Boolean) { + for (v in values) { + tree.add(v, unique) + assertTrue(InvariantChecker.isBinarySearchTree(tree)) + assertTrue(InvariantChecker.isColoredRight(tree)) + assertTrue(InvariantChecker.isBlackHeightBalanced(tree)) + } + } + + @Test + fun `test all added values are unique`() { + for (v in values) { + tree.add(v, unique = true) + } + Assertions.assertEquals(values.sorted().distinct(), tree.iterator().asSequence().toList()) + // Don't use toSet in `actual` part of assertEquals because of false-positive effect + } + + @ParameterizedTest(name = "Are unique elements added: {0}") + @ValueSource(booleans = [true, false]) + fun `test values deletion invariant`(unique: Boolean) { + values.forEach { tree.add(it, unique) } + values.shuffle() + for (v in values) { + tree.remove(v) + assertTrue(InvariantChecker.isBinarySearchTree(tree)) + assertTrue(InvariantChecker.isColoredRight(tree)) + assertTrue(InvariantChecker.isBlackHeightBalanced(tree)) + } + + Assertions.assertEquals(null, tree.wrappedRoot) // Tree is empty + } + + @Test + fun `test values are being removed gradually`() { + val uniqueValues = values.toSet() + var countOfUniqueValues = uniqueValues.size + values.forEach { tree.add(it, unique = true) } + + for (v in uniqueValues) { + assertEquals(countOfUniqueValues, tree.iterator().asSequence().toList().size) + tree.remove(v) + countOfUniqueValues-- + } + + Assertions.assertEquals(0, tree.iterator().asSequence().toList().size) + } +} \ No newline at end of file diff --git a/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt b/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt index 41fe554..6115725 100644 --- a/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt +++ b/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt @@ -1,9 +1,12 @@ package utils import bst.BinarySearchTree +import bst.RBTree import bst.node.BinTreeNode import bst.wrapper.WrappedAVLNode +import bst.node.RedBlackTreeNode import bst.wrapper.WrappedBinNode +import bst.wrapper.WrappedRBNode import java.util.* import kotlin.math.abs @@ -34,7 +37,7 @@ object InvariantChecker { return true } - fun > checkNeighborHeights(node: WrappedAVLNode?): Boolean { + fun > checkNeighborHeights(node: WrappedAVLNode?): Boolean { if (node == null) { return true } @@ -56,5 +59,51 @@ object InvariantChecker { val leftHeight = calculateHeight(node.left) val rightHeight = calculateHeight(node.right) return 1 + maxOf(leftHeight, rightHeight) - } -} \ No newline at end of file + + private fun > isBlack(root: WrappedRBNode?): Boolean { + root ?: return true + return root.color == RedBlackTreeNode.Color.BLACK + } + + fun > isColoredRight(tree: RBTree?): Boolean { + fun helper(root: WrappedRBNode?): Boolean { + root ?: return true + if (root.color == RedBlackTreeNode.Color.RED && !isBlack(root.parent) + ) + return false + + return helper(root.left) && helper(root.right) + } + return helper(tree?.wrappedRoot) && isBlack(tree?.wrappedRoot) + } + + fun > isBlackHeightBalanced(tree: RBTree?): Boolean { + fun helper(root: WrappedRBNode?): Boolean { + root ?: return true + + val leftHeight = blackHeight(root.left) + val rightHeight = blackHeight(root.right) + if (leftHeight != rightHeight) { + return false + } + + return helper(root.left) && helper(root.right) + } + return helper(tree?.wrappedRoot) + } + + private fun > blackHeight(node: WrappedRBNode?): Int { + if (node == null) { + return 0 + } + + val leftHeight = blackHeight(node.left) + val rightHeight = blackHeight(node.right) + + return if (node.color == RedBlackTreeNode.Color.BLACK) { + maxOf(leftHeight, rightHeight) + 1 + } else { + maxOf(leftHeight, rightHeight) + } + } + } \ No newline at end of file From 589d20d46ca8125ef51e9e8746eb2d7c457f7c8f Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Wed, 5 Apr 2023 17:52:57 +0300 Subject: [PATCH 043/125] fix: Update rotations and fix wrong root recoloring --- .../main/kotlin/bst/balancer/RBBalancer.kt | 184 ++++++++++-------- 1 file changed, 103 insertions(+), 81 deletions(-) diff --git a/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt b/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt index d70e5f9..4765dee 100644 --- a/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt +++ b/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt @@ -4,53 +4,84 @@ import bst.node.RBNode import bst.node.RedBlackTreeNode class RBBalancer> : BinTreeBalancer> { - private fun rotateLeft(node: RedBlackTreeNode?, root: RedBlackTreeNode?): RedBlackTreeNode? { - val child = node?.right ?: return root - var newRoot = root + override fun add(root: RedBlackTreeNode?, value: E, unique: Boolean): RedBlackTreeNode { + val newNode = RBNode(value) - node.right = child.left - child.left?.parent = node - child.parent = node.parent + fun addToSubtree(subtree: RedBlackTreeNode?): RedBlackTreeNode { + val node = subtree ?: return newNode - if (node.parent == null) newRoot = child - else { - if (node == node.parent?.left) node.parent?.left = child - else node.parent?.right = child + if (value < node.value) node.left = addToSubtree(node.left).also { it.parent = node } + else if (value > node.value) node.right = addToSubtree(node.right).also { it.parent = node } + else { + if (unique) node.value = value + else node.right = addToSubtree(node.right).also { it.parent = node } + } + + return node } - child.left = node - node.parent = child + return fixAfterInsertion(newNode, addToSubtree(root)) + ?: throw Exception("after insertion root must be not null") + } + + private fun rotateLeft(node: RedBlackTreeNode?, root: RedBlackTreeNode?): RedBlackTreeNode? { + val rightChild = node?.right ?: return null + node.right = rightChild.left + + if (rightChild.left != null) { + rightChild.left?.parent = node + } + + rightChild.parent = node.parent + var newRoot = root + + if (node.parent == null) { + newRoot = rightChild + } else if (node === node.parent?.left) { + node.parent?.left = rightChild + } else { + node.parent?.right = rightChild + } + rightChild.left = node + node.parent = rightChild return newRoot } private fun rotateRight(node: RedBlackTreeNode?, root: RedBlackTreeNode?): RedBlackTreeNode? { - val child = node?.left ?: return root - var newRoot = root + val leftChild = node?.left ?: return null + node.left = leftChild.right + + if (leftChild.right != null) { + leftChild.right?.parent = node + } - node.left = child.right - child.right?.parent = node - child.parent = node.parent + leftChild.parent = node.parent + var newRoot = root - if (node.parent == null) newRoot = child - else { - if (node == node.parent?.left) node.parent?.left - else node.parent?.right = child + if (node.parent == null) { + // node was the root of the tree + newRoot = leftChild + } else if (node === node.parent?.right) { + node.parent?.right = leftChild + } else { + node.parent?.left = leftChild } - child.right = node - node.parent = child + leftChild.right = node + node.parent = leftChild + return newRoot } private fun fixAfterInsertion(node: RedBlackTreeNode, root: RedBlackTreeNode): RedBlackTreeNode? { - if (node.parent == null) return root + if (node.parent == null) return root.also { it.color = RedBlackTreeNode.Color.BLACK } var current: RedBlackTreeNode? = node var newRoot: RedBlackTreeNode? = root while (current?.parent?.color == RedBlackTreeNode.Color.RED) { - if (current.parent == current.parent?.parent?.left) { + if (current.parent === current.parent?.parent?.left) { val uncle = current.parent?.parent?.right if (uncle?.color == RedBlackTreeNode.Color.RED) { current.parent?.color = RedBlackTreeNode.Color.BLACK @@ -90,49 +121,55 @@ class RBBalancer> : BinTreeBalancer> { return newRoot } - override fun add(root: RedBlackTreeNode?, value: E, unique: Boolean): RedBlackTreeNode { - val newNode = RBNode(value) - - fun addToSubtree(subtree: RedBlackTreeNode?): RedBlackTreeNode { - val node = subtree ?: return newNode - - if (value < node.value) node.left = addToSubtree(node.left).also { it.parent = node } - else if (value > node.value) node.right = addToSubtree(node.right).also { it.parent = node } - else { - if (unique) node.value = value - else node.right = addToSubtree(node.right).also { it.parent = node } - } + override fun remove(root: RedBlackTreeNode?, value: E): RedBlackTreeNode? { + var node = findNode(root, value) ?: return root + val color = node.color + var newRoot = root - return node + if (node.left != null && node.right != null) { + val successor = minValueNode(node.right ?: throw Exception("node.right must be not null")) + node = successor } - return fixAfterInsertion(newNode, addToSubtree(root)) - ?: throw Exception("after insertion root must be not null") - } + val replacement = node.left ?: node.right - private fun findNode(node: RedBlackTreeNode?, value: E): RedBlackTreeNode? { - node ?: return null - if (value == node.value) { - return node + if (replacement != null) { + if (node.parent == null) { + newRoot = replacement + } else if (node === node.parent?.left) { + node.parent?.left = replacement + } else { + node.parent?.right = replacement + } + if (color == RedBlackTreeNode.Color.BLACK) { + newRoot = fixAfterDeletion(replacement, newRoot) + } + } else if (node.parent == null) { + newRoot = null + } else { + if (color == RedBlackTreeNode.Color.BLACK) { + newRoot = fixAfterDeletion(node, newRoot) + } + if (node.parent != null) { + if (node === node.parent?.left) { + node.parent?.left = null + } else if (node === node.parent?.right) { + node.parent?.right = null + } + node.parent = null + } } - return findNode(if (value < node.value) node.left else node.right, value) + return newRoot } - private fun minValueNode(node: RedBlackTreeNode): RedBlackTreeNode { - var current = node - while (true) { - current = current.left ?: break - } - return current - } private fun fixAfterDeletion(node: RedBlackTreeNode?, root: RedBlackTreeNode?): RedBlackTreeNode? { var newRoot = root var current = node var sibling: RedBlackTreeNode? - while (current != newRoot && current?.color == RedBlackTreeNode.Color.BLACK) { - if (current == current.parent?.left) { + while (current !== newRoot && current?.color == RedBlackTreeNode.Color.BLACK) { + if (current === current.parent?.left) { sibling = current.parent?.right if (sibling?.color == RedBlackTreeNode.Color.RED) { sibling.color = RedBlackTreeNode.Color.BLACK @@ -183,37 +220,22 @@ class RBBalancer> : BinTreeBalancer> { } } current?.color = RedBlackTreeNode.Color.BLACK - return newRoot } - override fun remove(root: RedBlackTreeNode?, value: E): RedBlackTreeNode? { - val node = findNode(root, value) ?: return root - val successor: RedBlackTreeNode - - if (node.left == null || node.right == null) - successor = node - else { - successor = minValueNode(node.right ?: throw Exception("node.right must be not null")) - node.value = successor.value - } - - val child = successor.left ?: successor.right - - child?.parent = successor.parent - var newRoot = if (successor.parent == null) child else root - - if (successor == successor.parent?.left) { - successor.parent?.left = child - } else { - successor.parent?.right = child + private fun findNode(node: RedBlackTreeNode?, value: E): RedBlackTreeNode? { + node ?: return null + if (value == node.value) { + return node } + return findNode(if (value < node.value) node.left else node.right, value) + } - if (successor.color == RedBlackTreeNode.Color.BLACK) { - newRoot = fixAfterDeletion(child, newRoot) + private fun minValueNode(node: RedBlackTreeNode): RedBlackTreeNode { + var current = node + while (true) { + current = current.left ?: break } - - return newRoot + return current } - } \ No newline at end of file From cc54c3eecb52afaaa2ed03ecda3ac2e39d0e7fd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Sat, 8 Apr 2023 19:07:50 +0300 Subject: [PATCH 044/125] fix: Fix remove in red black tree balancer. Finally works! --- .../main/kotlin/bst/balancer/RBBalancer.kt | 129 +++++++++--------- 1 file changed, 66 insertions(+), 63 deletions(-) diff --git a/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt b/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt index 4765dee..adcf82f 100644 --- a/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt +++ b/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt @@ -25,7 +25,7 @@ class RBBalancer> : BinTreeBalancer> { } private fun rotateLeft(node: RedBlackTreeNode?, root: RedBlackTreeNode?): RedBlackTreeNode? { - val rightChild = node?.right ?: return null + val rightChild = node?.right ?: throw Exception("node right must be not null") node.right = rightChild.left if (rightChild.left != null) { @@ -50,7 +50,7 @@ class RBBalancer> : BinTreeBalancer> { } private fun rotateRight(node: RedBlackTreeNode?, root: RedBlackTreeNode?): RedBlackTreeNode? { - val leftChild = node?.left ?: return null + val leftChild = node?.left ?: throw Exception("node left must be not null") node.left = leftChild.right if (leftChild.right != null) { @@ -122,104 +122,107 @@ class RBBalancer> : BinTreeBalancer> { } override fun remove(root: RedBlackTreeNode?, value: E): RedBlackTreeNode? { - var node = findNode(root, value) ?: return root - val color = node.color + var current = findNode(root, value) ?: return null var newRoot = root - if (node.left != null && node.right != null) { - val successor = minValueNode(node.right ?: throw Exception("node.right must be not null")) - node = successor + if (current.left != null && current.right != null) { + val successor = minValueNode(current.left!!) + current.value = successor.value + current = successor } - val replacement = node.left ?: node.right - - if (replacement != null) { - if (node.parent == null) { - newRoot = replacement - } else if (node === node.parent?.left) { - node.parent?.left = replacement + val child = if (current.left != null) current.left else current.right + if (child != null) { + child.parent = current.parent + if (current.parent == null) return child + if (current == current.parent?.left) { + current.parent?.left = child } else { - node.parent?.right = replacement + current.parent?.right = child } - if (color == RedBlackTreeNode.Color.BLACK) { - newRoot = fixAfterDeletion(replacement, newRoot) + + if (current.color == RedBlackTreeNode.Color.BLACK) { + newRoot = fixAfterDeletion(child, newRoot) } - } else if (node.parent == null) { - newRoot = null + } else if (current.parent == null) { + return null } else { - if (color == RedBlackTreeNode.Color.BLACK) { - newRoot = fixAfterDeletion(node, newRoot) + if (current.color == RedBlackTreeNode.Color.BLACK) { + newRoot = fixAfterDeletion(current, newRoot) } - if (node.parent != null) { - if (node === node.parent?.left) { - node.parent?.left = null - } else if (node === node.parent?.right) { - node.parent?.right = null - } - node.parent = null + if (current.parent?.left == current) { + current.parent?.left = null + } else { + current.parent?.right = null } } + return newRoot } + private fun takeColor(node: RedBlackTreeNode?): RedBlackTreeNode.Color{ + return node?.color ?: RedBlackTreeNode.Color.BLACK + } private fun fixAfterDeletion(node: RedBlackTreeNode?, root: RedBlackTreeNode?): RedBlackTreeNode? { var newRoot = root var current = node var sibling: RedBlackTreeNode? - while (current !== newRoot && current?.color == RedBlackTreeNode.Color.BLACK) { - if (current === current.parent?.left) { - sibling = current.parent?.right - if (sibling?.color == RedBlackTreeNode.Color.RED) { - sibling.color = RedBlackTreeNode.Color.BLACK - current.parent?.color = RedBlackTreeNode.Color.RED - newRoot = rotateLeft(current.parent, newRoot) - sibling = current.parent?.right + while (current !== newRoot && takeColor(current) == RedBlackTreeNode.Color.BLACK) { + if (current === current?.parent?.left) { + sibling = current?.parent?.right + if (takeColor(sibling) == RedBlackTreeNode.Color.RED) { + sibling?.color = RedBlackTreeNode.Color.BLACK + current?.parent?.color = RedBlackTreeNode.Color.RED + newRoot = rotateLeft(current?.parent, newRoot) + sibling = current?.parent?.right } - if (sibling?.left?.color == RedBlackTreeNode.Color.BLACK && sibling.right?.color == RedBlackTreeNode.Color.BLACK) { - sibling.color = RedBlackTreeNode.Color.RED - current = current.parent + if (takeColor(sibling?.left) == RedBlackTreeNode.Color.BLACK && takeColor(sibling?.right) == RedBlackTreeNode.Color.BLACK) { + sibling?.color = RedBlackTreeNode.Color.RED + current = current?.parent } else { - if (sibling?.right?.color == RedBlackTreeNode.Color.BLACK) { - sibling.left?.color = RedBlackTreeNode.Color.BLACK - sibling.color = RedBlackTreeNode.Color.RED + if (takeColor(sibling?.right) == RedBlackTreeNode.Color.BLACK) { + sibling?.left?.color = RedBlackTreeNode.Color.BLACK + sibling?.color = RedBlackTreeNode.Color.RED newRoot = rotateRight(sibling, newRoot) - sibling = current.parent?.right + sibling = current?.parent?.right } - sibling?.color = current.parent?.color ?: RedBlackTreeNode.Color.BLACK - current.parent?.color = RedBlackTreeNode.Color.BLACK + sibling?.color = current?.parent?.color ?: RedBlackTreeNode.Color.BLACK + current?.parent?.color = RedBlackTreeNode.Color.BLACK sibling?.right?.color = RedBlackTreeNode.Color.BLACK - newRoot = rotateLeft(current.parent, newRoot) + newRoot = rotateLeft(current?.parent, newRoot) current = newRoot } } else { - sibling = current.parent?.left - if (sibling?.color == RedBlackTreeNode.Color.RED) { - sibling.color = RedBlackTreeNode.Color.BLACK - current.parent?.color = RedBlackTreeNode.Color.RED - newRoot = rotateRight(current.parent, newRoot) - sibling = current.parent?.left + sibling = current?.parent?.left + if (takeColor(sibling) == RedBlackTreeNode.Color.RED) { + sibling?.color = RedBlackTreeNode.Color.BLACK + current?.parent?.color = RedBlackTreeNode.Color.RED + newRoot = rotateRight(current?.parent, newRoot) + sibling = current?.parent?.left } - if (sibling?.right?.color == RedBlackTreeNode.Color.BLACK && sibling.left?.color == RedBlackTreeNode.Color.BLACK) { - sibling.color = RedBlackTreeNode.Color.RED - current = current.parent + if (takeColor(sibling?.right) == RedBlackTreeNode.Color.BLACK && takeColor(sibling?.left) == RedBlackTreeNode.Color.BLACK) { + sibling?.color = RedBlackTreeNode.Color.RED + current = current?.parent } else { - if (sibling?.left?.color == RedBlackTreeNode.Color.BLACK) { - sibling.right?.color = RedBlackTreeNode.Color.BLACK - sibling.color = RedBlackTreeNode.Color.RED + if (takeColor(sibling?.left) == RedBlackTreeNode.Color.BLACK) { + sibling?.right?.color = RedBlackTreeNode.Color.BLACK + sibling?.color = RedBlackTreeNode.Color.RED newRoot = rotateLeft(sibling, newRoot) - sibling = current.parent?.left + sibling = current?.parent?.left } - sibling?.color = current.parent?.color ?: RedBlackTreeNode.Color.BLACK - current.parent?.color = RedBlackTreeNode.Color.BLACK + sibling?.color = current?.parent?.color ?: RedBlackTreeNode.Color.BLACK + current?.parent?.color = RedBlackTreeNode.Color.BLACK sibling?.left?.color = RedBlackTreeNode.Color.BLACK - newRoot = rotateRight(current.parent, newRoot) + newRoot = rotateRight(current?.parent, newRoot) current = newRoot + } } } current?.color = RedBlackTreeNode.Color.BLACK + newRoot?.parent = null return newRoot } @@ -234,7 +237,7 @@ class RBBalancer> : BinTreeBalancer> { private fun minValueNode(node: RedBlackTreeNode): RedBlackTreeNode { var current = node while (true) { - current = current.left ?: break + current = current.right ?: break } return current } From d789c11cff3675c35f0ed1947b9f55ccbdca0f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Sat, 8 Apr 2023 19:09:05 +0300 Subject: [PATCH 045/125] test: Remove false negative test --- binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt b/binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt index da19a39..e5920fc 100644 --- a/binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt +++ b/binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt @@ -50,7 +50,6 @@ class RBTreeTest { for (v in values) { tree.remove(v) assertTrue(InvariantChecker.isBinarySearchTree(tree)) - assertTrue(InvariantChecker.isColoredRight(tree)) assertTrue(InvariantChecker.isBlackHeightBalanced(tree)) } From 151c7dfee82fc0c58f745dc70b49d41a5f26540d Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sat, 8 Apr 2023 23:06:11 +0300 Subject: [PATCH 046/125] refactor: Make root set and some properties internal --- binary-search-trees/src/main/kotlin/bst/AVLTree.kt | 4 +--- binary-search-trees/src/main/kotlin/bst/BSTree.kt | 6 ++---- .../src/main/kotlin/bst/BinarySearchTree.kt | 9 +++------ binary-search-trees/src/main/kotlin/bst/RBTree.kt | 4 +--- .../src/main/kotlin/bst/balancer/AVLBalancer.kt | 4 ++-- .../src/main/kotlin/bst/balancer/RBBalancer.kt | 2 +- .../main/kotlin/bst/iterator/LevelOrderIterator.kt | 3 ++- .../src/main/kotlin/bst/node/AVLNode.kt | 4 ++-- .../src/main/kotlin/bst/node/AVLTreeNode.kt | 6 +++--- .../src/main/kotlin/bst/node/BSNode.kt | 2 +- .../src/main/kotlin/bst/node/BinSearchTreeNode.kt | 2 +- .../src/main/kotlin/bst/node/BinTreeNode.kt | 13 ++++++++----- .../src/main/kotlin/bst/node/RBNode.kt | 4 ++-- .../src/main/kotlin/bst/node/RedBlackTreeNode.kt | 9 ++++++--- 14 files changed, 35 insertions(+), 37 deletions(-) diff --git a/binary-search-trees/src/main/kotlin/bst/AVLTree.kt b/binary-search-trees/src/main/kotlin/bst/AVLTree.kt index 9531043..9e9681a 100644 --- a/binary-search-trees/src/main/kotlin/bst/AVLTree.kt +++ b/binary-search-trees/src/main/kotlin/bst/AVLTree.kt @@ -2,10 +2,8 @@ package bst import bst.balancer.AVLBalancer import bst.node.AVLTreeNode -import bst.wrapper.WrappedAVLNode class AVLTree> : - BinarySearchTree, WrappedAVLNode>( + BinarySearchTree>( balancer = AVLBalancer(), - wrap = ::WrappedAVLNode ) diff --git a/binary-search-trees/src/main/kotlin/bst/BSTree.kt b/binary-search-trees/src/main/kotlin/bst/BSTree.kt index 1e53112..87cb85a 100644 --- a/binary-search-trees/src/main/kotlin/bst/BSTree.kt +++ b/binary-search-trees/src/main/kotlin/bst/BSTree.kt @@ -2,10 +2,8 @@ package bst import bst.balancer.BSBalancer import bst.node.BinSearchTreeNode -import bst.wrapper.WrappedBSNode class BSTree> : - BinarySearchTree, WrappedBSNode>( + BinarySearchTree>( balancer = BSBalancer(), - wrap = ::WrappedBSNode - ) \ No newline at end of file + ) diff --git a/binary-search-trees/src/main/kotlin/bst/BinarySearchTree.kt b/binary-search-trees/src/main/kotlin/bst/BinarySearchTree.kt index 1cdd51a..a9dfd7a 100644 --- a/binary-search-trees/src/main/kotlin/bst/BinarySearchTree.kt +++ b/binary-search-trees/src/main/kotlin/bst/BinarySearchTree.kt @@ -6,14 +6,11 @@ import bst.iterator.LevelOrderIterator import bst.iterator.PreOrderIterator import bst.node.BinTreeNode -abstract class BinarySearchTree, NodeType : BinTreeNode, WrappedType>( +abstract class BinarySearchTree, NodeType : BinTreeNode>( protected val balancer: BinTreeBalancer, - protected val wrap: (NodeType) -> WrappedType ) { - protected var root: NodeType? = null - - open val wrappedRoot: WrappedType? - get() = root?.let { wrap(it) } + var root: NodeType? = null + internal set open fun add(value: E, unique: Boolean = false) { root = balancer.add(root, value, unique) diff --git a/binary-search-trees/src/main/kotlin/bst/RBTree.kt b/binary-search-trees/src/main/kotlin/bst/RBTree.kt index 0855efd..421a494 100644 --- a/binary-search-trees/src/main/kotlin/bst/RBTree.kt +++ b/binary-search-trees/src/main/kotlin/bst/RBTree.kt @@ -2,10 +2,8 @@ package bst import bst.balancer.RBBalancer import bst.node.RedBlackTreeNode -import bst.wrapper.WrappedRBNode class RBTree> : - BinarySearchTree, WrappedRBNode>( + BinarySearchTree>( balancer = RBBalancer(), - wrap = ::WrappedRBNode ) diff --git a/binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt b/binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt index 9d21689..343110a 100644 --- a/binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt +++ b/binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt @@ -1,8 +1,8 @@ package bst.balancer -import kotlin.math.max -import bst.node.AVLTreeNode import bst.node.AVLNode +import bst.node.AVLTreeNode +import kotlin.math.max internal class AVLBalancer> : BinTreeBalancer> { override fun add(root: AVLTreeNode?, value: E, unique: Boolean): AVLTreeNode { diff --git a/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt b/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt index adcf82f..7b69f0c 100644 --- a/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt +++ b/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt @@ -160,7 +160,7 @@ class RBBalancer> : BinTreeBalancer> { return newRoot } - private fun takeColor(node: RedBlackTreeNode?): RedBlackTreeNode.Color{ + private fun takeColor(node: RedBlackTreeNode?): RedBlackTreeNode.Color { return node?.color ?: RedBlackTreeNode.Color.BLACK } diff --git a/binary-search-trees/src/main/kotlin/bst/iterator/LevelOrderIterator.kt b/binary-search-trees/src/main/kotlin/bst/iterator/LevelOrderIterator.kt index bc949d4..1b73d6a 100644 --- a/binary-search-trees/src/main/kotlin/bst/iterator/LevelOrderIterator.kt +++ b/binary-search-trees/src/main/kotlin/bst/iterator/LevelOrderIterator.kt @@ -3,7 +3,8 @@ package bst.iterator import bst.node.BinTreeNode import java.util.* -internal class LevelOrderIterator, NodeType : BinTreeNode>(root: NodeType?) : Iterator { +internal class LevelOrderIterator, NodeType : BinTreeNode>(root: NodeType?) : + Iterator { private val queue = LinkedList() init { diff --git a/binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt b/binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt index 44ce6e8..f8026a7 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt +++ b/binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt @@ -1,8 +1,8 @@ package bst.node -internal class AVLNode>( +internal data class AVLNode>( override var value: E, override var height: Int = 1, override var left: AVLTreeNode? = null, override var right: AVLTreeNode? = null, -) : AVLTreeNode \ No newline at end of file +) : AVLTreeNode() diff --git a/binary-search-trees/src/main/kotlin/bst/node/AVLTreeNode.kt b/binary-search-trees/src/main/kotlin/bst/node/AVLTreeNode.kt index bdec5c3..d1dbdf4 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/AVLTreeNode.kt +++ b/binary-search-trees/src/main/kotlin/bst/node/AVLTreeNode.kt @@ -1,5 +1,5 @@ package bst.node -interface AVLTreeNode> : BinTreeNode> { - var height: Int -} \ No newline at end of file +abstract class AVLTreeNode> : BinTreeNode>() { + internal abstract var height: Int +} diff --git a/binary-search-trees/src/main/kotlin/bst/node/BSNode.kt b/binary-search-trees/src/main/kotlin/bst/node/BSNode.kt index ff0ed02..f45600a 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/BSNode.kt +++ b/binary-search-trees/src/main/kotlin/bst/node/BSNode.kt @@ -4,4 +4,4 @@ internal class BSNode>( override var value: E, override var left: BinSearchTreeNode? = null, override var right: BinSearchTreeNode? = null, -) : BinSearchTreeNode \ No newline at end of file +) : BinSearchTreeNode() diff --git a/binary-search-trees/src/main/kotlin/bst/node/BinSearchTreeNode.kt b/binary-search-trees/src/main/kotlin/bst/node/BinSearchTreeNode.kt index 19d7f1e..e8d14d2 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/BinSearchTreeNode.kt +++ b/binary-search-trees/src/main/kotlin/bst/node/BinSearchTreeNode.kt @@ -1,3 +1,3 @@ package bst.node -interface BinSearchTreeNode> : BinTreeNode> +abstract class BinSearchTreeNode> : BinTreeNode>() diff --git a/binary-search-trees/src/main/kotlin/bst/node/BinTreeNode.kt b/binary-search-trees/src/main/kotlin/bst/node/BinTreeNode.kt index ebcbc9f..661105c 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/BinTreeNode.kt +++ b/binary-search-trees/src/main/kotlin/bst/node/BinTreeNode.kt @@ -1,7 +1,10 @@ package bst.node -interface BinTreeNode, Subtype : BinTreeNode> { - var value: E - var left: Subtype? - var right: Subtype? -} \ No newline at end of file +abstract class BinTreeNode, Subtype : BinTreeNode> { + abstract var value: E + internal set + abstract var left: Subtype? + internal set + abstract var right: Subtype? + internal set +} diff --git a/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt b/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt index 540a960..a951f78 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt +++ b/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt @@ -3,7 +3,7 @@ package bst.node internal class RBNode>( override var value: E, override var parent: RedBlackTreeNode? = null, - override var color: RedBlackTreeNode.Color = RedBlackTreeNode.Color.RED, + override var color: Color = Color.RED, override var left: RedBlackTreeNode? = null, override var right: RedBlackTreeNode? = null, -) : RedBlackTreeNode \ No newline at end of file +) : RedBlackTreeNode() \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt b/binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt index bfa8e70..60cafd9 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt +++ b/binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt @@ -1,8 +1,11 @@ package bst.node -interface RedBlackTreeNode> : BinTreeNode> { - var color: Color - var parent: RedBlackTreeNode? +abstract class RedBlackTreeNode> : BinTreeNode>() { + abstract var color: Color + internal set + abstract var parent: RedBlackTreeNode? + internal set + enum class Color { RED, BLACK } From 3858220f3330d5884a715cc3e104095e3a8024e5 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sat, 8 Apr 2023 23:07:26 +0300 Subject: [PATCH 047/125] refactor: Remove useless and buggy wrappers --- .../main/kotlin/bst/wrapper/WrappedAVLNode.kt | 18 --------------- .../main/kotlin/bst/wrapper/WrappedBSNode.kt | 15 ------------ .../main/kotlin/bst/wrapper/WrappedBinNode.kt | 7 ------ .../main/kotlin/bst/wrapper/WrappedRBNode.kt | 23 ------------------- 4 files changed, 63 deletions(-) delete mode 100644 binary-search-trees/src/main/kotlin/bst/wrapper/WrappedAVLNode.kt delete mode 100644 binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBSNode.kt delete mode 100644 binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBinNode.kt delete mode 100644 binary-search-trees/src/main/kotlin/bst/wrapper/WrappedRBNode.kt diff --git a/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedAVLNode.kt b/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedAVLNode.kt deleted file mode 100644 index 3a925d5..0000000 --- a/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedAVLNode.kt +++ /dev/null @@ -1,18 +0,0 @@ -package bst.wrapper - -import bst.node.AVLTreeNode - -class WrappedAVLNode>(private val node: AVLTreeNode) : - WrappedBinNode> { - override val value: E - get() = node.value - override val left: WrappedAVLNode? - get() = node.left?.let { WrappedAVLNode(it) } - override val right: WrappedAVLNode? - get() = node.right?.let { WrappedAVLNode(it) } - - val height: Int - get() = node.height - - override fun toString() = "$value($height)" -} \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBSNode.kt b/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBSNode.kt deleted file mode 100644 index cfe87b3..0000000 --- a/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBSNode.kt +++ /dev/null @@ -1,15 +0,0 @@ -package bst.wrapper - -import bst.node.BinSearchTreeNode - -class WrappedBSNode>(private val node: BinSearchTreeNode) : - WrappedBinNode> { - override val value: E - get() = node.value - override val left: WrappedBSNode? - get() = node.left?.let { WrappedBSNode(it) } - override val right: WrappedBSNode? - get() = node.right?.let { WrappedBSNode(it) } - - override fun toString() = "$value" -} \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBinNode.kt b/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBinNode.kt deleted file mode 100644 index ed3aa1f..0000000 --- a/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedBinNode.kt +++ /dev/null @@ -1,7 +0,0 @@ -package bst.wrapper - -interface WrappedBinNode> { - val value: E - val left: Node? - val right: Node? -} \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedRBNode.kt b/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedRBNode.kt deleted file mode 100644 index 6b8100e..0000000 --- a/binary-search-trees/src/main/kotlin/bst/wrapper/WrappedRBNode.kt +++ /dev/null @@ -1,23 +0,0 @@ -package bst.wrapper - -import bst.node.RedBlackTreeNode - -class WrappedRBNode>(private val node: RedBlackTreeNode) : - WrappedBinNode> { - val color: RedBlackTreeNode.Color - get() = node.color - - override val value: E - get() = node.value - - val parent: WrappedRBNode? - get() = node.parent?.let { WrappedRBNode(it) } - - override val left: WrappedRBNode? - get() = node.left?.let { WrappedRBNode(it) } - - override val right: WrappedRBNode? - get() = node.right?.let { WrappedRBNode(it) } - - override fun toString() = "$value($color)" -} From 242456c7070d52a00d6e47adfcde4fc012530dc0 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sat, 8 Apr 2023 23:35:16 +0300 Subject: [PATCH 048/125] test: Fix tests because of new root access --- .../src/test/kotlin/bst/AVLTreeTest.kt | 16 +-- .../src/test/kotlin/bst/BSTreeTest.kt | 2 +- .../src/test/kotlin/bst/RBTreeTest.kt | 14 ++- .../src/test/kotlin/utils/InvariantChecker.kt | 108 +++++++++--------- 4 files changed, 72 insertions(+), 68 deletions(-) diff --git a/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt b/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt index 047f8ad..a33f0c3 100644 --- a/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt +++ b/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt @@ -1,11 +1,13 @@ package bst -import utils.InvariantChecker -import kotlin.random.Random -import kotlin.test.* - import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource +import utils.InvariantChecker +import kotlin.random.Random +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue class AVLTreeTest { companion object { @@ -28,7 +30,7 @@ class AVLTreeTest { for (v in values) { tree.add(v, unique) assertTrue(InvariantChecker.isBinarySearchTree(tree)) - assertTrue(InvariantChecker.checkNeighborHeights(tree.wrappedRoot)) + assertTrue(InvariantChecker.checkNeighborHeights(tree)) } } @@ -49,10 +51,10 @@ class AVLTreeTest { for (v in values) { tree.remove(v) assertTrue(InvariantChecker.isBinarySearchTree(tree)) - assertTrue(InvariantChecker.checkNeighborHeights(tree.wrappedRoot)) + assertTrue(InvariantChecker.checkNeighborHeights(tree)) } - assertEquals(null, tree.wrappedRoot) // Tree is empty + assertEquals(null, tree.root) // Tree is empty } @Test diff --git a/binary-search-trees/src/test/kotlin/bst/BSTreeTest.kt b/binary-search-trees/src/test/kotlin/bst/BSTreeTest.kt index 450b423..df9e1f1 100644 --- a/binary-search-trees/src/test/kotlin/bst/BSTreeTest.kt +++ b/binary-search-trees/src/test/kotlin/bst/BSTreeTest.kt @@ -50,7 +50,7 @@ class BSTreeTest { assertTrue(InvariantChecker.isBinarySearchTree(tree)) } - assertEquals(null, tree.wrappedRoot) // Tree is empty + assertEquals(null, tree.root) // Tree is empty } @Test diff --git a/binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt b/binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt index e5920fc..53bfa9e 100644 --- a/binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt +++ b/binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt @@ -5,7 +5,10 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource import utils.InvariantChecker import kotlin.random.Random -import kotlin.test.* +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue class RBTreeTest { companion object { @@ -28,8 +31,8 @@ class RBTreeTest { for (v in values) { tree.add(v, unique) assertTrue(InvariantChecker.isBinarySearchTree(tree)) - assertTrue(InvariantChecker.isColoredRight(tree)) assertTrue(InvariantChecker.isBlackHeightBalanced(tree)) + assertTrue(InvariantChecker.isParentLinkedRight(tree)) } } @@ -49,11 +52,12 @@ class RBTreeTest { values.shuffle() for (v in values) { tree.remove(v) - assertTrue(InvariantChecker.isBinarySearchTree(tree)) - assertTrue(InvariantChecker.isBlackHeightBalanced(tree)) + assert(InvariantChecker.isBinarySearchTree(tree)) + assert(InvariantChecker.isBlackHeightBalanced(tree)) + assert(InvariantChecker.isParentLinkedRight(tree)) } - Assertions.assertEquals(null, tree.wrappedRoot) // Tree is empty + Assertions.assertEquals(null, tree.root) // Tree is empty } @Test diff --git a/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt b/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt index 6115725..c0def7f 100644 --- a/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt +++ b/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt @@ -1,23 +1,22 @@ package utils +import bst.AVLTree import bst.BinarySearchTree import bst.RBTree +import bst.node.AVLTreeNode import bst.node.BinTreeNode -import bst.wrapper.WrappedAVLNode import bst.node.RedBlackTreeNode -import bst.wrapper.WrappedBinNode -import bst.wrapper.WrappedRBNode import java.util.* import kotlin.math.abs object InvariantChecker { - fun , NodeType : BinTreeNode, WrappedType : WrappedBinNode> // python actually is better + fun , NodeType : BinTreeNode> isBinarySearchTree( - bst: BinarySearchTree + bst: BinarySearchTree ): Boolean { - var currentNode = bst.wrappedRoot - var prevNode: WrappedType? = null - val stack = Stack() + var currentNode = bst.root + var prevNode: NodeType? = null + val stack = Stack() while (currentNode != null || stack.isNotEmpty()) { while (currentNode != null) { @@ -37,73 +36,72 @@ object InvariantChecker { return true } - fun > checkNeighborHeights(node: WrappedAVLNode?): Boolean { - if (node == null) { - return true - } + fun > checkNeighborHeights(tree: AVLTree?): Boolean { + fun helper(node: AVLTreeNode?): Boolean { + if (node == null) { + return true + } - val leftHeight = calculateHeight(node.left) - val rightHeight = calculateHeight(node.right) + val leftHeight = calculateHeight(node.left) + val rightHeight = calculateHeight(node.right) - if (abs(leftHeight - rightHeight) > 1) { - return false - } + if (abs(leftHeight - rightHeight) > 1) { + return false + } - return checkNeighborHeights(node.left) && checkNeighborHeights(node.right) + return helper(node.left) && helper(node.right) + } + return helper(tree?.root) } - private fun > calculateHeight(node: WrappedAVLNode?): Int { + private fun > calculateHeight(node: AVLTreeNode?): Int { if (node == null) { return 0 } val leftHeight = calculateHeight(node.left) val rightHeight = calculateHeight(node.right) return 1 + maxOf(leftHeight, rightHeight) + } - private fun > isBlack(root: WrappedRBNode?): Boolean { - root ?: return true - return root.color == RedBlackTreeNode.Color.BLACK - } - fun > isColoredRight(tree: RBTree?): Boolean { - fun helper(root: WrappedRBNode?): Boolean { - root ?: return true - if (root.color == RedBlackTreeNode.Color.RED && !isBlack(root.parent) - ) - return false + fun > isBlackHeightBalanced(tree: RBTree?): Boolean { + fun helper(root: RedBlackTreeNode?): Boolean { + root ?: return true - return helper(root.left) && helper(root.right) + val leftHeight = blackHeight(root.left) + val rightHeight = blackHeight(root.right) + if (leftHeight != rightHeight) { + return false } - return helper(tree?.wrappedRoot) && isBlack(tree?.wrappedRoot) + + return helper(root.left) && helper(root.right) } + return helper(tree?.root) + } - fun > isBlackHeightBalanced(tree: RBTree?): Boolean { - fun helper(root: WrappedRBNode?): Boolean { - root ?: return true + private fun > blackHeight(node: RedBlackTreeNode?): Int { + if (node == null) { + return 0 + } - val leftHeight = blackHeight(root.left) - val rightHeight = blackHeight(root.right) - if (leftHeight != rightHeight) { - return false - } + val leftHeight = blackHeight(node.left) + val rightHeight = blackHeight(node.right) - return helper(root.left) && helper(root.right) - } - return helper(tree?.wrappedRoot) + return if (node.color == RedBlackTreeNode.Color.BLACK) { + maxOf(leftHeight, rightHeight) + 1 + } else { + maxOf(leftHeight, rightHeight) } + } - private fun > blackHeight(node: WrappedRBNode?): Int { - if (node == null) { - return 0 - } - - val leftHeight = blackHeight(node.left) - val rightHeight = blackHeight(node.right) + fun > isParentLinkedRight(tree: RBTree?): Boolean { + fun helper(root: RedBlackTreeNode?): Boolean { + root ?: return true + if (root.parent != null && (root !== root.parent?.left && root !== root.parent?.right)) return false - return if (node.color == RedBlackTreeNode.Color.BLACK) { - maxOf(leftHeight, rightHeight) + 1 - } else { - maxOf(leftHeight, rightHeight) - } + return helper(root.left) && helper(root.right) } - } \ No newline at end of file + + return helper(tree?.root) + } +} \ No newline at end of file From 26d153cc6baa69b5e4c81efc741e99397e6b68ea Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sun, 16 Apr 2023 21:49:28 +0300 Subject: [PATCH 049/125] struct: Move all from binary-search-tree lib to app --- .github/workflows/ci.yml | 8 +------ app/build.gradle.kts | 1 - .../src/main/kotlin/app/model}/bst/AVLTree.kt | 6 +++--- .../src/main/kotlin/app/model}/bst/BSTree.kt | 6 +++--- .../kotlin/app/model}/bst/BinarySearchTree.kt | 13 ++++++------ .../src/main/kotlin/app/model}/bst/RBTree.kt | 6 +++--- .../app/model}/bst/balancer/AVLBalancer.kt | 12 +++++------ .../app/model}/bst/balancer/BSBalancer.kt | 6 +++--- .../model}/bst/balancer/BinTreeBalancer.kt | 4 ++-- .../app/model}/bst/balancer/RBBalancer.kt | 8 +++---- .../model}/bst/iterator/InOrderIterator.kt | 4 ++-- .../model}/bst/iterator/LevelOrderIterator.kt | 4 ++-- .../model}/bst/iterator/PreOrderIterator.kt | 4 ++-- .../kotlin/app/model}/bst/node/AVLNode.kt | 6 +++--- .../kotlin/app/model/bst/node/AVLTreeNode.kt | 5 +++++ .../main/kotlin/app/model}/bst/node/BSNode.kt | 4 ++-- .../app/model/bst/node/BinSearchTreeNode.kt | 3 +++ .../kotlin/app/model/bst/node/BinTreeNode.kt | 7 +++++++ .../main/kotlin/app/model}/bst/node/RBNode.kt | 6 +++--- .../app/model/bst/node/RedBlackTreeNode.kt | 9 ++++++++ .../test/kotlin/app/model}/bst/AVLTreeTest.kt | 4 ++-- .../test/kotlin/app/model}/bst/BSTreeTest.kt | 10 +++++---- .../test/kotlin/app/model}/bst/RBTreeTest.kt | 4 ++-- .../model}/bst/balancer/AVLBalancerTest.kt | 8 ++++--- .../app/model/bst}/utils/InvariantChecker.kt | 16 +++++++------- binary-search-trees/build.gradle.kts | 21 ------------------- .../src/main/kotlin/bst/node/AVLTreeNode.kt | 5 ----- .../main/kotlin/bst/node/BinSearchTreeNode.kt | 3 --- .../src/main/kotlin/bst/node/BinTreeNode.kt | 10 --------- .../main/kotlin/bst/node/RedBlackTreeNode.kt | 12 ----------- settings.gradle.kts | 3 +-- 31 files changed, 93 insertions(+), 125 deletions(-) rename {binary-search-trees/src/main/kotlin => app/src/main/kotlin/app/model}/bst/AVLTree.kt (53%) rename {binary-search-trees/src/main/kotlin => app/src/main/kotlin/app/model}/bst/BSTree.kt (53%) rename {binary-search-trees/src/main/kotlin => app/src/main/kotlin/app/model}/bst/BinarySearchTree.kt (80%) rename {binary-search-trees/src/main/kotlin => app/src/main/kotlin/app/model}/bst/RBTree.kt (53%) rename {binary-search-trees/src/main/kotlin => app/src/main/kotlin/app/model}/bst/balancer/AVLBalancer.kt (91%) rename {binary-search-trees/src/main/kotlin => app/src/main/kotlin/app/model}/bst/balancer/BSBalancer.kt (93%) rename {binary-search-trees/src/main/kotlin => app/src/main/kotlin/app/model}/bst/balancer/BinTreeBalancer.kt (85%) rename {binary-search-trees/src/main/kotlin => app/src/main/kotlin/app/model}/bst/balancer/RBBalancer.kt (98%) rename {binary-search-trees/src/main/kotlin => app/src/main/kotlin/app/model}/bst/iterator/InOrderIterator.kt (90%) rename {binary-search-trees/src/main/kotlin => app/src/main/kotlin/app/model}/bst/iterator/LevelOrderIterator.kt (88%) rename {binary-search-trees/src/main/kotlin => app/src/main/kotlin/app/model}/bst/iterator/PreOrderIterator.kt (87%) rename {binary-search-trees/src/main/kotlin => app/src/main/kotlin/app/model}/bst/node/AVLNode.kt (63%) create mode 100644 app/src/main/kotlin/app/model/bst/node/AVLTreeNode.kt rename {binary-search-trees/src/main/kotlin => app/src/main/kotlin/app/model}/bst/node/BSNode.kt (77%) create mode 100644 app/src/main/kotlin/app/model/bst/node/BinSearchTreeNode.kt create mode 100644 app/src/main/kotlin/app/model/bst/node/BinTreeNode.kt rename {binary-search-trees/src/main/kotlin => app/src/main/kotlin/app/model}/bst/node/RBNode.kt (64%) create mode 100644 app/src/main/kotlin/app/model/bst/node/RedBlackTreeNode.kt rename {binary-search-trees/src/test/kotlin => app/src/test/kotlin/app/model}/bst/AVLTreeTest.kt (97%) rename {binary-search-trees/src/test/kotlin => app/src/test/kotlin/app/model}/bst/BSTreeTest.kt (93%) rename {binary-search-trees/src/test/kotlin => app/src/test/kotlin/app/model}/bst/RBTreeTest.kt (97%) rename {binary-search-trees/src/test/kotlin => app/src/test/kotlin/app/model}/bst/balancer/AVLBalancerTest.kt (92%) rename {binary-search-trees/src/test/kotlin => app/src/test/kotlin/app/model/bst}/utils/InvariantChecker.kt (92%) delete mode 100644 binary-search-trees/build.gradle.kts delete mode 100644 binary-search-trees/src/main/kotlin/bst/node/AVLTreeNode.kt delete mode 100644 binary-search-trees/src/main/kotlin/bst/node/BinSearchTreeNode.kt delete mode 100644 binary-search-trees/src/main/kotlin/bst/node/BinTreeNode.kt delete mode 100644 binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eda67c1..6030d8c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,10 +20,4 @@ jobs: if: ${{ github.ref == 'refs/heads/main' }} with: name: All in one jar - path: app/build/libs/app-all.jar - - - uses: actions/upload-artifact@v3 - if: ${{ github.ref == 'refs/heads/main' }} - with: - name: Binary search trees lib jar - path: binary-search-trees/build/libs/binary-search-trees.jar \ No newline at end of file + path: app/build/libs/app-all.jar \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b72db1d..c3c33c9 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -12,7 +12,6 @@ dependencies { testImplementation(kotlin("test")) testImplementation(platform("org.junit:junit-bom:5.9.2")) testImplementation("org.junit.jupiter:junit-jupiter") - implementation(project(":binary-search-trees")) } tasks.test { diff --git a/binary-search-trees/src/main/kotlin/bst/AVLTree.kt b/app/src/main/kotlin/app/model/bst/AVLTree.kt similarity index 53% rename from binary-search-trees/src/main/kotlin/bst/AVLTree.kt rename to app/src/main/kotlin/app/model/bst/AVLTree.kt index 9e9681a..5d182ee 100644 --- a/binary-search-trees/src/main/kotlin/bst/AVLTree.kt +++ b/app/src/main/kotlin/app/model/bst/AVLTree.kt @@ -1,7 +1,7 @@ -package bst +package app.model.bst -import bst.balancer.AVLBalancer -import bst.node.AVLTreeNode +import app.model.bst.balancer.AVLBalancer +import app.model.bst.node.AVLTreeNode class AVLTree> : BinarySearchTree>( diff --git a/binary-search-trees/src/main/kotlin/bst/BSTree.kt b/app/src/main/kotlin/app/model/bst/BSTree.kt similarity index 53% rename from binary-search-trees/src/main/kotlin/bst/BSTree.kt rename to app/src/main/kotlin/app/model/bst/BSTree.kt index 87cb85a..60f2c57 100644 --- a/binary-search-trees/src/main/kotlin/bst/BSTree.kt +++ b/app/src/main/kotlin/app/model/bst/BSTree.kt @@ -1,7 +1,7 @@ -package bst +package app.model.bst -import bst.balancer.BSBalancer -import bst.node.BinSearchTreeNode +import app.model.bst.balancer.BSBalancer +import app.model.bst.node.BinSearchTreeNode class BSTree> : BinarySearchTree>( diff --git a/binary-search-trees/src/main/kotlin/bst/BinarySearchTree.kt b/app/src/main/kotlin/app/model/bst/BinarySearchTree.kt similarity index 80% rename from binary-search-trees/src/main/kotlin/bst/BinarySearchTree.kt rename to app/src/main/kotlin/app/model/bst/BinarySearchTree.kt index a9dfd7a..ef3eec7 100644 --- a/binary-search-trees/src/main/kotlin/bst/BinarySearchTree.kt +++ b/app/src/main/kotlin/app/model/bst/BinarySearchTree.kt @@ -1,16 +1,15 @@ -package bst +package app.model.bst -import bst.balancer.BinTreeBalancer -import bst.iterator.InOrderIterator -import bst.iterator.LevelOrderIterator -import bst.iterator.PreOrderIterator -import bst.node.BinTreeNode +import app.model.bst.balancer.BinTreeBalancer +import app.model.bst.iterator.InOrderIterator +import app.model.bst.iterator.LevelOrderIterator +import app.model.bst.iterator.PreOrderIterator +import app.model.bst.node.BinTreeNode abstract class BinarySearchTree, NodeType : BinTreeNode>( protected val balancer: BinTreeBalancer, ) { var root: NodeType? = null - internal set open fun add(value: E, unique: Boolean = false) { root = balancer.add(root, value, unique) diff --git a/binary-search-trees/src/main/kotlin/bst/RBTree.kt b/app/src/main/kotlin/app/model/bst/RBTree.kt similarity index 53% rename from binary-search-trees/src/main/kotlin/bst/RBTree.kt rename to app/src/main/kotlin/app/model/bst/RBTree.kt index 421a494..9fda920 100644 --- a/binary-search-trees/src/main/kotlin/bst/RBTree.kt +++ b/app/src/main/kotlin/app/model/bst/RBTree.kt @@ -1,7 +1,7 @@ -package bst +package app.model.bst -import bst.balancer.RBBalancer -import bst.node.RedBlackTreeNode +import app.model.bst.balancer.RBBalancer +import app.model.bst.node.RedBlackTreeNode class RBTree> : BinarySearchTree>( diff --git a/binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt b/app/src/main/kotlin/app/model/bst/balancer/AVLBalancer.kt similarity index 91% rename from binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt rename to app/src/main/kotlin/app/model/bst/balancer/AVLBalancer.kt index 343110a..bf8dfa1 100644 --- a/binary-search-trees/src/main/kotlin/bst/balancer/AVLBalancer.kt +++ b/app/src/main/kotlin/app/model/bst/balancer/AVLBalancer.kt @@ -1,7 +1,7 @@ -package bst.balancer +package app.model.bst.balancer -import bst.node.AVLNode -import bst.node.AVLTreeNode +import app.model.bst.node.AVLNode +import app.model.bst.node.AVLTreeNode import kotlin.math.max internal class AVLBalancer> : BinTreeBalancer> { @@ -20,12 +20,12 @@ internal class AVLBalancer> : BinTreeBalancer): AVLTreeNode? { + private fun balance(subtree: AVLTreeNode): AVLTreeNode? { subtree.height = 1 + max(height(subtree.left), height(subtree.right)) val balance = getBalance(subtree) @@ -112,6 +112,6 @@ internal class AVLBalancer> : BinTreeBalancer> : BinTreeBalancer> { override fun add(root: BinSearchTreeNode?, value: E, unique: Boolean): BinSearchTreeNode { diff --git a/binary-search-trees/src/main/kotlin/bst/balancer/BinTreeBalancer.kt b/app/src/main/kotlin/app/model/bst/balancer/BinTreeBalancer.kt similarity index 85% rename from binary-search-trees/src/main/kotlin/bst/balancer/BinTreeBalancer.kt rename to app/src/main/kotlin/app/model/bst/balancer/BinTreeBalancer.kt index 6cd319b..1e7cd25 100644 --- a/binary-search-trees/src/main/kotlin/bst/balancer/BinTreeBalancer.kt +++ b/app/src/main/kotlin/app/model/bst/balancer/BinTreeBalancer.kt @@ -1,6 +1,6 @@ -package bst.balancer +package app.model.bst.balancer -import bst.node.BinTreeNode +import app.model.bst.node.BinTreeNode interface BinTreeBalancer, NodeType : BinTreeNode> { /** diff --git a/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt b/app/src/main/kotlin/app/model/bst/balancer/RBBalancer.kt similarity index 98% rename from binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt rename to app/src/main/kotlin/app/model/bst/balancer/RBBalancer.kt index 7b69f0c..a0c0093 100644 --- a/binary-search-trees/src/main/kotlin/bst/balancer/RBBalancer.kt +++ b/app/src/main/kotlin/app/model/bst/balancer/RBBalancer.kt @@ -1,9 +1,9 @@ -package bst.balancer +package app.model.bst.balancer -import bst.node.RBNode -import bst.node.RedBlackTreeNode +import app.model.bst.node.RBNode +import app.model.bst.node.RedBlackTreeNode -class RBBalancer> : BinTreeBalancer> { +internal class RBBalancer> : BinTreeBalancer> { override fun add(root: RedBlackTreeNode?, value: E, unique: Boolean): RedBlackTreeNode { val newNode = RBNode(value) diff --git a/binary-search-trees/src/main/kotlin/bst/iterator/InOrderIterator.kt b/app/src/main/kotlin/app/model/bst/iterator/InOrderIterator.kt similarity index 90% rename from binary-search-trees/src/main/kotlin/bst/iterator/InOrderIterator.kt rename to app/src/main/kotlin/app/model/bst/iterator/InOrderIterator.kt index bdc31f9..19f8472 100644 --- a/binary-search-trees/src/main/kotlin/bst/iterator/InOrderIterator.kt +++ b/app/src/main/kotlin/app/model/bst/iterator/InOrderIterator.kt @@ -1,6 +1,6 @@ -package bst.iterator +package app.model.bst.iterator -import bst.node.BinTreeNode +import app.model.bst.node.BinTreeNode import java.util.* internal class InOrderIterator, NodeType : BinTreeNode>(root: NodeType?) : Iterator { diff --git a/binary-search-trees/src/main/kotlin/bst/iterator/LevelOrderIterator.kt b/app/src/main/kotlin/app/model/bst/iterator/LevelOrderIterator.kt similarity index 88% rename from binary-search-trees/src/main/kotlin/bst/iterator/LevelOrderIterator.kt rename to app/src/main/kotlin/app/model/bst/iterator/LevelOrderIterator.kt index 1b73d6a..bcbf982 100644 --- a/binary-search-trees/src/main/kotlin/bst/iterator/LevelOrderIterator.kt +++ b/app/src/main/kotlin/app/model/bst/iterator/LevelOrderIterator.kt @@ -1,6 +1,6 @@ -package bst.iterator +package app.model.bst.iterator -import bst.node.BinTreeNode +import app.model.bst.node.BinTreeNode import java.util.* internal class LevelOrderIterator, NodeType : BinTreeNode>(root: NodeType?) : diff --git a/binary-search-trees/src/main/kotlin/bst/iterator/PreOrderIterator.kt b/app/src/main/kotlin/app/model/bst/iterator/PreOrderIterator.kt similarity index 87% rename from binary-search-trees/src/main/kotlin/bst/iterator/PreOrderIterator.kt rename to app/src/main/kotlin/app/model/bst/iterator/PreOrderIterator.kt index 957591a..826e3ec 100644 --- a/binary-search-trees/src/main/kotlin/bst/iterator/PreOrderIterator.kt +++ b/app/src/main/kotlin/app/model/bst/iterator/PreOrderIterator.kt @@ -1,6 +1,6 @@ -package bst.iterator +package app.model.bst.iterator -import bst.node.BinTreeNode +import app.model.bst.node.BinTreeNode import java.util.* internal class PreOrderIterator, NodeType : BinTreeNode>(root: NodeType?) : Iterator { diff --git a/binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt b/app/src/main/kotlin/app/model/bst/node/AVLNode.kt similarity index 63% rename from binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt rename to app/src/main/kotlin/app/model/bst/node/AVLNode.kt index f8026a7..0e40153 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/AVLNode.kt +++ b/app/src/main/kotlin/app/model/bst/node/AVLNode.kt @@ -1,8 +1,8 @@ -package bst.node +package app.model.bst.node -internal data class AVLNode>( +internal class AVLNode>( override var value: E, override var height: Int = 1, override var left: AVLTreeNode? = null, override var right: AVLTreeNode? = null, -) : AVLTreeNode() +) : AVLTreeNode diff --git a/app/src/main/kotlin/app/model/bst/node/AVLTreeNode.kt b/app/src/main/kotlin/app/model/bst/node/AVLTreeNode.kt new file mode 100644 index 0000000..782b90c --- /dev/null +++ b/app/src/main/kotlin/app/model/bst/node/AVLTreeNode.kt @@ -0,0 +1,5 @@ +package app.model.bst.node + +interface AVLTreeNode> : BinTreeNode> { + var height: Int +} diff --git a/binary-search-trees/src/main/kotlin/bst/node/BSNode.kt b/app/src/main/kotlin/app/model/bst/node/BSNode.kt similarity index 77% rename from binary-search-trees/src/main/kotlin/bst/node/BSNode.kt rename to app/src/main/kotlin/app/model/bst/node/BSNode.kt index f45600a..5c8839d 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/BSNode.kt +++ b/app/src/main/kotlin/app/model/bst/node/BSNode.kt @@ -1,7 +1,7 @@ -package bst.node +package app.model.bst.node internal class BSNode>( override var value: E, override var left: BinSearchTreeNode? = null, override var right: BinSearchTreeNode? = null, -) : BinSearchTreeNode() +) : BinSearchTreeNode diff --git a/app/src/main/kotlin/app/model/bst/node/BinSearchTreeNode.kt b/app/src/main/kotlin/app/model/bst/node/BinSearchTreeNode.kt new file mode 100644 index 0000000..cd2d66a --- /dev/null +++ b/app/src/main/kotlin/app/model/bst/node/BinSearchTreeNode.kt @@ -0,0 +1,3 @@ +package app.model.bst.node + +interface BinSearchTreeNode> : BinTreeNode> diff --git a/app/src/main/kotlin/app/model/bst/node/BinTreeNode.kt b/app/src/main/kotlin/app/model/bst/node/BinTreeNode.kt new file mode 100644 index 0000000..2d9dd3d --- /dev/null +++ b/app/src/main/kotlin/app/model/bst/node/BinTreeNode.kt @@ -0,0 +1,7 @@ +package app.model.bst.node + +interface BinTreeNode, Subtype : BinTreeNode> { + var value: E + var left: Subtype? + var right: Subtype? +} diff --git a/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt b/app/src/main/kotlin/app/model/bst/node/RBNode.kt similarity index 64% rename from binary-search-trees/src/main/kotlin/bst/node/RBNode.kt rename to app/src/main/kotlin/app/model/bst/node/RBNode.kt index a951f78..31df9bd 100644 --- a/binary-search-trees/src/main/kotlin/bst/node/RBNode.kt +++ b/app/src/main/kotlin/app/model/bst/node/RBNode.kt @@ -1,9 +1,9 @@ -package bst.node +package app.model.bst.node internal class RBNode>( override var value: E, override var parent: RedBlackTreeNode? = null, - override var color: Color = Color.RED, + override var color: RedBlackTreeNode.Color = RedBlackTreeNode.Color.RED, override var left: RedBlackTreeNode? = null, override var right: RedBlackTreeNode? = null, -) : RedBlackTreeNode() \ No newline at end of file +) : RedBlackTreeNode \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/bst/node/RedBlackTreeNode.kt b/app/src/main/kotlin/app/model/bst/node/RedBlackTreeNode.kt new file mode 100644 index 0000000..f804911 --- /dev/null +++ b/app/src/main/kotlin/app/model/bst/node/RedBlackTreeNode.kt @@ -0,0 +1,9 @@ +package app.model.bst.node + +interface RedBlackTreeNode> : BinTreeNode> { + var color: Color + var parent: RedBlackTreeNode? + enum class Color { + RED, BLACK + } +} diff --git a/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt b/app/src/test/kotlin/app/model/bst/AVLTreeTest.kt similarity index 97% rename from binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt rename to app/src/test/kotlin/app/model/bst/AVLTreeTest.kt index a33f0c3..872094e 100644 --- a/binary-search-trees/src/test/kotlin/bst/AVLTreeTest.kt +++ b/app/src/test/kotlin/app/model/bst/AVLTreeTest.kt @@ -1,8 +1,8 @@ -package bst +package app.model.bst +import app.model.bst.utils.InvariantChecker import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource -import utils.InvariantChecker import kotlin.random.Random import kotlin.test.BeforeTest import kotlin.test.Test diff --git a/binary-search-trees/src/test/kotlin/bst/BSTreeTest.kt b/app/src/test/kotlin/app/model/bst/BSTreeTest.kt similarity index 93% rename from binary-search-trees/src/test/kotlin/bst/BSTreeTest.kt rename to app/src/test/kotlin/app/model/bst/BSTreeTest.kt index df9e1f1..e246077 100644 --- a/binary-search-trees/src/test/kotlin/bst/BSTreeTest.kt +++ b/app/src/test/kotlin/app/model/bst/BSTreeTest.kt @@ -1,11 +1,13 @@ -package bst +package app.model.bst -import utils.InvariantChecker -import kotlin.random.Random -import kotlin.test.* +import app.model.bst.utils.InvariantChecker import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource +import kotlin.random.Random +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertTrue class BSTreeTest { companion object { diff --git a/binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt b/app/src/test/kotlin/app/model/bst/RBTreeTest.kt similarity index 97% rename from binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt rename to app/src/test/kotlin/app/model/bst/RBTreeTest.kt index 53bfa9e..34e89cf 100644 --- a/binary-search-trees/src/test/kotlin/bst/RBTreeTest.kt +++ b/app/src/test/kotlin/app/model/bst/RBTreeTest.kt @@ -1,9 +1,9 @@ -package bst +package app.model.bst +import app.model.bst.utils.InvariantChecker import org.junit.jupiter.api.Assertions import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource -import utils.InvariantChecker import kotlin.random.Random import kotlin.test.BeforeTest import kotlin.test.Test diff --git a/binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt similarity index 92% rename from binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt rename to app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt index 31d3fca..b11d6d7 100644 --- a/binary-search-trees/src/test/kotlin/bst/balancer/AVLBalancerTest.kt +++ b/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt @@ -1,7 +1,9 @@ -package bst.balancer +package app.model.bst.balancer -import bst.node.AVLNode -import kotlin.test.* +import app.model.bst.node.AVLNode +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNull class AVLBalancerTest { private val balancer = AVLBalancer() diff --git a/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt b/app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt similarity index 92% rename from binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt rename to app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt index c0def7f..be45b89 100644 --- a/binary-search-trees/src/test/kotlin/utils/InvariantChecker.kt +++ b/app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt @@ -1,11 +1,11 @@ -package utils - -import bst.AVLTree -import bst.BinarySearchTree -import bst.RBTree -import bst.node.AVLTreeNode -import bst.node.BinTreeNode -import bst.node.RedBlackTreeNode +package app.model.bst.utils + +import app.model.bst.AVLTree +import app.model.bst.BinarySearchTree +import app.model.bst.RBTree +import app.model.bst.node.AVLTreeNode +import app.model.bst.node.BinTreeNode +import app.model.bst.node.RedBlackTreeNode import java.util.* import kotlin.math.abs diff --git a/binary-search-trees/build.gradle.kts b/binary-search-trees/build.gradle.kts deleted file mode 100644 index 3a4bc02..0000000 --- a/binary-search-trees/build.gradle.kts +++ /dev/null @@ -1,21 +0,0 @@ -plugins { - id("org.jetbrains.kotlin.jvm") version "1.8.10" -} - -repositories { - mavenCentral() -} - -dependencies { - testImplementation(kotlin("test")) - testImplementation(platform("org.junit:junit-bom:5.9.2")) - testImplementation("org.junit.jupiter:junit-jupiter") -} - -tasks.test { - useJUnitPlatform() -} - -kotlin { - jvmToolchain(8) -} \ No newline at end of file diff --git a/binary-search-trees/src/main/kotlin/bst/node/AVLTreeNode.kt b/binary-search-trees/src/main/kotlin/bst/node/AVLTreeNode.kt deleted file mode 100644 index d1dbdf4..0000000 --- a/binary-search-trees/src/main/kotlin/bst/node/AVLTreeNode.kt +++ /dev/null @@ -1,5 +0,0 @@ -package bst.node - -abstract class AVLTreeNode> : BinTreeNode>() { - internal abstract var height: Int -} diff --git a/binary-search-trees/src/main/kotlin/bst/node/BinSearchTreeNode.kt b/binary-search-trees/src/main/kotlin/bst/node/BinSearchTreeNode.kt deleted file mode 100644 index e8d14d2..0000000 --- a/binary-search-trees/src/main/kotlin/bst/node/BinSearchTreeNode.kt +++ /dev/null @@ -1,3 +0,0 @@ -package bst.node - -abstract class BinSearchTreeNode> : BinTreeNode>() diff --git a/binary-search-trees/src/main/kotlin/bst/node/BinTreeNode.kt b/binary-search-trees/src/main/kotlin/bst/node/BinTreeNode.kt deleted file mode 100644 index 661105c..0000000 --- a/binary-search-trees/src/main/kotlin/bst/node/BinTreeNode.kt +++ /dev/null @@ -1,10 +0,0 @@ -package bst.node - -abstract class BinTreeNode, Subtype : BinTreeNode> { - abstract var value: E - internal set - abstract var left: Subtype? - internal set - abstract var right: Subtype? - internal set -} diff --git a/binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt b/binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt deleted file mode 100644 index 60cafd9..0000000 --- a/binary-search-trees/src/main/kotlin/bst/node/RedBlackTreeNode.kt +++ /dev/null @@ -1,12 +0,0 @@ -package bst.node - -abstract class RedBlackTreeNode> : BinTreeNode>() { - abstract var color: Color - internal set - abstract var parent: RedBlackTreeNode? - internal set - - enum class Color { - RED, BLACK - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 25a4981..a394eca 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -8,5 +8,4 @@ */ rootProject.name = "trees-4" -include("app") -include("binary-search-trees") +include("app") \ No newline at end of file From f7cf2d954d976d8f34389000901ee12b763e210b Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sun, 16 Apr 2023 22:39:48 +0300 Subject: [PATCH 050/125] feat: Add serialization deps --- app/build.gradle.kts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c3c33c9..48497ac 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,5 +1,6 @@ plugins { - id("org.jetbrains.kotlin.jvm") version "1.8.10" + kotlin("jvm") version "1.8.10" + kotlin("plugin.serialization") version "1.8.10" id("io.ktor.plugin") version "2.2.4" application } @@ -12,6 +13,8 @@ dependencies { testImplementation(kotlin("test")) testImplementation(platform("org.junit:junit-bom:5.9.2")) testImplementation("org.junit.jupiter:junit-jupiter") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") + } tasks.test { From 66a90231f23c500d215f96747eafaac18112bced Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sun, 16 Apr 2023 22:40:47 +0300 Subject: [PATCH 051/125] feat: Add template for repositories --- .../main/kotlin/app/model/repo/JsonRepo.kt | 20 ++++++++++++ .../main/kotlin/app/model/repo/Neo4jRepo.kt | 20 ++++++++++++ .../kotlin/app/model/repo/PostgresRepo.kt | 20 ++++++++++++ .../main/kotlin/app/model/repo/Repository.kt | 24 ++++++++++++++ .../model/repo/serialization/Serializable.kt | 32 +++++++++++++++++++ .../strategy/SerializationStrategy.kt | 15 +++++++++ 6 files changed, 131 insertions(+) create mode 100644 app/src/main/kotlin/app/model/repo/JsonRepo.kt create mode 100644 app/src/main/kotlin/app/model/repo/Neo4jRepo.kt create mode 100644 app/src/main/kotlin/app/model/repo/PostgresRepo.kt create mode 100644 app/src/main/kotlin/app/model/repo/Repository.kt create mode 100644 app/src/main/kotlin/app/model/repo/serialization/Serializable.kt create mode 100644 app/src/main/kotlin/app/model/repo/serialization/strategy/SerializationStrategy.kt diff --git a/app/src/main/kotlin/app/model/repo/JsonRepo.kt b/app/src/main/kotlin/app/model/repo/JsonRepo.kt new file mode 100644 index 0000000..1a6e93a --- /dev/null +++ b/app/src/main/kotlin/app/model/repo/JsonRepo.kt @@ -0,0 +1,20 @@ +package app.model.repo + +import app.model.bst.BinarySearchTree +import app.model.bst.node.BinTreeNode +import app.model.repo.serialization.strategy.SerializationStrategy + +class JsonRepo, + Node : BinTreeNode, + BST : BinarySearchTree>( + strategy: SerializationStrategy +) : Repository(strategy) { + override fun save(tree: BST) { + TODO("Not yet implemented") + } + + override fun load(factory: () -> BST): BST { + TODO("Not yet implemented") + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt b/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt new file mode 100644 index 0000000..9394dcd --- /dev/null +++ b/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt @@ -0,0 +1,20 @@ +package app.model.repo + +import app.model.bst.BinarySearchTree +import app.model.bst.node.BinTreeNode +import app.model.repo.serialization.strategy.SerializationStrategy + +class Neo4jRepo, + Node : BinTreeNode, + BST : BinarySearchTree>( + strategy: SerializationStrategy +) : Repository(strategy) { + override fun save(tree: BST) { + TODO("Not yet implemented") + } + + override fun load(factory: () -> BST): BST { + TODO("Not yet implemented") + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/PostgresRepo.kt b/app/src/main/kotlin/app/model/repo/PostgresRepo.kt new file mode 100644 index 0000000..029688c --- /dev/null +++ b/app/src/main/kotlin/app/model/repo/PostgresRepo.kt @@ -0,0 +1,20 @@ +package app.model.repo + +import app.model.bst.BinarySearchTree +import app.model.bst.node.BinTreeNode +import app.model.repo.serialization.strategy.SerializationStrategy + +class PostgresRepo, + Node : BinTreeNode, + BST : BinarySearchTree>( + strategy: SerializationStrategy +) : Repository(strategy) { + override fun save(tree: BST) { + TODO("Not yet implemented") + } + + override fun load(factory: () -> BST): BST { + TODO("Not yet implemented") + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/Repository.kt b/app/src/main/kotlin/app/model/repo/Repository.kt new file mode 100644 index 0000000..c19c4c8 --- /dev/null +++ b/app/src/main/kotlin/app/model/repo/Repository.kt @@ -0,0 +1,24 @@ +package app.model.repo + +import app.model.bst.BinarySearchTree +import app.model.bst.node.BinTreeNode +import app.model.repo.serialization.SerializableNode +import app.model.repo.serialization.strategy.SerializationStrategy + +abstract class Repository, + Node : BinTreeNode, + BST : BinarySearchTree>( + protected val strategy: SerializationStrategy +) { + protected fun Node.toSerializableNode(): SerializableNode { + return SerializableNode( + strategy.collectValue(this), + strategy.collectMetadata(this), + left?.toSerializableNode(), + right?.toSerializableNode() + ) + } + + abstract fun save(tree: BST) + abstract fun load(factory: () -> BST): BST +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/serialization/Serializable.kt b/app/src/main/kotlin/app/model/repo/serialization/Serializable.kt new file mode 100644 index 0000000..8ce119e --- /dev/null +++ b/app/src/main/kotlin/app/model/repo/serialization/Serializable.kt @@ -0,0 +1,32 @@ +package app.model.repo.serialization + +import kotlinx.serialization.Serializable + +@Serializable +enum class TypeOfTree(val savingName: String) { + BINARY_SEARCH_TREE("BINARY_SEARCH_TREE"), + RED_BLACK_TREE("RED_BLACK_TREE"), + AVL_TREE("AVL_TREE") +} + +@Serializable +class SerializableNode( + val value: SerializableValue, + val metadata: Metadata, + val left: SerializableNode? = null, + val right: SerializableNode? = null, +) + +@Serializable +class SerializableTree( + val typeOfTree: TypeOfTree, + val root: SerializableNode? +) + +@Serializable +@JvmInline +value class Metadata(val value: String) + +@Serializable +@JvmInline +value class SerializableValue(val value: String) \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/serialization/strategy/SerializationStrategy.kt b/app/src/main/kotlin/app/model/repo/serialization/strategy/SerializationStrategy.kt new file mode 100644 index 0000000..6999e66 --- /dev/null +++ b/app/src/main/kotlin/app/model/repo/serialization/strategy/SerializationStrategy.kt @@ -0,0 +1,15 @@ +package app.model.repo.serialization.strategy + +import app.model.bst.node.BinTreeNode +import app.model.repo.serialization.Metadata +import app.model.repo.serialization.SerializableNode +import app.model.repo.serialization.SerializableValue +import app.model.repo.serialization.TypeOfTree + +interface SerializationStrategy, + Node : BinTreeNode> { + val typeOfTree: TypeOfTree + fun collectMetadata(node: Node): Metadata + fun collectValue(node: Node): SerializableValue + fun buildNode(node: SerializableNode): Node +} \ No newline at end of file From be9581f424bb7fbd562eda0e98534498df3f3a6a Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sun, 16 Apr 2023 22:51:34 +0300 Subject: [PATCH 052/125] ci: Add dependabot for dependecy tracking --- .github/dependabot.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..cb2d165 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "gradle" + directory: "/" + schedule: + interval: "daily" \ No newline at end of file From 1cfb44be3d67a91e28c371b3f3ccfce0627333f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Apr 2023 19:56:50 +0000 Subject: [PATCH 053/125] build(deps): Bump jvm from 1.8.10 to 1.8.20 Bumps [jvm](https://github.com/JetBrains/kotlin) from 1.8.10 to 1.8.20. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/v1.8.20/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v1.8.10...v1.8.20) --- updated-dependencies: - dependency-name: jvm dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 48497ac..bd5c9cd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - kotlin("jvm") version "1.8.10" + kotlin("jvm") version "1.8.20" kotlin("plugin.serialization") version "1.8.10" id("io.ktor.plugin") version "2.2.4" application From 551ed228fd7373640c65fb5dd3e674488ba39ff2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Apr 2023 20:05:34 +0000 Subject: [PATCH 054/125] build(deps): Bump plugin.serialization from 1.8.10 to 1.8.20 Bumps [plugin.serialization](https://github.com/JetBrains/kotlin) from 1.8.10 to 1.8.20. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/v1.8.20/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v1.8.10...v1.8.20) --- updated-dependencies: - dependency-name: plugin.serialization dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bd5c9cd..aacadd8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,6 +1,6 @@ plugins { kotlin("jvm") version "1.8.20" - kotlin("plugin.serialization") version "1.8.10" + kotlin("plugin.serialization") version "1.8.20" id("io.ktor.plugin") version "2.2.4" application } From 4b4ff05372ef3e42b2b72d346d1b4d2d17181f24 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Mon, 17 Apr 2023 00:35:53 +0300 Subject: [PATCH 055/125] ci: Add coverage report using jacoco --- .github/workflows/ci.yml | 15 ++++++++++++++- app/build.gradle.kts | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6030d8c..e14f9be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,13 @@ jobs: uses: gradle/gradle-build-action@v2 - name: Run build with Gradle Wrapper run: ./gradlew build + + - name: Print coverage report + env: + report_path: app/build/coverage/test/jacocoTestReport.csv + run: | + awk -F"," '{ instructions += $4 + $5; covered += $5; branches += $6 + $7; branches_covered +=$7 } END { print "Instructions covered:", covered"/"instructions, "--", 100*covered/instructions"%"; print "Branches covered:", branches_covered"/"branches, "--", 100*branches_covered/branches"%" }' $report_path + - name: Create fat .jar file on main if: ${{ github.ref == 'refs/heads/main' }} run: ./gradlew app:buildFatJar @@ -20,4 +27,10 @@ jobs: if: ${{ github.ref == 'refs/heads/main' }} with: name: All in one jar - path: app/build/libs/app-all.jar \ No newline at end of file + path: app/build/libs/app-all.jar + + - uses: actions/upload-artifact@v3 + if: ${{ github.ref == 'refs/heads/main' }} + with: + name: Upload coverage report + path: app/build/coverage/test/* \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index aacadd8..386c6f7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -2,8 +2,21 @@ plugins { kotlin("jvm") version "1.8.20" kotlin("plugin.serialization") version "1.8.20" id("io.ktor.plugin") version "2.2.4" + id("jacoco") application } +jacoco { + toolVersion = "0.8.7" + reportsDirectory.set(layout.buildDirectory.dir("coverage")) + +} +tasks.withType { + reports { + xml.required.set(true) + csv.required.set(true) + html.required.set(false) + } +} repositories { mavenCentral() @@ -19,7 +32,9 @@ dependencies { tasks.test { useJUnitPlatform() + finalizedBy(tasks.jacocoTestReport) } + tasks.jar { manifest.attributes["Main-Class"] = "app.AppKt" } From cadc5c5c09a5d3d13b3722c521876b2114efd775 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Mon, 17 Apr 2023 00:39:53 +0300 Subject: [PATCH 056/125] ci: Fix ci.yml structure --- .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 e14f9be..346531a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - name: Print coverage report env: report_path: app/build/coverage/test/jacocoTestReport.csv - run: | + run: | awk -F"," '{ instructions += $4 + $5; covered += $5; branches += $6 + $7; branches_covered +=$7 } END { print "Instructions covered:", covered"/"instructions, "--", 100*covered/instructions"%"; print "Branches covered:", branches_covered"/"branches, "--", 100*branches_covered/branches"%" }' $report_path - name: Create fat .jar file on main From d3d0c735ac18d28ce2bbed5f84c459a0610e2167 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Mon, 17 Apr 2023 00:48:03 +0300 Subject: [PATCH 057/125] feat: Add information about binary trees and features --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index 1ad076d..fbe63d3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,26 @@ # trees +## Основные фичи + +1. Поддержка 3 видов (AVL, RB, BS) деревьев поиска с возможностью добавления собственных реализаций +2. (WIP) Поддержка сохранения состояния дерева и восстановаления его из Json, Postgres и Neo4j +3. (WIP) Визуализация различных деревьев поиска + +## Деревья поиска + +Чтобы создать новый вид дерева нужно сделать 3 действия. Написать балансировщик, возможно, особый тип `BinTreeNode` и +создать класс отнаследованный от `BinarySearchTree`. + +```kotlin +class RBTree> : + BinarySearchTree>( + balancer = RBBalancer(), + ) +``` + +Все наследники `BinarySearchTree` автоматически умеют выполнять поиск, вставку, удаление значений из дерева, а так же +интерироваться по нему различными способами — выполнять inorder, preorder, levelorder обходы + ## Внесение изменений Внимательно прочитайте раздел [CONTRIBUTING](./CONTRIBUTING.md). From c33775a6bc42d4937330d6912efd27a30c2a2c11 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Mon, 17 Apr 2023 17:38:21 +0300 Subject: [PATCH 058/125] fix: Update exception names and remove !! (boom) --- .../main/kotlin/app/model/bst/balancer/AVLBalancer.kt | 8 ++++---- app/src/main/kotlin/app/model/bst/balancer/BSBalancer.kt | 2 +- app/src/main/kotlin/app/model/bst/balancer/RBBalancer.kt | 9 ++++----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/app/src/main/kotlin/app/model/bst/balancer/AVLBalancer.kt b/app/src/main/kotlin/app/model/bst/balancer/AVLBalancer.kt index bf8dfa1..10a9731 100644 --- a/app/src/main/kotlin/app/model/bst/balancer/AVLBalancer.kt +++ b/app/src/main/kotlin/app/model/bst/balancer/AVLBalancer.kt @@ -6,7 +6,7 @@ import kotlin.math.max internal class AVLBalancer> : BinTreeBalancer> { override fun add(root: AVLTreeNode?, value: E, unique: Boolean): AVLTreeNode { - fun insertToSubtree(subtree: AVLTreeNode?): AVLTreeNode { + fun insertToSubtree(subtree: AVLTreeNode?): AVLTreeNode? { if (subtree == null) { return AVLNode(value) } @@ -20,9 +20,9 @@ internal class AVLBalancer> : BinTreeBalancer): AVLTreeNode? { @@ -107,7 +107,7 @@ internal class AVLBalancer> : BinTreeBalancer> : BinTreeBalancer> : BinTreeBalancer?, root: RedBlackTreeNode?): RedBlackTreeNode? { - val rightChild = node?.right ?: throw Exception("node right must be not null") + val rightChild = node?.right ?: throw IllegalStateException("Node to rotate must have a right child") node.right = rightChild.left if (rightChild.left != null) { @@ -50,7 +50,7 @@ internal class RBBalancer> : BinTreeBalancer?, root: RedBlackTreeNode?): RedBlackTreeNode? { - val leftChild = node?.left ?: throw Exception("node left must be not null") + val leftChild = node?.left ?: throw IllegalStateException("Node to rotate must have a left child") node.left = leftChild.right if (leftChild.right != null) { @@ -61,7 +61,6 @@ internal class RBBalancer> : BinTreeBalancer> : BinTreeBalancer Date: Mon, 17 Apr 2023 22:16:00 +0300 Subject: [PATCH 059/125] feat: Implement strategies for all trees --- .../main/kotlin/app/model/repo/JsonRepo.kt | 2 +- .../main/kotlin/app/model/repo/Neo4jRepo.kt | 2 +- .../kotlin/app/model/repo/PostgresRepo.kt | 2 +- .../main/kotlin/app/model/repo/Repository.kt | 6 +-- .../model/repo/serialization/Serializable.kt | 1 + .../serialization/strategy/AVLTreeStrategy.kt | 28 +++++++++++++ .../serialization/strategy/BSTreeStrategy.kt | 26 ++++++++++++ .../serialization/strategy/RBTreeStrategy.kt | 41 +++++++++++++++++++ .../strategy/SerializationStrategy.kt | 16 +++++--- 9 files changed, 112 insertions(+), 12 deletions(-) create mode 100644 app/src/main/kotlin/app/model/repo/serialization/strategy/AVLTreeStrategy.kt create mode 100644 app/src/main/kotlin/app/model/repo/serialization/strategy/BSTreeStrategy.kt create mode 100644 app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt diff --git a/app/src/main/kotlin/app/model/repo/JsonRepo.kt b/app/src/main/kotlin/app/model/repo/JsonRepo.kt index 1a6e93a..414ad43 100644 --- a/app/src/main/kotlin/app/model/repo/JsonRepo.kt +++ b/app/src/main/kotlin/app/model/repo/JsonRepo.kt @@ -7,7 +7,7 @@ import app.model.repo.serialization.strategy.SerializationStrategy class JsonRepo, Node : BinTreeNode, BST : BinarySearchTree>( - strategy: SerializationStrategy + strategy: SerializationStrategy ) : Repository(strategy) { override fun save(tree: BST) { TODO("Not yet implemented") diff --git a/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt b/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt index 9394dcd..0a3f09a 100644 --- a/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt +++ b/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt @@ -7,7 +7,7 @@ import app.model.repo.serialization.strategy.SerializationStrategy class Neo4jRepo, Node : BinTreeNode, BST : BinarySearchTree>( - strategy: SerializationStrategy + strategy: SerializationStrategy ) : Repository(strategy) { override fun save(tree: BST) { TODO("Not yet implemented") diff --git a/app/src/main/kotlin/app/model/repo/PostgresRepo.kt b/app/src/main/kotlin/app/model/repo/PostgresRepo.kt index 029688c..9bc657b 100644 --- a/app/src/main/kotlin/app/model/repo/PostgresRepo.kt +++ b/app/src/main/kotlin/app/model/repo/PostgresRepo.kt @@ -7,7 +7,7 @@ import app.model.repo.serialization.strategy.SerializationStrategy class PostgresRepo, Node : BinTreeNode, BST : BinarySearchTree>( - strategy: SerializationStrategy + strategy: SerializationStrategy ) : Repository(strategy) { override fun save(tree: BST) { TODO("Not yet implemented") diff --git a/app/src/main/kotlin/app/model/repo/Repository.kt b/app/src/main/kotlin/app/model/repo/Repository.kt index c19c4c8..7f37364 100644 --- a/app/src/main/kotlin/app/model/repo/Repository.kt +++ b/app/src/main/kotlin/app/model/repo/Repository.kt @@ -8,12 +8,12 @@ import app.model.repo.serialization.strategy.SerializationStrategy abstract class Repository, Node : BinTreeNode, BST : BinarySearchTree>( - protected val strategy: SerializationStrategy + protected val strategy: SerializationStrategy ) { protected fun Node.toSerializableNode(): SerializableNode { return SerializableNode( - strategy.collectValue(this), - strategy.collectMetadata(this), + strategy.serializeValue(this.value), + strategy.serializeMetadata(this), left?.toSerializableNode(), right?.toSerializableNode() ) diff --git a/app/src/main/kotlin/app/model/repo/serialization/Serializable.kt b/app/src/main/kotlin/app/model/repo/serialization/Serializable.kt index 8ce119e..69a83c8 100644 --- a/app/src/main/kotlin/app/model/repo/serialization/Serializable.kt +++ b/app/src/main/kotlin/app/model/repo/serialization/Serializable.kt @@ -19,6 +19,7 @@ class SerializableNode( @Serializable class SerializableTree( + val verboseName: String, val typeOfTree: TypeOfTree, val root: SerializableNode? ) diff --git a/app/src/main/kotlin/app/model/repo/serialization/strategy/AVLTreeStrategy.kt b/app/src/main/kotlin/app/model/repo/serialization/strategy/AVLTreeStrategy.kt new file mode 100644 index 0000000..c728ada --- /dev/null +++ b/app/src/main/kotlin/app/model/repo/serialization/strategy/AVLTreeStrategy.kt @@ -0,0 +1,28 @@ +package app.model.repo.serialization.strategy + +import app.model.bst.node.AVLNode +import app.model.bst.node.AVLTreeNode +import app.model.repo.serialization.Metadata +import app.model.repo.serialization.SerializableNode +import app.model.repo.serialization.SerializableValue +import app.model.repo.serialization.TypeOfTree + +class AVLTreeStrategy>( + serializeValue: (E) -> SerializableValue, + deserializeValue: (SerializableValue) -> E +) : SerializationStrategy, Int>(serializeValue, deserializeValue) { + override val typeOfTree: TypeOfTree = TypeOfTree.AVL_TREE + + override fun buildNode(node: SerializableNode?): AVLTreeNode? = node?.let { + AVLNode( + value = deserializeValue(node.value), + left = buildNode(node.left), + right = buildNode(node.right), + height = deserializeMetadata(node.metadata) + ) + } + + override fun deserializeMetadata(metadata: Metadata) = metadata.value.toInt() + + override fun serializeMetadata(node: AVLTreeNode) = Metadata(node.height.toString()) +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/serialization/strategy/BSTreeStrategy.kt b/app/src/main/kotlin/app/model/repo/serialization/strategy/BSTreeStrategy.kt new file mode 100644 index 0000000..5b48920 --- /dev/null +++ b/app/src/main/kotlin/app/model/repo/serialization/strategy/BSTreeStrategy.kt @@ -0,0 +1,26 @@ +package app.model.repo.serialization.strategy + +import app.model.bst.node.BSNode +import app.model.bst.node.BinSearchTreeNode +import app.model.repo.serialization.Metadata +import app.model.repo.serialization.SerializableNode +import app.model.repo.serialization.SerializableValue +import app.model.repo.serialization.TypeOfTree + +class BSTreeStrategy>( + serializeValue: (E) -> SerializableValue, + deserializeValue: (SerializableValue) -> E +) : SerializationStrategy, String>(serializeValue, deserializeValue) { + override val typeOfTree: TypeOfTree = TypeOfTree.BINARY_SEARCH_TREE + override fun buildNode(node: SerializableNode?): BinSearchTreeNode? = node?.let { + BSNode( + value = deserializeValue(node.value), + left = buildNode(node.left), + right = buildNode(node.right) + ) + } + + override fun deserializeMetadata(metadata: Metadata) = "" + + override fun serializeMetadata(node: BinSearchTreeNode) = Metadata("") +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt b/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt new file mode 100644 index 0000000..00d7be7 --- /dev/null +++ b/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt @@ -0,0 +1,41 @@ +package app.model.repo.serialization.strategy + +import app.model.bst.node.RBNode +import app.model.bst.node.RedBlackTreeNode +import app.model.repo.serialization.Metadata +import app.model.repo.serialization.SerializableNode +import app.model.repo.serialization.SerializableValue +import app.model.repo.serialization.TypeOfTree + +class RBTreeStrategy>( + serializeValue: (E) -> SerializableValue, + deserializeValue: (SerializableValue) -> E +) : SerializationStrategy, RedBlackTreeNode.Color>(serializeValue, deserializeValue) { + override val typeOfTree: TypeOfTree = TypeOfTree.RED_BLACK_TREE + override fun buildNode(node: SerializableNode?): RedBlackTreeNode? = node?.let { + RBNode( + value = deserializeValue(node.value), + left = buildNode(node.left), + right = buildNode(node.right), + color = deserializeMetadata(node.metadata) + ) + } + + override fun deserializeMetadata(metadata: Metadata): RedBlackTreeNode.Color { + return when (metadata.value) { + "RED" -> RedBlackTreeNode.Color.RED + "BLACK" -> RedBlackTreeNode.Color.BLACK + else -> throw IllegalArgumentException("Can deserialize 'RED', 'BLACK' metadata value strings only") + } + } + + override fun serializeMetadata(node: RedBlackTreeNode): Metadata { + return Metadata( + when (node.value) { + RedBlackTreeNode.Color.RED -> "RED" + else -> "BLACK" + } + ) + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/serialization/strategy/SerializationStrategy.kt b/app/src/main/kotlin/app/model/repo/serialization/strategy/SerializationStrategy.kt index 6999e66..3477e08 100644 --- a/app/src/main/kotlin/app/model/repo/serialization/strategy/SerializationStrategy.kt +++ b/app/src/main/kotlin/app/model/repo/serialization/strategy/SerializationStrategy.kt @@ -6,10 +6,14 @@ import app.model.repo.serialization.SerializableNode import app.model.repo.serialization.SerializableValue import app.model.repo.serialization.TypeOfTree -interface SerializationStrategy, - Node : BinTreeNode> { - val typeOfTree: TypeOfTree - fun collectMetadata(node: Node): Metadata - fun collectValue(node: Node): SerializableValue - fun buildNode(node: SerializableNode): Node + +abstract class SerializationStrategy, + Node : BinTreeNode, M>( + val serializeValue: (E) -> SerializableValue, + val deserializeValue: (SerializableValue) -> E +) { + abstract val typeOfTree: TypeOfTree + abstract fun buildNode(node: SerializableNode?): Node? + abstract fun deserializeMetadata(metadata: Metadata): M + abstract fun serializeMetadata(node: Node): Metadata } \ No newline at end of file From 61a9afce6dd4959b45c5ef4950b84ac5878c54d6 Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Tue, 18 Apr 2023 01:49:06 +0300 Subject: [PATCH 060/125] test: Fix the problem with the immutable root in AVLBalancerTest --- .../app/model/bst/balancer/AVLBalancerTest.kt | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt index b11d6d7..0abbe8f 100644 --- a/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt +++ b/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt @@ -1,6 +1,5 @@ package app.model.bst.balancer -import app.model.bst.node.AVLNode import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNull @@ -9,13 +8,13 @@ class AVLBalancerTest { private val balancer = AVLBalancer() @Test fun `test method 'add' in avl tree balancer`() { - val root = AVLNode(5) - balancer.add(root, 3, true) - balancer.add(root, 7, true) - balancer.add(root, 2, true) - balancer.add(root, 4, true) - balancer.add(root, 6, true) - balancer.add(root, 8, true) + var root = balancer.add(null, 2, true) + root = balancer.add(root, 3, true) + root = balancer.add(root, 4, true) + root = balancer.add(root, 5, true) + root = balancer.add(root, 6, true) + root = balancer.add(root, 7, true) + root = balancer.add(root, 8, true) /* constructed tree: @@ -31,19 +30,19 @@ class AVLBalancerTest { assertEquals(2, root.left?.left?.value) assertEquals(4, root.left?.right?.value) assertEquals(7, root.right?.value) - assertEquals(6, root.right?.left?.value) assertEquals(8, root.right?.right?.value) + assertEquals(6, root.right?.left?.value) } @Test fun `test method 'remove' in avl tree balancer`() { - val root = AVLNode(5) - balancer.add(root, 3, true) - balancer.add(root, 7, true) - balancer.add(root, 2, true) - balancer.add(root, 4, true) - balancer.add(root, 6, true) - balancer.add(root, 8, true) + var root = balancer.add(null, 5, true) + root = balancer.add(root, 3, true) + root = balancer.add(root, 7, true) + root = balancer.add(root, 2, true) + root = balancer.add(root, 4, true) + root = balancer.add(root, 6, true) + root = balancer.add(root, 8, true) /* constructed tree: @@ -54,23 +53,41 @@ class AVLBalancerTest { 2 4 6 8 */ - balancer.remove(root, 2) + balancer.remove(root, 5) /* constructed tree: - 5 + 6 / \ 3 7 - \ / \ - 4 6 8 + / \ \ + 2 4 8 */ - assertEquals(5, root.value) + assertEquals(6, root.value) assertEquals(3, root.left?.value) - assertNull(root.left?.left) + assertEquals(2, root.left?.left?.value) assertEquals(4, root.left?.right?.value) assertEquals(7, root.right?.value) - assertEquals(6, root.right?.left?.value) + assertNull(root.right?.left?.value) + assertEquals(8, root.right?.right?.value) + + balancer.remove(root, 3) + + /* + constructed tree: + 6 + / \ + 4 7 + / \ + 2 8 + */ + + assertEquals(6, root.value) + assertEquals(4, root.left?.value) + assertEquals(2, root.left?.left?.value) + assertNull(root.left?.right?.value) + assertEquals(7, root.right?.value) assertEquals(8, root.right?.right?.value) } } From d9434b385ee575cbef660f54d1abfc6e79f959b3 Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Tue, 18 Apr 2023 16:37:00 +0300 Subject: [PATCH 061/125] test: Fix a bug with a non-changing root when remove --- .../kotlin/app/model/bst/balancer/AVLBalancerTest.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt index 0abbe8f..6bb0cd9 100644 --- a/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt +++ b/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt @@ -36,12 +36,12 @@ class AVLBalancerTest { @Test fun `test method 'remove' in avl tree balancer`() { - var root = balancer.add(null, 5, true) + var root = balancer.add(null, 2, true) root = balancer.add(root, 3, true) - root = balancer.add(root, 7, true) - root = balancer.add(root, 2, true) root = balancer.add(root, 4, true) + root = balancer.add(root, 5, true) root = balancer.add(root, 6, true) + root = balancer.add(root, 7, true) root = balancer.add(root, 8, true) /* @@ -53,7 +53,7 @@ class AVLBalancerTest { 2 4 6 8 */ - balancer.remove(root, 5) + root = balancer.remove(root, 5)!! /* constructed tree: @@ -72,7 +72,7 @@ class AVLBalancerTest { assertNull(root.right?.left?.value) assertEquals(8, root.right?.right?.value) - balancer.remove(root, 3) + root = balancer.remove(root, 3)!! /* constructed tree: From a6965e01a12423bbd6f1d16a36f237268851f9c0 Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Tue, 18 Apr 2023 17:40:48 +0300 Subject: [PATCH 062/125] test: Remove '!!' from test --- .../app/model/bst/balancer/AVLBalancerTest.kt | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt index 6bb0cd9..a514894 100644 --- a/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt +++ b/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt @@ -36,13 +36,13 @@ class AVLBalancerTest { @Test fun `test method 'remove' in avl tree balancer`() { - var root = balancer.add(null, 2, true) - root = balancer.add(root, 3, true) - root = balancer.add(root, 4, true) - root = balancer.add(root, 5, true) - root = balancer.add(root, 6, true) - root = balancer.add(root, 7, true) - root = balancer.add(root, 8, true) + var root = balancer?.add(null, 2, true) + root = balancer?.add(root, 3, true) + root = balancer?.add(root, 4, true) + root = balancer?.add(root, 5, true) + root = balancer?.add(root, 6, true) + root = balancer?.add(root, 7, true) + root = balancer?.add(root, 8, true) /* constructed tree: @@ -53,7 +53,7 @@ class AVLBalancerTest { 2 4 6 8 */ - root = balancer.remove(root, 5)!! + root = balancer.remove(root, 5) /* constructed tree: @@ -64,15 +64,15 @@ class AVLBalancerTest { 2 4 8 */ - assertEquals(6, root.value) - assertEquals(3, root.left?.value) - assertEquals(2, root.left?.left?.value) - assertEquals(4, root.left?.right?.value) - assertEquals(7, root.right?.value) - assertNull(root.right?.left?.value) - assertEquals(8, root.right?.right?.value) + assertEquals(6, root?.value) + assertEquals(3, root?.left?.value) + assertEquals(2, root?.left?.left?.value) + assertEquals(4, root?.left?.right?.value) + assertEquals(7, root?.right?.value) + assertNull(root?.right?.left?.value) + assertEquals(8, root?.right?.right?.value) - root = balancer.remove(root, 3)!! + root = balancer.remove(root, 3) /* constructed tree: @@ -83,11 +83,11 @@ class AVLBalancerTest { 2 8 */ - assertEquals(6, root.value) - assertEquals(4, root.left?.value) - assertEquals(2, root.left?.left?.value) - assertNull(root.left?.right?.value) - assertEquals(7, root.right?.value) - assertEquals(8, root.right?.right?.value) + assertEquals(6, root?.value) + assertEquals(4, root?.left?.value) + assertEquals(2, root?.left?.left?.value) + assertNull(root?.left?.right?.value) + assertEquals(7, root?.right?.value) + assertEquals(8, root?.right?.right?.value) } } From 1b55a6757cf3287b561e42186444759bd42c3b4a Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 18 Apr 2023 20:26:55 +0300 Subject: [PATCH 063/125] feat: Add docker compose with postgres and neo4j for devs --- dev-docker-compose.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 dev-docker-compose.yml diff --git a/dev-docker-compose.yml b/dev-docker-compose.yml new file mode 100644 index 0000000..ba83097 --- /dev/null +++ b/dev-docker-compose.yml @@ -0,0 +1,21 @@ +version: '3.9' + +services: + neo4j: + image: neo4j:latest + container_name: neo4j + ports: + - "7474:7474" + - "7687:7687" + environment: + - NEO4J_AUTH=neo4j/password + + postgres: + image: postgres:latest + container_name: postgres + ports: + - "5432:5432" + environment: + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=password + - POSTGRES_DB=trees \ No newline at end of file From f0a1c6efbee00a1b48155e969492c45bc75b5bea Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 18 Apr 2023 20:27:52 +0300 Subject: [PATCH 064/125] feat: Add neo4j saver and update signatures --- .../main/kotlin/app/model/repo/JsonRepo.kt | 8 +- .../main/kotlin/app/model/repo/Neo4jRepo.kt | 116 +++++++++++++++++- .../kotlin/app/model/repo/PostgresRepo.kt | 8 +- .../main/kotlin/app/model/repo/Repository.kt | 15 ++- 4 files changed, 137 insertions(+), 10 deletions(-) diff --git a/app/src/main/kotlin/app/model/repo/JsonRepo.kt b/app/src/main/kotlin/app/model/repo/JsonRepo.kt index 414ad43..e9eb6d2 100644 --- a/app/src/main/kotlin/app/model/repo/JsonRepo.kt +++ b/app/src/main/kotlin/app/model/repo/JsonRepo.kt @@ -9,11 +9,15 @@ class JsonRepo, BST : BinarySearchTree>( strategy: SerializationStrategy ) : Repository(strategy) { - override fun save(tree: BST) { + override fun save(verboseName: String, tree: BST) { TODO("Not yet implemented") } - override fun load(factory: () -> BST): BST { + override fun loadByVerboseName(verboseName: String, factory: () -> BST): BST { + TODO("Not yet implemented") + } + + override fun deleteByVerboseName(verboseName: String) { TODO("Not yet implemented") } diff --git a/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt b/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt index 0a3f09a..14701a4 100644 --- a/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt +++ b/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt @@ -2,19 +2,127 @@ package app.model.repo import app.model.bst.BinarySearchTree import app.model.bst.node.BinTreeNode +import app.model.repo.serialization.* import app.model.repo.serialization.strategy.SerializationStrategy +import org.neo4j.ogm.annotation.* +import org.neo4j.ogm.config.Configuration +import org.neo4j.ogm.cypher.ComparisonOperator +import org.neo4j.ogm.cypher.Filter +import org.neo4j.ogm.cypher.Filters +import org.neo4j.ogm.session.SessionFactory + +@NodeEntity +class SerializableNodeEntity( + @Property + var value: SerializableValue, + + @Property + var metadata: Metadata, + + @Relationship(type = "LEFT") + var left: SerializableNodeEntity? = null, + + @Relationship(type = "RIGHT") + var right: SerializableNodeEntity? = null, +) { + @Id + @GeneratedValue + var id: Long? = null +} + +@NodeEntity +class SerializableTreeEntity( + @Property + var verboseName: String, + + @Property + var typeOfTree: TypeOfTree, + + @Relationship(type = "ROOT") + var root: SerializableNodeEntity? = null, +) { + + @Id + @GeneratedValue + var id: Long? = null + +} class Neo4jRepo, Node : BinTreeNode, BST : BinarySearchTree>( strategy: SerializationStrategy ) : Repository(strategy) { - override fun save(tree: BST) { - TODO("Not yet implemented") + private val configuration = Configuration.Builder() + .uri("bolt://localhost") + .credentials("neo4j", "password") //TODO: use settings for this parameters + .build() + private val sessionFactory = SessionFactory(configuration, "app.model.repo") + private val session = sessionFactory.openSession() + + private fun SerializableNodeEntity.toNode(): SerializableNode { + return SerializableNode( + value, + metadata, + left?.toNode(), + right?.toNode() + ) + } + + private fun SerializableTreeEntity.toTree(): SerializableTree { + return SerializableTree( + verboseName, + typeOfTree, + root?.toNode() + ) + } + + + private fun SerializableNode.toEntity(): SerializableNodeEntity { + return SerializableNodeEntity( + value, + metadata, + left?.toEntity(), + right?.toEntity() + ) + } + + private fun SerializableTree.toEntity(): SerializableTreeEntity { + return SerializableTreeEntity( + verboseName, + typeOfTree, + root?.toEntity() + ) } - override fun load(factory: () -> BST): BST { - TODO("Not yet implemented") + override fun save(verboseName: String, tree: BST) { + deleteByVerboseName(verboseName) + val entityTree = tree.toSerializableTree(verboseName).toEntity() + session.save(entityTree) } + private fun findByVerboseName(verboseName: String) = session.loadAll( + SerializableTreeEntity::class.java, + Filters().and( + Filter("verboseName", ComparisonOperator.EQUALS, verboseName) + ).and( + Filter("typeOfTree", ComparisonOperator.EQUALS, strategy.typeOfTree) + ), + -1 + ) + + override fun loadByVerboseName(verboseName: String, factory: () -> BST): BST { + val treeEntity = findByVerboseName(verboseName).singleOrNull() + + return factory().apply { + root = strategy.buildNode(treeEntity?.toTree()?.root) + } + } + + override fun deleteByVerboseName(verboseName: String) { + session.query( + "MATCH toDelete=(t:SerializableTreeEntity {typeOfTree: '\$typeOfTree', verboseName : '\$verboseName'})-[*]->() DETACH DELETE toDelete", + mapOf("typeOfTree" to strategy.typeOfTree, "verboseName" to verboseName) + ) + } } \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/PostgresRepo.kt b/app/src/main/kotlin/app/model/repo/PostgresRepo.kt index 9bc657b..6ad0b6b 100644 --- a/app/src/main/kotlin/app/model/repo/PostgresRepo.kt +++ b/app/src/main/kotlin/app/model/repo/PostgresRepo.kt @@ -9,11 +9,15 @@ class PostgresRepo, BST : BinarySearchTree>( strategy: SerializationStrategy ) : Repository(strategy) { - override fun save(tree: BST) { + override fun save(verboseName: String, tree: BST) { TODO("Not yet implemented") } - override fun load(factory: () -> BST): BST { + override fun loadByVerboseName(verboseName: String, factory: () -> BST): BST { + TODO("Not yet implemented") + } + + override fun deleteByVerboseName(verboseName: String) { TODO("Not yet implemented") } diff --git a/app/src/main/kotlin/app/model/repo/Repository.kt b/app/src/main/kotlin/app/model/repo/Repository.kt index 7f37364..bf9f321 100644 --- a/app/src/main/kotlin/app/model/repo/Repository.kt +++ b/app/src/main/kotlin/app/model/repo/Repository.kt @@ -3,6 +3,7 @@ package app.model.repo import app.model.bst.BinarySearchTree import app.model.bst.node.BinTreeNode import app.model.repo.serialization.SerializableNode +import app.model.repo.serialization.SerializableTree import app.model.repo.serialization.strategy.SerializationStrategy abstract class Repository, @@ -19,6 +20,16 @@ abstract class Repository, ) } - abstract fun save(tree: BST) - abstract fun load(factory: () -> BST): BST + + protected fun BST.toSerializableTree(verboseName: String): SerializableTree { + return SerializableTree( + verboseName = verboseName, + typeOfTree = strategy.typeOfTree, + root = this.root?.toSerializableNode() + ) + } + + abstract fun save(verboseName: String, tree: BST) + abstract fun loadByVerboseName(verboseName: String, factory: () -> BST): BST + abstract fun deleteByVerboseName(verboseName: String) } \ No newline at end of file From 556b3bac3526e9aa6aeb14df16a47a2eae28af8d Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 18 Apr 2023 20:28:39 +0300 Subject: [PATCH 065/125] feat: Add OGM for neo4j --- app/build.gradle.kts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 386c6f7..2d36e37 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -3,6 +3,8 @@ plugins { kotlin("plugin.serialization") version "1.8.20" id("io.ktor.plugin") version "2.2.4" id("jacoco") + id("org.jetbrains.kotlin.plugin.noarg") version "1.8.20" + application } jacoco { @@ -26,6 +28,8 @@ dependencies { testImplementation(kotlin("test")) testImplementation(platform("org.junit:junit-bom:5.9.2")) testImplementation("org.junit.jupiter:junit-jupiter") + implementation("org.neo4j:neo4j-ogm-core:4.0.5") + runtimeOnly("org.neo4j:neo4j-ogm-bolt-driver:4.0.5") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") } @@ -38,6 +42,11 @@ tasks.test { tasks.jar { manifest.attributes["Main-Class"] = "app.AppKt" } +noArg { + annotation("org.neo4j.ogm.annotation.NodeEntity") + annotation("org.neo4j.ogm.annotation.RelationshipEntity") +} + kotlin { jvmToolchain(8) } From b37efeffdd398bd506b96844b034c78e64660fd3 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 18 Apr 2023 20:36:09 +0300 Subject: [PATCH 066/125] fix: Remove useless quotes --- app/src/main/kotlin/app/model/repo/Neo4jRepo.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt b/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt index 14701a4..4ddaa1e 100644 --- a/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt +++ b/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt @@ -121,7 +121,7 @@ class Neo4jRepo, override fun deleteByVerboseName(verboseName: String) { session.query( - "MATCH toDelete=(t:SerializableTreeEntity {typeOfTree: '\$typeOfTree', verboseName : '\$verboseName'})-[*]->() DETACH DELETE toDelete", + "MATCH toDelete=(t:SerializableTreeEntity {typeOfTree: \$typeOfTree, verboseName : \$verboseName})-[*]->() DETACH DELETE toDelete", mapOf("typeOfTree" to strategy.typeOfTree, "verboseName" to verboseName) ) } From 66c1d74dfab60a165cdaf2c641347c21936afbf8 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 18 Apr 2023 21:00:57 +0300 Subject: [PATCH 067/125] fix: Delete now works with trees without root --- app/src/main/kotlin/app/model/repo/Neo4jRepo.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt b/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt index 4ddaa1e..76432c6 100644 --- a/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt +++ b/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt @@ -121,7 +121,7 @@ class Neo4jRepo, override fun deleteByVerboseName(verboseName: String) { session.query( - "MATCH toDelete=(t:SerializableTreeEntity {typeOfTree: \$typeOfTree, verboseName : \$verboseName})-[*]->() DETACH DELETE toDelete", + "MATCH toDelete=(t:SerializableTreeEntity {typeOfTree: \$typeOfTree, verboseName : \$verboseName})-[*0..]->() DETACH DELETE toDelete", mapOf("typeOfTree" to strategy.typeOfTree, "verboseName" to verboseName) ) } From 4a847cc685a0e05a187a118765c2bfe8b37f1ec2 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 18 Apr 2023 21:05:11 +0300 Subject: [PATCH 068/125] fix: Remove default configuration property --- app/src/main/kotlin/app/model/repo/Neo4jRepo.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt b/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt index 76432c6..4000eb9 100644 --- a/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt +++ b/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt @@ -51,12 +51,9 @@ class SerializableTreeEntity( class Neo4jRepo, Node : BinTreeNode, BST : BinarySearchTree>( - strategy: SerializationStrategy + strategy: SerializationStrategy, + configuration: Configuration ) : Repository(strategy) { - private val configuration = Configuration.Builder() - .uri("bolt://localhost") - .credentials("neo4j", "password") //TODO: use settings for this parameters - .build() private val sessionFactory = SessionFactory(configuration, "app.model.repo") private val session = sessionFactory.openSession() From c6afb41af227495135b3081c80bc2099d60c0a68 Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Tue, 18 Apr 2023 21:49:30 +0300 Subject: [PATCH 069/125] test: Fix a problem with warnings related to the type of root --- .../app/model/bst/balancer/AVLBalancerTest.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt index a514894..2388001 100644 --- a/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt +++ b/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt @@ -1,5 +1,6 @@ package app.model.bst.balancer +import app.model.bst.node.AVLTreeNode import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNull @@ -36,13 +37,13 @@ class AVLBalancerTest { @Test fun `test method 'remove' in avl tree balancer`() { - var root = balancer?.add(null, 2, true) - root = balancer?.add(root, 3, true) - root = balancer?.add(root, 4, true) - root = balancer?.add(root, 5, true) - root = balancer?.add(root, 6, true) - root = balancer?.add(root, 7, true) - root = balancer?.add(root, 8, true) + var root: AVLTreeNode? = balancer.add(null, 2, true) + root = balancer.add(root, 3, true) + root = balancer.add(root, 4, true) + root = balancer.add(root, 5, true) + root = balancer.add(root, 6, true) + root = balancer.add(root, 7, true) + root = balancer.add(root, 8, true) /* constructed tree: From c771c3cd9d96ea5a8979a1345308a8404f0bbad3 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 18 Apr 2023 21:34:34 +0300 Subject: [PATCH 070/125] fix: Fix parent restoration process for RedBlackTree --- .../serialization/strategy/RBTreeStrategy.kt | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt b/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt index 00d7be7..f1cc200 100644 --- a/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt +++ b/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt @@ -12,13 +12,20 @@ class RBTreeStrategy>( deserializeValue: (SerializableValue) -> E ) : SerializationStrategy, RedBlackTreeNode.Color>(serializeValue, deserializeValue) { override val typeOfTree: TypeOfTree = TypeOfTree.RED_BLACK_TREE - override fun buildNode(node: SerializableNode?): RedBlackTreeNode? = node?.let { - RBNode( - value = deserializeValue(node.value), - left = buildNode(node.left), - right = buildNode(node.right), - color = deserializeMetadata(node.metadata) - ) + override fun buildNode(node: SerializableNode?): RedBlackTreeNode? { + fun buildNodeWithParent(node: SerializableNode?, parent: RedBlackTreeNode?): RedBlackTreeNode? { + node ?: return null + val rbNode = RBNode( + value = deserializeValue(node.value), + color = deserializeMetadata(node.metadata) + ) + rbNode.parent = parent + rbNode.left = buildNodeWithParent(node.left, rbNode) + rbNode.right = buildNodeWithParent(node.right, rbNode) + return rbNode + } + + return buildNodeWithParent(node, null) } override fun deserializeMetadata(metadata: Metadata): RedBlackTreeNode.Color { From 890117aaea7fbcdc5b4c58a5befb1b2062bd3057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Mon, 17 Apr 2023 21:52:49 +0300 Subject: [PATCH 071/125] test: Add test to check the add and remove methods of rb and avl trees --- .../app/model/bst/balancer/BSTBalancerTest.kt | 83 +++++++++++++++++++ .../app/model/bst/balancer/RBBalancerTest.kt | 81 ++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt create mode 100644 app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt diff --git a/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt new file mode 100644 index 0000000..7215b52 --- /dev/null +++ b/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt @@ -0,0 +1,83 @@ + +package app.model.bst.balancer + + +import app.model.bst.BSTree +import kotlin.test.Test +import kotlin.test.assertEquals + +class BSTBalancerTest { + + @Test + fun `test method 'add' in bs tree`() { + val tree = BSTree() + + tree.add(5) + tree.add(1) + tree.add(7) + tree.add(4) + tree.add(6) + tree.add(3) + + /* + constructed tree: + 5 + / \ + 1 7 + \ / + 4 6 + / + 3 + */ + + assertEquals(5, tree.root?.value) + assertEquals(1, tree.root?.left?.value) + assertEquals(4, tree.root?.left?.right?.value) + assertEquals(3, tree.root?.left?.right?.left?.value) + assertEquals(7, tree.root?.right?.value) + assertEquals(6, tree.root?.right?.left?.value) + } + + @Test + fun `test method 'remove' in bs tree`() { + val tree = BSTree() + + tree.add(5) + tree.add(1) + tree.add(7) + tree.add(4) + tree.add(6) + tree.add(3) + + /* + constructed tree: + 5 + / \ + 1 7 + \ / + 4 6 + / + 3 + */ + + tree.remove(5) + + /* + constructed tree: + 6 + / \ + 1 7 + \ + 4 + / + 3 + */ + + + assertEquals(6, tree.root?.value) + assertEquals(1, tree.root?.left?.value) + assertEquals(4, tree.root?.left?.right?.value) + assertEquals(7, tree.root?.right?.value) + assertEquals(3, tree.root?.left?.right?.left?.value) + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt new file mode 100644 index 0000000..6ea907a --- /dev/null +++ b/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt @@ -0,0 +1,81 @@ +package app.model.bst.balancer + +import app.model.bst.RBTree +import app.model.bst.node.RedBlackTreeNode +import kotlin.test.Test +import kotlin.test.assertEquals + +class RBBalancerTest { + + + @Test + fun `test method 'add' in rb tree`() { + val tree = RBTree() + + tree.add(1) + tree.add(2 ) + tree.add(3 ) + tree.add(4 ) + + + /* + constructed tree: + 2(BLACK) + / \ + (BLACK)1 3(BLACK) + \ + 4(RED) + */ + + + assertEquals(2, tree.root?.value) + assertEquals(1, tree.root?.left?.value) + assertEquals(3, tree.root?.right?.value) + assertEquals(4, tree.root?.right?.right?.value) + assertEquals(RedBlackTreeNode.Color.BLACK, tree.root?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, tree.root?.left?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, tree.root?.right?.color) + assertEquals(RedBlackTreeNode.Color.RED, tree.root?.right?.right?.color) + + } + + @Test + fun `test method 'remove' in rb tree`() { + val tree = RBTree() + + tree.add(1) + tree.add(2) + tree.add(3) + tree.add(4) + + + /* + constructed tree: + 2(BLACK) + / \ + (BLACK)1 3(BLACK) + \ + 4(RED) + */ + + + tree.remove( 2) + + + /* + constructed tree: + 3(BLACK) + / \ + 1(BLACK) 4(BLACK) + */ + + + assertEquals(3, tree.root?.value) + assertEquals(1, tree.root?.left?.value) + assertEquals(4, tree.root?.right?.value) + assertEquals(RedBlackTreeNode.Color.BLACK, tree.root?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, tree.root?.left?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, tree.root?.right?.color) + } + +} \ No newline at end of file From dcecdcb45b3b455822a2bc446082a2e510506404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Tue, 18 Apr 2023 14:13:55 +0300 Subject: [PATCH 072/125] test: Add test balance rb and bs tree --- .../app/model/bst/balancer/BSTBalancerTest.kt | 53 +++++++++---------- .../app/model/bst/balancer/RBBalancerTest.kt | 52 +++++++++--------- 2 files changed, 50 insertions(+), 55 deletions(-) diff --git a/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt index 7215b52..dadbbca 100644 --- a/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt +++ b/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt @@ -7,17 +7,16 @@ import kotlin.test.Test import kotlin.test.assertEquals class BSTBalancerTest { - + private val balancer = BSBalancer() @Test fun `test method 'add' in bs tree`() { - val tree = BSTree() + var root = balancer.add(null, 5, true) - tree.add(5) - tree.add(1) - tree.add(7) - tree.add(4) - tree.add(6) - tree.add(3) + root = balancer.add(root, 1, true) + root = balancer.add(root , 7, true) + root = balancer.add(root,4, true ) + root = balancer.add(root , 6, true) + root = balancer.add(root,3, true ) /* constructed tree: @@ -30,24 +29,24 @@ class BSTBalancerTest { 3 */ - assertEquals(5, tree.root?.value) - assertEquals(1, tree.root?.left?.value) - assertEquals(4, tree.root?.left?.right?.value) - assertEquals(3, tree.root?.left?.right?.left?.value) - assertEquals(7, tree.root?.right?.value) - assertEquals(6, tree.root?.right?.left?.value) + assertEquals(5, root.value) + assertEquals(1, root.left?.value) + assertEquals(4, root.left?.right?.value) + assertEquals(3, root.left?.right?.left?.value) + assertEquals(7, root.right?.value) + assertEquals(6, root.right?.left?.value) } @Test fun `test method 'remove' in bs tree`() { - val tree = BSTree() + var root = balancer.add(null, 5, true) + + root = balancer.add(root, 1, true) + root = balancer.add(root , 7, true) + root = balancer.add(root,4, true ) + root = balancer.add(root , 6, true) + root = balancer.add(root,3, true ) - tree.add(5) - tree.add(1) - tree.add(7) - tree.add(4) - tree.add(6) - tree.add(3) /* constructed tree: @@ -60,7 +59,7 @@ class BSTBalancerTest { 3 */ - tree.remove(5) + root = balancer.remove(root,5)!! /* constructed tree: @@ -74,10 +73,10 @@ class BSTBalancerTest { */ - assertEquals(6, tree.root?.value) - assertEquals(1, tree.root?.left?.value) - assertEquals(4, tree.root?.left?.right?.value) - assertEquals(7, tree.root?.right?.value) - assertEquals(3, tree.root?.left?.right?.left?.value) + assertEquals(6, root.value) + assertEquals(1, root.left?.value) + assertEquals(4, root.left?.right?.value) + assertEquals(7, root.right?.value) + assertEquals(3, root.left?.right?.left?.value) } } \ No newline at end of file diff --git a/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt index 6ea907a..0dbccb9 100644 --- a/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt +++ b/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt @@ -6,16 +6,15 @@ import kotlin.test.Test import kotlin.test.assertEquals class RBBalancerTest { - + private val balancer = RBBalancer() @Test fun `test method 'add' in rb tree`() { - val tree = RBTree() + var root = balancer.add(null, 1, true) - tree.add(1) - tree.add(2 ) - tree.add(3 ) - tree.add(4 ) + root = balancer.add(root, 2, true) + root = balancer.add(root , 3, true) + root = balancer.add(root,4, true ) /* @@ -28,27 +27,24 @@ class RBBalancerTest { */ - assertEquals(2, tree.root?.value) - assertEquals(1, tree.root?.left?.value) - assertEquals(3, tree.root?.right?.value) - assertEquals(4, tree.root?.right?.right?.value) - assertEquals(RedBlackTreeNode.Color.BLACK, tree.root?.color) - assertEquals(RedBlackTreeNode.Color.BLACK, tree.root?.left?.color) - assertEquals(RedBlackTreeNode.Color.BLACK, tree.root?.right?.color) - assertEquals(RedBlackTreeNode.Color.RED, tree.root?.right?.right?.color) + assertEquals(2, root.value) + assertEquals(1, root.left?.value) + assertEquals(3, root.right?.value) + assertEquals(4, root.right?.right?.value) + assertEquals(RedBlackTreeNode.Color.BLACK, root.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root.left?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root.right?.color) + assertEquals(RedBlackTreeNode.Color.RED, root.right?.right?.color) } @Test fun `test method 'remove' in rb tree`() { - val tree = RBTree() - - tree.add(1) - tree.add(2) - tree.add(3) - tree.add(4) - + var root = balancer.add(null, 1, true) + root = balancer.add(root, 2, true) + root = balancer.add(root , 3, true) + root = balancer.add(root,4, true ) /* constructed tree: 2(BLACK) @@ -59,7 +55,7 @@ class RBBalancerTest { */ - tree.remove( 2) + root = balancer.remove(root,2)!! /* @@ -70,12 +66,12 @@ class RBBalancerTest { */ - assertEquals(3, tree.root?.value) - assertEquals(1, tree.root?.left?.value) - assertEquals(4, tree.root?.right?.value) - assertEquals(RedBlackTreeNode.Color.BLACK, tree.root?.color) - assertEquals(RedBlackTreeNode.Color.BLACK, tree.root?.left?.color) - assertEquals(RedBlackTreeNode.Color.BLACK, tree.root?.right?.color) + assertEquals(3, root.value) + assertEquals(1, root.left?.value) + assertEquals(4, root.right?.value) + assertEquals(RedBlackTreeNode.Color.BLACK, root.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root.left?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root.right?.color) } } \ No newline at end of file From 535e7b8b9e40ac0353248feab0583d1b073c47e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Tue, 18 Apr 2023 23:15:22 +0300 Subject: [PATCH 073/125] test: Remove the 'boom', correct the name, correct the ugly brackets --- .../app/model/bst/balancer/BSTBalancerTest.kt | 22 +++++++------- .../app/model/bst/balancer/RBBalancerTest.kt | 29 +++++++++---------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt index dadbbca..a566fde 100644 --- a/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt +++ b/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt @@ -1,15 +1,13 @@ - package app.model.bst.balancer - -import app.model.bst.BSTree +import app.model.bst.node.BinSearchTreeNode import kotlin.test.Test import kotlin.test.assertEquals class BSTBalancerTest { private val balancer = BSBalancer() @Test - fun `test method 'add' in bs tree`() { + fun `test method 'add' in bs balancer`() { var root = balancer.add(null, 5, true) root = balancer.add(root, 1, true) @@ -38,8 +36,8 @@ class BSTBalancerTest { } @Test - fun `test method 'remove' in bs tree`() { - var root = balancer.add(null, 5, true) + fun `test method 'remove' in bs balancer`() { + var root: BinSearchTreeNode? = balancer.add(null, 5, true) root = balancer.add(root, 1, true) root = balancer.add(root , 7, true) @@ -59,7 +57,7 @@ class BSTBalancerTest { 3 */ - root = balancer.remove(root,5)!! + root = balancer.remove(root,5) /* constructed tree: @@ -73,10 +71,10 @@ class BSTBalancerTest { */ - assertEquals(6, root.value) - assertEquals(1, root.left?.value) - assertEquals(4, root.left?.right?.value) - assertEquals(7, root.right?.value) - assertEquals(3, root.left?.right?.left?.value) + assertEquals(6, root?.value) + assertEquals(1, root?.left?.value) + assertEquals(4, root?.left?.right?.value) + assertEquals(7, root?.right?.value) + assertEquals(3, root?.left?.right?.left?.value) } } \ No newline at end of file diff --git a/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt index 0dbccb9..bb79897 100644 --- a/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt +++ b/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt @@ -1,6 +1,5 @@ package app.model.bst.balancer -import app.model.bst.RBTree import app.model.bst.node.RedBlackTreeNode import kotlin.test.Test import kotlin.test.assertEquals @@ -9,7 +8,7 @@ class RBBalancerTest { private val balancer = RBBalancer() @Test - fun `test method 'add' in rb tree`() { + fun `test method 'add' in rb balancer`() { var root = balancer.add(null, 1, true) root = balancer.add(root, 2, true) @@ -39,8 +38,8 @@ class RBBalancerTest { } @Test - fun `test method 'remove' in rb tree`() { - var root = balancer.add(null, 1, true) + fun `test method 'remove' in rb balancer`() { + var root: RedBlackTreeNode? = balancer.add(null, 1, true) root = balancer.add(root, 2, true) root = balancer.add(root , 3, true) @@ -48,14 +47,14 @@ class RBBalancerTest { /* constructed tree: 2(BLACK) - / \ - (BLACK)1 3(BLACK) - \ - 4(RED) + / \ + 1(BLACK) 3(BLACK) + \ + 4(RED) */ - root = balancer.remove(root,2)!! + root = balancer.remove(root,2) /* @@ -66,12 +65,12 @@ class RBBalancerTest { */ - assertEquals(3, root.value) - assertEquals(1, root.left?.value) - assertEquals(4, root.right?.value) - assertEquals(RedBlackTreeNode.Color.BLACK, root.color) - assertEquals(RedBlackTreeNode.Color.BLACK, root.left?.color) - assertEquals(RedBlackTreeNode.Color.BLACK, root.right?.color) + assertEquals(3, root?.value) + assertEquals(1, root?.left?.value) + assertEquals(4, root?.right?.value) + assertEquals(RedBlackTreeNode.Color.BLACK, root?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root?.left?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root?.right?.color) } } \ No newline at end of file From d941b2421ac3fad528bf5b9e75474dbde5ad04e3 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Wed, 19 Apr 2023 01:04:50 +0300 Subject: [PATCH 074/125] docs: Add docs for any freaking classes, methods etc --- app/src/main/kotlin/app/model/bst/AVLTree.kt | 10 ++++ app/src/main/kotlin/app/model/bst/BSTree.kt | 9 +++ .../kotlin/app/model/bst/BinarySearchTree.kt | 53 ++++++++++++++++- app/src/main/kotlin/app/model/bst/RBTree.kt | 15 +++++ .../app/model/bst/balancer/BinTreeBalancer.kt | 12 ++++ .../app/model/bst/iterator/InOrderIterator.kt | 19 ++++++ .../model/bst/iterator/LevelOrderIterator.kt | 19 ++++++ .../model/bst/iterator/PreOrderIterator.kt | 19 ++++++ .../main/kotlin/app/model/bst/node/AVLNode.kt | 9 +++ .../kotlin/app/model/bst/node/AVLTreeNode.kt | 11 +++- .../main/kotlin/app/model/bst/node/BSNode.kt | 11 +++- .../app/model/bst/node/BinSearchTreeNode.kt | 9 ++- .../kotlin/app/model/bst/node/BinTreeNode.kt | 11 +++- .../main/kotlin/app/model/bst/node/RBNode.kt | 11 ++++ .../app/model/bst/node/RedBlackTreeNode.kt | 19 +++++- .../main/kotlin/app/model/repo/Neo4jRepo.kt | 59 ++++++++++++++++++- .../main/kotlin/app/model/repo/Repository.kt | 36 ++++++++++- .../model/repo/serialization/Serializable.kt | 30 ++++++++++ .../serialization/strategy/AVLTreeStrategy.kt | 29 +++++++++ .../serialization/strategy/BSTreeStrategy.kt | 30 ++++++++++ .../serialization/strategy/RBTreeStrategy.kt | 32 ++++++++++ .../strategy/SerializationStrategy.kt | 35 ++++++++++- 22 files changed, 477 insertions(+), 11 deletions(-) diff --git a/app/src/main/kotlin/app/model/bst/AVLTree.kt b/app/src/main/kotlin/app/model/bst/AVLTree.kt index 5d182ee..cbfbb39 100644 --- a/app/src/main/kotlin/app/model/bst/AVLTree.kt +++ b/app/src/main/kotlin/app/model/bst/AVLTree.kt @@ -3,6 +3,16 @@ package app.model.bst import app.model.bst.balancer.AVLBalancer import app.model.bst.node.AVLTreeNode +/** + * AVLTree is a self-balancing binary search tree + * It uses the AVLBalancer to maintain balance and ensure that the height of the left and right subtrees of any node + * differ by at most one. + * + * @param E the type of elements stored in the tree + * + * @see BinarySearchTree + * @see AVLBalancer + */ class AVLTree> : BinarySearchTree>( balancer = AVLBalancer(), diff --git a/app/src/main/kotlin/app/model/bst/BSTree.kt b/app/src/main/kotlin/app/model/bst/BSTree.kt index 60f2c57..a663992 100644 --- a/app/src/main/kotlin/app/model/bst/BSTree.kt +++ b/app/src/main/kotlin/app/model/bst/BSTree.kt @@ -3,6 +3,15 @@ package app.model.bst import app.model.bst.balancer.BSBalancer import app.model.bst.node.BinSearchTreeNode +/** + * BSTree is a binary search tree that implements the BinarySearchTree interface. + * It uses the BSBalancer to insert values to the tree. + * + * @param E the type of elements stored in the tree + * + * @see BinarySearchTree + * @see BSBalancer + */ class BSTree> : BinarySearchTree>( balancer = BSBalancer(), diff --git a/app/src/main/kotlin/app/model/bst/BinarySearchTree.kt b/app/src/main/kotlin/app/model/bst/BinarySearchTree.kt index ef3eec7..3f08d48 100644 --- a/app/src/main/kotlin/app/model/bst/BinarySearchTree.kt +++ b/app/src/main/kotlin/app/model/bst/BinarySearchTree.kt @@ -6,35 +6,86 @@ import app.model.bst.iterator.LevelOrderIterator import app.model.bst.iterator.PreOrderIterator import app.model.bst.node.BinTreeNode +/** + * An abstract class representing a binary search tree. + * + * @param the type of elements stored in the tree + * @param the type of node used in the tree + */ abstract class BinarySearchTree, NodeType : BinTreeNode>( + /** + * The balancer used to perform all magic with balance + */ protected val balancer: BinTreeBalancer, ) { + /** + * The root node of the tree. + */ var root: NodeType? = null + /** + * Adds a value to the tree. + * + * @param value the value to add + * @param unique whether to only add unique values (replaces old with new one if unique and found) + */ open fun add(value: E, unique: Boolean = false) { root = balancer.add(root, value, unique) } + /** + * Removes a value from the tree. + * + * @param value the value to remove + */ open fun remove(value: E) { root = balancer.remove(root, value) } + /** + * Checks if a value is in the tree. + * + * @param value the value to check for + * @return true if the value is in the tree, false otherwise + */ operator fun contains(value: E): Boolean { return search(root, value) } + /** + * Returns an iterator over the elements in the tree in in-order traversal order. + * + * @return an iterator over the elements in the tree in in-order traversal order + */ operator fun iterator(): Iterator { return InOrderIterator(root) } + /** + * Returns an iterator over the elements in the tree in pre-order traversal order. + * + * @return an iterator over the elements in the tree in pre-order traversal order + */ fun preOrderIterator(): Iterator { return PreOrderIterator(root) } + /** + * Returns an iterator over the elements in the tree in level-order traversal order. + * + * @return an iterator over the elements in the tree in level-order traversal order + */ fun levelOrderIterator(): Iterator { return LevelOrderIterator(root) } + /** + * Recursively searches for a value in the tree. + * + * @param node the node to start the search from + * @param value the value to search for + * @return true if the value is in the tree, false otherwise + */ private tailrec fun search(node: NodeType?, value: E): Boolean { if (node == null) { return false @@ -46,4 +97,4 @@ abstract class BinarySearchTree, NodeType : BinTreeNode> : BinarySearchTree>( balancer = RBBalancer(), diff --git a/app/src/main/kotlin/app/model/bst/balancer/BinTreeBalancer.kt b/app/src/main/kotlin/app/model/bst/balancer/BinTreeBalancer.kt index 1e7cd25..c98e6c6 100644 --- a/app/src/main/kotlin/app/model/bst/balancer/BinTreeBalancer.kt +++ b/app/src/main/kotlin/app/model/bst/balancer/BinTreeBalancer.kt @@ -2,14 +2,26 @@ package app.model.bst.balancer import app.model.bst.node.BinTreeNode +/** + * An interface for a binary tree balancer. + * @param E the type of element stored in the tree, must implement Comparable interface. + * @param NodeType the type of node used in the tree, must implement BinTreeNode interface. + */ interface BinTreeBalancer, NodeType : BinTreeNode> { /** * Adds a new node with a value to the root's subtree, and rebalances it if necessary. + * @param root the root node of the subtree to add the new node to. + * @param value the value to add to the tree. + * @param unique whether to insert only unique values in the tree. + * @return the new root node of the subtree. */ fun add(root: NodeType?, value: E, unique: Boolean): NodeType /** * Removes a node with a value from the root's subtree, and rebalances it if necessary. + * @param root the root node of the subtree to remove the node from. + * @param value the value to remove from the tree. + * @return the new root node of the subtree. */ fun remove(root: NodeType?, value: E): NodeType? } \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/bst/iterator/InOrderIterator.kt b/app/src/main/kotlin/app/model/bst/iterator/InOrderIterator.kt index 19f8472..5e99baf 100644 --- a/app/src/main/kotlin/app/model/bst/iterator/InOrderIterator.kt +++ b/app/src/main/kotlin/app/model/bst/iterator/InOrderIterator.kt @@ -3,6 +3,19 @@ package app.model.bst.iterator import app.model.bst.node.BinTreeNode import java.util.* +/** + * InOrderIterator is an internal class that implements the Iterator interface for a binary tree. + * It iterates over the elements of the tree in in-order traversal order. + * The tree stores elements of type E, which must implement the Comparable interface. + * The NodeType parameter specifies the type of nodes in the tree. + * + * @param E the type of elements stored in the tree, which must implement the Comparable interface. + * @param NodeType the type of nodes in the tree. + * @property root the root node of the tree. + * + * @see Iterator + * @see BinTreeNode + */ internal class InOrderIterator, NodeType : BinTreeNode>(root: NodeType?) : Iterator { private val stack = LinkedList() @@ -14,10 +27,16 @@ internal class InOrderIterator, NodeType : BinTreeNode, NodeType : BinTreeNode>(root: NodeType?) : Iterator { private val queue = LinkedList() @@ -11,10 +24,16 @@ internal class LevelOrderIterator, NodeType : BinTreeNode, NodeType : BinTreeNode>(root: NodeType?) : Iterator { private val stack = LinkedList() @@ -10,10 +23,16 @@ internal class PreOrderIterator, NodeType : BinTreeNode>( override var value: E, override var height: Int = 1, diff --git a/app/src/main/kotlin/app/model/bst/node/AVLTreeNode.kt b/app/src/main/kotlin/app/model/bst/node/AVLTreeNode.kt index 782b90c..c7cbda2 100644 --- a/app/src/main/kotlin/app/model/bst/node/AVLTreeNode.kt +++ b/app/src/main/kotlin/app/model/bst/node/AVLTreeNode.kt @@ -1,5 +1,14 @@ package app.model.bst.node +/** + * Represents a node in an AVL Tree. + * + * @param E the type of element stored in the node + * @see BinTreeNode + */ interface AVLTreeNode> : BinTreeNode> { + /** + * The height of the node, which is the length of the longest path from the node to a leaf node. + */ var height: Int -} +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/bst/node/BSNode.kt b/app/src/main/kotlin/app/model/bst/node/BSNode.kt index 5c8839d..69c2047 100644 --- a/app/src/main/kotlin/app/model/bst/node/BSNode.kt +++ b/app/src/main/kotlin/app/model/bst/node/BSNode.kt @@ -1,7 +1,16 @@ package app.model.bst.node +/** + * Represents a node in a Binary Search Tree. + * + * @param E the type of element stored in the node + * @property value the value stored in the node. + * @property left the left child node of this node, or null if this node has no left child. + * @property right the right child node of this node, or null if this node has no right child. + * @see BinSearchTreeNode + */ internal class BSNode>( override var value: E, override var left: BinSearchTreeNode? = null, override var right: BinSearchTreeNode? = null, -) : BinSearchTreeNode +) : BinSearchTreeNode \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/bst/node/BinSearchTreeNode.kt b/app/src/main/kotlin/app/model/bst/node/BinSearchTreeNode.kt index cd2d66a..74a0d29 100644 --- a/app/src/main/kotlin/app/model/bst/node/BinSearchTreeNode.kt +++ b/app/src/main/kotlin/app/model/bst/node/BinSearchTreeNode.kt @@ -1,3 +1,10 @@ package app.model.bst.node -interface BinSearchTreeNode> : BinTreeNode> +/** + * Represents a node in a Binary Search Tree. + * + * @param E the type of element stored in the node + * @see BinTreeNode + */ +interface BinSearchTreeNode> : BinTreeNode> { +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/bst/node/BinTreeNode.kt b/app/src/main/kotlin/app/model/bst/node/BinTreeNode.kt index 2d9dd3d..26a85ed 100644 --- a/app/src/main/kotlin/app/model/bst/node/BinTreeNode.kt +++ b/app/src/main/kotlin/app/model/bst/node/BinTreeNode.kt @@ -1,7 +1,16 @@ package app.model.bst.node +/** + * Represents a node in any Binary Tree. + * + * @param E the type of element stored in the node + * @param Subtype the subtype of the node + * @property value the value stored in the node. + * @property left the left child node of this node, or null if this node has no left child. + * @property right the right child node of this node, or null if this node has no right child. + */ interface BinTreeNode, Subtype : BinTreeNode> { var value: E var left: Subtype? var right: Subtype? -} +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/bst/node/RBNode.kt b/app/src/main/kotlin/app/model/bst/node/RBNode.kt index 31df9bd..62f5145 100644 --- a/app/src/main/kotlin/app/model/bst/node/RBNode.kt +++ b/app/src/main/kotlin/app/model/bst/node/RBNode.kt @@ -1,5 +1,16 @@ package app.model.bst.node +/** + * Represents a node in a Red-Black Tree. + * + * @param E the type of element stored in the node + * @property value the value stored in the node. + * @property parent the parent node of this node, or null if this node is the root of the tree. + * @property color the color of the node, which can be either RED or BLACK. + * @property left the left child node of this node, or null if this node has no left child. + * @property right the right child node of this node, or null if this node has no right child. + * @see RedBlackTreeNode + */ internal class RBNode>( override var value: E, override var parent: RedBlackTreeNode? = null, diff --git a/app/src/main/kotlin/app/model/bst/node/RedBlackTreeNode.kt b/app/src/main/kotlin/app/model/bst/node/RedBlackTreeNode.kt index f804911..8feb05e 100644 --- a/app/src/main/kotlin/app/model/bst/node/RedBlackTreeNode.kt +++ b/app/src/main/kotlin/app/model/bst/node/RedBlackTreeNode.kt @@ -1,9 +1,26 @@ package app.model.bst.node +/** + * Represents a node in a Red-Black Tree. + * + * @param E the type of element stored in the node + * @see BinTreeNode + */ interface RedBlackTreeNode> : BinTreeNode> { + /** + * The color of the node, which can be either RED or BLACK. + */ var color: Color + + /** + * The parent node of this node, or null if this node is the root of the tree. + */ var parent: RedBlackTreeNode? + + /** + * An enum representing the possible colors of a Red-Black Tree node. + */ enum class Color { RED, BLACK } -} +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt b/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt index 4000eb9..7624868 100644 --- a/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt +++ b/app/src/main/kotlin/app/model/repo/Neo4jRepo.kt @@ -48,15 +48,31 @@ class SerializableTreeEntity( } +/** + * A Neo4j repository for serializable tree data structures. + * + * @param the type of elements stored in the tree + * @param the type of nodes in the tree + * @param the type of binary search tree being serialized or deserialized + * @property strategy the serialization strategy used by the repository + * @property configuration the Neo4j configuration used by the repository + */ class Neo4jRepo, Node : BinTreeNode, BST : BinarySearchTree>( strategy: SerializationStrategy, configuration: Configuration ) : Repository(strategy) { + private val sessionFactory = SessionFactory(configuration, "app.model.repo") private val session = sessionFactory.openSession() + /** + * Converts a serializable node entity to a serializable node. + * + * @receiver the serializable node entity to convert + * @return the serializable node that was converted from the Neo4j ogm entity + */ private fun SerializableNodeEntity.toNode(): SerializableNode { return SerializableNode( value, @@ -66,6 +82,12 @@ class Neo4jRepo, ) } + /** + * Converts a serializable tree entity to a serializable tree. + * + * @receiver the serializable tree entity to convert + * @return the serializable tree that was converted from the Neo4j ogm entity + */ private fun SerializableTreeEntity.toTree(): SerializableTree { return SerializableTree( verboseName, @@ -74,7 +96,12 @@ class Neo4jRepo, ) } - + /** + * Converts a serializable node to a serializable node entity. + * + * @receiver the serializable node to convert + * @return the serializable node entity that was converted from the node + */ private fun SerializableNode.toEntity(): SerializableNodeEntity { return SerializableNodeEntity( value, @@ -84,6 +111,12 @@ class Neo4jRepo, ) } + /** + * Converts a serializable tree to a serializable tree entity. + * + * @receiver the serializable tree to convert + * @return the serializable tree entity that was converted from the tree + */ private fun SerializableTree.toEntity(): SerializableTreeEntity { return SerializableTreeEntity( verboseName, @@ -92,12 +125,24 @@ class Neo4jRepo, ) } + /** + * Saves a binary search tree to the Neo4j database. + * + * @param verboseName the name of the tree being saved + * @param tree the binary search tree to save + */ override fun save(verboseName: String, tree: BST) { deleteByVerboseName(verboseName) val entityTree = tree.toSerializableTree(verboseName).toEntity() session.save(entityTree) } + /** + * Finds a serializable tree entity by its verbose name. + * + * @param verboseName the verbose name of the tree entity to find + * @return a list of serializable tree entities matching the verbose name and type of tree + */ private fun findByVerboseName(verboseName: String) = session.loadAll( SerializableTreeEntity::class.java, Filters().and( @@ -108,6 +153,13 @@ class Neo4jRepo, -1 ) + /** + * Loads a binary search tree from the Neo4j database by its verbose name. + * + * @param verboseName the verbose name of the tree to load + * @param factory a function that creates a new instance of the binary search tree being loaded + * @return the binary search tree loaded from the database + */ override fun loadByVerboseName(verboseName: String, factory: () -> BST): BST { val treeEntity = findByVerboseName(verboseName).singleOrNull() @@ -116,6 +168,11 @@ class Neo4jRepo, } } + /** + * Deletes a serializable tree entity and all of its related nodes and relationships from the Neo4j database. + * + * @param verboseName the verbose name of the tree entity to delete + */ override fun deleteByVerboseName(verboseName: String) { session.query( "MATCH toDelete=(t:SerializableTreeEntity {typeOfTree: \$typeOfTree, verboseName : \$verboseName})-[*0..]->() DETACH DELETE toDelete", diff --git a/app/src/main/kotlin/app/model/repo/Repository.kt b/app/src/main/kotlin/app/model/repo/Repository.kt index bf9f321..5fa24f7 100644 --- a/app/src/main/kotlin/app/model/repo/Repository.kt +++ b/app/src/main/kotlin/app/model/repo/Repository.kt @@ -6,11 +6,24 @@ import app.model.repo.serialization.SerializableNode import app.model.repo.serialization.SerializableTree import app.model.repo.serialization.strategy.SerializationStrategy +/** + * An abstract class representing a repository for binary search trees. + * @param E the type of element stored in the tree + * @param Node the type of node used in the tree + * @param BST the type of binary search tree stored in the repository + * @property strategy the serialization strategy used to serialize and deserialize the tree. + * @constructor creates a new Repository with the given serialization strategy. + */ abstract class Repository, Node : BinTreeNode, BST : BinarySearchTree>( protected val strategy: SerializationStrategy ) { + /** + * Converts a node to a serializable node using the serialization strategy. + * @param Node the node to convert. + * @return the serializable node. + */ protected fun Node.toSerializableNode(): SerializableNode { return SerializableNode( strategy.serializeValue(this.value), @@ -20,7 +33,11 @@ abstract class Repository, ) } - + /** + * Converts a binary search tree to a serializable tree using the serialization strategy. + * @param verboseName the verbose name of the tree. + * @return the serializable tree. + */ protected fun BST.toSerializableTree(verboseName: String): SerializableTree { return SerializableTree( verboseName = verboseName, @@ -29,7 +46,24 @@ abstract class Repository, ) } + /** + * Saves a binary search tree to the repository. + * @param verboseName the verbose name of the tree. + * @param tree the tree to save. + */ abstract fun save(verboseName: String, tree: BST) + + /** + * Loads a binary search tree from the repository by its verbose name. + * @param verboseName the verbose name of the tree. + * @param factory a factory function to create a new instance of the tree. + * @return the loaded tree. + */ abstract fun loadByVerboseName(verboseName: String, factory: () -> BST): BST + + /** + * Deletes a binary search tree from the repository by its verbose name. + * @param verboseName the verbose name of the tree to delete. + */ abstract fun deleteByVerboseName(verboseName: String) } \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/serialization/Serializable.kt b/app/src/main/kotlin/app/model/repo/serialization/Serializable.kt index 69a83c8..902d026 100644 --- a/app/src/main/kotlin/app/model/repo/serialization/Serializable.kt +++ b/app/src/main/kotlin/app/model/repo/serialization/Serializable.kt @@ -2,6 +2,11 @@ package app.model.repo.serialization import kotlinx.serialization.Serializable +/** + * An enum representing the type of tree being serialized or deserialized. + * + * @property savingName the name of the tree type used for serialization + */ @Serializable enum class TypeOfTree(val savingName: String) { BINARY_SEARCH_TREE("BINARY_SEARCH_TREE"), @@ -9,6 +14,14 @@ enum class TypeOfTree(val savingName: String) { AVL_TREE("AVL_TREE") } +/** + * A serializable node in a tree data structure. + * + * @property value the value stored in the node + * @property metadata the metadata associated with the node + * @property left the left child of the node + * @property right the right child of the node + */ @Serializable class SerializableNode( val value: SerializableValue, @@ -17,6 +30,13 @@ class SerializableNode( val right: SerializableNode? = null, ) +/** + * A serializable tree data structure. + * + * @property verboseName the verbose name of the tree + * @property typeOfTree the type of tree being serialized or deserialized + * @property root the root node of the tree + */ @Serializable class SerializableTree( val verboseName: String, @@ -24,10 +44,20 @@ class SerializableTree( val root: SerializableNode? ) +/** + * A metadata value (actually a string) for a serializable node. + * + * @property value the value of the metadata + */ @Serializable @JvmInline value class Metadata(val value: String) +/** + * A serializable value (actually a string) stored in a tree node. + * + * @property value the value of the serializable value + */ @Serializable @JvmInline value class SerializableValue(val value: String) \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/serialization/strategy/AVLTreeStrategy.kt b/app/src/main/kotlin/app/model/repo/serialization/strategy/AVLTreeStrategy.kt index c728ada..11277c5 100644 --- a/app/src/main/kotlin/app/model/repo/serialization/strategy/AVLTreeStrategy.kt +++ b/app/src/main/kotlin/app/model/repo/serialization/strategy/AVLTreeStrategy.kt @@ -7,12 +7,29 @@ import app.model.repo.serialization.SerializableNode import app.model.repo.serialization.SerializableValue import app.model.repo.serialization.TypeOfTree +/** + * A serialization strategy for AVL tree data structures. + * + * @param the type of elements stored in the AVL tree + * @param serializeValue a function that serializes an element of type E to a SerializableValue + * @param deserializeValue a function that deserializes a SerializableValue to an element of type E + */ class AVLTreeStrategy>( serializeValue: (E) -> SerializableValue, deserializeValue: (SerializableValue) -> E ) : SerializationStrategy, Int>(serializeValue, deserializeValue) { + + /** + * The type of tree that this strategy serializes and deserializes. + */ override val typeOfTree: TypeOfTree = TypeOfTree.AVL_TREE + /** + * Builds an AVL tree node from a serializable node. + * + * @param node the serializable node to build from + * @return the AVL tree node that was built + */ override fun buildNode(node: SerializableNode?): AVLTreeNode? = node?.let { AVLNode( value = deserializeValue(node.value), @@ -22,7 +39,19 @@ class AVLTreeStrategy>( ) } + /** + * Deserializes the metadata for an AVL tree node. + * + * @param metadata the metadata to deserialize + * @return the height of the AVL tree node + */ override fun deserializeMetadata(metadata: Metadata) = metadata.value.toInt() + /** + * Serializes the metadata for an AVL tree node. + * + * @param node the AVL tree node to serialize metadata for + * @return a metadata object containing the height of the AVL tree node + */ override fun serializeMetadata(node: AVLTreeNode) = Metadata(node.height.toString()) } \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/serialization/strategy/BSTreeStrategy.kt b/app/src/main/kotlin/app/model/repo/serialization/strategy/BSTreeStrategy.kt index 5b48920..af928e4 100644 --- a/app/src/main/kotlin/app/model/repo/serialization/strategy/BSTreeStrategy.kt +++ b/app/src/main/kotlin/app/model/repo/serialization/strategy/BSTreeStrategy.kt @@ -7,11 +7,29 @@ import app.model.repo.serialization.SerializableNode import app.model.repo.serialization.SerializableValue import app.model.repo.serialization.TypeOfTree +/** + * A serialization strategy for binary search tree data structures. + * + * @param the type of elements stored in the binary search tree + * @param serializeValue a function that serializes an element of type E to a SerializableValue + * @param deserializeValue a function that deserializes a SerializableValue to an element of type E + */ class BSTreeStrategy>( serializeValue: (E) -> SerializableValue, deserializeValue: (SerializableValue) -> E ) : SerializationStrategy, String>(serializeValue, deserializeValue) { + + /** + * The type of tree that this strategy serializes and deserializes. + */ override val typeOfTree: TypeOfTree = TypeOfTree.BINARY_SEARCH_TREE + + /** + * Builds a binary search tree node from a serializable node. + * + * @param node the serializable node to build from + * @return the binary search tree node that was built + */ override fun buildNode(node: SerializableNode?): BinSearchTreeNode? = node?.let { BSNode( value = deserializeValue(node.value), @@ -20,7 +38,19 @@ class BSTreeStrategy>( ) } + /** + * Deserializes the metadata for a binary search tree node. + * + * @param metadata the metadata to deserialize + * @return an empty string, since binary search tree nodes do not have metadata + */ override fun deserializeMetadata(metadata: Metadata) = "" + /** + * Serializes the metadata for a binary search tree node. + * + * @param node the binary search tree node to serialize metadata for + * @return an empty metadata object, since binary search tree nodes do not have metadata + */ override fun serializeMetadata(node: BinSearchTreeNode) = Metadata("") } \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt b/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt index f1cc200..90cbd0e 100644 --- a/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt +++ b/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt @@ -7,11 +7,30 @@ import app.model.repo.serialization.SerializableNode import app.model.repo.serialization.SerializableValue import app.model.repo.serialization.TypeOfTree +/** + * A class representing a strategy for serializing and deserializing red-black tree data structures. + * + * @param E the type of element stored in the red-black tree + * @property serializeValue a function that serializes an element of type E into a [SerializableValue] + * @property deserializeValue a function that deserializes a [SerializableValue] into an element of type E + * @constructor creates a new [RBTreeStrategy] with the given serialization and deserialization functions + */ class RBTreeStrategy>( serializeValue: (E) -> SerializableValue, deserializeValue: (SerializableValue) -> E ) : SerializationStrategy, RedBlackTreeNode.Color>(serializeValue, deserializeValue) { + + /** + * The type of tree being serialized or deserialized. + */ override val typeOfTree: TypeOfTree = TypeOfTree.RED_BLACK_TREE + + /** + * Builds a [RedBlackTreeNode] from a [SerializableNode]. + * + * @param node the [SerializableNode] to build the [RedBlackTreeNode] from + * @return the [RedBlackTreeNode] built from the [SerializableNode], or null if the [SerializableNode] is null + */ override fun buildNode(node: SerializableNode?): RedBlackTreeNode? { fun buildNodeWithParent(node: SerializableNode?, parent: RedBlackTreeNode?): RedBlackTreeNode? { node ?: return null @@ -28,6 +47,13 @@ class RBTreeStrategy>( return buildNodeWithParent(node, null) } + /** + * Deserializes metadata of type [RedBlackTreeNode.Color] from a [Metadata] object. + * + * @param metadata the [Metadata] object to deserialize the metadata from + * @return the deserialized metadata of type [RedBlackTreeNode.Color] + * @throws IllegalArgumentException if the metadata value is not "RED" or "BLACK" + */ override fun deserializeMetadata(metadata: Metadata): RedBlackTreeNode.Color { return when (metadata.value) { "RED" -> RedBlackTreeNode.Color.RED @@ -36,6 +62,12 @@ class RBTreeStrategy>( } } + /** + * Serializes metadata of type [RedBlackTreeNode.Color] into a [Metadata] object. + * + * @param node the node to serialize the metadata from + * @return the serialized metadata as a [Metadata] object + */ override fun serializeMetadata(node: RedBlackTreeNode): Metadata { return Metadata( when (node.value) { diff --git a/app/src/main/kotlin/app/model/repo/serialization/strategy/SerializationStrategy.kt b/app/src/main/kotlin/app/model/repo/serialization/strategy/SerializationStrategy.kt index 3477e08..7a57c66 100644 --- a/app/src/main/kotlin/app/model/repo/serialization/strategy/SerializationStrategy.kt +++ b/app/src/main/kotlin/app/model/repo/serialization/strategy/SerializationStrategy.kt @@ -6,14 +6,43 @@ import app.model.repo.serialization.SerializableNode import app.model.repo.serialization.SerializableValue import app.model.repo.serialization.TypeOfTree - -abstract class SerializationStrategy, - Node : BinTreeNode, M>( +/** + * An abstract class representing a strategy for serializing and deserializing binary tree data structures. + * + * @param E the type of element stored in the binary tree + * @param Node the type of node used in the binary tree + * @param M the type of metadata associated with each node in the binary tree + * @property serializeValue a function that serializes an element of type E into a [SerializableValue] + * @property deserializeValue a function that deserializes a [SerializableValue] into an element of type E + * @property typeOfTree an abstract property representing the type of binary tree being serialized or deserialized + */ +abstract class SerializationStrategy, Node : BinTreeNode, M>( val serializeValue: (E) -> SerializableValue, val deserializeValue: (SerializableValue) -> E ) { abstract val typeOfTree: TypeOfTree + + /** + * Builds a node of type [Node] from a [SerializableNode]. + * + * @param node the [SerializableNode] to build the [Node] from + * @return the [Node] built from the [SerializableNode], or null if the [SerializableNode] is null + */ abstract fun buildNode(node: SerializableNode?): Node? + + /** + * Deserializes metadata of type [M] from a [Metadata] object. + * + * @param metadata the [Metadata] object to deserialize the metadata from + * @return the deserialized metadata of type [M] + */ abstract fun deserializeMetadata(metadata: Metadata): M + + /** + * Serializes metadata of type [M] into a [Metadata] object. + * + * @param node the node to serialize the metadata from + * @return the serialized metadata as a [Metadata] object + */ abstract fun serializeMetadata(node: Node): Metadata } \ No newline at end of file From 7d42ff1279e8bc4b756a22772b0197d2dd029572 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Wed, 19 Apr 2023 01:22:04 +0300 Subject: [PATCH 075/125] refactor: Reformat all code with default idea formatter --- .github/workflows/ci.yml | 2 +- .../app/model/bst/balancer/AVLBalancer.kt | 5 ++++- .../app/model/bst/balancer/BSBalancer.kt | 5 ++++- .../app/model/bst/balancer/RBBalancer.kt | 5 ++++- .../app/model/bst/balancer/AVLBalancerTest.kt | 1 + .../app/model/bst/balancer/BSTBalancerTest.kt | 19 ++++++++++--------- .../app/model/bst/balancer/RBBalancerTest.kt | 10 +++++----- 7 files changed, 29 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 346531a..ed3fee6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: env: report_path: app/build/coverage/test/jacocoTestReport.csv run: | - awk -F"," '{ instructions += $4 + $5; covered += $5; branches += $6 + $7; branches_covered +=$7 } END { print "Instructions covered:", covered"/"instructions, "--", 100*covered/instructions"%"; print "Branches covered:", branches_covered"/"branches, "--", 100*branches_covered/branches"%" }' $report_path + awk -F"," '{ instructions += $4 + $5; covered += $5; branches += $6 + $7; branches_covered +=$7 } END { print "Instructions covered:", covered"/"instructions, "--", 100*covered/instructions"%"; print "Branches covered:", branches_covered"/"branches, "--", 100*branches_covered/branches"%" }' $report_path - name: Create fat .jar file on main if: ${{ github.ref == 'refs/heads/main' }} diff --git a/app/src/main/kotlin/app/model/bst/balancer/AVLBalancer.kt b/app/src/main/kotlin/app/model/bst/balancer/AVLBalancer.kt index 10a9731..05b4464 100644 --- a/app/src/main/kotlin/app/model/bst/balancer/AVLBalancer.kt +++ b/app/src/main/kotlin/app/model/bst/balancer/AVLBalancer.kt @@ -107,7 +107,10 @@ internal class AVLBalancer> : BinTreeBalancer> : BinTreeBalancer> : BinTreeBalancer() + @Test fun `test method 'add' in avl tree balancer`() { var root = balancer.add(null, 2, true) diff --git a/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt index a566fde..a42e0fd 100644 --- a/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt +++ b/app/src/test/kotlin/app/model/bst/balancer/BSTBalancerTest.kt @@ -6,15 +6,16 @@ import kotlin.test.assertEquals class BSTBalancerTest { private val balancer = BSBalancer() + @Test fun `test method 'add' in bs balancer`() { var root = balancer.add(null, 5, true) root = balancer.add(root, 1, true) - root = balancer.add(root , 7, true) - root = balancer.add(root,4, true ) - root = balancer.add(root , 6, true) - root = balancer.add(root,3, true ) + root = balancer.add(root, 7, true) + root = balancer.add(root, 4, true) + root = balancer.add(root, 6, true) + root = balancer.add(root, 3, true) /* constructed tree: @@ -40,10 +41,10 @@ class BSTBalancerTest { var root: BinSearchTreeNode? = balancer.add(null, 5, true) root = balancer.add(root, 1, true) - root = balancer.add(root , 7, true) - root = balancer.add(root,4, true ) - root = balancer.add(root , 6, true) - root = balancer.add(root,3, true ) + root = balancer.add(root, 7, true) + root = balancer.add(root, 4, true) + root = balancer.add(root, 6, true) + root = balancer.add(root, 3, true) /* @@ -57,7 +58,7 @@ class BSTBalancerTest { 3 */ - root = balancer.remove(root,5) + root = balancer.remove(root, 5) /* constructed tree: diff --git a/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt index bb79897..a8c6737 100644 --- a/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt +++ b/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt @@ -12,8 +12,8 @@ class RBBalancerTest { var root = balancer.add(null, 1, true) root = balancer.add(root, 2, true) - root = balancer.add(root , 3, true) - root = balancer.add(root,4, true ) + root = balancer.add(root, 3, true) + root = balancer.add(root, 4, true) /* @@ -42,8 +42,8 @@ class RBBalancerTest { var root: RedBlackTreeNode? = balancer.add(null, 1, true) root = balancer.add(root, 2, true) - root = balancer.add(root , 3, true) - root = balancer.add(root,4, true ) + root = balancer.add(root, 3, true) + root = balancer.add(root, 4, true) /* constructed tree: 2(BLACK) @@ -54,7 +54,7 @@ class RBBalancerTest { */ - root = balancer.remove(root,2) + root = balancer.remove(root, 2) /* From d86d9a5cc134d132f1ed7ba55c4bc1299c1926d9 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Wed, 19 Apr 2023 01:37:34 +0300 Subject: [PATCH 076/125] ci: Fix awk string --- .github/workflows/ci.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed3fee6..2be5881 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: [ macos-latest, ubuntu-latest, windows-latest ] + steps: - name: Checkout project sources uses: actions/checkout@v3 @@ -16,9 +21,7 @@ jobs: - name: Print coverage report env: report_path: app/build/coverage/test/jacocoTestReport.csv - run: | - awk -F"," '{ instructions += $4 + $5; covered += $5; branches += $6 + $7; branches_covered +=$7 } END { print "Instructions covered:", covered"/"instructions, "--", 100*covered/instructions"%"; print "Branches covered:", branches_covered"/"branches, "--", 100*branches_covered/branches"%" }' $report_path - + run: awk -F"," '{ instructions += $4 + $5; covered += $5; branches += $6 + $7; branches_covered +=$7 } END { print "Instructions covered:", covered"/"instructions, "--", 100*covered/instructions"%"; print "Branches covered:", branches_covered"/"branches, "--", 100*branches_covered/branches"%" }' $report_path - name: Create fat .jar file on main if: ${{ github.ref == 'refs/heads/main' }} run: ./gradlew app:buildFatJar From 32b5697771968f7832e8b1515bdb580a4312111f Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Wed, 19 Apr 2023 08:10:52 +0300 Subject: [PATCH 077/125] ci: Remove buggy awk script --- .github/workflows/ci.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2be5881..b2d5ee6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,10 +18,6 @@ jobs: - name: Run build with Gradle Wrapper run: ./gradlew build - - name: Print coverage report - env: - report_path: app/build/coverage/test/jacocoTestReport.csv - run: awk -F"," '{ instructions += $4 + $5; covered += $5; branches += $6 + $7; branches_covered +=$7 } END { print "Instructions covered:", covered"/"instructions, "--", 100*covered/instructions"%"; print "Branches covered:", branches_covered"/"branches, "--", 100*branches_covered/branches"%" }' $report_path - name: Create fat .jar file on main if: ${{ github.ref == 'refs/heads/main' }} run: ./gradlew app:buildFatJar From d241f949dc78f85d0b2d68dcbba8419def115ad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Wed, 19 Apr 2023 09:17:18 +0300 Subject: [PATCH 078/125] feat: Add information about saving to the README --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index fbe63d3..2a600c2 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,36 @@ class RBTree> : Все наследники `BinarySearchTree` автоматически умеют выполнять поиск, вставку, удаление значений из дерева, а так же интерироваться по нему различными способами — выполнять inorder, preorder, levelorder обходы +### Сохранение + +Каждое из трёх доступных деревьев можно сохранить одним из следующих способов на выбор: + + - PostgreSQL + - neo4j + +Пример: +```Kotlin +val repo = Neo4jRepo( + st, Configuration.Builder() + .uri("bolt://localhost") + .credentials("neo4j", "password") + .build() +) + +val randomizer = Random(42) + +for (i in 0..100) { + val tree = AVLTree() + (0..10).forEach { tree.add(randomizer.nextInt(10000)) } + repo.save("avl-$i", tree) +} +``` + +Поднять docker можно следующим способом: + +``` +docker compose -f "dev-docker-compose.yml" up +``` ## Внесение изменений Внимательно прочитайте раздел [CONTRIBUTING](./CONTRIBUTING.md). From cb12f73bebe1fb0996a29cdac85586756e8a0490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Wed, 19 Apr 2023 09:28:21 +0300 Subject: [PATCH 079/125] feat: Change example --- README.md | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 2a600c2..898bf2a 100644 --- a/README.md +++ b/README.md @@ -26,24 +26,31 @@ class RBTree> : Каждое из трёх доступных деревьев можно сохранить одним из следующих способов на выбор: - PostgreSQL - - neo4j + - Neo4j -Пример: +Пример Neo4j: ```Kotlin +val st = AVLTreeStrategy({ SerializableValue(it.toString()) }, { it.value.toInt() }) val repo = Neo4jRepo( st, Configuration.Builder() .uri("bolt://localhost") .credentials("neo4j", "password") .build() ) +``` -val randomizer = Random(42) +Пример PostgreSQL: +```Kotlin +val db = Database.connect( + "jdbc:postgresql://localhost:5432/", driver = "org.postgresql.Driver", + user = "postgres", password = "password" +) -for (i in 0..100) { - val tree = AVLTree() - (0..10).forEach { tree.add(randomizer.nextInt(10000)) } - repo.save("avl-$i", tree) -} +val avlRepo = PostgresRepo( + AVLTreeStrategy({ SerializableValue(it.toString()) }, + { it.value.toInt() }), + db +) ``` Поднять docker можно следующим способом: From 21caccbd382b5ead7a54aa7cd72e061017d6b27e Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Wed, 19 Apr 2023 09:22:22 +0300 Subject: [PATCH 080/125] feat: Add postgresql saver --- app/build.gradle.kts | 4 + .../kotlin/app/model/repo/PostgresRepo.kt | 116 ++++++++++++++++-- 2 files changed, 113 insertions(+), 7 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2d36e37..903c152 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -30,7 +30,11 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter") implementation("org.neo4j:neo4j-ogm-core:4.0.5") runtimeOnly("org.neo4j:neo4j-ogm-bolt-driver:4.0.5") + implementation("org.postgresql:postgresql:42.5.4") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") + implementation("org.jetbrains.exposed", "exposed-core", "0.40.1") + implementation("org.jetbrains.exposed", "exposed-dao", "0.40.1") + implementation("org.jetbrains.exposed", "exposed-jdbc", "0.40.1") } diff --git a/app/src/main/kotlin/app/model/repo/PostgresRepo.kt b/app/src/main/kotlin/app/model/repo/PostgresRepo.kt index 6ad0b6b..a9bd29e 100644 --- a/app/src/main/kotlin/app/model/repo/PostgresRepo.kt +++ b/app/src/main/kotlin/app/model/repo/PostgresRepo.kt @@ -2,23 +2,125 @@ package app.model.repo import app.model.bst.BinarySearchTree import app.model.bst.node.BinTreeNode +import app.model.repo.serialization.Metadata +import app.model.repo.serialization.SerializableNode +import app.model.repo.serialization.SerializableTree +import app.model.repo.serialization.SerializableValue import app.model.repo.serialization.strategy.SerializationStrategy +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.Database +import org.jetbrains.exposed.sql.ReferenceOption +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 + +private object NodesTable : IntIdTable("nodes") { + val value = text("data") + val metadata = text("metadata") + val left = reference("left_id", NodesTable).nullable() + val right = reference("right_id", NodesTable).nullable() + val tree = reference("tree_id", TreesTable, onDelete = ReferenceOption.CASCADE) +} + +private object TreesTable : IntIdTable("trees") { + val verboseName = text("name") + val typeOfTree = text("type") + val root = reference("root_node_id", NodesTable).nullable() + + init { + uniqueIndex(verboseName, typeOfTree) + } +} + +class DatabaseNodeEntity(id: EntityID) : IntEntity(id) { + companion object : IntEntityClass(NodesTable) + + var value by NodesTable.value + var metadata by NodesTable.metadata + var left by DatabaseNodeEntity optionalReferencedOn NodesTable.left + var right by DatabaseNodeEntity optionalReferencedOn NodesTable.right + var tree by DatabaseTreeEntity referencedOn NodesTable.tree +} + +class DatabaseTreeEntity(id: EntityID) : IntEntity(id) { + companion object : IntEntityClass(TreesTable) + + var verboseName by TreesTable.verboseName + var typeOfTree by TreesTable.typeOfTree + var root by DatabaseNodeEntity optionalReferencedOn TreesTable.root +} + class PostgresRepo, Node : BinTreeNode, BST : BinarySearchTree>( - strategy: SerializationStrategy + strategy: SerializationStrategy, + private val db: Database ) : Repository(strategy) { - override fun save(verboseName: String, tree: BST) { - TODO("Not yet implemented") + init { + transaction(db) { + SchemaUtils.create(TreesTable) + SchemaUtils.create(NodesTable) + } + } + + private fun SerializableNode.toEntity(tree: DatabaseTreeEntity): DatabaseNodeEntity { + return DatabaseNodeEntity.new { + this@new.value = this@toEntity.value.value + this@new.metadata = this@toEntity.metadata.value + this@new.left = this@toEntity.left?.toEntity(tree) + this@new.right = this@toEntity.right?.toEntity(tree) + this@new.tree = tree + } + } + + private fun SerializableTree.toEntity(): DatabaseTreeEntity { + return DatabaseTreeEntity.new { + this@new.verboseName = this@toEntity.verboseName + this@new.typeOfTree = strategy.typeOfTree.toString() + }.also { it.root = root?.toEntity(it) } + } + + private fun DatabaseTreeEntity.toTree(): SerializableTree { + return SerializableTree( + verboseName = verboseName, + typeOfTree = strategy.typeOfTree, + root = root?.toNode(), + ) } - override fun loadByVerboseName(verboseName: String, factory: () -> BST): BST { - TODO("Not yet implemented") + private fun DatabaseNodeEntity.toNode(): SerializableNode { + return SerializableNode( + SerializableValue(value), + Metadata(metadata), + left?.toNode(), + right?.toNode() + ) } - override fun deleteByVerboseName(verboseName: String) { - TODO("Not yet implemented") + + override fun save(verboseName: String, tree: BST): Unit = transaction(db) { + deleteByVerboseName(verboseName) + tree.toSerializableTree(verboseName).toEntity() } + + override fun loadByVerboseName(verboseName: String, factory: () -> BST): BST = + transaction(db) { + val entity = DatabaseTreeEntity.find( + TreesTable.typeOfTree eq strategy.typeOfTree.toString() and (TreesTable.verboseName eq verboseName) + ).firstOrNull() + + factory().apply { root = strategy.buildNode(entity?.root?.toNode()) } + } + + override fun deleteByVerboseName(verboseName: String): Unit = transaction(db) { + DatabaseTreeEntity.find( + TreesTable.typeOfTree eq strategy.typeOfTree.toString() and (TreesTable.verboseName eq verboseName) + ).firstOrNull()?.delete() + } } \ No newline at end of file From 59f5e5ced16729d0ed8ae5227a4e1403f8f83de7 Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Sun, 23 Apr 2023 20:15:27 +0300 Subject: [PATCH 081/125] test: Add a check for left and right turns with the 'add' method --- .../app/model/bst/balancer/AVLBalancerTest.kt | 158 +++++++++++++++++- 1 file changed, 153 insertions(+), 5 deletions(-) diff --git a/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt index 74cfb43..f3bf4f3 100644 --- a/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt +++ b/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt @@ -9,28 +9,176 @@ class AVLBalancerTest { private val balancer = AVLBalancer() @Test - fun `test method 'add' in avl tree balancer`() { + fun `test left turn when 'add'`() { + var root = balancer.add(null, 8, true) + root = balancer.add(root, 7, true) + + /* + constructed tree: + 8 + / + 7 + */ + + assertEquals(8,root.value) + assertEquals(7,root.left?.value) + + root = balancer.add(root, 6, true) + + /* + constructed tree: + 7 + / \ + 6 8 + */ + + assertEquals(7,root.value) + assertEquals(6,root.left?.value) + assertEquals(8,root.right?.value) + + root = balancer.add(root, 5, true) + root = balancer.add(root, 4, true) + + /* + constructed tree: + 7 + / \ + 5 8 + / \ + 4 6 + */ + + assertEquals(7,root.value) + assertEquals(5,root.left?.value) + assertEquals(8,root.right?.value) + assertEquals(4,root.left?.left?.value) + assertEquals(6,root.left?.right?.value) + + root = balancer.add(root, 3, true) + + /* + constructed tree: + 5 + / \ + 4 7 + / / \ + 3 6 8 + */ + + assertEquals(5,root.value) + assertEquals(4,root.left?.value) + assertEquals(7,root.right?.value) + assertEquals(3,root.left?.left?.value) + assertEquals(6,root.right?.left?.value) + assertEquals(8,root.right?.right?.value) + + root = balancer.add(root, 2, true) + + /* + constructed tree: + 5 + / \ + 3 7 + / \ / \ + 2 4 6 8 + */ + + assertEquals(3,root.left?.value) + assertEquals(2,root.left?.left?.value) + assertEquals(4,root.left?.right?.value) + + root = balancer.add(root, 1, true) + root = balancer.add(root, 0, true) + + /* + constructed tree: + 5 + / \ + 3 7 + / \ / \ + 1 4 6 8 + / \ + 0 2 + */ + + assertEquals(1,root.left?.left?.value) + assertEquals(0,root.left?.left?.left?.value) + assertEquals(2,root.left?.left?.right?.value) + } + + @Test + fun `test right turn when 'add'`() { var root = balancer.add(null, 2, true) root = balancer.add(root, 3, true) + + /* + constructed tree: + 2 + \ + 3 + */ + + assertEquals(2,root.value) + assertEquals(3,root.right?.value) + root = balancer.add(root, 4, true) + + /* + constructed tree: + 3 + / \ + 2 4 + */ + + assertEquals(3,root.value) + assertEquals(2,root.left?.value) + assertEquals(4,root.right?.value) + root = balancer.add(root, 5, true) root = balancer.add(root, 6, true) + + /* + constructed tree: + 3 + / \ + 2 5 + / \ + 4 6 + */ + + assertEquals(5,root.right?.value) + assertEquals(4,root.right?.left?.value) + assertEquals(6,root.right?.right?.value) + root = balancer.add(root, 7, true) - root = balancer.add(root, 8, true) /* constructed tree: 5 / \ - 3 7 - / \ / \ - 2 4 6 8 + 3 6 + / \ \ + 2 4 7 */ assertEquals(5, root.value) assertEquals(3, root.left?.value) assertEquals(2, root.left?.left?.value) assertEquals(4, root.left?.right?.value) + assertEquals(6, root.right?.value) + assertEquals(7, root.right?.right?.value) + + root = balancer.add(root, 8, true) + + /* + constructed tree: + 5 + / \ + 3 7 + / \ / \ + 2 4 6 8 + */ + assertEquals(7, root.right?.value) assertEquals(8, root.right?.right?.value) assertEquals(6, root.right?.left?.value) From 531ba90dae907fb825f96795e118a97d055f7a34 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Apr 2023 16:04:43 +0000 Subject: [PATCH 082/125] build(deps): Bump org.postgresql:postgresql from 42.5.4 to 42.6.0 Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.5.4 to 42.6.0. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.5.4...REL42.6.0) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 903c152..f2129d8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -30,7 +30,7 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter") implementation("org.neo4j:neo4j-ogm-core:4.0.5") runtimeOnly("org.neo4j:neo4j-ogm-bolt-driver:4.0.5") - implementation("org.postgresql:postgresql:42.5.4") + implementation("org.postgresql:postgresql:42.6.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") implementation("org.jetbrains.exposed", "exposed-core", "0.40.1") implementation("org.jetbrains.exposed", "exposed-dao", "0.40.1") From 78f023429465561ecd0ccc3ac853284066f910c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Sat, 22 Apr 2023 02:53:55 +0300 Subject: [PATCH 083/125] fix: Change README --- README.md | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 898bf2a..f0f9109 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,18 @@ # trees +Наше приложение рисует и управляет тремя типами бинарных деревьев: красно-черное, AVL и обычное дерево поиска. +Оно позволяет добавлять и удалять элементы из деревьев, а также сохранять деревья, над которыми велась работа, что +обеспечивает сохранение данных между сеансами работы приложения. + + ## Основные фичи 1. Поддержка 3 видов (AVL, RB, BS) деревьев поиска с возможностью добавления собственных реализаций 2. (WIP) Поддержка сохранения состояния дерева и восстановаления его из Json, Postgres и Neo4j 3. (WIP) Визуализация различных деревьев поиска +# Информация про архитектуру проекта + ## Деревья поиска Чтобы создать новый вид дерева нужно сделать 3 действия. Написать балансировщик, возможно, особый тип `BinTreeNode` и @@ -19,9 +26,28 @@ class RBTree> : ``` Все наследники `BinarySearchTree` автоматически умеют выполнять поиск, вставку, удаление значений из дерева, а так же -интерироваться по нему различными способами — выполнять inorder, preorder, levelorder обходы +интерироваться по нему различными способами — выполнять inorder, preorder, levelorder обходы. + +## Использование + +Создать дерево и использовать доступные для него методы можно следующим образом: + +```kotlin +val tree = RBTree() + +tree.add(2) +tree.add(5) +tree.add(1) + +tree.remove(2) +``` + +Тип создаваемого дерева указывается одним из следующих способов: RBTree<Тип>(), AVLTree<>(), BSTree<>(). + +Для RB, AVl, или BS дерева соответственно. + -### Сохранение +## Сохранение Каждое из трёх доступных деревьев можно сохранить одним из следующих способов на выбор: @@ -53,7 +79,10 @@ val avlRepo = PostgresRepo( ) ``` -Поднять docker можно следующим способом: +Для корректной работы базы данных приложения, а также правильного отображения деревьев необходимо поднять docker +compose. + +Сделать это можно следующим способом: ``` docker compose -f "dev-docker-compose.yml" up From 801a1f8cdec1d1c7e8dc790dd7bc4b74d14c4b90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Sat, 22 Apr 2023 02:58:01 +0300 Subject: [PATCH 084/125] fix: Add html report in jacoco --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f2129d8..a1156b3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -16,7 +16,7 @@ tasks.withType { reports { xml.required.set(true) csv.required.set(true) - html.required.set(false) + html.required.set(true) } } From c92ff0a41f4682a2643faa1e6ce302b118855aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Sat, 22 Apr 2023 03:12:05 +0300 Subject: [PATCH 085/125] fix: Add a description to the isParentLinkedRight(), change the minValueNode --- app/src/main/kotlin/app/model/bst/balancer/RBBalancer.kt | 4 ++-- .../test/kotlin/app/model/bst/utils/InvariantChecker.kt | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/app/model/bst/balancer/RBBalancer.kt b/app/src/main/kotlin/app/model/bst/balancer/RBBalancer.kt index 4b19057..8ca3041 100644 --- a/app/src/main/kotlin/app/model/bst/balancer/RBBalancer.kt +++ b/app/src/main/kotlin/app/model/bst/balancer/RBBalancer.kt @@ -126,7 +126,7 @@ internal class RBBalancer> : BinTreeBalancer> : BinTreeBalancer): RedBlackTreeNode { var current = node while (true) { - current = current.right ?: break + current = current.left ?: break } return current } diff --git a/app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt b/app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt index be45b89..de0876e 100644 --- a/app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt +++ b/app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt @@ -94,6 +94,14 @@ object InvariantChecker { } } + /* + This function checks that the tree elements + + point to each other correctly. For example, that + + node.left.parent is the same as node + */ + fun > isParentLinkedRight(tree: RBTree?): Boolean { fun helper(root: RedBlackTreeNode?): Boolean { root ?: return true From bfa34918a5e44a71037d96a93840d8153aaf5dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Sun, 23 Apr 2023 17:52:31 +0300 Subject: [PATCH 086/125] add: Add more granular tests for rb balancer --- .../app/model/bst/balancer/RBBalancerTest.kt | 211 ++++++++++++++++-- 1 file changed, 191 insertions(+), 20 deletions(-) diff --git a/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt index a8c6737..7fb60bb 100644 --- a/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt +++ b/app/src/test/kotlin/app/model/bst/balancer/RBBalancerTest.kt @@ -9,48 +9,69 @@ class RBBalancerTest { @Test fun `test method 'add' in rb balancer`() { - var root = balancer.add(null, 1, true) + var root: RedBlackTreeNode? = balancer.add(null, 1, true) root = balancer.add(root, 2, true) root = balancer.add(root, 3, true) root = balancer.add(root, 4, true) - + root = balancer.add(root, 5, true) + root = balancer.add(root, 6, true) + root = balancer.add(root, 7, true) + root = balancer.add(root, 8, true) + root = balancer.add(root, 9, true) /* constructed tree: - 2(BLACK) - / \ - (BLACK)1 3(BLACK) - \ - 4(RED) + 4(BLACK) + / \ + (RED)2 6(RED) + / \ / \ + (BLACK)1 3(BLACK) (BLACK)5 8(BLACK) + / \ + 7(RED) 9(RED) + */ - assertEquals(2, root.value) - assertEquals(1, root.left?.value) - assertEquals(3, root.right?.value) - assertEquals(4, root.right?.right?.value) + assertEquals(4, root.value) + assertEquals(2, root.left?.value) + assertEquals(6, root.right?.value) + assertEquals(8, root.right?.right?.value) + assertEquals(5, root.right?.left?.value) + assertEquals(1, root.left?.left?.value) + assertEquals(3, root.left?.right?.value) + assertEquals(7, root.right?.right?.left?.value) + assertEquals(9, root.right?.right?.right?.value) assertEquals(RedBlackTreeNode.Color.BLACK, root.color) - assertEquals(RedBlackTreeNode.Color.BLACK, root.left?.color) - assertEquals(RedBlackTreeNode.Color.BLACK, root.right?.color) - assertEquals(RedBlackTreeNode.Color.RED, root.right?.right?.color) + assertEquals(RedBlackTreeNode.Color.RED, root.left?.color) + assertEquals(RedBlackTreeNode.Color.RED, root.right?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root.right?.right?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root.right?.left?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root.left?.left?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root.left?.right?.color) + assertEquals(RedBlackTreeNode.Color.RED, root.right?.right?.left?.color) + assertEquals(RedBlackTreeNode.Color.RED, root.right?.right?.right?.color) + } @Test - fun `test method 'remove' in rb balancer`() { + fun `test method 'remove' in rb balancer, remove root`() { var root: RedBlackTreeNode? = balancer.add(null, 1, true) root = balancer.add(root, 2, true) root = balancer.add(root, 3, true) root = balancer.add(root, 4, true) + root = balancer.add(root, 5, true) + + /* constructed tree: - 2(BLACK) - / \ - 1(BLACK) 3(BLACK) - \ - 4(RED) + 2(BLACK) + / \ + (BLACK)1 4(BLACK) + / \ + (RED)3 5(RED) */ @@ -62,15 +83,165 @@ class RBBalancerTest { 3(BLACK) / \ 1(BLACK) 4(BLACK) + \ + 5(RED) */ assertEquals(3, root?.value) assertEquals(1, root?.left?.value) assertEquals(4, root?.right?.value) + assertEquals(5, root?.right?.right?.value) + assertEquals(RedBlackTreeNode.Color.BLACK, root?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root?.left?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root?.right?.color) + assertEquals(RedBlackTreeNode.Color.RED, root?.right?.right?.color) + } + + @Test + fun `test method 'remove' in rb balancer, remove black node near the root`() { + var root: RedBlackTreeNode? = balancer.add(null, 1, true) + + root = balancer.add(root, 2, true) + root = balancer.add(root, 3, true) + root = balancer.add(root, 4, true) + root = balancer.add(root, 5, true) + + + /* + constructed tree: + 2(BLACK) + / \ + (BLACK)1 4(BLACK) + / \ + (RED)3 5(RED) + */ + + + root = balancer.remove(root, 1) + + + /* + constructed tree: + 4(BLACK) + / \ + 2(BLACK) 5(BLACK) + \ + 3(RED) + */ + + + assertEquals(4, root?.value) + assertEquals(2, root?.left?.value) + assertEquals(5, root?.right?.value) + assertEquals(3, root?.left?.right?.value) + assertEquals(RedBlackTreeNode.Color.BLACK, root?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root?.left?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root?.right?.color) + assertEquals(RedBlackTreeNode.Color.RED, root?.left?.right?.color) + } + + @Test + fun `test method 'remove' in rb balancer, remove red node near the root`() { + var root: RedBlackTreeNode? = balancer.add(null, 1, true) + + root = balancer.add(root, 2, true) + root = balancer.add(root, 3, true) + root = balancer.add(root, 4, true) + root = balancer.add(root, 5, true) + + + /* + constructed tree: + 2(BLACK) + / \ + (BLACK)1 4(BLACK) + / \ + (RED)3 5(RED) + */ + + + root = balancer.remove(root, 5) + + + /* + constructed tree: + 2(BLACK) + / \ + (BLACK)1 4(BLACK) + / + (RED)3 + */ + + + assertEquals(2, root?.value) + assertEquals(1, root?.left?.value) + assertEquals(4, root?.right?.value) + assertEquals(3, root?.right?.left?.value) assertEquals(RedBlackTreeNode.Color.BLACK, root?.color) assertEquals(RedBlackTreeNode.Color.BLACK, root?.left?.color) assertEquals(RedBlackTreeNode.Color.BLACK, root?.right?.color) + assertEquals(RedBlackTreeNode.Color.RED, root?.right?.left?.color) + } + + @Test + fun `test method 'remove' in rb balancer, remove node, with many descendants`() { + var root: RedBlackTreeNode? = balancer.add(null, 1, true) + + root = balancer.add(root, 2, true) + root = balancer.add(root, 3, true) + root = balancer.add(root, 4, true) + root = balancer.add(root, 5, true) + root = balancer.add(root, 6, true) + root = balancer.add(root, 7, true) + root = balancer.add(root, 8, true) + root = balancer.add(root, 9, true) + + /* + constructed tree: + 4(BLACK) + / \ + (RED)2 6(RED) + / \ / \ + (BLACK)1 3(BLACK) (BLACK)5 8(BLACK) + / \ + 7(RED) 9(RED) + + */ + + + root = balancer.remove(root, 6) + + + /* + constructed tree: + 4(BLACK) + / \ + (RED)2 7(RED) + / \ / \ + (BLACK)1 3(BLACK) (BLACK)5 8(BLACK) + \ + 9(RED) + */ + + + + assertEquals(4, root?.value) + assertEquals(2, root?.left?.value) + assertEquals(7, root?.right?.value) + assertEquals(8, root?.right?.right?.value) + assertEquals(5, root?.right?.left?.value) + assertEquals(1, root?.left?.left?.value) + assertEquals(3, root?.left?.right?.value) + assertEquals(9, root?.right?.right?.right?.value) + assertEquals(RedBlackTreeNode.Color.BLACK, root?.color) + assertEquals(RedBlackTreeNode.Color.RED, root?.left?.color) + assertEquals(RedBlackTreeNode.Color.RED, root?.right?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root?.right?.right?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root?.right?.left?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root?.left?.left?.color) + assertEquals(RedBlackTreeNode.Color.BLACK, root?.left?.right?.color) + assertEquals(RedBlackTreeNode.Color.RED, root?.right?.right?.right?.color) } } \ No newline at end of file From 55e7e91823da919a59345a7fc92ed5977e031feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Sun, 23 Apr 2023 21:09:31 +0300 Subject: [PATCH 087/125] fix: Add the use of repo to the README, to clarify for docker --- README.md | 63 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index f0f9109..7fa992d 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,15 @@ обеспечивает сохранение данных между сеансами работы приложения. -## Основные фичи +### Основные фичи 1. Поддержка 3 видов (AVL, RB, BS) деревьев поиска с возможностью добавления собственных реализаций -2. (WIP) Поддержка сохранения состояния дерева и восстановаления его из Json, Postgres и Neo4j +2. (WIP) Поддержка сохранения состояния дерева и восстановления его из Json, Postgres и Neo4j 3. (WIP) Визуализация различных деревьев поиска -# Информация про архитектуру проекта +## Информация про архитектуру проекта -## Деревья поиска +### Деревья поиска Чтобы создать новый вид дерева нужно сделать 3 действия. Написать балансировщик, возможно, особый тип `BinTreeNode` и создать класс отнаследованный от `BinarySearchTree`. @@ -26,9 +26,9 @@ class RBTree> : ``` Все наследники `BinarySearchTree` автоматически умеют выполнять поиск, вставку, удаление значений из дерева, а так же -интерироваться по нему различными способами — выполнять inorder, preorder, levelorder обходы. +итерироваться по нему различными способами — выполнять inorder, preorder, levelorder обходы. -## Использование +### Использование Создать дерево и использовать доступные для него методы можно следующим образом: @@ -40,14 +40,19 @@ tree.add(5) tree.add(1) tree.remove(2) + +tree.search(1) ``` +search возвращает Boolean + + Тип создаваемого дерева указывается одним из следующих способов: RBTree<Тип>(), AVLTree<>(), BSTree<>(). -Для RB, AVl, или BS дерева соответственно. +Для RB, AVL, или BS дерева соответственно. -## Сохранение +### Cохранение Каждое из трёх доступных деревьев можно сохранить одним из следующих способов на выбор: @@ -56,38 +61,56 @@ tree.remove(2) Пример Neo4j: ```Kotlin -val st = AVLTreeStrategy({ SerializableValue(it.toString()) }, { it.value.toInt() }) +val strategy = AVLTreeStrategy({ SerializableValue(it.toString()) }, { it.value.toInt() }) val repo = Neo4jRepo( - st, Configuration.Builder() + strategy, Configuration.Builder() .uri("bolt://localhost") .credentials("neo4j", "password") .build() ) + +val tree = RBTree() + +repo.save("myTree", tree) + +repo.loadByVerboseName("myTree", ::RBTree) + +repo.deleteByVerboseNam("myTree") + ``` Пример PostgreSQL: ```Kotlin -val db = Database.connect( +val database = Database.connect( "jdbc:postgresql://localhost:5432/", driver = "org.postgresql.Driver", user = "postgres", password = "password" ) -val avlRepo = PostgresRepo( +val repo = PostgresRepo( AVLTreeStrategy({ SerializableValue(it.toString()) }, { it.value.toInt() }), - db + database ) + +val tree = AVLTree() + +repo.save("myTree", tree) + +repo.loadByVerboseName("myTree", ::AVLTree) + +repo.deleteByVerboseNam("myTree") ``` -Для корректной работы базы данных приложения, а также правильного отображения деревьев необходимо поднять docker -compose. - -Сделать это можно следующим способом: +Для корректной работы базы данных приложения, а также правильного отображения деревьев необходимо поднять docker. + +Чтобы это сделать нужно обратиться к [документации](https://docs.docker.com/desktop/). + +Также это сделать можно следующим способом: ``` docker compose -f "dev-docker-compose.yml" up ``` -## Внесение изменений +### Внесение изменений Внимательно прочитайте раздел [CONTRIBUTING](./CONTRIBUTING.md). @@ -98,6 +121,6 @@ docker compose -f "dev-docker-compose.yml" up 3. Запушьте ветку в origin (`git push origin feat/add-amazing-feature`) 4. Откройте пулл реквест -## Лицензия +### Лицензия -Этот проект используeт лицензию MIT. Подробнее в [LICENSE](./LICENSE) \ No newline at end of file +Этот проект используeт лицензию MIT. Подробнее в [LICENSE](./LICENSE). \ No newline at end of file From 4f2769ff1746eaccf31112d23bd362383914e9d8 Mon Sep 17 00:00:00 2001 From: Vadim <88928096+toadharvard@users.noreply.github.com> Date: Sun, 23 Apr 2023 21:21:12 +0300 Subject: [PATCH 088/125] feat: Update README --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7fa992d..436821f 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ tree.add(1) tree.remove(2) -tree.search(1) +1 in tree // true ``` search возвращает Boolean @@ -110,7 +110,7 @@ repo.deleteByVerboseNam("myTree") ``` docker compose -f "dev-docker-compose.yml" up ``` -### Внесение изменений +## Внесение изменений Внимательно прочитайте раздел [CONTRIBUTING](./CONTRIBUTING.md). @@ -121,6 +121,6 @@ docker compose -f "dev-docker-compose.yml" up 3. Запушьте ветку в origin (`git push origin feat/add-amazing-feature`) 4. Откройте пулл реквест -### Лицензия +## Лицензия -Этот проект используeт лицензию MIT. Подробнее в [LICENSE](./LICENSE). \ No newline at end of file +Этот проект используeт лицензию MIT. Подробнее в [LICENSE](./LICENSE). From b2c22f4d72aa3f1fbe6b3f2715111a8a2bbd120b Mon Sep 17 00:00:00 2001 From: Vadim <88928096+toadharvard@users.noreply.github.com> Date: Sun, 23 Apr 2023 21:23:49 +0300 Subject: [PATCH 089/125] feat: Make BinarySearchTree iterable --- app/src/main/kotlin/app/model/bst/BinarySearchTree.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/app/model/bst/BinarySearchTree.kt b/app/src/main/kotlin/app/model/bst/BinarySearchTree.kt index 3f08d48..41076fa 100644 --- a/app/src/main/kotlin/app/model/bst/BinarySearchTree.kt +++ b/app/src/main/kotlin/app/model/bst/BinarySearchTree.kt @@ -17,7 +17,7 @@ abstract class BinarySearchTree, NodeType : BinTreeNode, -) { +): Iterable { /** * The root node of the tree. */ @@ -57,7 +57,7 @@ abstract class BinarySearchTree, NodeType : BinTreeNode { + override operator fun iterator(): Iterator { return InOrderIterator(root) } @@ -97,4 +97,4 @@ abstract class BinarySearchTree, NodeType : BinTreeNode Date: Sun, 23 Apr 2023 21:29:27 +0300 Subject: [PATCH 090/125] fix: Make function description better --- .../kotlin/app/model/bst/utils/InvariantChecker.kt | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt b/app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt index de0876e..028c509 100644 --- a/app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt +++ b/app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt @@ -94,13 +94,10 @@ object InvariantChecker { } } - /* - This function checks that the tree elements - - point to each other correctly. For example, that - - node.left.parent is the same as node - */ + /** + * Checks that all nodes linked correctly. + * For example, that node.left.parent is the same as node. + **/ fun > isParentLinkedRight(tree: RBTree?): Boolean { fun helper(root: RedBlackTreeNode?): Boolean { @@ -112,4 +109,4 @@ object InvariantChecker { return helper(tree?.root) } -} \ No newline at end of file +} From e43b8e1f9130b2ace1f412fd1ee5e6fa176c665a Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Sun, 23 Apr 2023 04:26:28 +0300 Subject: [PATCH 091/125] test: Add a test for LevelOrderIterator --- .../kotlin/iterator/LevelOrderIterator.kt | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 app/src/test/kotlin/iterator/LevelOrderIterator.kt diff --git a/app/src/test/kotlin/iterator/LevelOrderIterator.kt b/app/src/test/kotlin/iterator/LevelOrderIterator.kt new file mode 100644 index 0000000..ef2af83 --- /dev/null +++ b/app/src/test/kotlin/iterator/LevelOrderIterator.kt @@ -0,0 +1,174 @@ +package iterator + +import app.model.bst.AVLTree +import app.model.bst.BSTree +import app.model.bst.RBTree +import kotlin.test.Test +import kotlin.test.assertEquals + +class LevelOrderIteratorTest { + @Test + fun `test levelOrderIterator to BSTree`() { + val tree = BSTree() + tree.add(8) + tree.add(4) + tree.add(10) + tree.add(3) + tree.add(1) + tree.add(5) + tree.add(9) + tree.add(7) + tree.add(6) + tree.add(2) + /* 8 + / \ + 4 10 + / \ / \ + 3 5 9 null + / \ / \ + 1 null null 7 + / \ / \ + null 2 6 null + */ + val iterator = tree.levelOrderIterator() + + // 8 + var res = iterator.next() + assertEquals(res, tree.root?.value) + + // / \ + // 4 10 + res = iterator.next() + assertEquals(res, tree.root?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.value) + + // / \ / \ + // 3 5 9 null + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.value) + + // / \ / \ + // 1 null null 7 + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.right?.value) + + // / \ / \ + // null 2 6 null + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.left?.right?.value) + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.right?.left?.value) + } + + @Test + fun `test levelOrderIterator to AVLTree`() { + val tree = AVLTree() + for (i in 0..10) { + tree.add(i) + } + /* 3 + / \ + 1 7 + / \ / \ + 0 2 5 9 + / \ / \ + 4 6 8 10 + */ + val iterator = tree.levelOrderIterator() + + // 3 + var res = iterator.next() + assertEquals(res, tree.root?.value) + + // / \ + // 1 7 + res = iterator.next() + assertEquals(res, tree.root?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.value) + + // / \ / \ + // 0 2 5 9 + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.value) + + // / \ / \ + // 4 6 8 10 + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.right?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.value) + } + + @Test + fun `test levelOrderIterator to RBTree`() { + val tree = RBTree() + for (i in 0..10) { + tree.add(i) + } + /* 3 + / \ + 1 5 + / \ / \ + 0 2 4 7 + / \ + 6 9 + / \ + 8 10 + */ + val iterator = tree.levelOrderIterator() + + // 3 + var res = iterator.next() + assertEquals(res, tree.root?.value) + + // / \ + // 1 5 + res = iterator.next() + assertEquals(res, tree.root?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.value) + + // / \ / \ + // 0 2 4 7 + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.value) + + // / \ + // 6 9 + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.value) + + // / \ + // 8 10 + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.right?.value) + } +} \ No newline at end of file From cde4644d28a678b8861a9e0c5d05bebdd02b5de1 Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Sun, 23 Apr 2023 05:19:41 +0300 Subject: [PATCH 092/125] test: Add a test for InOrderIteratot --- .../kotlin/iterator/InOrderIteratorTest.kt | 167 ++++++++++++++++++ ...rIterator.kt => LevelOrderIteratorTest.kt} | 0 2 files changed, 167 insertions(+) create mode 100644 app/src/test/kotlin/iterator/InOrderIteratorTest.kt rename app/src/test/kotlin/iterator/{LevelOrderIterator.kt => LevelOrderIteratorTest.kt} (100%) diff --git a/app/src/test/kotlin/iterator/InOrderIteratorTest.kt b/app/src/test/kotlin/iterator/InOrderIteratorTest.kt new file mode 100644 index 0000000..8c3d04e --- /dev/null +++ b/app/src/test/kotlin/iterator/InOrderIteratorTest.kt @@ -0,0 +1,167 @@ +package iterator + +import app.model.bst.AVLTree +import app.model.bst.BSTree +import app.model.bst.RBTree +import kotlin.test.Test +import kotlin.test.assertEquals + +class InOrderIteratorTest { + @Test + fun `test InlOrderIterator to BSTree`() { + val tree = BSTree() + tree.add(8) + tree.add(4) + tree.add(10) + tree.add(3) + tree.add(1) + tree.add(5) + tree.add(9) + tree.add(7) + tree.add(6) + tree.add(2) + /* 8 + / \ + 4 10 + / \ / \ + 3 5 9 null + / \ / \ + 1 null null 7 + / \ / \ + null 2 6 null + */ + val iterator = tree.iterator() + + var res = iterator.next() + assertEquals(res,tree.root?.left?.left?.left?.value) //1 + + res = iterator.next() + assertEquals(res,tree.root?.left?.left?.left?.right?.value) //2 + + res = iterator.next() + assertEquals(res,tree.root?.left?.left?.value) //3 + + res = iterator.next() + assertEquals(res,tree.root?.left?.value) //4 + + res = iterator.next() + assertEquals(res,tree.root?.left?.right?.value) //5 + + res = iterator.next() + assertEquals(res,tree.root?.left?.right?.right?.left?.value) //6 + + res = iterator.next() + assertEquals(res,tree.root?.left?.right?.right?.value) //7 + + res = iterator.next() + assertEquals(res,tree.root?.value) //8 + + res = iterator.next() + assertEquals(res,tree.root?.right?.left?.value) //9 + + res = iterator.next() + assertEquals(res,tree.root?.right?.value) //10 + } + + @Test + fun `test InlOrderIterator to AVLTree`() { + val tree = AVLTree() + for (i in 0..10) { + tree.add(i) + } + /* 3 + / \ + 1 7 + / \ / \ + 0 2 5 9 + / \ / \ + 4 6 8 10 + */ + val iterator = tree.iterator() + + var res = iterator.next() + assertEquals(res,tree.root?.left?.left?.value) //0 + + res = iterator.next() + assertEquals(res,tree.root?.left?.value) //1 + + res = iterator.next() + assertEquals(res,tree.root?.left?.right?.value) //2 + + res = iterator.next() + assertEquals(res,tree.root?.value) //3 + + res = iterator.next() + assertEquals(res,tree.root?.right?.left?.left?.value) //4 + + res = iterator.next() + assertEquals(res,tree.root?.right?.left?.value) //5 + + res = iterator.next() + assertEquals(res,tree.root?.right?.left?.right?.value) //6 + + res = iterator.next() + assertEquals(res,tree.root?.right?.value) //7 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.left?.value) //8 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.value) //9 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.right?.value) //10 + } + + @Test + fun `test InOrderIterator to RBTree`() { + val tree = RBTree() + for (i in 0..10) { + tree.add(i) + } + /* 3 + / \ + 1 5 + / \ / \ + 0 2 4 7 + / \ + 6 9 + / \ + 8 10 + */ + val iterator = tree.iterator() + + var res = iterator.next() + assertEquals(res,tree.root?.left?.left?.value) //0 + + res = iterator.next() + assertEquals(res,tree.root?.left?.value) //1 + + res = iterator.next() + assertEquals(res,tree.root?.left?.right?.value) //2 + + res = iterator.next() + assertEquals(res,tree.root?.value) //3 + + res = iterator.next() + assertEquals(res,tree.root?.right?.left?.value) //4 + + res = iterator.next() + assertEquals(res,tree.root?.right?.value) //5 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.left?.value)//6 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.value) //7 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.right?.left?.value) //8 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.right?.value) //9 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.right?.right?.value) //10 + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/iterator/LevelOrderIterator.kt b/app/src/test/kotlin/iterator/LevelOrderIteratorTest.kt similarity index 100% rename from app/src/test/kotlin/iterator/LevelOrderIterator.kt rename to app/src/test/kotlin/iterator/LevelOrderIteratorTest.kt From b8f06cd9c911f1707d9edbe62b2d18121327bdef Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Sun, 23 Apr 2023 05:55:28 +0300 Subject: [PATCH 093/125] test: Add a test for PreOrderIteratot --- .../test/kotlin/iterator/PreOrderIterator.kt | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 app/src/test/kotlin/iterator/PreOrderIterator.kt diff --git a/app/src/test/kotlin/iterator/PreOrderIterator.kt b/app/src/test/kotlin/iterator/PreOrderIterator.kt new file mode 100644 index 0000000..6d53c7b --- /dev/null +++ b/app/src/test/kotlin/iterator/PreOrderIterator.kt @@ -0,0 +1,167 @@ +package iterator + +import app.model.bst.AVLTree +import app.model.bst.BSTree +import app.model.bst.RBTree +import kotlin.test.Test +import kotlin.test.assertEquals + +class PreOrderIterator { + @Test + fun `test PreOrderIterator to BSTree`() { + val tree = BSTree() + tree.add(8) + tree.add(4) + tree.add(10) + tree.add(3) + tree.add(1) + tree.add(5) + tree.add(9) + tree.add(7) + tree.add(6) + tree.add(2) + /* 8 + / \ + 4 10 + / \ / \ + 3 5 9 null + / \ / \ + 1 null null 7 + / \ / \ + null 2 6 null + */ + val iterator = tree.preOrderIterator() + + var res = iterator.next() + assertEquals(res, tree.root?.value) //8 + + res = iterator.next() + assertEquals(res, tree.root?.left?.value) //4 + + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.value) //3 + + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.left?.value) //1 + + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.left?.right?.value) //2 + + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.value) //5 + + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.right?.value) //7 + + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.right?.left?.value) //6 + + res = iterator.next() + assertEquals(res, tree.root?.right?.value) //10 + + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.value) //9 + } + + @Test + fun `test levelOrderIterator to AVLTree`() { + val tree = AVLTree() + for (i in 0..10) { + tree.add(i) + } + /* 3 + / \ + 1 7 + / \ / \ + 0 2 5 9 + / \ / \ + 4 6 8 10 + */ + val iterator = tree.preOrderIterator() + + var res = iterator.next() + assertEquals(res, tree.root?.value) //3 + + res = iterator.next() + assertEquals(res, tree.root?.left?.value) //1 + + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.value) //0 + + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.value) //2 + + res = iterator.next() + assertEquals(res, tree.root?.right?.value) //7 + + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.value) //5 + + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.left?.value) //4 + + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.right?.value) //6 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.value) //9 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.left?.value) //8 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.value) //10 + } + + @Test + fun `test levelOrderIterator to RBTree`() { + val tree = RBTree() + for (i in 0..10) { + tree.add(i) + } + /* 3 + / \ + 1 5 + / \ / \ + 0 2 4 7 + / \ + 6 9 + / \ + 8 10 + */ + val iterator = tree.preOrderIterator() + + var res = iterator.next() + assertEquals(res, tree.root?.value) //3 + + res = iterator.next() + assertEquals(res, tree.root?.left?.value) //1 + + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.value) //0 + + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.value) //2 + + res = iterator.next() + assertEquals(res, tree.root?.right?.value) //5 + + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.value) //4 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.value) //7 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.left?.value) //6 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.value) //9 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.left?.value) //8 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.right?.value) //10 + } +} \ No newline at end of file From 278d2d7825fd3e24ac752e8bbe8b53102b78eb2f Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Sun, 23 Apr 2023 20:05:18 +0300 Subject: [PATCH 094/125] struct: Move iterator tests to the desired folder --- .../model/bst/iterator/InOrderIteratorTest.kt | 167 +++++++++++++++++ .../bst/iterator/LevelOrderIteratorTest.kt | 174 ++++++++++++++++++ .../model/bst/iterator/PreOrderIterator.kt | 167 +++++++++++++++++ 3 files changed, 508 insertions(+) create mode 100644 app/src/test/kotlin/app/model/bst/iterator/InOrderIteratorTest.kt create mode 100644 app/src/test/kotlin/app/model/bst/iterator/LevelOrderIteratorTest.kt create mode 100644 app/src/test/kotlin/app/model/bst/iterator/PreOrderIterator.kt diff --git a/app/src/test/kotlin/app/model/bst/iterator/InOrderIteratorTest.kt b/app/src/test/kotlin/app/model/bst/iterator/InOrderIteratorTest.kt new file mode 100644 index 0000000..8c3d04e --- /dev/null +++ b/app/src/test/kotlin/app/model/bst/iterator/InOrderIteratorTest.kt @@ -0,0 +1,167 @@ +package iterator + +import app.model.bst.AVLTree +import app.model.bst.BSTree +import app.model.bst.RBTree +import kotlin.test.Test +import kotlin.test.assertEquals + +class InOrderIteratorTest { + @Test + fun `test InlOrderIterator to BSTree`() { + val tree = BSTree() + tree.add(8) + tree.add(4) + tree.add(10) + tree.add(3) + tree.add(1) + tree.add(5) + tree.add(9) + tree.add(7) + tree.add(6) + tree.add(2) + /* 8 + / \ + 4 10 + / \ / \ + 3 5 9 null + / \ / \ + 1 null null 7 + / \ / \ + null 2 6 null + */ + val iterator = tree.iterator() + + var res = iterator.next() + assertEquals(res,tree.root?.left?.left?.left?.value) //1 + + res = iterator.next() + assertEquals(res,tree.root?.left?.left?.left?.right?.value) //2 + + res = iterator.next() + assertEquals(res,tree.root?.left?.left?.value) //3 + + res = iterator.next() + assertEquals(res,tree.root?.left?.value) //4 + + res = iterator.next() + assertEquals(res,tree.root?.left?.right?.value) //5 + + res = iterator.next() + assertEquals(res,tree.root?.left?.right?.right?.left?.value) //6 + + res = iterator.next() + assertEquals(res,tree.root?.left?.right?.right?.value) //7 + + res = iterator.next() + assertEquals(res,tree.root?.value) //8 + + res = iterator.next() + assertEquals(res,tree.root?.right?.left?.value) //9 + + res = iterator.next() + assertEquals(res,tree.root?.right?.value) //10 + } + + @Test + fun `test InlOrderIterator to AVLTree`() { + val tree = AVLTree() + for (i in 0..10) { + tree.add(i) + } + /* 3 + / \ + 1 7 + / \ / \ + 0 2 5 9 + / \ / \ + 4 6 8 10 + */ + val iterator = tree.iterator() + + var res = iterator.next() + assertEquals(res,tree.root?.left?.left?.value) //0 + + res = iterator.next() + assertEquals(res,tree.root?.left?.value) //1 + + res = iterator.next() + assertEquals(res,tree.root?.left?.right?.value) //2 + + res = iterator.next() + assertEquals(res,tree.root?.value) //3 + + res = iterator.next() + assertEquals(res,tree.root?.right?.left?.left?.value) //4 + + res = iterator.next() + assertEquals(res,tree.root?.right?.left?.value) //5 + + res = iterator.next() + assertEquals(res,tree.root?.right?.left?.right?.value) //6 + + res = iterator.next() + assertEquals(res,tree.root?.right?.value) //7 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.left?.value) //8 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.value) //9 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.right?.value) //10 + } + + @Test + fun `test InOrderIterator to RBTree`() { + val tree = RBTree() + for (i in 0..10) { + tree.add(i) + } + /* 3 + / \ + 1 5 + / \ / \ + 0 2 4 7 + / \ + 6 9 + / \ + 8 10 + */ + val iterator = tree.iterator() + + var res = iterator.next() + assertEquals(res,tree.root?.left?.left?.value) //0 + + res = iterator.next() + assertEquals(res,tree.root?.left?.value) //1 + + res = iterator.next() + assertEquals(res,tree.root?.left?.right?.value) //2 + + res = iterator.next() + assertEquals(res,tree.root?.value) //3 + + res = iterator.next() + assertEquals(res,tree.root?.right?.left?.value) //4 + + res = iterator.next() + assertEquals(res,tree.root?.right?.value) //5 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.left?.value)//6 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.value) //7 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.right?.left?.value) //8 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.right?.value) //9 + + res = iterator.next() + assertEquals(res,tree.root?.right?.right?.right?.right?.value) //10 + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/app/model/bst/iterator/LevelOrderIteratorTest.kt b/app/src/test/kotlin/app/model/bst/iterator/LevelOrderIteratorTest.kt new file mode 100644 index 0000000..ef2af83 --- /dev/null +++ b/app/src/test/kotlin/app/model/bst/iterator/LevelOrderIteratorTest.kt @@ -0,0 +1,174 @@ +package iterator + +import app.model.bst.AVLTree +import app.model.bst.BSTree +import app.model.bst.RBTree +import kotlin.test.Test +import kotlin.test.assertEquals + +class LevelOrderIteratorTest { + @Test + fun `test levelOrderIterator to BSTree`() { + val tree = BSTree() + tree.add(8) + tree.add(4) + tree.add(10) + tree.add(3) + tree.add(1) + tree.add(5) + tree.add(9) + tree.add(7) + tree.add(6) + tree.add(2) + /* 8 + / \ + 4 10 + / \ / \ + 3 5 9 null + / \ / \ + 1 null null 7 + / \ / \ + null 2 6 null + */ + val iterator = tree.levelOrderIterator() + + // 8 + var res = iterator.next() + assertEquals(res, tree.root?.value) + + // / \ + // 4 10 + res = iterator.next() + assertEquals(res, tree.root?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.value) + + // / \ / \ + // 3 5 9 null + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.value) + + // / \ / \ + // 1 null null 7 + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.right?.value) + + // / \ / \ + // null 2 6 null + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.left?.right?.value) + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.right?.left?.value) + } + + @Test + fun `test levelOrderIterator to AVLTree`() { + val tree = AVLTree() + for (i in 0..10) { + tree.add(i) + } + /* 3 + / \ + 1 7 + / \ / \ + 0 2 5 9 + / \ / \ + 4 6 8 10 + */ + val iterator = tree.levelOrderIterator() + + // 3 + var res = iterator.next() + assertEquals(res, tree.root?.value) + + // / \ + // 1 7 + res = iterator.next() + assertEquals(res, tree.root?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.value) + + // / \ / \ + // 0 2 5 9 + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.value) + + // / \ / \ + // 4 6 8 10 + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.right?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.value) + } + + @Test + fun `test levelOrderIterator to RBTree`() { + val tree = RBTree() + for (i in 0..10) { + tree.add(i) + } + /* 3 + / \ + 1 5 + / \ / \ + 0 2 4 7 + / \ + 6 9 + / \ + 8 10 + */ + val iterator = tree.levelOrderIterator() + + // 3 + var res = iterator.next() + assertEquals(res, tree.root?.value) + + // / \ + // 1 5 + res = iterator.next() + assertEquals(res, tree.root?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.value) + + // / \ / \ + // 0 2 4 7 + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.value) + + // / \ + // 6 9 + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.value) + + // / \ + // 8 10 + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.left?.value) + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.right?.value) + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/app/model/bst/iterator/PreOrderIterator.kt b/app/src/test/kotlin/app/model/bst/iterator/PreOrderIterator.kt new file mode 100644 index 0000000..6d53c7b --- /dev/null +++ b/app/src/test/kotlin/app/model/bst/iterator/PreOrderIterator.kt @@ -0,0 +1,167 @@ +package iterator + +import app.model.bst.AVLTree +import app.model.bst.BSTree +import app.model.bst.RBTree +import kotlin.test.Test +import kotlin.test.assertEquals + +class PreOrderIterator { + @Test + fun `test PreOrderIterator to BSTree`() { + val tree = BSTree() + tree.add(8) + tree.add(4) + tree.add(10) + tree.add(3) + tree.add(1) + tree.add(5) + tree.add(9) + tree.add(7) + tree.add(6) + tree.add(2) + /* 8 + / \ + 4 10 + / \ / \ + 3 5 9 null + / \ / \ + 1 null null 7 + / \ / \ + null 2 6 null + */ + val iterator = tree.preOrderIterator() + + var res = iterator.next() + assertEquals(res, tree.root?.value) //8 + + res = iterator.next() + assertEquals(res, tree.root?.left?.value) //4 + + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.value) //3 + + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.left?.value) //1 + + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.left?.right?.value) //2 + + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.value) //5 + + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.right?.value) //7 + + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.right?.left?.value) //6 + + res = iterator.next() + assertEquals(res, tree.root?.right?.value) //10 + + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.value) //9 + } + + @Test + fun `test levelOrderIterator to AVLTree`() { + val tree = AVLTree() + for (i in 0..10) { + tree.add(i) + } + /* 3 + / \ + 1 7 + / \ / \ + 0 2 5 9 + / \ / \ + 4 6 8 10 + */ + val iterator = tree.preOrderIterator() + + var res = iterator.next() + assertEquals(res, tree.root?.value) //3 + + res = iterator.next() + assertEquals(res, tree.root?.left?.value) //1 + + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.value) //0 + + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.value) //2 + + res = iterator.next() + assertEquals(res, tree.root?.right?.value) //7 + + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.value) //5 + + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.left?.value) //4 + + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.right?.value) //6 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.value) //9 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.left?.value) //8 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.value) //10 + } + + @Test + fun `test levelOrderIterator to RBTree`() { + val tree = RBTree() + for (i in 0..10) { + tree.add(i) + } + /* 3 + / \ + 1 5 + / \ / \ + 0 2 4 7 + / \ + 6 9 + / \ + 8 10 + */ + val iterator = tree.preOrderIterator() + + var res = iterator.next() + assertEquals(res, tree.root?.value) //3 + + res = iterator.next() + assertEquals(res, tree.root?.left?.value) //1 + + res = iterator.next() + assertEquals(res, tree.root?.left?.left?.value) //0 + + res = iterator.next() + assertEquals(res, tree.root?.left?.right?.value) //2 + + res = iterator.next() + assertEquals(res, tree.root?.right?.value) //5 + + res = iterator.next() + assertEquals(res, tree.root?.right?.left?.value) //4 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.value) //7 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.left?.value) //6 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.value) //9 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.left?.value) //8 + + res = iterator.next() + assertEquals(res, tree.root?.right?.right?.right?.right?.value) //10 + } +} \ No newline at end of file From 9e80c8fdb9e0fca0dff84f743bae7b13137298ac Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Sun, 23 Apr 2023 20:33:28 +0300 Subject: [PATCH 095/125] refactor: Change the package for bst --- .../test/kotlin/app/model/bst/iterator/InOrderIteratorTest.kt | 2 +- .../kotlin/app/model/bst/iterator/LevelOrderIteratorTest.kt | 2 +- .../test/kotlin/app/model/bst/iterator/PreOrderIterator.kt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/test/kotlin/app/model/bst/iterator/InOrderIteratorTest.kt b/app/src/test/kotlin/app/model/bst/iterator/InOrderIteratorTest.kt index 8c3d04e..f458dea 100644 --- a/app/src/test/kotlin/app/model/bst/iterator/InOrderIteratorTest.kt +++ b/app/src/test/kotlin/app/model/bst/iterator/InOrderIteratorTest.kt @@ -1,4 +1,4 @@ -package iterator +package app.model.bst.iterator import app.model.bst.AVLTree import app.model.bst.BSTree diff --git a/app/src/test/kotlin/app/model/bst/iterator/LevelOrderIteratorTest.kt b/app/src/test/kotlin/app/model/bst/iterator/LevelOrderIteratorTest.kt index ef2af83..f3dd072 100644 --- a/app/src/test/kotlin/app/model/bst/iterator/LevelOrderIteratorTest.kt +++ b/app/src/test/kotlin/app/model/bst/iterator/LevelOrderIteratorTest.kt @@ -1,4 +1,4 @@ -package iterator +package app.model.bst.iterator import app.model.bst.AVLTree import app.model.bst.BSTree diff --git a/app/src/test/kotlin/app/model/bst/iterator/PreOrderIterator.kt b/app/src/test/kotlin/app/model/bst/iterator/PreOrderIterator.kt index 6d53c7b..91848e7 100644 --- a/app/src/test/kotlin/app/model/bst/iterator/PreOrderIterator.kt +++ b/app/src/test/kotlin/app/model/bst/iterator/PreOrderIterator.kt @@ -1,4 +1,4 @@ -package iterator +package app.model.bst.iterator import app.model.bst.AVLTree import app.model.bst.BSTree @@ -6,7 +6,7 @@ import app.model.bst.RBTree import kotlin.test.Test import kotlin.test.assertEquals -class PreOrderIterator { +class PreOrderIteratorTest { @Test fun `test PreOrderIterator to BSTree`() { val tree = BSTree() From b7f364b4c56969d3dc31d7cbf97b8d541f91ac64 Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Sun, 23 Apr 2023 21:36:40 +0300 Subject: [PATCH 096/125] struct: Remove duplicate tests for iterators --- .../kotlin/iterator/InOrderIteratorTest.kt | 167 ----------------- .../kotlin/iterator/LevelOrderIteratorTest.kt | 174 ------------------ .../test/kotlin/iterator/PreOrderIterator.kt | 167 ----------------- 3 files changed, 508 deletions(-) delete mode 100644 app/src/test/kotlin/iterator/InOrderIteratorTest.kt delete mode 100644 app/src/test/kotlin/iterator/LevelOrderIteratorTest.kt delete mode 100644 app/src/test/kotlin/iterator/PreOrderIterator.kt diff --git a/app/src/test/kotlin/iterator/InOrderIteratorTest.kt b/app/src/test/kotlin/iterator/InOrderIteratorTest.kt deleted file mode 100644 index 8c3d04e..0000000 --- a/app/src/test/kotlin/iterator/InOrderIteratorTest.kt +++ /dev/null @@ -1,167 +0,0 @@ -package iterator - -import app.model.bst.AVLTree -import app.model.bst.BSTree -import app.model.bst.RBTree -import kotlin.test.Test -import kotlin.test.assertEquals - -class InOrderIteratorTest { - @Test - fun `test InlOrderIterator to BSTree`() { - val tree = BSTree() - tree.add(8) - tree.add(4) - tree.add(10) - tree.add(3) - tree.add(1) - tree.add(5) - tree.add(9) - tree.add(7) - tree.add(6) - tree.add(2) - /* 8 - / \ - 4 10 - / \ / \ - 3 5 9 null - / \ / \ - 1 null null 7 - / \ / \ - null 2 6 null - */ - val iterator = tree.iterator() - - var res = iterator.next() - assertEquals(res,tree.root?.left?.left?.left?.value) //1 - - res = iterator.next() - assertEquals(res,tree.root?.left?.left?.left?.right?.value) //2 - - res = iterator.next() - assertEquals(res,tree.root?.left?.left?.value) //3 - - res = iterator.next() - assertEquals(res,tree.root?.left?.value) //4 - - res = iterator.next() - assertEquals(res,tree.root?.left?.right?.value) //5 - - res = iterator.next() - assertEquals(res,tree.root?.left?.right?.right?.left?.value) //6 - - res = iterator.next() - assertEquals(res,tree.root?.left?.right?.right?.value) //7 - - res = iterator.next() - assertEquals(res,tree.root?.value) //8 - - res = iterator.next() - assertEquals(res,tree.root?.right?.left?.value) //9 - - res = iterator.next() - assertEquals(res,tree.root?.right?.value) //10 - } - - @Test - fun `test InlOrderIterator to AVLTree`() { - val tree = AVLTree() - for (i in 0..10) { - tree.add(i) - } - /* 3 - / \ - 1 7 - / \ / \ - 0 2 5 9 - / \ / \ - 4 6 8 10 - */ - val iterator = tree.iterator() - - var res = iterator.next() - assertEquals(res,tree.root?.left?.left?.value) //0 - - res = iterator.next() - assertEquals(res,tree.root?.left?.value) //1 - - res = iterator.next() - assertEquals(res,tree.root?.left?.right?.value) //2 - - res = iterator.next() - assertEquals(res,tree.root?.value) //3 - - res = iterator.next() - assertEquals(res,tree.root?.right?.left?.left?.value) //4 - - res = iterator.next() - assertEquals(res,tree.root?.right?.left?.value) //5 - - res = iterator.next() - assertEquals(res,tree.root?.right?.left?.right?.value) //6 - - res = iterator.next() - assertEquals(res,tree.root?.right?.value) //7 - - res = iterator.next() - assertEquals(res,tree.root?.right?.right?.left?.value) //8 - - res = iterator.next() - assertEquals(res,tree.root?.right?.right?.value) //9 - - res = iterator.next() - assertEquals(res,tree.root?.right?.right?.right?.value) //10 - } - - @Test - fun `test InOrderIterator to RBTree`() { - val tree = RBTree() - for (i in 0..10) { - tree.add(i) - } - /* 3 - / \ - 1 5 - / \ / \ - 0 2 4 7 - / \ - 6 9 - / \ - 8 10 - */ - val iterator = tree.iterator() - - var res = iterator.next() - assertEquals(res,tree.root?.left?.left?.value) //0 - - res = iterator.next() - assertEquals(res,tree.root?.left?.value) //1 - - res = iterator.next() - assertEquals(res,tree.root?.left?.right?.value) //2 - - res = iterator.next() - assertEquals(res,tree.root?.value) //3 - - res = iterator.next() - assertEquals(res,tree.root?.right?.left?.value) //4 - - res = iterator.next() - assertEquals(res,tree.root?.right?.value) //5 - - res = iterator.next() - assertEquals(res,tree.root?.right?.right?.left?.value)//6 - - res = iterator.next() - assertEquals(res,tree.root?.right?.right?.value) //7 - - res = iterator.next() - assertEquals(res,tree.root?.right?.right?.right?.left?.value) //8 - - res = iterator.next() - assertEquals(res,tree.root?.right?.right?.right?.value) //9 - - res = iterator.next() - assertEquals(res,tree.root?.right?.right?.right?.right?.value) //10 - } -} \ No newline at end of file diff --git a/app/src/test/kotlin/iterator/LevelOrderIteratorTest.kt b/app/src/test/kotlin/iterator/LevelOrderIteratorTest.kt deleted file mode 100644 index ef2af83..0000000 --- a/app/src/test/kotlin/iterator/LevelOrderIteratorTest.kt +++ /dev/null @@ -1,174 +0,0 @@ -package iterator - -import app.model.bst.AVLTree -import app.model.bst.BSTree -import app.model.bst.RBTree -import kotlin.test.Test -import kotlin.test.assertEquals - -class LevelOrderIteratorTest { - @Test - fun `test levelOrderIterator to BSTree`() { - val tree = BSTree() - tree.add(8) - tree.add(4) - tree.add(10) - tree.add(3) - tree.add(1) - tree.add(5) - tree.add(9) - tree.add(7) - tree.add(6) - tree.add(2) - /* 8 - / \ - 4 10 - / \ / \ - 3 5 9 null - / \ / \ - 1 null null 7 - / \ / \ - null 2 6 null - */ - val iterator = tree.levelOrderIterator() - - // 8 - var res = iterator.next() - assertEquals(res, tree.root?.value) - - // / \ - // 4 10 - res = iterator.next() - assertEquals(res, tree.root?.left?.value) - res = iterator.next() - assertEquals(res, tree.root?.right?.value) - - // / \ / \ - // 3 5 9 null - res = iterator.next() - assertEquals(res, tree.root?.left?.left?.value) - res = iterator.next() - assertEquals(res, tree.root?.left?.right?.value) - res = iterator.next() - assertEquals(res, tree.root?.right?.left?.value) - - // / \ / \ - // 1 null null 7 - res = iterator.next() - assertEquals(res, tree.root?.left?.left?.left?.value) - res = iterator.next() - assertEquals(res, tree.root?.left?.right?.right?.value) - - // / \ / \ - // null 2 6 null - res = iterator.next() - assertEquals(res, tree.root?.left?.left?.left?.right?.value) - res = iterator.next() - assertEquals(res, tree.root?.left?.right?.right?.left?.value) - } - - @Test - fun `test levelOrderIterator to AVLTree`() { - val tree = AVLTree() - for (i in 0..10) { - tree.add(i) - } - /* 3 - / \ - 1 7 - / \ / \ - 0 2 5 9 - / \ / \ - 4 6 8 10 - */ - val iterator = tree.levelOrderIterator() - - // 3 - var res = iterator.next() - assertEquals(res, tree.root?.value) - - // / \ - // 1 7 - res = iterator.next() - assertEquals(res, tree.root?.left?.value) - res = iterator.next() - assertEquals(res, tree.root?.right?.value) - - // / \ / \ - // 0 2 5 9 - res = iterator.next() - assertEquals(res, tree.root?.left?.left?.value) - res = iterator.next() - assertEquals(res, tree.root?.left?.right?.value) - res = iterator.next() - assertEquals(res, tree.root?.right?.left?.value) - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.value) - - // / \ / \ - // 4 6 8 10 - res = iterator.next() - assertEquals(res, tree.root?.right?.left?.left?.value) - res = iterator.next() - assertEquals(res, tree.root?.right?.left?.right?.value) - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.left?.value) - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.right?.value) - } - - @Test - fun `test levelOrderIterator to RBTree`() { - val tree = RBTree() - for (i in 0..10) { - tree.add(i) - } - /* 3 - / \ - 1 5 - / \ / \ - 0 2 4 7 - / \ - 6 9 - / \ - 8 10 - */ - val iterator = tree.levelOrderIterator() - - // 3 - var res = iterator.next() - assertEquals(res, tree.root?.value) - - // / \ - // 1 5 - res = iterator.next() - assertEquals(res, tree.root?.left?.value) - res = iterator.next() - assertEquals(res, tree.root?.right?.value) - - // / \ / \ - // 0 2 4 7 - res = iterator.next() - assertEquals(res, tree.root?.left?.left?.value) - res = iterator.next() - assertEquals(res, tree.root?.left?.right?.value) - res = iterator.next() - assertEquals(res, tree.root?.right?.left?.value) - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.value) - - // / \ - // 6 9 - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.left?.value) - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.right?.value) - - // / \ - // 8 10 - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.right?.left?.value) - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.right?.right?.value) - } -} \ No newline at end of file diff --git a/app/src/test/kotlin/iterator/PreOrderIterator.kt b/app/src/test/kotlin/iterator/PreOrderIterator.kt deleted file mode 100644 index 6d53c7b..0000000 --- a/app/src/test/kotlin/iterator/PreOrderIterator.kt +++ /dev/null @@ -1,167 +0,0 @@ -package iterator - -import app.model.bst.AVLTree -import app.model.bst.BSTree -import app.model.bst.RBTree -import kotlin.test.Test -import kotlin.test.assertEquals - -class PreOrderIterator { - @Test - fun `test PreOrderIterator to BSTree`() { - val tree = BSTree() - tree.add(8) - tree.add(4) - tree.add(10) - tree.add(3) - tree.add(1) - tree.add(5) - tree.add(9) - tree.add(7) - tree.add(6) - tree.add(2) - /* 8 - / \ - 4 10 - / \ / \ - 3 5 9 null - / \ / \ - 1 null null 7 - / \ / \ - null 2 6 null - */ - val iterator = tree.preOrderIterator() - - var res = iterator.next() - assertEquals(res, tree.root?.value) //8 - - res = iterator.next() - assertEquals(res, tree.root?.left?.value) //4 - - res = iterator.next() - assertEquals(res, tree.root?.left?.left?.value) //3 - - res = iterator.next() - assertEquals(res, tree.root?.left?.left?.left?.value) //1 - - res = iterator.next() - assertEquals(res, tree.root?.left?.left?.left?.right?.value) //2 - - res = iterator.next() - assertEquals(res, tree.root?.left?.right?.value) //5 - - res = iterator.next() - assertEquals(res, tree.root?.left?.right?.right?.value) //7 - - res = iterator.next() - assertEquals(res, tree.root?.left?.right?.right?.left?.value) //6 - - res = iterator.next() - assertEquals(res, tree.root?.right?.value) //10 - - res = iterator.next() - assertEquals(res, tree.root?.right?.left?.value) //9 - } - - @Test - fun `test levelOrderIterator to AVLTree`() { - val tree = AVLTree() - for (i in 0..10) { - tree.add(i) - } - /* 3 - / \ - 1 7 - / \ / \ - 0 2 5 9 - / \ / \ - 4 6 8 10 - */ - val iterator = tree.preOrderIterator() - - var res = iterator.next() - assertEquals(res, tree.root?.value) //3 - - res = iterator.next() - assertEquals(res, tree.root?.left?.value) //1 - - res = iterator.next() - assertEquals(res, tree.root?.left?.left?.value) //0 - - res = iterator.next() - assertEquals(res, tree.root?.left?.right?.value) //2 - - res = iterator.next() - assertEquals(res, tree.root?.right?.value) //7 - - res = iterator.next() - assertEquals(res, tree.root?.right?.left?.value) //5 - - res = iterator.next() - assertEquals(res, tree.root?.right?.left?.left?.value) //4 - - res = iterator.next() - assertEquals(res, tree.root?.right?.left?.right?.value) //6 - - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.value) //9 - - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.left?.value) //8 - - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.right?.value) //10 - } - - @Test - fun `test levelOrderIterator to RBTree`() { - val tree = RBTree() - for (i in 0..10) { - tree.add(i) - } - /* 3 - / \ - 1 5 - / \ / \ - 0 2 4 7 - / \ - 6 9 - / \ - 8 10 - */ - val iterator = tree.preOrderIterator() - - var res = iterator.next() - assertEquals(res, tree.root?.value) //3 - - res = iterator.next() - assertEquals(res, tree.root?.left?.value) //1 - - res = iterator.next() - assertEquals(res, tree.root?.left?.left?.value) //0 - - res = iterator.next() - assertEquals(res, tree.root?.left?.right?.value) //2 - - res = iterator.next() - assertEquals(res, tree.root?.right?.value) //5 - - res = iterator.next() - assertEquals(res, tree.root?.right?.left?.value) //4 - - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.value) //7 - - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.left?.value) //6 - - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.right?.value) //9 - - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.right?.left?.value) //8 - - res = iterator.next() - assertEquals(res, tree.root?.right?.right?.right?.right?.value) //10 - } -} \ No newline at end of file From 03fbfe5858493039265fb41a71784306445aa0cc Mon Sep 17 00:00:00 2001 From: Vadim <88928096+toadharvard@users.noreply.github.com> Date: Sun, 23 Apr 2023 21:39:57 +0300 Subject: [PATCH 097/125] fix: Rename file name --- .../iterator/{PreOrderIterator.kt => PreOrderIteratorTest.kt} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename app/src/test/kotlin/app/model/bst/iterator/{PreOrderIterator.kt => PreOrderIteratorTest.kt} (99%) diff --git a/app/src/test/kotlin/app/model/bst/iterator/PreOrderIterator.kt b/app/src/test/kotlin/app/model/bst/iterator/PreOrderIteratorTest.kt similarity index 99% rename from app/src/test/kotlin/app/model/bst/iterator/PreOrderIterator.kt rename to app/src/test/kotlin/app/model/bst/iterator/PreOrderIteratorTest.kt index 91848e7..46fb9b4 100644 --- a/app/src/test/kotlin/app/model/bst/iterator/PreOrderIterator.kt +++ b/app/src/test/kotlin/app/model/bst/iterator/PreOrderIteratorTest.kt @@ -164,4 +164,4 @@ class PreOrderIteratorTest { res = iterator.next() assertEquals(res, tree.root?.right?.right?.right?.right?.value) //10 } -} \ No newline at end of file +} From ba5a58c255810a193d97d892f5d6d07f95d0294c Mon Sep 17 00:00:00 2001 From: Efim Perevalov Date: Wed, 19 Apr 2023 08:15:49 +0300 Subject: [PATCH 098/125] feat: Add save, load and delete for json --- README.md | 18 +++++++++-- app/build.gradle.kts | 1 + .../main/kotlin/app/model/repo/JsonRepo.kt | 32 ++++++++++++++++--- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 436821f..84967b6 100644 --- a/README.md +++ b/README.md @@ -56,12 +56,27 @@ search возвращает Boolean Каждое из трёх доступных деревьев можно сохранить одним из следующих способов на выбор: + - Json - PostgreSQL - Neo4j -Пример Neo4j: +Пример Json: ```Kotlin val strategy = AVLTreeStrategy({ SerializableValue(it.toString()) }, { it.value.toInt() }) +val repo = JsonRepo(strategy) + +val tree = AVLTree() + +repo.save("myTree", tree) + +repo.loadByVerboseName("myTree",::AVLTree) + +repo.deleteByVerboseName("myTree") +``` + +Пример Neo4j: +```Kotlin +val strategy = RBTreeStrategy({ SerializableValue(it.toString()) }, { it.value.toInt() }) val repo = Neo4jRepo( strategy, Configuration.Builder() .uri("bolt://localhost") @@ -76,7 +91,6 @@ repo.save("myTree", tree) repo.loadByVerboseName("myTree", ::RBTree) repo.deleteByVerboseNam("myTree") - ``` Пример PostgreSQL: diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a1156b3..d6399b8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -35,6 +35,7 @@ dependencies { implementation("org.jetbrains.exposed", "exposed-core", "0.40.1") implementation("org.jetbrains.exposed", "exposed-dao", "0.40.1") implementation("org.jetbrains.exposed", "exposed-jdbc", "0.40.1") + implementation("com.google.code.gson:gson:2.10.1") } diff --git a/app/src/main/kotlin/app/model/repo/JsonRepo.kt b/app/src/main/kotlin/app/model/repo/JsonRepo.kt index e9eb6d2..28f72ca 100644 --- a/app/src/main/kotlin/app/model/repo/JsonRepo.kt +++ b/app/src/main/kotlin/app/model/repo/JsonRepo.kt @@ -2,23 +2,47 @@ package app.model.repo import app.model.bst.BinarySearchTree import app.model.bst.node.BinTreeNode +import app.model.repo.serialization.SerializableTree import app.model.repo.serialization.strategy.SerializationStrategy +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import java.io.File class JsonRepo, Node : BinTreeNode, BST : BinarySearchTree>( strategy: SerializationStrategy ) : Repository(strategy) { + private var builder: GsonBuilder = GsonBuilder() + private var gson: Gson = builder.create() + private val sC = File.separatorChar override fun save(verboseName: String, tree: BST) { - TODO("Not yet implemented") + try { + val json = gson.toJson(tree.toSerializableTree(verboseName)) + val file = File("app${sC}src${sC}main${sC}resources${sC}$verboseName.json") + file.writeText(json) + } catch (e: Exception) { + throw IllegalArgumentException("Impossible to save tree with provided verbose name") + } } override fun loadByVerboseName(verboseName: String, factory: () -> BST): BST { - TODO("Not yet implemented") + try { + val file = File("app${sC}src${sC}main${sC}resources${sC}$verboseName.json") + val json = file.readText() + val serializableTree = gson.fromJson(json, SerializableTree::class.java) + return factory().apply { root = strategy.buildNode(serializableTree.root) } + } catch (e: Exception) { + throw IllegalArgumentException("Impossible to load tree with provided arguments") + } } override fun deleteByVerboseName(verboseName: String) { - TODO("Not yet implemented") + try { + val file = File("app${sC}src${sC}main${sC}resources${sC}$verboseName.json") + file.delete() + } catch (e: Exception) { + throw IllegalArgumentException("Impossible to delete tree with provided verbose name") + } } - } \ No newline at end of file From 619df6ac8d0805a0a45243be640b58a4f537a836 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sat, 29 Apr 2023 09:55:17 +0300 Subject: [PATCH 099/125] fix: Remove unnecessary gson dependecy --- app/build.gradle.kts | 1 - .../main/kotlin/app/model/repo/JsonRepo.kt | 24 +++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d6399b8..a1156b3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -35,7 +35,6 @@ dependencies { implementation("org.jetbrains.exposed", "exposed-core", "0.40.1") implementation("org.jetbrains.exposed", "exposed-dao", "0.40.1") implementation("org.jetbrains.exposed", "exposed-jdbc", "0.40.1") - implementation("com.google.code.gson:gson:2.10.1") } diff --git a/app/src/main/kotlin/app/model/repo/JsonRepo.kt b/app/src/main/kotlin/app/model/repo/JsonRepo.kt index 28f72ca..f7f4ede 100644 --- a/app/src/main/kotlin/app/model/repo/JsonRepo.kt +++ b/app/src/main/kotlin/app/model/repo/JsonRepo.kt @@ -4,8 +4,9 @@ import app.model.bst.BinarySearchTree import app.model.bst.node.BinTreeNode import app.model.repo.serialization.SerializableTree import app.model.repo.serialization.strategy.SerializationStrategy -import com.google.gson.Gson -import com.google.gson.GsonBuilder +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json import java.io.File class JsonRepo, @@ -13,13 +14,16 @@ class JsonRepo, BST : BinarySearchTree>( strategy: SerializationStrategy ) : Repository(strategy) { - private var builder: GsonBuilder = GsonBuilder() - private var gson: Gson = builder.create() - private val sC = File.separatorChar + private val savingDirectory: String + get() { + val sC = File.separatorChar + return "app${sC}src${sC}main${sC}resources${sC}" + } + override fun save(verboseName: String, tree: BST) { try { - val json = gson.toJson(tree.toSerializableTree(verboseName)) - val file = File("app${sC}src${sC}main${sC}resources${sC}$verboseName.json") + val json = Json.encodeToString(tree.toSerializableTree(verboseName)) + val file = File("$savingDirectory$verboseName.json") file.writeText(json) } catch (e: Exception) { throw IllegalArgumentException("Impossible to save tree with provided verbose name") @@ -28,9 +32,9 @@ class JsonRepo, override fun loadByVerboseName(verboseName: String, factory: () -> BST): BST { try { - val file = File("app${sC}src${sC}main${sC}resources${sC}$verboseName.json") + val file = File("$savingDirectory$verboseName.json") val json = file.readText() - val serializableTree = gson.fromJson(json, SerializableTree::class.java) + val serializableTree = Json.decodeFromString(json) return factory().apply { root = strategy.buildNode(serializableTree.root) } } catch (e: Exception) { throw IllegalArgumentException("Impossible to load tree with provided arguments") @@ -39,7 +43,7 @@ class JsonRepo, override fun deleteByVerboseName(verboseName: String) { try { - val file = File("app${sC}src${sC}main${sC}resources${sC}$verboseName.json") + val file = File("$savingDirectory$verboseName.json") file.delete() } catch (e: Exception) { throw IllegalArgumentException("Impossible to delete tree with provided verbose name") From 6390eecd1f06b51950f9a0d29b652a2460fa15c8 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 25 Apr 2023 19:16:47 +0300 Subject: [PATCH 100/125] fix: Add iterable interface --- app/src/main/kotlin/app/App.kt | 128 ++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/app/App.kt b/app/src/main/kotlin/app/App.kt index 192a445..262a013 100644 --- a/app/src/main/kotlin/app/App.kt +++ b/app/src/main/kotlin/app/App.kt @@ -1,5 +1,131 @@ package app +import app.model.bst.RBTree +import app.model.bst.node.RedBlackTreeNode +import app.model.repo.PostgresRepo +import app.model.repo.serialization.SerializableValue +import app.model.repo.serialization.strategy.RBTreeStrategy +import org.jetbrains.exposed.sql.Database +import kotlin.random.Random + fun main() { - println("Hello kotlin") + val tree = RBTree() + val rand = Random(0) + val values = List(10000) { rand.nextInt(1000) } + values.forEach { + tree.add(it) + } + + val saver = PostgresRepo( + RBTreeStrategy( + { SerializableValue(it.toString()) }, + { it.value.toInt() } + ), + Database.connect( + "jdbc:postgresql://localhost:5432/", + driver = "org.postgresql.Driver", + user = "postgres", + password = "password" + ) + ) + saver.save("tmp", tree) + val a = saver.loadByVerboseName("tmp", ::RBTree) + println(a.iterator().asSequence().toList() == values.sorted()) +} + +object TreePrinter { + /** + * Print a tree + * + * @param root + * tree root node + */ + fun , Node : RedBlackTreeNode> print(root: Node?) { + val lines: MutableList> = ArrayList() + var level: MutableList = ArrayList() + var next: MutableList = ArrayList() + level.add(root) + var nn = 1 + var widest = 0 + while (nn != 0) { + val line: MutableList = ArrayList() + nn = 0 + for (n in level) { + if (n == null) { + line.add(null) + next.add(null) + next.add(null) + } else { + val aa = "${n.value}${n.color}" + line.add(aa) + if (aa.length > widest) widest = aa.length + next.add(n.left as Node?) + next.add(n.right as Node?) + if (n.left != null) nn++ + if (n.right != null) nn++ + } + } + if (widest % 2 == 1) widest++ + lines.add(line) + val tmp = level + level = next + next = tmp + next.clear() + } + var perpiece = lines[lines.size - 1].size * (widest + 4) + for (i in lines.indices) { + val line = lines[i] + val hpw = Math.floor((perpiece / 2f).toDouble()).toInt() - 1 + if (i > 0) { + for (j in line.indices) { + + // split node + var c = ' ' + if (j % 2 == 1) { + if (line[j - 1] != null) { + c = if (line[j] != null) '┴' else '┘' + } else { + if (j < line.size && line[j] != null) c = '└' + } + } + print(c) + + // lines and spaces + if (line[j] == null) { + for (k in 0 until perpiece - 1) { + print(" ") + } + } else { + for (k in 0 until hpw) { + print(if (j % 2 == 0) " " else "─") + } + print(if (j % 2 == 0) "┌" else "┐") + for (k in 0 until hpw) { + print(if (j % 2 == 0) "─" else " ") + } + } + } + println() + } + + // print line of numbers + for (j in line.indices) { + var f = line[j] + if (f == null) f = "" + val gap1 = Math.ceil((perpiece / 2f - f.length / 2f).toDouble()).toInt() + val gap2 = Math.floor((perpiece / 2f - f.length / 2f).toDouble()).toInt() + + // a number + for (k in 0 until gap1) { + print(" ") + } + print(f) + for (k in 0 until gap2) { + print(" ") + } + } + println() + perpiece /= 2 + } + } } From caf71616e4193e9be569a4713905c434cbc90cec Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 25 Apr 2023 19:19:09 +0300 Subject: [PATCH 101/125] ci: Remove ktor task --- .github/workflows/ci.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b2d5ee6..86e5a00 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,16 +18,6 @@ jobs: - name: Run build with Gradle Wrapper run: ./gradlew build - - name: Create fat .jar file on main - if: ${{ github.ref == 'refs/heads/main' }} - run: ./gradlew app:buildFatJar - - - uses: actions/upload-artifact@v3 - if: ${{ github.ref == 'refs/heads/main' }} - with: - name: All in one jar - path: app/build/libs/app-all.jar - - uses: actions/upload-artifact@v3 if: ${{ github.ref == 'refs/heads/main' }} with: From d5ec647729f1372b2178f506699f26514170790d Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 25 Apr 2023 19:27:09 +0300 Subject: [PATCH 102/125] feat: Add graph drawing ui with scale, dragging etc. Co-authored-by: aartdem <96226530+aartdem@users.noreply.github.com> Co-authored-by: Andrei <15161335+therain7@users.noreply.github.com> --- app/build.gradle.kts | 65 +++--- app/src/main/kotlin/app/App.kt | 190 +++++++----------- app/src/main/kotlin/app/view/Graph.kt | 67 ++++++ app/src/main/kotlin/app/view/GraphLine.kt | 35 ++++ app/src/main/kotlin/app/view/GraphNode.kt | 65 ++++++ app/src/main/kotlin/app/view/GraphTree.kt | 45 +++++ app/src/main/kotlin/app/view/NodeText.kt | 25 +++ .../main/kotlin/app/view/Transformation.kt | 22 ++ app/src/main/kotlin/app/view/model/Node.kt | 35 ++++ settings.gradle.kts | 15 +- 10 files changed, 410 insertions(+), 154 deletions(-) create mode 100644 app/src/main/kotlin/app/view/Graph.kt create mode 100644 app/src/main/kotlin/app/view/GraphLine.kt create mode 100644 app/src/main/kotlin/app/view/GraphNode.kt create mode 100644 app/src/main/kotlin/app/view/GraphTree.kt create mode 100644 app/src/main/kotlin/app/view/NodeText.kt create mode 100644 app/src/main/kotlin/app/view/Transformation.kt create mode 100644 app/src/main/kotlin/app/view/model/Node.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a1156b3..0ad3b33 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,27 +1,18 @@ +import org.jetbrains.compose.desktop.application.dsl.TargetFormat + + +repositories { + mavenCentral() + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") + google() +} + plugins { kotlin("jvm") version "1.8.20" + id("org.jetbrains.compose") version "1.4.0" kotlin("plugin.serialization") version "1.8.20" - id("io.ktor.plugin") version "2.2.4" id("jacoco") id("org.jetbrains.kotlin.plugin.noarg") version "1.8.20" - - application -} -jacoco { - toolVersion = "0.8.7" - reportsDirectory.set(layout.buildDirectory.dir("coverage")) - -} -tasks.withType { - reports { - xml.required.set(true) - csv.required.set(true) - html.required.set(true) - } -} - -repositories { - mavenCentral() } dependencies { @@ -30,12 +21,27 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter") implementation("org.neo4j:neo4j-ogm-core:4.0.5") runtimeOnly("org.neo4j:neo4j-ogm-bolt-driver:4.0.5") - implementation("org.postgresql:postgresql:42.6.0") + implementation("org.postgresql:postgresql:42.5.4") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") implementation("org.jetbrains.exposed", "exposed-core", "0.40.1") implementation("org.jetbrains.exposed", "exposed-dao", "0.40.1") implementation("org.jetbrains.exposed", "exposed-jdbc", "0.40.1") + implementation(compose.desktop.currentOs) + implementation(compose.material3) + implementation(compose.materialIconsExtended) +} +jacoco { + toolVersion = "0.8.7" + reportsDirectory.set(layout.buildDirectory.dir("coverage")) +} + +tasks.withType { + reports { + xml.required.set(true) + csv.required.set(true) + html.required.set(true) + } } tasks.test { @@ -43,18 +49,19 @@ tasks.test { finalizedBy(tasks.jacocoTestReport) } -tasks.jar { - manifest.attributes["Main-Class"] = "app.AppKt" -} noArg { annotation("org.neo4j.ogm.annotation.NodeEntity") annotation("org.neo4j.ogm.annotation.RelationshipEntity") } -kotlin { - jvmToolchain(8) -} -application { - // Define the main class for the application. - mainClass.set("app.AppKt") +compose.desktop { + application { + mainClass = "app.AppKt" + + nativeDistributions { + targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) + packageName = "trees-visualizer" + packageVersion = "1.0.0" + } + } } diff --git a/app/src/main/kotlin/app/App.kt b/app/src/main/kotlin/app/App.kt index 262a013..ef9b68d 100644 --- a/app/src/main/kotlin/app/App.kt +++ b/app/src/main/kotlin/app/App.kt @@ -1,131 +1,87 @@ -package app - -import app.model.bst.RBTree -import app.model.bst.node.RedBlackTreeNode -import app.model.repo.PostgresRepo -import app.model.repo.serialization.SerializableValue -import app.model.repo.serialization.strategy.RBTreeStrategy -import org.jetbrains.exposed.sql.Database -import kotlin.random.Random +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.runtime.remember +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.unit.dp +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 app.view.Graph +import app.view.model.Node +import java.awt.Dimension fun main() { - val tree = RBTree() - val rand = Random(0) - val values = List(10000) { rand.nextInt(1000) } - values.forEach { - tree.add(it) - } - - val saver = PostgresRepo( - RBTreeStrategy( - { SerializableValue(it.toString()) }, - { it.value.toInt() } - ), - Database.connect( - "jdbc:postgresql://localhost:5432/", - driver = "org.postgresql.Driver", - user = "postgres", - password = "password" - ) - ) - saver.save("tmp", tree) - val a = saver.loadByVerboseName("tmp", ::RBTree) - println(a.iterator().asSequence().toList() == values.sorted()) -} + application { + Window( + onCloseRequest = ::exitApplication, + title = "graph visualizer", + state = rememberWindowState( + position = WindowPosition(alignment = Alignment.Center), + size = DpSize(800.dp, 800.dp), + ), + ) { + window.minimumSize = Dimension(800, 800) + MaterialTheme( + colorScheme = MaterialTheme.colorScheme.copy( + surface = Color(red = 235, green = 235, blue = 237) + ) + ) { + val tree = remember { getTree() } + Box(Modifier.fillMaxSize().background(MaterialTheme.colorScheme.surface)) { + Row( + modifier = Modifier.padding(20.dp) + ) { + Surface( + modifier = Modifier.fillMaxSize().weight(4f).padding( + 1.dp + ), + shape = MaterialTheme.shapes.medium, + color = Color.White + ) { + Graph(tree, 50.dp) + } -object TreePrinter { - /** - * Print a tree - * - * @param root - * tree root node - */ - fun , Node : RedBlackTreeNode> print(root: Node?) { - val lines: MutableList> = ArrayList() - var level: MutableList = ArrayList() - var next: MutableList = ArrayList() - level.add(root) - var nn = 1 - var widest = 0 - while (nn != 0) { - val line: MutableList = ArrayList() - nn = 0 - for (n in level) { - if (n == null) { - line.add(null) - next.add(null) - next.add(null) - } else { - val aa = "${n.value}${n.color}" - line.add(aa) - if (aa.length > widest) widest = aa.length - next.add(n.left as Node?) - next.add(n.right as Node?) - if (n.left != null) nn++ - if (n.right != null) nn++ + } } + } - if (widest % 2 == 1) widest++ - lines.add(line) - val tmp = level - level = next - next = tmp - next.clear() } - var perpiece = lines[lines.size - 1].size * (widest + 4) - for (i in lines.indices) { - val line = lines[i] - val hpw = Math.floor((perpiece / 2f).toDouble()).toInt() - 1 - if (i > 0) { - for (j in line.indices) { + } +} - // split node - var c = ' ' - if (j % 2 == 1) { - if (line[j - 1] != null) { - c = if (line[j] != null) '┴' else '┘' - } else { - if (j < line.size && line[j] != null) c = '└' - } - } - print(c) +fun getTree(): Node { + var x = 10.dp + val root = Node("abc", x, 150.dp) - // lines and spaces - if (line[j] == null) { - for (k in 0 until perpiece - 1) { - print(" ") - } - } else { - for (k in 0 until hpw) { - print(if (j % 2 == 0) " " else "─") - } - print(if (j % 2 == 0) "┌" else "┐") - for (k in 0 until hpw) { - print(if (j % 2 == 0) "─" else " ") - } - } - } - println() - } - // print line of numbers - for (j in line.indices) { - var f = line[j] - if (f == null) f = "" - val gap1 = Math.ceil((perpiece / 2f - f.length / 2f).toDouble()).toInt() - val gap2 = Math.floor((perpiece / 2f - f.length / 2f).toDouble()).toInt() + var cur = root + var side = "left" + for (i in 1..100) { + x += 100.dp + when (side) { + "left" -> { + cur.left = Node("$i", x, 150.dp) + cur = cur.left!! + side = "right" + } - // a number - for (k in 0 until gap1) { - print(" ") - } - print(f) - for (k in 0 until gap2) { - print(" ") - } + "right" -> { + cur.right = Node("$i", x, 150.dp) + cur = cur.right!! + side = "left" } - println() - perpiece /= 2 } } + + return root } + diff --git a/app/src/main/kotlin/app/view/Graph.kt b/app/src/main/kotlin/app/view/Graph.kt new file mode 100644 index 0000000..8e5f814 --- /dev/null +++ b/app/src/main/kotlin/app/view/Graph.kt @@ -0,0 +1,67 @@ +package app.view + +import androidx.compose.foundation.gestures.detectDragGestures +import androidx.compose.foundation.layout.* +import androidx.compose.material3.* +import androidx.compose.material3.ButtonDefaults.textButtonColors +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.input.pointer.PointerEventType +import androidx.compose.ui.input.pointer.onPointerEvent +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex +import app.view.model.Node +import kotlin.math.max +import kotlin.math.min + + +@OptIn(ExperimentalComposeUiApi::class) +@Composable +fun Graph(root: Node, nodeSize: Dp) { + val screenDrag = remember { ScreenDrag(0f, 0f) } + val screenScale = remember { ScreenScale(1f, Offset(0f, 0f)) } + + Box(modifier = Modifier.fillMaxSize().onPointerEvent(PointerEventType.Scroll) { + screenDrag.x -= it.changes.first().scrollDelta.x * 50 // let's scroll faster brbrbr + + val scrollPos = it.changes.first().position + val prevScale = screenScale.scale + screenScale.scale = min( + max( + screenScale.scale - it.changes.first().scrollDelta.y / 15, // let's zoom slower + 0.5f // min scale + ), 2f // max scale + ) + + val relScale = screenScale.scale / prevScale + screenScale.posRelXYScale = Offset( + screenScale.posRelXYScale.x * relScale + scrollPos.x * (1 - relScale), + screenScale.posRelXYScale.y * relScale + scrollPos.y * (1 - relScale) + ) + }.pointerInput(Unit) { + detectDragGestures { change, dragAmount -> + change.consume() + screenDrag.x += dragAmount.x / screenScale.scale + screenDrag.y += dragAmount.y / screenScale.scale + } + }) { + Tree( + rootNode = root, screenDrag = screenDrag, screenScale = screenScale, nodeSize = nodeSize + ) + TextButton( + modifier = Modifier.align(Alignment.TopEnd).zIndex(3f).padding(5.dp), onClick = { + screenScale.scale = 1f + screenScale.posRelXYScale = Offset(0f, 0f) + screenDrag.x = 0f + screenDrag.y = 0f + }, colors = textButtonColors( + containerColor = MaterialTheme.colorScheme.surface + ) + ) { Text("Reset view", color = MaterialTheme.colorScheme.primary) } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/GraphLine.kt b/app/src/main/kotlin/app/view/GraphLine.kt new file mode 100644 index 0000000..dfa975e --- /dev/null +++ b/app/src/main/kotlin/app/view/GraphLine.kt @@ -0,0 +1,35 @@ +package app.view + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +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.model.Node + +@Composable +fun GraphLine( + modifier: Modifier = Modifier, + start: Node, + end: Node, + nodeSize: Dp, + screenDrag: ScreenDrag, + screenScale: ScreenScale +) { + Canvas(modifier = modifier.fillMaxSize()) { + drawLine( + start = Offset( + ((start.x + nodeSize / 2).toPx() + screenDrag.x) * screenScale.scale + screenScale.posRelXYScale.x, + ((start.y + nodeSize / 2).toPx() + screenDrag.y) * screenScale.scale + screenScale.posRelXYScale.y, + ), + end = Offset( + ((end.x + nodeSize / 2).toPx() + screenDrag.x) * screenScale.scale + screenScale.posRelXYScale.x, + ((end.y + nodeSize / 2).toPx() + screenDrag.y) * screenScale.scale + screenScale.posRelXYScale.y, + ), + strokeWidth = 2f * screenScale.scale, + color = Color.Black + ) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/GraphNode.kt b/app/src/main/kotlin/app/view/GraphNode.kt new file mode 100644 index 0000000..4257392 --- /dev/null +++ b/app/src/main/kotlin/app/view/GraphNode.kt @@ -0,0 +1,65 @@ +package app.view + +import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.detectDragGestures +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.layout.Measurable +import androidx.compose.ui.layout.layout +import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex +import app.view.model.Node +import kotlin.math.roundToInt + +@Composable +fun GraphNode( + modifier: Modifier = Modifier, + node: Node, + nodeSize: Dp = 50.dp, + screenDrag: ScreenDrag, + screenScale: ScreenScale +) { + Box(modifier = modifier + .zIndex(2f) + .layout { measurable: Measurable, _: Constraints -> + val placeable = measurable.measure( + Constraints.fixed( + (nodeSize * screenScale.scale).roundToPx(), + (nodeSize * screenScale.scale).roundToPx() + ) + ) + + layout(placeable.width, placeable.height) { + placeable.placeRelative( + ((node.x.toPx() + screenDrag.x) * screenScale.scale + screenScale.posRelXYScale.x).roundToInt(), + ((node.y.toPx() + screenDrag.y) * screenScale.scale + screenScale.posRelXYScale.y).roundToInt(), + ) + } + } + .background( + color = MaterialTheme.colorScheme.primary, + shape = CircleShape + ) + + .pointerInput(node.value, screenScale) { + detectDragGestures { change, dragAmount -> + change.consume() + node.x += (dragAmount.x / screenScale.scale).toDp() + node.y += (dragAmount.y / screenScale.scale).toDp() + } + } + ) { + NodeText( + modifier = Modifier.align(Alignment.Center), + text = node.value, + scaleProvider = { screenScale.scale } + ) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/GraphTree.kt b/app/src/main/kotlin/app/view/GraphTree.kt new file mode 100644 index 0000000..91f618f --- /dev/null +++ b/app/src/main/kotlin/app/view/GraphTree.kt @@ -0,0 +1,45 @@ +package app.view + +import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.Dp +import app.view.model.Node + + +@Composable +fun Tree( + rootNode: Node?, + nodeSize: Dp, + screenDrag: ScreenDrag, + screenScale: ScreenScale, +) { + val stack = mutableListOf() + stack.add(rootNode) + var currentParent: Node? = null + + while (stack.isNotEmpty()) { + val currentNode = stack.removeLast() + + currentNode?.let { node -> + currentParent?.let { parent -> + GraphLine( + start = parent, + end = node, + nodeSize = nodeSize, + screenDrag = screenDrag, + screenScale = screenScale + ) + } + + stack.add(node.right) + stack.add(node.left) + currentParent = node + + GraphNode( + node = node, + screenDrag = screenDrag, + screenScale = screenScale, + nodeSize = nodeSize + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/NodeText.kt b/app/src/main/kotlin/app/view/NodeText.kt new file mode 100644 index 0000000..173cbe3 --- /dev/null +++ b/app/src/main/kotlin/app/view/NodeText.kt @@ -0,0 +1,25 @@ +package app.view + +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle + +@Composable +fun NodeText( + modifier: Modifier = Modifier, + text: String, + scaleProvider: () -> Float, + style: TextStyle = MaterialTheme.typography.bodyMedium, +) { + Text( + modifier = modifier, + text = text, + color = MaterialTheme.colorScheme.onPrimary, + style = style.copy( + fontSize = style.fontSize * scaleProvider(), + lineHeight = style.lineHeight * scaleProvider() + ) + ) +} diff --git a/app/src/main/kotlin/app/view/Transformation.kt b/app/src/main/kotlin/app/view/Transformation.kt new file mode 100644 index 0000000..6f2689e --- /dev/null +++ b/app/src/main/kotlin/app/view/Transformation.kt @@ -0,0 +1,22 @@ +package app.view + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.geometry.Offset + +class ScreenDrag( + x: Float, + y: Float +) { + var x by mutableStateOf(x) + var y by mutableStateOf(y) +} + +class ScreenScale( + scale: Float, + posRelScale: Offset +) { + var scale by mutableStateOf(scale) + var posRelXYScale by mutableStateOf(posRelScale) +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/model/Node.kt b/app/src/main/kotlin/app/view/model/Node.kt new file mode 100644 index 0000000..efdf101 --- /dev/null +++ b/app/src/main/kotlin/app/view/model/Node.kt @@ -0,0 +1,35 @@ +package app.view.model + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.unit.Dp + + +class Node( + val value: String, + x: Dp, + y: Dp, + left: Node? = null, + right: Node? = null +) { + var x by mutableStateOf(x) + var y by mutableStateOf(y) + var left by mutableStateOf(left) + var right by mutableStateOf(right) + + override fun toString(): String = value + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Node) return false + + return hashCode() == other.hashCode() + } + + override fun hashCode(): Int { + var result = value.hashCode() + result = 31 * result + (left?.hashCode() ?: 0) + result = 31 * result + (right?.hashCode() ?: 0) + return result + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index a394eca..42b3f29 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,11 +1,10 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * The settings file is used to specify which projects to include in your build. - * - * Detailed information about configuring a multi-project build in Gradle can be found - * in the user manual at https://docs.gradle.org/7.2/userguide/multi_project_builds.html - */ +pluginManagement { + repositories { + gradlePluginPortal() + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") + } +} rootProject.name = "trees-4" + include("app") \ No newline at end of file From a5b6be2bde04994f342863b40eab3ff95e538e65 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sun, 30 Apr 2023 13:12:57 +0300 Subject: [PATCH 103/125] struct: Move all graph things to one folder --- .../main/kotlin/app/view/{ => graph}/Graph.kt | 23 ++++--------------- .../kotlin/app/view/{ => graph}/GraphLine.kt | 4 +++- .../kotlin/app/view/{ => graph}/GraphNode.kt | 5 +++- .../kotlin/app/view/{ => graph}/GraphTree.kt | 4 +++- 4 files changed, 15 insertions(+), 21 deletions(-) rename app/src/main/kotlin/app/view/{ => graph}/Graph.kt (68%) rename app/src/main/kotlin/app/view/{ => graph}/GraphLine.kt (93%) rename app/src/main/kotlin/app/view/{ => graph}/GraphNode.kt (95%) rename app/src/main/kotlin/app/view/{ => graph}/GraphTree.kt (93%) diff --git a/app/src/main/kotlin/app/view/Graph.kt b/app/src/main/kotlin/app/view/graph/Graph.kt similarity index 68% rename from app/src/main/kotlin/app/view/Graph.kt rename to app/src/main/kotlin/app/view/graph/Graph.kt index 8e5f814..4b0ffe7 100644 --- a/app/src/main/kotlin/app/view/Graph.kt +++ b/app/src/main/kotlin/app/view/graph/Graph.kt @@ -1,11 +1,9 @@ -package app.view +package app.view.graph import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.* import androidx.compose.material3.* -import androidx.compose.material3.ButtonDefaults.textButtonColors import androidx.compose.runtime.* -import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset @@ -13,8 +11,8 @@ import androidx.compose.ui.input.pointer.PointerEventType import androidx.compose.ui.input.pointer.onPointerEvent import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import androidx.compose.ui.zIndex +import app.view.ScreenDrag +import app.view.ScreenScale import app.view.model.Node import kotlin.math.max import kotlin.math.min @@ -22,9 +20,8 @@ import kotlin.math.min @OptIn(ExperimentalComposeUiApi::class) @Composable -fun Graph(root: Node, nodeSize: Dp) { - val screenDrag = remember { ScreenDrag(0f, 0f) } - val screenScale = remember { ScreenScale(1f, Offset(0f, 0f)) } +fun Graph(root: Node, nodeSize: Dp, screenDrag: ScreenDrag, screenScale: ScreenScale) { + Box(modifier = Modifier.fillMaxSize().onPointerEvent(PointerEventType.Scroll) { screenDrag.x -= it.changes.first().scrollDelta.x * 50 // let's scroll faster brbrbr @@ -53,15 +50,5 @@ fun Graph(root: Node, nodeSize: Dp) { Tree( rootNode = root, screenDrag = screenDrag, screenScale = screenScale, nodeSize = nodeSize ) - TextButton( - modifier = Modifier.align(Alignment.TopEnd).zIndex(3f).padding(5.dp), onClick = { - screenScale.scale = 1f - screenScale.posRelXYScale = Offset(0f, 0f) - screenDrag.x = 0f - screenDrag.y = 0f - }, colors = textButtonColors( - containerColor = MaterialTheme.colorScheme.surface - ) - ) { Text("Reset view", color = MaterialTheme.colorScheme.primary) } } } \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/GraphLine.kt b/app/src/main/kotlin/app/view/graph/GraphLine.kt similarity index 93% rename from app/src/main/kotlin/app/view/GraphLine.kt rename to app/src/main/kotlin/app/view/graph/GraphLine.kt index dfa975e..8ba911f 100644 --- a/app/src/main/kotlin/app/view/GraphLine.kt +++ b/app/src/main/kotlin/app/view/graph/GraphLine.kt @@ -1,4 +1,4 @@ -package app.view +package app.view.graph import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.fillMaxSize @@ -7,6 +7,8 @@ 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.ScreenDrag +import app.view.ScreenScale import app.view.model.Node @Composable diff --git a/app/src/main/kotlin/app/view/GraphNode.kt b/app/src/main/kotlin/app/view/graph/GraphNode.kt similarity index 95% rename from app/src/main/kotlin/app/view/GraphNode.kt rename to app/src/main/kotlin/app/view/graph/GraphNode.kt index 4257392..9f1d8ae 100644 --- a/app/src/main/kotlin/app/view/GraphNode.kt +++ b/app/src/main/kotlin/app/view/graph/GraphNode.kt @@ -1,4 +1,4 @@ -package app.view +package app.view.graph import androidx.compose.foundation.background import androidx.compose.foundation.gestures.detectDragGestures @@ -15,6 +15,9 @@ import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex +import app.view.NodeText +import app.view.ScreenDrag +import app.view.ScreenScale import app.view.model.Node import kotlin.math.roundToInt diff --git a/app/src/main/kotlin/app/view/GraphTree.kt b/app/src/main/kotlin/app/view/graph/GraphTree.kt similarity index 93% rename from app/src/main/kotlin/app/view/GraphTree.kt rename to app/src/main/kotlin/app/view/graph/GraphTree.kt index 91f618f..69ccf35 100644 --- a/app/src/main/kotlin/app/view/GraphTree.kt +++ b/app/src/main/kotlin/app/view/graph/GraphTree.kt @@ -1,7 +1,9 @@ -package app.view +package app.view.graph import androidx.compose.runtime.Composable import androidx.compose.ui.unit.Dp +import app.view.ScreenDrag +import app.view.ScreenScale import app.view.model.Node From b8c09e5742ee13c9a9d061dc62d6051656125608 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Sun, 30 Apr 2023 13:13:43 +0300 Subject: [PATCH 104/125] feat: Add dropdown menu for tree operations --- app/src/main/kotlin/app/App.kt | 168 ++++++++++++++++++++++++++++----- 1 file changed, 144 insertions(+), 24 deletions(-) diff --git a/app/src/main/kotlin/app/App.kt b/app/src/main/kotlin/app/App.kt index ef9b68d..ec1c853 100644 --- a/app/src/main/kotlin/app/App.kt +++ b/app/src/main/kotlin/app/App.kt @@ -1,21 +1,26 @@ import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.runtime.remember +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Remove +import androidx.compose.material.icons.filled.Search +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp -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 app.view.Graph +import androidx.compose.ui.window.* +import app.view.ScreenDrag +import app.view.ScreenScale +import app.view.graph.Graph import app.view.model.Node import java.awt.Dimension @@ -36,26 +41,123 @@ fun main() { ) ) { val tree = remember { getTree() } + val screenDrag = remember { ScreenDrag(0f, 0f) } + val screenScale = remember { ScreenScale(1f, Offset(0f, 0f)) } + + Box(Modifier.fillMaxSize().background(MaterialTheme.colorScheme.surface)) { - Row( - modifier = Modifier.padding(20.dp) - ) { - Surface( - modifier = Modifier.fillMaxSize().weight(4f).padding( - 1.dp - ), - shape = MaterialTheme.shapes.medium, - color = Color.White - ) { - Graph(tree, 50.dp) - } + Graph(tree, 50.dp, screenDrag, screenScale) + GraphControls( + Modifier.padding(10.dp).align(Alignment.TopEnd).clip( + RoundedCornerShape(10.dp) + ).background(Color.LightGray), screenDrag, screenScale + ) + } + } + } + } +} + + +@Composable +fun GraphControls(modifier: Modifier, screenDrag: ScreenDrag, screenScale: ScreenScale) { + Box(modifier) { + Column(Modifier.padding(10.dp).width(210.dp).verticalScroll(rememberScrollState())) { + HiddenSettings( + "Tree operations", + hidden = false + ) { + Column { + InputField({ print(it) }, Icons.Default.Add) + InputField({ print(it) }, Icons.Default.Remove) + InputField({ print(it) }, Icons.Default.Search) + } + } + HiddenSettings( + "Save tree to...", + hidden = true + ) { + Column { + Button( + {}, Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Json") + } + Button( + {}, Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Neo4j") + } + Button( + {}, Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Postgresql") } } + } + + HiddenSettings( + "Load tree from...", + hidden = true + ) { + Column { + Button( + {}, Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Json") + } + Button( + {}, Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Neo4j") + } + Button( + {}, Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Postgresql") + } + } } } } + +} + + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun InputField(action: (String) -> Unit, icon: ImageVector) { + var text by remember { mutableStateOf("") } + + Row(Modifier.padding(5.dp)) { + OutlinedTextField( + value = text, + onValueChange = { text = it }, + modifier = Modifier.width(150.dp).height(50.dp).padding(end = 5.dp), + ) + IconButton( + onClick = { action(text) }, + modifier = Modifier.background( + color = MaterialTheme.colorScheme.tertiary, + shape = RoundedCornerShape(8.dp) + ).size(50.dp), + content = { + Icon( + imageVector = icon, + contentDescription = null, + tint = Color.White + ) + } + ) + } } fun getTree(): Node { @@ -85,3 +187,21 @@ fun getTree(): Node { return root } +@Composable +fun HiddenSettings(text: String, hidden: Boolean = true, content: @Composable () -> Unit) { + var expanded by remember { mutableStateOf(!hidden) } + + Button( + modifier = Modifier.fillMaxWidth(), + onClick = { expanded = !expanded } + ) { + Text(text) + } + + Row(verticalAlignment = Alignment.CenterVertically) { + if (expanded) { + content() + + } + } +} \ No newline at end of file From 5b95a05f6d082d423c35980fbcf8dcceab298a65 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 2 May 2023 12:54:13 +0300 Subject: [PATCH 105/125] feat: Add `add`, `remove` oprations for trees --- app/src/main/kotlin/app/App.kt | 164 +++++++++--------- app/src/main/kotlin/app/view/Constants.kt | 5 + app/src/main/kotlin/app/view/DrawableNode.kt | 23 +++ app/src/main/kotlin/app/view/graph/Graph.kt | 7 +- .../main/kotlin/app/view/graph/GraphLine.kt | 17 +- .../main/kotlin/app/view/graph/GraphNode.kt | 17 +- .../main/kotlin/app/view/graph/GraphTree.kt | 44 ++--- app/src/main/kotlin/app/view/model/Node.kt | 35 ---- .../main/kotlin/app/view/model/TreeEditor.kt | 122 +++++++++++++ 9 files changed, 266 insertions(+), 168 deletions(-) create mode 100644 app/src/main/kotlin/app/view/Constants.kt create mode 100644 app/src/main/kotlin/app/view/DrawableNode.kt delete mode 100644 app/src/main/kotlin/app/view/model/Node.kt create mode 100644 app/src/main/kotlin/app/view/model/TreeEditor.kt diff --git a/app/src/main/kotlin/app/App.kt b/app/src/main/kotlin/app/App.kt index ec1c853..ff3a97f 100644 --- a/app/src/main/kotlin/app/App.kt +++ b/app/src/main/kotlin/app/App.kt @@ -1,3 +1,4 @@ + import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState @@ -18,10 +19,10 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.window.* -import app.view.ScreenDrag -import app.view.ScreenScale +import app.view.* import app.view.graph.Graph -import app.view.model.Node +import app.view.model.AVLTreeEditor +import app.view.model.TreeEditor import java.awt.Dimension fun main() { @@ -40,59 +41,101 @@ fun main() { surface = Color(red = 235, green = 235, blue = 237) ) ) { - val tree = remember { getTree() } - val screenDrag = remember { ScreenDrag(0f, 0f) } - val screenScale = remember { ScreenScale(1f, Offset(0f, 0f)) } - - - Box(Modifier.fillMaxSize().background(MaterialTheme.colorScheme.surface)) { - Graph(tree, 50.dp, screenDrag, screenScale) - GraphControls( - Modifier.padding(10.dp).align(Alignment.TopEnd).clip( - RoundedCornerShape(10.dp) - ).background(Color.LightGray), screenDrag, screenScale - ) - } + TreeEditorView( + AVLTreeEditor() + ) } } } } +class DrawableTree( + root: DrawableNode? +) { + var root by mutableStateOf(root) +} + +@Composable +fun TreeEditorView(editor: TreeEditor<*, *>) { + val drawableTree by remember { + mutableStateOf( + DrawableTree( + null + ) + ) + } + + val screenDrag = remember { ScreenDrag(0f, 0f) } + val screenScale = remember { ScreenScale(1f, Offset(0f, 0f)) } + + Box(Modifier.fillMaxSize().background(MaterialTheme.colorScheme.surface)) { + Graph(drawableTree, screenDrag, screenScale) + GraphControls( + editor, drawableTree, Modifier.padding(10.dp).align(Alignment.TopEnd).clip( + RoundedCornerShape(10.dp) + ).background(Color.LightGray), screenDrag, screenScale + ) + } +} + @Composable -fun GraphControls(modifier: Modifier, screenDrag: ScreenDrag, screenScale: ScreenScale) { +fun GraphControls( + editor: TreeEditor<*, *>, tree: DrawableTree?, modifier: Modifier, screenDrag: ScreenDrag, screenScale: ScreenScale +) { Box(modifier) { Column(Modifier.padding(10.dp).width(210.dp).verticalScroll(rememberScrollState())) { HiddenSettings( - "Tree operations", - hidden = false + "Tree operations", hidden = false ) { Column { - InputField({ print(it) }, Icons.Default.Add) - InputField({ print(it) }, Icons.Default.Remove) + InputField({ tree?.root = editor.addToTree(it) }, Icons.Default.Add) + InputField({ tree?.root = editor.removeFromTree(it) }, Icons.Default.Remove) InputField({ print(it) }, Icons.Default.Search) + Row { + Button( + { + + }, + Modifier.weight(1f).fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Reset view") + } + Button( + { + editor.resetCoordinates(tree?.root) + }, + Modifier.weight(1f).fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Reset tree") + } + } } } HiddenSettings( - "Save tree to...", - hidden = true + "Save tree to...", hidden = true ) { Column { Button( - {}, Modifier.fillMaxWidth(), + {}, + Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) ) { Text("Json") } Button( - {}, Modifier.fillMaxWidth(), + {}, + Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) ) { Text("Neo4j") } Button( - {}, Modifier.fillMaxWidth(), + {}, + Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) ) { Text("Postgresql") @@ -102,24 +145,28 @@ fun GraphControls(modifier: Modifier, screenDrag: ScreenDrag, screenScale: Scree HiddenSettings( - "Load tree from...", - hidden = true + "Load tree from...", hidden = true ) { Column { Button( - {}, Modifier.fillMaxWidth(), + {}, + Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) ) { Text("Json") } Button( - {}, Modifier.fillMaxWidth(), + {}, + Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) ) { Text("Neo4j") } Button( - {}, Modifier.fillMaxWidth(), + { + + }, + Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) ) { Text("Postgresql") @@ -128,7 +175,6 @@ fun GraphControls(modifier: Modifier, screenDrag: ScreenDrag, screenScale: Scree } } } - } @@ -143,65 +189,27 @@ fun InputField(action: (String) -> Unit, icon: ImageVector) { onValueChange = { text = it }, modifier = Modifier.width(150.dp).height(50.dp).padding(end = 5.dp), ) - IconButton( - onClick = { action(text) }, - modifier = Modifier.background( - color = MaterialTheme.colorScheme.tertiary, - shape = RoundedCornerShape(8.dp) - ).size(50.dp), - content = { - Icon( - imageVector = icon, - contentDescription = null, - tint = Color.White - ) - } - ) + IconButton(onClick = { action(text) }, modifier = Modifier.background( + color = MaterialTheme.colorScheme.tertiary, shape = RoundedCornerShape(8.dp) + ).size(50.dp), content = { + Icon( + imageVector = icon, contentDescription = null, tint = Color.White + ) + }) } } -fun getTree(): Node { - var x = 10.dp - val root = Node("abc", x, 150.dp) - - - var cur = root - var side = "left" - for (i in 1..100) { - x += 100.dp - when (side) { - "left" -> { - cur.left = Node("$i", x, 150.dp) - cur = cur.left!! - side = "right" - } - - "right" -> { - cur.right = Node("$i", x, 150.dp) - cur = cur.right!! - side = "left" - } - } - } - - return root -} - @Composable fun HiddenSettings(text: String, hidden: Boolean = true, content: @Composable () -> Unit) { var expanded by remember { mutableStateOf(!hidden) } - Button( - modifier = Modifier.fillMaxWidth(), - onClick = { expanded = !expanded } - ) { + Button(modifier = Modifier.fillMaxWidth(), onClick = { expanded = !expanded }) { Text(text) } Row(verticalAlignment = Alignment.CenterVertically) { if (expanded) { content() - } } } \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/Constants.kt b/app/src/main/kotlin/app/view/Constants.kt new file mode 100644 index 0000000..3374a81 --- /dev/null +++ b/app/src/main/kotlin/app/view/Constants.kt @@ -0,0 +1,5 @@ +package app.view + +import androidx.compose.ui.unit.dp + +val defaultNodeSize = 50.dp \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/DrawableNode.kt b/app/src/main/kotlin/app/view/DrawableNode.kt new file mode 100644 index 0000000..a3c11ca --- /dev/null +++ b/app/src/main/kotlin/app/view/DrawableNode.kt @@ -0,0 +1,23 @@ +package app.view + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + + +class DrawableNode( + val value: String, + x: Dp = 0.dp, + y: Dp = 0.dp, + left: DrawableNode? = null, + right: DrawableNode? = null, + val color: Color = Color.DarkGray +) { + var x by mutableStateOf(x) + var y by mutableStateOf(y) + var left by mutableStateOf(left) + var right by mutableStateOf(right) +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/graph/Graph.kt b/app/src/main/kotlin/app/view/graph/Graph.kt index 4b0ffe7..4fdc948 100644 --- a/app/src/main/kotlin/app/view/graph/Graph.kt +++ b/app/src/main/kotlin/app/view/graph/Graph.kt @@ -1,5 +1,6 @@ package app.view.graph +import DrawableTree import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.* import androidx.compose.material3.* @@ -10,17 +11,15 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.pointer.PointerEventType import androidx.compose.ui.input.pointer.onPointerEvent import androidx.compose.ui.input.pointer.pointerInput -import androidx.compose.ui.unit.Dp import app.view.ScreenDrag import app.view.ScreenScale -import app.view.model.Node import kotlin.math.max import kotlin.math.min @OptIn(ExperimentalComposeUiApi::class) @Composable -fun Graph(root: Node, nodeSize: Dp, screenDrag: ScreenDrag, screenScale: ScreenScale) { +fun Graph(root: DrawableTree?, screenDrag: ScreenDrag, screenScale: ScreenScale) { Box(modifier = Modifier.fillMaxSize().onPointerEvent(PointerEventType.Scroll) { @@ -48,7 +47,7 @@ fun Graph(root: Node, nodeSize: Dp, screenDrag: ScreenDrag, screenScale: ScreenS } }) { Tree( - rootNode = root, screenDrag = screenDrag, screenScale = screenScale, nodeSize = nodeSize + rootNode = root?.root, screenDrag = screenDrag, screenScale = screenScale ) } } \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/graph/GraphLine.kt b/app/src/main/kotlin/app/view/graph/GraphLine.kt index 8ba911f..1b9e177 100644 --- a/app/src/main/kotlin/app/view/graph/GraphLine.kt +++ b/app/src/main/kotlin/app/view/graph/GraphLine.kt @@ -6,29 +6,28 @@ import androidx.compose.runtime.Composable 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.DrawableNode import app.view.ScreenDrag import app.view.ScreenScale -import app.view.model.Node +import app.view.defaultNodeSize @Composable fun GraphLine( modifier: Modifier = Modifier, - start: Node, - end: Node, - nodeSize: Dp, + start: DrawableNode, + end: DrawableNode, screenDrag: ScreenDrag, screenScale: ScreenScale ) { Canvas(modifier = modifier.fillMaxSize()) { drawLine( start = Offset( - ((start.x + nodeSize / 2).toPx() + screenDrag.x) * screenScale.scale + screenScale.posRelXYScale.x, - ((start.y + nodeSize / 2).toPx() + screenDrag.y) * screenScale.scale + screenScale.posRelXYScale.y, + ((start.x + defaultNodeSize / 2).toPx() + screenDrag.x) * screenScale.scale + screenScale.posRelXYScale.x, + ((start.y + defaultNodeSize / 2).toPx() + screenDrag.y) * screenScale.scale + screenScale.posRelXYScale.y, ), end = Offset( - ((end.x + nodeSize / 2).toPx() + screenDrag.x) * screenScale.scale + screenScale.posRelXYScale.x, - ((end.y + nodeSize / 2).toPx() + screenDrag.y) * screenScale.scale + screenScale.posRelXYScale.y, + ((end.x + defaultNodeSize / 2).toPx() + screenDrag.x) * screenScale.scale + screenScale.posRelXYScale.x, + ((end.y + defaultNodeSize / 2).toPx() + screenDrag.y) * screenScale.scale + screenScale.posRelXYScale.y, ), strokeWidth = 2f * screenScale.scale, color = Color.Black diff --git a/app/src/main/kotlin/app/view/graph/GraphNode.kt b/app/src/main/kotlin/app/view/graph/GraphNode.kt index 9f1d8ae..e710e16 100644 --- a/app/src/main/kotlin/app/view/graph/GraphNode.kt +++ b/app/src/main/kotlin/app/view/graph/GraphNode.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.Box import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -12,20 +11,14 @@ import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.Measurable import androidx.compose.ui.layout.layout import androidx.compose.ui.unit.Constraints -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex -import app.view.NodeText -import app.view.ScreenDrag -import app.view.ScreenScale -import app.view.model.Node +import app.view.* import kotlin.math.roundToInt @Composable fun GraphNode( modifier: Modifier = Modifier, - node: Node, - nodeSize: Dp = 50.dp, + node: DrawableNode, screenDrag: ScreenDrag, screenScale: ScreenScale ) { @@ -34,8 +27,8 @@ fun GraphNode( .layout { measurable: Measurable, _: Constraints -> val placeable = measurable.measure( Constraints.fixed( - (nodeSize * screenScale.scale).roundToPx(), - (nodeSize * screenScale.scale).roundToPx() + (defaultNodeSize * screenScale.scale).roundToPx(), + (defaultNodeSize * screenScale.scale).roundToPx() ) ) @@ -47,7 +40,7 @@ fun GraphNode( } } .background( - color = MaterialTheme.colorScheme.primary, + color = node.color, shape = CircleShape ) diff --git a/app/src/main/kotlin/app/view/graph/GraphTree.kt b/app/src/main/kotlin/app/view/graph/GraphTree.kt index 69ccf35..0dfbc97 100644 --- a/app/src/main/kotlin/app/view/graph/GraphTree.kt +++ b/app/src/main/kotlin/app/view/graph/GraphTree.kt @@ -1,47 +1,31 @@ package app.view.graph import androidx.compose.runtime.Composable -import androidx.compose.ui.unit.Dp +import app.view.DrawableNode import app.view.ScreenDrag import app.view.ScreenScale -import app.view.model.Node @Composable fun Tree( - rootNode: Node?, - nodeSize: Dp, + rootNode: DrawableNode?, screenDrag: ScreenDrag, screenScale: ScreenScale, + parent: DrawableNode? = null ) { - val stack = mutableListOf() - stack.add(rootNode) - var currentParent: Node? = null - - while (stack.isNotEmpty()) { - val currentNode = stack.removeLast() - - currentNode?.let { node -> - currentParent?.let { parent -> - GraphLine( - start = parent, - end = node, - nodeSize = nodeSize, - screenDrag = screenDrag, - screenScale = screenScale - ) - } - - stack.add(node.right) - stack.add(node.left) - currentParent = node - - GraphNode( - node = node, + rootNode?.let { + parent?.let { parent -> + GraphLine( + start = parent, + end = it, screenDrag = screenDrag, - screenScale = screenScale, - nodeSize = nodeSize + screenScale = screenScale ) } + + Tree(rootNode.left, screenDrag, screenScale, it) + Tree(rootNode.right, screenDrag, screenScale, it) + + GraphNode(node = rootNode, screenDrag = screenDrag, screenScale = screenScale) } } \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/model/Node.kt b/app/src/main/kotlin/app/view/model/Node.kt deleted file mode 100644 index efdf101..0000000 --- a/app/src/main/kotlin/app/view/model/Node.kt +++ /dev/null @@ -1,35 +0,0 @@ -package app.view.model - -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.compose.ui.unit.Dp - - -class Node( - val value: String, - x: Dp, - y: Dp, - left: Node? = null, - right: Node? = null -) { - var x by mutableStateOf(x) - var y by mutableStateOf(y) - var left by mutableStateOf(left) - var right by mutableStateOf(right) - - override fun toString(): String = value - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is Node) return false - - return hashCode() == other.hashCode() - } - - override fun hashCode(): Int { - var result = value.hashCode() - result = 31 * result + (left?.hashCode() ?: 0) - result = 31 * result + (right?.hashCode() ?: 0) - return result - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/model/TreeEditor.kt b/app/src/main/kotlin/app/view/model/TreeEditor.kt new file mode 100644 index 0000000..872a5f3 --- /dev/null +++ b/app/src/main/kotlin/app/view/model/TreeEditor.kt @@ -0,0 +1,122 @@ +package app.view.model + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import app.model.bst.AVLTree +import app.model.bst.BSTree +import app.model.bst.BinarySearchTree +import app.model.bst.RBTree +import app.model.bst.node.AVLTreeNode +import app.model.bst.node.BinSearchTreeNode +import app.model.bst.node.BinTreeNode +import app.model.bst.node.RedBlackTreeNode +import app.view.DrawableNode +import app.view.defaultNodeSize + + +abstract class TreeEditor, BST : BinarySearchTree> { + abstract val tree: BST + + fun resetCoordinates(node: DrawableNode?) { + node?.let { + calcLeft(node, 0.dp, 0.dp) + calcRight(node, 0.dp, 0.dp) + } + } + + private fun countWidth(node: DrawableNode?): Pair { + var leftWidth = 0 + var rightWidth = 0 + if (node?.left != null) { + leftWidth = countWidth(node.left).toList().sum() + 1 + } + if (node?.right != null) { + rightWidth = countWidth(node.right).toList().sum() + 1 + } + return Pair(leftWidth, rightWidth) + } + + private fun calcLeft(node: DrawableNode?, parentX: Dp, parentY: Dp) { + var count = 0 + if (node?.right != null) { + count = countWidth(node).second + } + val x = parentX - defaultNodeSize - (defaultNodeSize * count) + val y = parentY + defaultNodeSize + node?.x = x + node?.y = y + if (node?.left != null) calcLeft(node.left, x, y) + if (node?.right != null) calcRight(node.right, x, y) + } + + + private fun calcRight(node: DrawableNode?, parentX: Dp, parentY: Dp) { + var count = 0 + if (node?.left != null) { + count = countWidth(node).first + } + val x = parentX + defaultNodeSize + (defaultNodeSize * count) + val y = parentY + defaultNodeSize + node?.x = x + node?.y = y + if (node?.left != null) calcLeft(node.left, x, y) + if (node?.right != null) calcRight(node.right, x, y) + } + fun addToTree(value: String): DrawableNode? { + this.tree.add(value) + return toDrawableNode(this.tree.root).also { resetCoordinates(it) } + } + + fun removeFromTree(value: String): DrawableNode? { + this.tree.remove(value) + return toDrawableNode(this.tree.root).also { resetCoordinates(it) } + } + + abstract fun toDrawableNode(node: N?): DrawableNode? +} + +class BSTreeEditor : TreeEditor, BinarySearchTree>>() { + override fun toDrawableNode(node: BinSearchTreeNode?): DrawableNode? { + return node?.let { + DrawableNode( + node.value, + left = toDrawableNode(node.left), + right = toDrawableNode(node.right), + ) + } + } + + override val tree = BSTree() +} + + +class RBTreeEditor : TreeEditor, BinarySearchTree>>() { + override fun toDrawableNode(node: RedBlackTreeNode?): DrawableNode? { + return node?.let { + DrawableNode( + node.value, + left = toDrawableNode(node.left), + right = toDrawableNode(node.right), + color = if (it.color == RedBlackTreeNode.Color.RED) Color.Red else Color.DarkGray + ) + } + } + + override val tree = RBTree() +} + + +class AVLTreeEditor : TreeEditor, BinarySearchTree>>() { + override fun toDrawableNode(node: AVLTreeNode?): DrawableNode? { + return node?.let { + DrawableNode( + node.value, + left = toDrawableNode(node.left), + right = toDrawableNode(node.right), + ) + } + } + + override val tree = AVLTree() +} From 51879cb0088bd4cbb5555d461c8b4c68f0d20ebe Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 2 May 2023 13:42:35 +0300 Subject: [PATCH 106/125] feat: Add `search` to visualizer --- app/src/main/kotlin/app/App.kt | 14 ++++++++++---- app/src/main/kotlin/app/view/model/TreeEditor.kt | 13 +++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/app/src/main/kotlin/app/App.kt b/app/src/main/kotlin/app/App.kt index ff3a97f..d0b63dd 100644 --- a/app/src/main/kotlin/app/App.kt +++ b/app/src/main/kotlin/app/App.kt @@ -1,4 +1,3 @@ - import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState @@ -19,6 +18,8 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.window.* +import app.model.bst.BinarySearchTree +import app.model.bst.node.BinTreeNode import app.view.* import app.view.graph.Graph import app.view.model.AVLTreeEditor @@ -80,8 +81,12 @@ fun TreeEditorView(editor: TreeEditor<*, *>) { } @Composable -fun GraphControls( - editor: TreeEditor<*, *>, tree: DrawableTree?, modifier: Modifier, screenDrag: ScreenDrag, screenScale: ScreenScale +fun , BST : BinarySearchTree> GraphControls( + editor: TreeEditor, + tree: DrawableTree?, + modifier: Modifier, + screenDrag: ScreenDrag, + screenScale: ScreenScale ) { Box(modifier) { Column(Modifier.padding(10.dp).width(210.dp).verticalScroll(rememberScrollState())) { @@ -91,7 +96,7 @@ fun GraphControls( Column { InputField({ tree?.root = editor.addToTree(it) }, Icons.Default.Add) InputField({ tree?.root = editor.removeFromTree(it) }, Icons.Default.Remove) - InputField({ print(it) }, Icons.Default.Search) + InputField({ tree?.root = editor.findNodeInTree(it) ?: tree?.root }, Icons.Default.Search) Row { Button( { @@ -104,6 +109,7 @@ fun GraphControls( } Button( { + tree?.root = editor.toDrawableNode(editor.tree.root) editor.resetCoordinates(tree?.root) }, Modifier.weight(1f).fillMaxWidth(), diff --git a/app/src/main/kotlin/app/view/model/TreeEditor.kt b/app/src/main/kotlin/app/view/model/TreeEditor.kt index 872a5f3..0f3572f 100644 --- a/app/src/main/kotlin/app/view/model/TreeEditor.kt +++ b/app/src/main/kotlin/app/view/model/TreeEditor.kt @@ -19,6 +19,7 @@ abstract class TreeEditor, BST : BinarySearchTree, BST : BinarySearchTree, BST : BinarySearchTree Date: Tue, 2 May 2023 14:05:14 +0300 Subject: [PATCH 107/125] fix: Fix `search` visualization --- app/src/main/kotlin/app/App.kt | 20 ++++++++++++++----- .../main/kotlin/app/view/graph/GraphNode.kt | 2 +- .../main/kotlin/app/view/model/TreeEditor.kt | 1 - 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/src/main/kotlin/app/App.kt b/app/src/main/kotlin/app/App.kt index d0b63dd..f9bb407 100644 --- a/app/src/main/kotlin/app/App.kt +++ b/app/src/main/kotlin/app/App.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.window.* @@ -69,13 +70,16 @@ fun TreeEditorView(editor: TreeEditor<*, *>) { val screenDrag = remember { ScreenDrag(0f, 0f) } val screenScale = remember { ScreenScale(1f, Offset(0f, 0f)) } + var graphViewWidth by remember { mutableStateOf(0) } - Box(Modifier.fillMaxSize().background(MaterialTheme.colorScheme.surface)) { + Box(Modifier.fillMaxSize().background(MaterialTheme.colorScheme.surface).onSizeChanged { + graphViewWidth = it.width + }) { Graph(drawableTree, screenDrag, screenScale) GraphControls( editor, drawableTree, Modifier.padding(10.dp).align(Alignment.TopEnd).clip( RoundedCornerShape(10.dp) - ).background(Color.LightGray), screenDrag, screenScale + ).background(Color.LightGray), screenDrag, screenScale, graphViewWidth ) } } @@ -86,7 +90,8 @@ fun , BST : BinarySearchTree> GraphControl tree: DrawableTree?, modifier: Modifier, screenDrag: ScreenDrag, - screenScale: ScreenScale + screenScale: ScreenScale, + width: Int, ) { Box(modifier) { Column(Modifier.padding(10.dp).width(210.dp).verticalScroll(rememberScrollState())) { @@ -96,11 +101,16 @@ fun , BST : BinarySearchTree> GraphControl Column { InputField({ tree?.root = editor.addToTree(it) }, Icons.Default.Add) InputField({ tree?.root = editor.removeFromTree(it) }, Icons.Default.Remove) - InputField({ tree?.root = editor.findNodeInTree(it) ?: tree?.root }, Icons.Default.Search) + InputField({ + tree?.root = editor.findNodeInTree(it) + editor.resetCoordinates(tree?.root) + }, Icons.Default.Search) Row { Button( { - + screenDrag.x = width / 2 - (defaultNodeSize / 2 + (tree?.root?.x ?: 0.dp)).value + screenDrag.y = defaultNodeSize.value + screenScale.scale = 1f }, Modifier.weight(1f).fillMaxWidth(), colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) diff --git a/app/src/main/kotlin/app/view/graph/GraphNode.kt b/app/src/main/kotlin/app/view/graph/GraphNode.kt index e710e16..6c98f8d 100644 --- a/app/src/main/kotlin/app/view/graph/GraphNode.kt +++ b/app/src/main/kotlin/app/view/graph/GraphNode.kt @@ -44,7 +44,7 @@ fun GraphNode( shape = CircleShape ) - .pointerInput(node.value, screenScale) { + .pointerInput(node, screenScale) { detectDragGestures { change, dragAmount -> change.consume() node.x += (dragAmount.x / screenScale.scale).toDp() diff --git a/app/src/main/kotlin/app/view/model/TreeEditor.kt b/app/src/main/kotlin/app/view/model/TreeEditor.kt index 0f3572f..d27632d 100644 --- a/app/src/main/kotlin/app/view/model/TreeEditor.kt +++ b/app/src/main/kotlin/app/view/model/TreeEditor.kt @@ -19,7 +19,6 @@ abstract class TreeEditor, BST : BinarySearchTree Date: Tue, 2 May 2023 14:30:01 +0300 Subject: [PATCH 108/125] fix: Fix text in input fields and nodes --- app/src/main/kotlin/app/App.kt | 6 +++++- app/src/main/kotlin/app/view/NodeText.kt | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/app/App.kt b/app/src/main/kotlin/app/App.kt index f9bb407..104bae3 100644 --- a/app/src/main/kotlin/app/App.kt +++ b/app/src/main/kotlin/app/App.kt @@ -26,6 +26,7 @@ import app.view.graph.Graph import app.view.model.AVLTreeEditor import app.view.model.TreeEditor import java.awt.Dimension +import java.lang.Integer.min fun main() { application { @@ -202,8 +203,11 @@ fun InputField(action: (String) -> Unit, icon: ImageVector) { Row(Modifier.padding(5.dp)) { OutlinedTextField( value = text, - onValueChange = { text = it }, + onValueChange = { it -> + text = it.slice(0..min(10, it.length - 1)) + }, modifier = Modifier.width(150.dp).height(50.dp).padding(end = 5.dp), + maxLines = 1 ) IconButton(onClick = { action(text) }, modifier = Modifier.background( color = MaterialTheme.colorScheme.tertiary, shape = RoundedCornerShape(8.dp) diff --git a/app/src/main/kotlin/app/view/NodeText.kt b/app/src/main/kotlin/app/view/NodeText.kt index 173cbe3..15c08e8 100644 --- a/app/src/main/kotlin/app/view/NodeText.kt +++ b/app/src/main/kotlin/app/view/NodeText.kt @@ -15,7 +15,7 @@ fun NodeText( ) { Text( modifier = modifier, - text = text, + text = if (text.length > 4) text.substring(0, 4) + ".." else text, color = MaterialTheme.colorScheme.onPrimary, style = style.copy( fontSize = style.fontSize * scaleProvider(), From 7bf09d15764300e51e05d473b7e633485adf1589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D1=8C=D1=8F=D1=87=D0=BA=D0=BE=D0=B2=20=D0=92=D0=B8?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B8=D0=B9?= <86203628+YazoonDinalt@users.noreply.github.com> Date: Tue, 2 May 2023 18:41:40 +0300 Subject: [PATCH 109/125] fix: Add a tree selection --- app/src/main/kotlin/app/App.kt | 46 +++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/app/App.kt b/app/src/main/kotlin/app/App.kt index 104bae3..1739bde 100644 --- a/app/src/main/kotlin/app/App.kt +++ b/app/src/main/kotlin/app/App.kt @@ -24,6 +24,8 @@ import app.model.bst.node.BinTreeNode import app.view.* import app.view.graph.Graph import app.view.model.AVLTreeEditor +import app.view.model.BSTreeEditor +import app.view.model.RBTreeEditor import app.view.model.TreeEditor import java.awt.Dimension import java.lang.Integer.min @@ -40,13 +42,51 @@ fun main() { ) { window.minimumSize = Dimension(800, 800) MaterialTheme( + colorScheme = MaterialTheme.colorScheme.copy( surface = Color(red = 235, green = 235, blue = 237) ) ) { - TreeEditorView( - AVLTreeEditor() - ) + var showDialog by remember { mutableStateOf(true) } + + if (showDialog) { + Dialog( + onCloseRequest = { showDialog = false }, + content = { + Column( + modifier = Modifier.padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + androidx.compose.material.Text(text = "Choose tree") + Spacer(modifier = Modifier.height(16.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + androidx.compose.material.Button( + modifier = Modifier.padding(horizontal = 8.dp), + onClick = { showDialog = false; TreeEditorView(BSTreeEditor()) } + ) { + TreeEditorView(BSTreeEditor()) + androidx.compose.material.Text(text = "BSTree") + } + androidx.compose.material.Button( + modifier = Modifier.padding(horizontal = 8.dp), + onClick = { showDialog = false; TreeEditorView(AVLTreeEditor()) } + ) { + androidx.compose.material.Text(text = "AVLTree") + } + androidx.compose.material.Button( + modifier = Modifier.padding(horizontal = 8.dp), + onClick = { showDialog = false; TreeEditorView(RBTreeEditor()) } + ) { + androidx.compose.material.Text(text = "RBTree") + } + } + } + } + ) + } } } } From 37861911dae54d0170828daf1cfee65926d8bafc Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 2 May 2023 19:00:09 +0300 Subject: [PATCH 110/125] fix: Fix dialog window drawing --- app/src/main/kotlin/app/App.kt | 90 ++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 37 deletions(-) diff --git a/app/src/main/kotlin/app/App.kt b/app/src/main/kotlin/app/App.kt index 1739bde..58bac38 100644 --- a/app/src/main/kotlin/app/App.kt +++ b/app/src/main/kotlin/app/App.kt @@ -47,49 +47,65 @@ fun main() { surface = Color(red = 235, green = 235, blue = 237) ) ) { - var showDialog by remember { mutableStateOf(true) } + TreeChoiceDialog() + } + } + } +} - if (showDialog) { - Dialog( - onCloseRequest = { showDialog = false }, - content = { - Column( - modifier = Modifier.padding(16.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - androidx.compose.material.Text(text = "Choose tree") - Spacer(modifier = Modifier.height(16.dp)) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceEvenly - ) { - androidx.compose.material.Button( - modifier = Modifier.padding(horizontal = 8.dp), - onClick = { showDialog = false; TreeEditorView(BSTreeEditor()) } - ) { - TreeEditorView(BSTreeEditor()) - androidx.compose.material.Text(text = "BSTree") - } - androidx.compose.material.Button( - modifier = Modifier.padding(horizontal = 8.dp), - onClick = { showDialog = false; TreeEditorView(AVLTreeEditor()) } - ) { - androidx.compose.material.Text(text = "AVLTree") - } - androidx.compose.material.Button( - modifier = Modifier.padding(horizontal = 8.dp), - onClick = { showDialog = false; TreeEditorView(RBTreeEditor()) } - ) { - androidx.compose.material.Text(text = "RBTree") - } - } - } +@Composable +fun TreeChoiceDialog() { + var showDialog by remember { mutableStateOf(true) } + var chosenTreeEditor: TreeEditor<*, *> by remember { mutableStateOf(BSTreeEditor()) } + + + if (showDialog) { + Dialog( + onCloseRequest = { showDialog = false } + ) { + Column( + modifier = Modifier.padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + androidx.compose.material.Text(text = "Choose tree") + Spacer(modifier = Modifier.height(16.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + androidx.compose.material.Button( + modifier = Modifier.padding(horizontal = 8.dp), + onClick = { + showDialog = false + chosenTreeEditor = BSTreeEditor() } - ) + ) { + androidx.compose.material.Text(text = "BSTree") + } + androidx.compose.material.Button( + modifier = Modifier.padding(horizontal = 8.dp), + onClick = { + showDialog = false + chosenTreeEditor = AVLTreeEditor() + } + ) { + androidx.compose.material.Text(text = "AVLTree") + } + androidx.compose.material.Button( + modifier = Modifier.padding(horizontal = 8.dp), + onClick = { + showDialog = false + chosenTreeEditor = RBTreeEditor() + } + ) { + androidx.compose.material.Text(text = "RBTree") + } } } } } + + TreeEditorView(chosenTreeEditor) } From 4a6d2e0a4777ee8ba2fbab6cb4678021197b8db2 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 2 May 2023 19:29:04 +0300 Subject: [PATCH 111/125] fix: Fix reset view align --- app/src/main/kotlin/app/App.kt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/app/src/main/kotlin/app/App.kt b/app/src/main/kotlin/app/App.kt index 58bac38..7bc0aad 100644 --- a/app/src/main/kotlin/app/App.kt +++ b/app/src/main/kotlin/app/App.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.window.* @@ -57,8 +58,6 @@ fun main() { fun TreeChoiceDialog() { var showDialog by remember { mutableStateOf(true) } var chosenTreeEditor: TreeEditor<*, *> by remember { mutableStateOf(BSTreeEditor()) } - - if (showDialog) { Dialog( onCloseRequest = { showDialog = false } @@ -150,6 +149,8 @@ fun , BST : BinarySearchTree> GraphControl screenScale: ScreenScale, width: Int, ) { + + val currentDensity = LocalDensity.current Box(modifier) { Column(Modifier.padding(10.dp).width(210.dp).verticalScroll(rememberScrollState())) { HiddenSettings( @@ -165,9 +166,13 @@ fun , BST : BinarySearchTree> GraphControl Row { Button( { - screenDrag.x = width / 2 - (defaultNodeSize / 2 + (tree?.root?.x ?: 0.dp)).value - screenDrag.y = defaultNodeSize.value - screenScale.scale = 1f + currentDensity.run { + screenDrag.x = + -(tree?.root?.x ?: 0.dp).toPx() + width / 2 - defaultNodeSize.toPx() / 2 + screenDrag.y = -(tree?.root?.y ?: 0.dp).toPx() + defaultNodeSize.toPx() + screenScale.scale = 1f + } + }, Modifier.weight(1f).fillMaxWidth(), colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) From add147ee3603c975f7859d8ac4bf20bbac67f96f Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 2 May 2023 21:04:47 +0300 Subject: [PATCH 112/125] refactor: Move out components from App --- app/src/main/kotlin/app/App.kt | 274 +----------------- .../kotlin/app/model/bst/BinarySearchTree.kt | 2 +- app/src/main/kotlin/app/view/DrawableTree.kt | 11 + .../main/kotlin/app/view/HiddenSettings.kt | 24 ++ app/src/main/kotlin/app/view/InputField.kt | 36 +++ .../main/kotlin/app/view/TreeChoiceDialog.kt | 68 +++++ .../main/kotlin/app/view/TreeEditorView.kt | 45 +++ app/src/main/kotlin/app/view/graph/Graph.kt | 2 +- .../kotlin/app/view/graph/GraphControls.kt | 135 +++++++++ 9 files changed, 327 insertions(+), 270 deletions(-) create mode 100644 app/src/main/kotlin/app/view/DrawableTree.kt create mode 100644 app/src/main/kotlin/app/view/HiddenSettings.kt create mode 100644 app/src/main/kotlin/app/view/InputField.kt create mode 100644 app/src/main/kotlin/app/view/TreeChoiceDialog.kt create mode 100644 app/src/main/kotlin/app/view/TreeEditorView.kt create mode 100644 app/src/main/kotlin/app/view/graph/GraphControls.kt diff --git a/app/src/main/kotlin/app/App.kt b/app/src/main/kotlin/app/App.kt index 7bc0aad..f9d1e59 100644 --- a/app/src/main/kotlin/app/App.kt +++ b/app/src/main/kotlin/app/App.kt @@ -1,35 +1,14 @@ -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Add -import androidx.compose.material.icons.filled.Remove -import androidx.compose.material.icons.filled.Search -import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.material3.MaterialTheme import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.layout.onSizeChanged -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.* -import app.model.bst.BinarySearchTree -import app.model.bst.node.BinTreeNode -import app.view.* -import app.view.graph.Graph -import app.view.model.AVLTreeEditor -import app.view.model.BSTreeEditor -import app.view.model.RBTreeEditor -import app.view.model.TreeEditor +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 app.view.TreeChoiceDialog import java.awt.Dimension -import java.lang.Integer.min fun main() { application { @@ -52,245 +31,4 @@ fun main() { } } } -} - -@Composable -fun TreeChoiceDialog() { - var showDialog by remember { mutableStateOf(true) } - var chosenTreeEditor: TreeEditor<*, *> by remember { mutableStateOf(BSTreeEditor()) } - if (showDialog) { - Dialog( - onCloseRequest = { showDialog = false } - ) { - Column( - modifier = Modifier.padding(16.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - androidx.compose.material.Text(text = "Choose tree") - Spacer(modifier = Modifier.height(16.dp)) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceEvenly - ) { - androidx.compose.material.Button( - modifier = Modifier.padding(horizontal = 8.dp), - onClick = { - showDialog = false - chosenTreeEditor = BSTreeEditor() - } - ) { - androidx.compose.material.Text(text = "BSTree") - } - androidx.compose.material.Button( - modifier = Modifier.padding(horizontal = 8.dp), - onClick = { - showDialog = false - chosenTreeEditor = AVLTreeEditor() - } - ) { - androidx.compose.material.Text(text = "AVLTree") - } - androidx.compose.material.Button( - modifier = Modifier.padding(horizontal = 8.dp), - onClick = { - showDialog = false - chosenTreeEditor = RBTreeEditor() - } - ) { - androidx.compose.material.Text(text = "RBTree") - } - } - } - } - } - - TreeEditorView(chosenTreeEditor) -} - - -class DrawableTree( - root: DrawableNode? -) { - var root by mutableStateOf(root) -} - -@Composable -fun TreeEditorView(editor: TreeEditor<*, *>) { - val drawableTree by remember { - mutableStateOf( - DrawableTree( - null - ) - ) - } - - val screenDrag = remember { ScreenDrag(0f, 0f) } - val screenScale = remember { ScreenScale(1f, Offset(0f, 0f)) } - var graphViewWidth by remember { mutableStateOf(0) } - - Box(Modifier.fillMaxSize().background(MaterialTheme.colorScheme.surface).onSizeChanged { - graphViewWidth = it.width - }) { - Graph(drawableTree, screenDrag, screenScale) - GraphControls( - editor, drawableTree, Modifier.padding(10.dp).align(Alignment.TopEnd).clip( - RoundedCornerShape(10.dp) - ).background(Color.LightGray), screenDrag, screenScale, graphViewWidth - ) - } -} - -@Composable -fun , BST : BinarySearchTree> GraphControls( - editor: TreeEditor, - tree: DrawableTree?, - modifier: Modifier, - screenDrag: ScreenDrag, - screenScale: ScreenScale, - width: Int, -) { - - val currentDensity = LocalDensity.current - Box(modifier) { - Column(Modifier.padding(10.dp).width(210.dp).verticalScroll(rememberScrollState())) { - HiddenSettings( - "Tree operations", hidden = false - ) { - Column { - InputField({ tree?.root = editor.addToTree(it) }, Icons.Default.Add) - InputField({ tree?.root = editor.removeFromTree(it) }, Icons.Default.Remove) - InputField({ - tree?.root = editor.findNodeInTree(it) - editor.resetCoordinates(tree?.root) - }, Icons.Default.Search) - Row { - Button( - { - currentDensity.run { - screenDrag.x = - -(tree?.root?.x ?: 0.dp).toPx() + width / 2 - defaultNodeSize.toPx() / 2 - screenDrag.y = -(tree?.root?.y ?: 0.dp).toPx() + defaultNodeSize.toPx() - screenScale.scale = 1f - } - - }, - Modifier.weight(1f).fillMaxWidth(), - colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) - ) { - Text("Reset view") - } - Button( - { - tree?.root = editor.toDrawableNode(editor.tree.root) - editor.resetCoordinates(tree?.root) - }, - Modifier.weight(1f).fillMaxWidth(), - colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) - ) { - Text("Reset tree") - } - } - } - } - - HiddenSettings( - "Save tree to...", hidden = true - ) { - Column { - Button( - {}, - Modifier.fillMaxWidth(), - colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) - ) { - Text("Json") - } - Button( - {}, - Modifier.fillMaxWidth(), - colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) - ) { - Text("Neo4j") - } - Button( - {}, - Modifier.fillMaxWidth(), - colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) - ) { - Text("Postgresql") - } - } - } - - - HiddenSettings( - "Load tree from...", hidden = true - ) { - Column { - Button( - {}, - Modifier.fillMaxWidth(), - colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) - ) { - Text("Json") - } - Button( - {}, - Modifier.fillMaxWidth(), - colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) - ) { - Text("Neo4j") - } - Button( - { - - }, - Modifier.fillMaxWidth(), - colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) - ) { - Text("Postgresql") - } - } - } - } - } -} - - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun InputField(action: (String) -> Unit, icon: ImageVector) { - var text by remember { mutableStateOf("") } - - Row(Modifier.padding(5.dp)) { - OutlinedTextField( - value = text, - onValueChange = { it -> - text = it.slice(0..min(10, it.length - 1)) - }, - modifier = Modifier.width(150.dp).height(50.dp).padding(end = 5.dp), - maxLines = 1 - ) - IconButton(onClick = { action(text) }, modifier = Modifier.background( - color = MaterialTheme.colorScheme.tertiary, shape = RoundedCornerShape(8.dp) - ).size(50.dp), content = { - Icon( - imageVector = icon, contentDescription = null, tint = Color.White - ) - }) - } -} - -@Composable -fun HiddenSettings(text: String, hidden: Boolean = true, content: @Composable () -> Unit) { - var expanded by remember { mutableStateOf(!hidden) } - - Button(modifier = Modifier.fillMaxWidth(), onClick = { expanded = !expanded }) { - Text(text) - } - - Row(verticalAlignment = Alignment.CenterVertically) { - if (expanded) { - content() - } - } } \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/bst/BinarySearchTree.kt b/app/src/main/kotlin/app/model/bst/BinarySearchTree.kt index 41076fa..78cc6c3 100644 --- a/app/src/main/kotlin/app/model/bst/BinarySearchTree.kt +++ b/app/src/main/kotlin/app/model/bst/BinarySearchTree.kt @@ -17,7 +17,7 @@ abstract class BinarySearchTree, NodeType : BinTreeNode, -): Iterable { +) : Iterable { /** * The root node of the tree. */ diff --git a/app/src/main/kotlin/app/view/DrawableTree.kt b/app/src/main/kotlin/app/view/DrawableTree.kt new file mode 100644 index 0000000..5a820d6 --- /dev/null +++ b/app/src/main/kotlin/app/view/DrawableTree.kt @@ -0,0 +1,11 @@ +package app.view + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue + +class DrawableTree( + root: DrawableNode? +) { + var root by mutableStateOf(root) +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/HiddenSettings.kt b/app/src/main/kotlin/app/view/HiddenSettings.kt new file mode 100644 index 0000000..a39c59a --- /dev/null +++ b/app/src/main/kotlin/app/view/HiddenSettings.kt @@ -0,0 +1,24 @@ +package app.view + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier + +@Composable +fun HiddenSettings(text: String, hidden: Boolean = true, content: @Composable () -> Unit) { + var expanded by remember { mutableStateOf(!hidden) } + + Button(modifier = Modifier.fillMaxWidth(), onClick = { expanded = !expanded }) { + Text(text) + } + + Row(verticalAlignment = Alignment.CenterVertically) { + if (expanded) { + content() + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/InputField.kt b/app/src/main/kotlin/app/view/InputField.kt new file mode 100644 index 0000000..750e2ce --- /dev/null +++ b/app/src/main/kotlin/app/view/InputField.kt @@ -0,0 +1,36 @@ +package app.view + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.unit.dp + + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun InputField(action: (String) -> Unit, icon: ImageVector) { + var text by remember { mutableStateOf("") } + + Row(Modifier.padding(5.dp)) { + OutlinedTextField( + value = text, + onValueChange = { it -> + text = it.slice(0..Integer.min(10, it.length - 1)) + }, + modifier = Modifier.width(150.dp).height(50.dp).padding(end = 5.dp), + maxLines = 1 + ) + IconButton(onClick = { action(text) }, modifier = Modifier.background( + color = MaterialTheme.colorScheme.tertiary, shape = RoundedCornerShape(8.dp) + ).size(50.dp), content = { + Icon( + imageVector = icon, contentDescription = null, tint = Color.White + ) + }) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/TreeChoiceDialog.kt b/app/src/main/kotlin/app/view/TreeChoiceDialog.kt new file mode 100644 index 0000000..0d505b5 --- /dev/null +++ b/app/src/main/kotlin/app/view/TreeChoiceDialog.kt @@ -0,0 +1,68 @@ +package app.view + +import androidx.compose.foundation.layout.* +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.unit.dp +import androidx.compose.ui.window.Dialog +import app.view.model.AVLTreeEditor +import app.view.model.BSTreeEditor +import app.view.model.RBTreeEditor +import app.view.model.TreeEditor + + +@Composable +fun TreeChoiceDialog() { + var showDialog by remember { mutableStateOf(true) } + var chosenTreeEditor: TreeEditor<*, *> by remember { mutableStateOf(BSTreeEditor()) } + if (showDialog) { + Dialog( + onCloseRequest = { showDialog = false } + ) { + Column( + modifier = Modifier.padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text(text = "Choose tree") + Spacer(modifier = Modifier.height(16.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + Button( + modifier = Modifier.padding(horizontal = 8.dp), + onClick = { + showDialog = false + chosenTreeEditor = BSTreeEditor() + } + ) { + Text(text = "BSTree") + } + Button( + modifier = Modifier.padding(horizontal = 8.dp), + onClick = { + showDialog = false + chosenTreeEditor = AVLTreeEditor() + } + ) { + Text(text = "AVLTree") + } + Button( + modifier = Modifier.padding(horizontal = 8.dp), + onClick = { + showDialog = false + chosenTreeEditor = RBTreeEditor() + } + ) { + Text(text = "RBTree") + } + } + } + } + } + + TreeEditorView(chosenTreeEditor) +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/TreeEditorView.kt b/app/src/main/kotlin/app/view/TreeEditorView.kt new file mode 100644 index 0000000..cea3d05 --- /dev/null +++ b/app/src/main/kotlin/app/view/TreeEditorView.kt @@ -0,0 +1,45 @@ +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.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import app.view.graph.Graph +import app.view.graph.GraphControls +import app.view.model.TreeEditor + + +@Composable +fun TreeEditorView(editor: TreeEditor<*, *>) { + val drawableTree by remember { + mutableStateOf( + DrawableTree( + null + ) + ) + } + + val screenDrag = remember { ScreenDrag(0f, 0f) } + val screenScale = remember { ScreenScale(1f, Offset(0f, 0f)) } + + Box(Modifier.fillMaxSize().background(MaterialTheme.colorScheme.surface)) { + Graph(drawableTree, screenDrag, screenScale) + GraphControls( + editor, drawableTree, Modifier.padding(10.dp).align(Alignment.TopEnd).clip( + RoundedCornerShape(10.dp) + ).background(Color.LightGray), screenDrag, screenScale + ) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/graph/Graph.kt b/app/src/main/kotlin/app/view/graph/Graph.kt index 4fdc948..c413a13 100644 --- a/app/src/main/kotlin/app/view/graph/Graph.kt +++ b/app/src/main/kotlin/app/view/graph/Graph.kt @@ -1,6 +1,5 @@ package app.view.graph -import DrawableTree import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.* import androidx.compose.material3.* @@ -11,6 +10,7 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.pointer.PointerEventType import androidx.compose.ui.input.pointer.onPointerEvent import androidx.compose.ui.input.pointer.pointerInput +import app.view.DrawableTree import app.view.ScreenDrag import app.view.ScreenScale import kotlin.math.max diff --git a/app/src/main/kotlin/app/view/graph/GraphControls.kt b/app/src/main/kotlin/app/view/graph/GraphControls.kt new file mode 100644 index 0000000..6bad3f8 --- /dev/null +++ b/app/src/main/kotlin/app/view/graph/GraphControls.kt @@ -0,0 +1,135 @@ +package app.view.graph + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Remove +import androidx.compose.material.icons.filled.Search +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.dp +import app.model.bst.BinarySearchTree +import app.model.bst.node.BinTreeNode +import app.view.* +import app.view.model.TreeEditor + + +@Composable +fun , BST : BinarySearchTree> GraphControls( + editor: TreeEditor, + tree: DrawableTree?, + modifier: Modifier, + screenDrag: ScreenDrag, + screenScale: ScreenScale, +) { + + val currentDensity = LocalDensity.current + Box(modifier) { + Column(Modifier.padding(10.dp).width(210.dp).verticalScroll(rememberScrollState())) { + HiddenSettings( + "Tree operations", hidden = false + ) { + Column { + InputField({ tree?.root = editor.addToTree(it) }, Icons.Default.Add) + InputField({ tree?.root = editor.removeFromTree(it) }, Icons.Default.Remove) + InputField({ + tree?.root = editor.findNodeInTree(it) + editor.resetCoordinates(tree?.root) + }, Icons.Default.Search) + Row { + Button( + { + currentDensity.run { + screenScale.scale = 1f + screenDrag.x = 0f + screenDrag.y = 0f + } + + }, + Modifier.weight(1f).fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Reset view") + } + Button( + { + tree?.root = editor.toDrawableNode(editor.tree.root) + editor.resetCoordinates(tree?.root) + }, + Modifier.weight(1f).fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Reset tree") + } + } + } + } + + HiddenSettings( + "Save tree to...", hidden = true + ) { + Column { + Button( + {}, + Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Json") + } + Button( + {}, + Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Neo4j") + } + Button( + {}, + Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Postgresql") + } + } + } + + + HiddenSettings( + "Load tree from...", hidden = true + ) { + Column { + Button( + {}, + Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Json") + } + Button( + {}, + Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Neo4j") + } + Button( + { + + }, + Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) + ) { + Text("Postgresql") + } + } + } + } + } +} \ No newline at end of file From a985741f180643915d1f49eeb92b3aa7f05ac2bf Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 2 May 2023 23:23:21 +0300 Subject: [PATCH 113/125] fix: Fix balancer remove method --- .../app/model/bst/balancer/RBBalancer.kt | 2 +- .../kotlin/app/view/graph/GraphNodeText.kt | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 app/src/main/kotlin/app/view/graph/GraphNodeText.kt diff --git a/app/src/main/kotlin/app/model/bst/balancer/RBBalancer.kt b/app/src/main/kotlin/app/model/bst/balancer/RBBalancer.kt index 8ca3041..b9390a1 100644 --- a/app/src/main/kotlin/app/model/bst/balancer/RBBalancer.kt +++ b/app/src/main/kotlin/app/model/bst/balancer/RBBalancer.kt @@ -121,7 +121,7 @@ internal class RBBalancer> : BinTreeBalancer?, value: E): RedBlackTreeNode? { - var current = findNode(root, value) ?: return null + var current = findNode(root, value) ?: return root var newRoot = root if (current.left != null && current.right != null) { diff --git a/app/src/main/kotlin/app/view/graph/GraphNodeText.kt b/app/src/main/kotlin/app/view/graph/GraphNodeText.kt new file mode 100644 index 0000000..58db307 --- /dev/null +++ b/app/src/main/kotlin/app/view/graph/GraphNodeText.kt @@ -0,0 +1,25 @@ +package app.view.graph + +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle + +@Composable +fun GraphNodeText( + modifier: Modifier = Modifier, + text: String, + scaleProvider: () -> Float, + style: TextStyle = MaterialTheme.typography.bodyMedium, +) { + Text( + modifier = modifier, + text = if (text.length > 4) text.substring(0, 4) + ".." else text, + color = MaterialTheme.colorScheme.onPrimary, + style = style.copy( + fontSize = style.fontSize * scaleProvider(), + lineHeight = style.lineHeight * scaleProvider() + ) + ) +} From d36a1eebc0adf384439bc14cf3b26a6c72c77434 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 2 May 2023 23:23:59 +0300 Subject: [PATCH 114/125] feat: Add saving to json --- app/src/main/kotlin/app/Main.kt | 18 +++ .../main/kotlin/app/model/repo/JsonRepo.kt | 12 +- app/src/main/kotlin/app/view/NodeText.kt | 25 ---- .../kotlin/app/view/graph/GraphControls.kt | 38 +----- .../main/kotlin/app/view/graph/GraphNode.kt | 7 +- .../kotlin/app/view/model/FileIOHandler.kt | 110 ++++++++++++++++++ .../main/kotlin/app/view/model/TreeEditor.kt | 8 +- 7 files changed, 148 insertions(+), 70 deletions(-) create mode 100644 app/src/main/kotlin/app/Main.kt delete mode 100644 app/src/main/kotlin/app/view/NodeText.kt create mode 100644 app/src/main/kotlin/app/view/model/FileIOHandler.kt diff --git a/app/src/main/kotlin/app/Main.kt b/app/src/main/kotlin/app/Main.kt new file mode 100644 index 0000000..0fa5554 --- /dev/null +++ b/app/src/main/kotlin/app/Main.kt @@ -0,0 +1,18 @@ +package app + +import app.model.bst.RBTree + +fun main() { + val a = RBTree() + a.add("1000") + a.add("1000") + a.add("1000") + a.add("1000") + a.add("1000") + a.add("1000") + a.add("1000") + + a.remove("") + + print(a.root) +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/model/repo/JsonRepo.kt b/app/src/main/kotlin/app/model/repo/JsonRepo.kt index f7f4ede..d14acce 100644 --- a/app/src/main/kotlin/app/model/repo/JsonRepo.kt +++ b/app/src/main/kotlin/app/model/repo/JsonRepo.kt @@ -12,18 +12,12 @@ import java.io.File class JsonRepo, Node : BinTreeNode, BST : BinarySearchTree>( - strategy: SerializationStrategy + strategy: SerializationStrategy, + private val file: File, ) : Repository(strategy) { - private val savingDirectory: String - get() { - val sC = File.separatorChar - return "app${sC}src${sC}main${sC}resources${sC}" - } - override fun save(verboseName: String, tree: BST) { try { val json = Json.encodeToString(tree.toSerializableTree(verboseName)) - val file = File("$savingDirectory$verboseName.json") file.writeText(json) } catch (e: Exception) { throw IllegalArgumentException("Impossible to save tree with provided verbose name") @@ -32,7 +26,6 @@ class JsonRepo, override fun loadByVerboseName(verboseName: String, factory: () -> BST): BST { try { - val file = File("$savingDirectory$verboseName.json") val json = file.readText() val serializableTree = Json.decodeFromString(json) return factory().apply { root = strategy.buildNode(serializableTree.root) } @@ -43,7 +36,6 @@ class JsonRepo, override fun deleteByVerboseName(verboseName: String) { try { - val file = File("$savingDirectory$verboseName.json") file.delete() } catch (e: Exception) { throw IllegalArgumentException("Impossible to delete tree with provided verbose name") diff --git a/app/src/main/kotlin/app/view/NodeText.kt b/app/src/main/kotlin/app/view/NodeText.kt deleted file mode 100644 index 15c08e8..0000000 --- a/app/src/main/kotlin/app/view/NodeText.kt +++ /dev/null @@ -1,25 +0,0 @@ -package app.view - -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.TextStyle - -@Composable -fun NodeText( - modifier: Modifier = Modifier, - text: String, - scaleProvider: () -> Float, - style: TextStyle = MaterialTheme.typography.bodyMedium, -) { - Text( - modifier = modifier, - text = if (text.length > 4) text.substring(0, 4) + ".." else text, - color = MaterialTheme.colorScheme.onPrimary, - style = style.copy( - fontSize = style.fontSize * scaleProvider(), - lineHeight = style.lineHeight * scaleProvider() - ) - ) -} diff --git a/app/src/main/kotlin/app/view/graph/GraphControls.kt b/app/src/main/kotlin/app/view/graph/GraphControls.kt index 6bad3f8..d65a1af 100644 --- a/app/src/main/kotlin/app/view/graph/GraphControls.kt +++ b/app/src/main/kotlin/app/view/graph/GraphControls.kt @@ -19,6 +19,7 @@ import app.model.bst.BinarySearchTree import app.model.bst.node.BinTreeNode import app.view.* import app.view.model.TreeEditor +import app.view.model.exportTreeToJson @Composable @@ -77,56 +78,29 @@ fun , BST : BinarySearchTree> GraphControl ) { Column { Button( - {}, + { + exportTreeToJson(editor.tree, editor.typeOfTree) + }, Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) ) { Text("Json") } - Button( - {}, - Modifier.fillMaxWidth(), - colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) - ) { - Text("Neo4j") - } - Button( - {}, - Modifier.fillMaxWidth(), - colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) - ) { - Text("Postgresql") - } } } - HiddenSettings( "Load tree from...", hidden = true ) { Column { - Button( - {}, - Modifier.fillMaxWidth(), - colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) - ) { - Text("Json") - } - Button( - {}, - Modifier.fillMaxWidth(), - colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) - ) { - Text("Neo4j") - } Button( { - + //editor.tree = importTreeFromJson() }, Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) ) { - Text("Postgresql") + Text("Json") } } } diff --git a/app/src/main/kotlin/app/view/graph/GraphNode.kt b/app/src/main/kotlin/app/view/graph/GraphNode.kt index 6c98f8d..a47689c 100644 --- a/app/src/main/kotlin/app/view/graph/GraphNode.kt +++ b/app/src/main/kotlin/app/view/graph/GraphNode.kt @@ -12,7 +12,10 @@ import androidx.compose.ui.layout.Measurable import androidx.compose.ui.layout.layout import androidx.compose.ui.unit.Constraints import androidx.compose.ui.zIndex -import app.view.* +import app.view.DrawableNode +import app.view.ScreenDrag +import app.view.ScreenScale +import app.view.defaultNodeSize import kotlin.math.roundToInt @Composable @@ -52,7 +55,7 @@ fun GraphNode( } } ) { - NodeText( + GraphNodeText( modifier = Modifier.align(Alignment.Center), text = node.value, scaleProvider = { screenScale.scale } diff --git a/app/src/main/kotlin/app/view/model/FileIOHandler.kt b/app/src/main/kotlin/app/view/model/FileIOHandler.kt new file mode 100644 index 0000000..4179d17 --- /dev/null +++ b/app/src/main/kotlin/app/view/model/FileIOHandler.kt @@ -0,0 +1,110 @@ +package app.view.model + +import androidx.compose.ui.awt.ComposeWindow +import app.model.bst.AVLTree +import app.model.bst.BSTree +import app.model.bst.BinarySearchTree +import app.model.bst.RBTree +import app.model.bst.node.AVLTreeNode +import app.model.bst.node.BinSearchTreeNode +import app.model.bst.node.BinTreeNode +import app.model.bst.node.RedBlackTreeNode +import app.model.repo.JsonRepo +import app.model.repo.serialization.SerializableTree +import app.model.repo.serialization.SerializableValue +import app.model.repo.serialization.TypeOfTree +import app.model.repo.serialization.strategy.AVLTreeStrategy +import app.model.repo.serialization.strategy.BSTreeStrategy +import app.model.repo.serialization.strategy.RBTreeStrategy +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import java.awt.FileDialog +import java.io.File + +@Suppress("UNCHECKED_CAST") +fun , BST : BinarySearchTree> exportTreeToJson( + tree: BST, + typeOfTree: TypeOfTree, +) { + val file = selectJsonFile(Mode.EXPORT) ?: return + when (typeOfTree) { + TypeOfTree.BINARY_SEARCH_TREE -> { + val strategy = BSTreeStrategy({ SerializableValue(it) }, { it.value }) + JsonRepo( + strategy, + file + ).save( + file.name, tree as + BinarySearchTree> + ) + } + + TypeOfTree.RED_BLACK_TREE -> { + val strategy = RBTreeStrategy({ SerializableValue(it) }, { it.value }) + JsonRepo( + strategy, + file + ).save( + file.name, tree as + BinarySearchTree> + ) + } + + TypeOfTree.AVL_TREE -> { + val strategy = AVLTreeStrategy({ SerializableValue(it) }, { it.value }) + JsonRepo( + strategy, + file + ).save( + file.name, tree as + BinarySearchTree> + ) + } + } +} + +enum class Mode { + IMPORT, + EXPORT +} + +@Suppress("UNCHECKED_CAST") +fun , BST : BinarySearchTree> importTreeFromJson(): BST? { + val file = selectJsonFile(Mode.IMPORT) ?: return null + val serializableTree = Json.decodeFromString(file.readText()) + return when (serializableTree.typeOfTree) { + TypeOfTree.BINARY_SEARCH_TREE -> { + val factory = { BSTree() } + val strategy = BSTreeStrategy({ SerializableValue(it) }, { it.value }) + JsonRepo(strategy, file).loadByVerboseName(file.name, factory) as BST + } + + TypeOfTree.RED_BLACK_TREE -> { + val factory = { RBTree() } + val strategy = RBTreeStrategy({ SerializableValue(it) }, { it.value }) + JsonRepo(strategy, file).loadByVerboseName(file.name, factory) as BST + } + + TypeOfTree.AVL_TREE -> { + val factory = { AVLTree() } + val strategy = AVLTreeStrategy({ SerializableValue(it) }, { it.value }) + JsonRepo(strategy, file).loadByVerboseName(file.name, factory) as BST + } + } +} + + +fun selectJsonFile(mode: Mode): File? { + val fd = if (mode == Mode.IMPORT) { + FileDialog(ComposeWindow(), "Choose file to import", FileDialog.LOAD) + } else { + FileDialog(ComposeWindow(), "Choose file to export", FileDialog.SAVE) + } + fd.file = "tree.json" + fd.isVisible = true + val fileString = fd.directory + fd.file + if (fileString != "nullnull") { + return File(fileString) + } + return null +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/view/model/TreeEditor.kt b/app/src/main/kotlin/app/view/model/TreeEditor.kt index d27632d..6b6ffb1 100644 --- a/app/src/main/kotlin/app/view/model/TreeEditor.kt +++ b/app/src/main/kotlin/app/view/model/TreeEditor.kt @@ -11,13 +11,14 @@ import app.model.bst.node.AVLTreeNode import app.model.bst.node.BinSearchTreeNode import app.model.bst.node.BinTreeNode import app.model.bst.node.RedBlackTreeNode +import app.model.repo.serialization.TypeOfTree import app.view.DrawableNode import app.view.defaultNodeSize abstract class TreeEditor, BST : BinarySearchTree> { abstract val tree: BST - + abstract val typeOfTree: TypeOfTree fun resetCoordinates(node: DrawableNode?) { node?.let { calcLeft(node, 0.dp, 0.dp) @@ -89,6 +90,7 @@ abstract class TreeEditor, BST : BinarySearchTree, BinarySearchTree>>() { + override val typeOfTree = TypeOfTree.BINARY_SEARCH_TREE override fun toDrawableNode(node: BinSearchTreeNode?): DrawableNode? { return node?.let { DrawableNode( @@ -104,6 +106,8 @@ class BSTreeEditor : TreeEditor, BinarySearchTree, BinarySearchTree>>() { + override val typeOfTree = TypeOfTree.RED_BLACK_TREE + override fun toDrawableNode(node: RedBlackTreeNode?): DrawableNode? { return node?.let { DrawableNode( @@ -120,6 +124,8 @@ class RBTreeEditor : TreeEditor, BinarySearchTree, BinarySearchTree>>() { + override val typeOfTree = TypeOfTree.AVL_TREE + override fun toDrawableNode(node: AVLTreeNode?): DrawableNode? { return node?.let { DrawableNode( From 1e92fd44de0512358c2bab63b4b1e3a37c612599 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 2 May 2023 23:24:55 +0300 Subject: [PATCH 115/125] fix: Remove invalid Main.kt --- app/src/main/kotlin/app/Main.kt | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 app/src/main/kotlin/app/Main.kt diff --git a/app/src/main/kotlin/app/Main.kt b/app/src/main/kotlin/app/Main.kt deleted file mode 100644 index 0fa5554..0000000 --- a/app/src/main/kotlin/app/Main.kt +++ /dev/null @@ -1,18 +0,0 @@ -package app - -import app.model.bst.RBTree - -fun main() { - val a = RBTree() - a.add("1000") - a.add("1000") - a.add("1000") - a.add("1000") - a.add("1000") - a.add("1000") - a.add("1000") - - a.remove("") - - print(a.root) -} \ No newline at end of file From 6076d5b25548c3e861dd8007f88c8617ad156967 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Tue, 2 May 2023 23:56:15 +0300 Subject: [PATCH 116/125] feat: Add loading from file with same typeOfTree --- .../model/repo/serialization/strategy/RBTreeStrategy.kt | 2 +- app/src/main/kotlin/app/view/graph/GraphControls.kt | 6 +++++- app/src/main/kotlin/app/view/model/FileIOHandler.kt | 3 ++- app/src/main/kotlin/app/view/model/TreeEditor.kt | 8 ++++---- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt b/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt index 90cbd0e..669269a 100644 --- a/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt +++ b/app/src/main/kotlin/app/model/repo/serialization/strategy/RBTreeStrategy.kt @@ -70,7 +70,7 @@ class RBTreeStrategy>( */ override fun serializeMetadata(node: RedBlackTreeNode): Metadata { return Metadata( - when (node.value) { + when (node.color) { RedBlackTreeNode.Color.RED -> "RED" else -> "BLACK" } diff --git a/app/src/main/kotlin/app/view/graph/GraphControls.kt b/app/src/main/kotlin/app/view/graph/GraphControls.kt index d65a1af..7483717 100644 --- a/app/src/main/kotlin/app/view/graph/GraphControls.kt +++ b/app/src/main/kotlin/app/view/graph/GraphControls.kt @@ -20,6 +20,7 @@ import app.model.bst.node.BinTreeNode import app.view.* import app.view.model.TreeEditor import app.view.model.exportTreeToJson +import app.view.model.importTreeFromJson @Composable @@ -95,7 +96,10 @@ fun , BST : BinarySearchTree> GraphControl Column { Button( { - //editor.tree = importTreeFromJson() + val t = importTreeFromJson(editor.typeOfTree) ?: return@Button + editor.tree = t + tree?.root = editor.toDrawableNode(editor.tree.root) + editor.resetCoordinates(tree?.root) }, Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.tertiary) diff --git a/app/src/main/kotlin/app/view/model/FileIOHandler.kt b/app/src/main/kotlin/app/view/model/FileIOHandler.kt index 4179d17..bcdffb1 100644 --- a/app/src/main/kotlin/app/view/model/FileIOHandler.kt +++ b/app/src/main/kotlin/app/view/model/FileIOHandler.kt @@ -69,9 +69,10 @@ enum class Mode { } @Suppress("UNCHECKED_CAST") -fun , BST : BinarySearchTree> importTreeFromJson(): BST? { +fun , BST : BinarySearchTree> importTreeFromJson(currentEditorType: TypeOfTree): BST? { val file = selectJsonFile(Mode.IMPORT) ?: return null val serializableTree = Json.decodeFromString(file.readText()) + if (currentEditorType != serializableTree.typeOfTree) return null //can load only same types of trees return when (serializableTree.typeOfTree) { TypeOfTree.BINARY_SEARCH_TREE -> { val factory = { BSTree() } diff --git a/app/src/main/kotlin/app/view/model/TreeEditor.kt b/app/src/main/kotlin/app/view/model/TreeEditor.kt index 6b6ffb1..ee70ef0 100644 --- a/app/src/main/kotlin/app/view/model/TreeEditor.kt +++ b/app/src/main/kotlin/app/view/model/TreeEditor.kt @@ -17,7 +17,7 @@ import app.view.defaultNodeSize abstract class TreeEditor, BST : BinarySearchTree> { - abstract val tree: BST + abstract var tree: BST abstract val typeOfTree: TypeOfTree fun resetCoordinates(node: DrawableNode?) { node?.let { @@ -101,7 +101,7 @@ class BSTreeEditor : TreeEditor, BinarySearchTree() + override var tree: BinarySearchTree> = BSTree() } @@ -119,7 +119,7 @@ class RBTreeEditor : TreeEditor, BinarySearchTree() + override var tree: BinarySearchTree> = RBTree() } @@ -136,5 +136,5 @@ class AVLTreeEditor : TreeEditor, BinarySearchTree() + override var tree: BinarySearchTree> = AVLTree() } From 71737ae5b9bfc7f2f798f2879a0e7c38327839b0 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Wed, 3 May 2023 00:30:46 +0300 Subject: [PATCH 117/125] refactor: Make full code refactor --- app/build.gradle.kts | 9 ++- app/src/main/kotlin/app/App.kt | 2 + .../app/model/bst/balancer/AVLBalancerTest.kt | 60 ++++++++--------- .../model/bst/iterator/InOrderIteratorTest.kt | 64 +++++++++---------- .../app/model/bst/utils/InvariantChecker.kt | 6 +- 5 files changed, 73 insertions(+), 68 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 0ad3b33..9da4d05 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -8,11 +8,11 @@ repositories { } plugins { - kotlin("jvm") version "1.8.20" + kotlin("jvm") version "1.8.0" id("org.jetbrains.compose") version "1.4.0" - kotlin("plugin.serialization") version "1.8.20" + kotlin("plugin.serialization") version "1.8.0" id("jacoco") - id("org.jetbrains.kotlin.plugin.noarg") version "1.8.20" + id("org.jetbrains.kotlin.plugin.noarg") version "1.8.0" } dependencies { @@ -53,6 +53,9 @@ noArg { annotation("org.neo4j.ogm.annotation.NodeEntity") annotation("org.neo4j.ogm.annotation.RelationshipEntity") } +kotlin { + jvmToolchain(17) +} compose.desktop { application { diff --git a/app/src/main/kotlin/app/App.kt b/app/src/main/kotlin/app/App.kt index f9d1e59..541d8d8 100644 --- a/app/src/main/kotlin/app/App.kt +++ b/app/src/main/kotlin/app/App.kt @@ -1,3 +1,5 @@ +package app + import androidx.compose.material3.MaterialTheme import androidx.compose.ui.Alignment import androidx.compose.ui.graphics.Color diff --git a/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt b/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt index f3bf4f3..4471e50 100644 --- a/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt +++ b/app/src/test/kotlin/app/model/bst/balancer/AVLBalancerTest.kt @@ -20,8 +20,8 @@ class AVLBalancerTest { 7 */ - assertEquals(8,root.value) - assertEquals(7,root.left?.value) + assertEquals(8, root.value) + assertEquals(7, root.left?.value) root = balancer.add(root, 6, true) @@ -32,9 +32,9 @@ class AVLBalancerTest { 6 8 */ - assertEquals(7,root.value) - assertEquals(6,root.left?.value) - assertEquals(8,root.right?.value) + assertEquals(7, root.value) + assertEquals(6, root.left?.value) + assertEquals(8, root.right?.value) root = balancer.add(root, 5, true) root = balancer.add(root, 4, true) @@ -48,11 +48,11 @@ class AVLBalancerTest { 4 6 */ - assertEquals(7,root.value) - assertEquals(5,root.left?.value) - assertEquals(8,root.right?.value) - assertEquals(4,root.left?.left?.value) - assertEquals(6,root.left?.right?.value) + assertEquals(7, root.value) + assertEquals(5, root.left?.value) + assertEquals(8, root.right?.value) + assertEquals(4, root.left?.left?.value) + assertEquals(6, root.left?.right?.value) root = balancer.add(root, 3, true) @@ -65,12 +65,12 @@ class AVLBalancerTest { 3 6 8 */ - assertEquals(5,root.value) - assertEquals(4,root.left?.value) - assertEquals(7,root.right?.value) - assertEquals(3,root.left?.left?.value) - assertEquals(6,root.right?.left?.value) - assertEquals(8,root.right?.right?.value) + assertEquals(5, root.value) + assertEquals(4, root.left?.value) + assertEquals(7, root.right?.value) + assertEquals(3, root.left?.left?.value) + assertEquals(6, root.right?.left?.value) + assertEquals(8, root.right?.right?.value) root = balancer.add(root, 2, true) @@ -83,9 +83,9 @@ class AVLBalancerTest { 2 4 6 8 */ - assertEquals(3,root.left?.value) - assertEquals(2,root.left?.left?.value) - assertEquals(4,root.left?.right?.value) + assertEquals(3, root.left?.value) + assertEquals(2, root.left?.left?.value) + assertEquals(4, root.left?.right?.value) root = balancer.add(root, 1, true) root = balancer.add(root, 0, true) @@ -101,9 +101,9 @@ class AVLBalancerTest { 0 2 */ - assertEquals(1,root.left?.left?.value) - assertEquals(0,root.left?.left?.left?.value) - assertEquals(2,root.left?.left?.right?.value) + assertEquals(1, root.left?.left?.value) + assertEquals(0, root.left?.left?.left?.value) + assertEquals(2, root.left?.left?.right?.value) } @Test @@ -118,8 +118,8 @@ class AVLBalancerTest { 3 */ - assertEquals(2,root.value) - assertEquals(3,root.right?.value) + assertEquals(2, root.value) + assertEquals(3, root.right?.value) root = balancer.add(root, 4, true) @@ -130,9 +130,9 @@ class AVLBalancerTest { 2 4 */ - assertEquals(3,root.value) - assertEquals(2,root.left?.value) - assertEquals(4,root.right?.value) + assertEquals(3, root.value) + assertEquals(2, root.left?.value) + assertEquals(4, root.right?.value) root = balancer.add(root, 5, true) root = balancer.add(root, 6, true) @@ -146,9 +146,9 @@ class AVLBalancerTest { 4 6 */ - assertEquals(5,root.right?.value) - assertEquals(4,root.right?.left?.value) - assertEquals(6,root.right?.right?.value) + assertEquals(5, root.right?.value) + assertEquals(4, root.right?.left?.value) + assertEquals(6, root.right?.right?.value) root = balancer.add(root, 7, true) diff --git a/app/src/test/kotlin/app/model/bst/iterator/InOrderIteratorTest.kt b/app/src/test/kotlin/app/model/bst/iterator/InOrderIteratorTest.kt index f458dea..19f6d1b 100644 --- a/app/src/test/kotlin/app/model/bst/iterator/InOrderIteratorTest.kt +++ b/app/src/test/kotlin/app/model/bst/iterator/InOrderIteratorTest.kt @@ -33,34 +33,34 @@ class InOrderIteratorTest { val iterator = tree.iterator() var res = iterator.next() - assertEquals(res,tree.root?.left?.left?.left?.value) //1 + assertEquals(res, tree.root?.left?.left?.left?.value) //1 res = iterator.next() - assertEquals(res,tree.root?.left?.left?.left?.right?.value) //2 + assertEquals(res, tree.root?.left?.left?.left?.right?.value) //2 res = iterator.next() - assertEquals(res,tree.root?.left?.left?.value) //3 + assertEquals(res, tree.root?.left?.left?.value) //3 res = iterator.next() - assertEquals(res,tree.root?.left?.value) //4 + assertEquals(res, tree.root?.left?.value) //4 res = iterator.next() - assertEquals(res,tree.root?.left?.right?.value) //5 + assertEquals(res, tree.root?.left?.right?.value) //5 res = iterator.next() - assertEquals(res,tree.root?.left?.right?.right?.left?.value) //6 + assertEquals(res, tree.root?.left?.right?.right?.left?.value) //6 res = iterator.next() - assertEquals(res,tree.root?.left?.right?.right?.value) //7 + assertEquals(res, tree.root?.left?.right?.right?.value) //7 res = iterator.next() - assertEquals(res,tree.root?.value) //8 + assertEquals(res, tree.root?.value) //8 res = iterator.next() - assertEquals(res,tree.root?.right?.left?.value) //9 + assertEquals(res, tree.root?.right?.left?.value) //9 res = iterator.next() - assertEquals(res,tree.root?.right?.value) //10 + assertEquals(res, tree.root?.right?.value) //10 } @Test @@ -80,37 +80,37 @@ class InOrderIteratorTest { val iterator = tree.iterator() var res = iterator.next() - assertEquals(res,tree.root?.left?.left?.value) //0 + assertEquals(res, tree.root?.left?.left?.value) //0 res = iterator.next() - assertEquals(res,tree.root?.left?.value) //1 + assertEquals(res, tree.root?.left?.value) //1 res = iterator.next() - assertEquals(res,tree.root?.left?.right?.value) //2 + assertEquals(res, tree.root?.left?.right?.value) //2 res = iterator.next() - assertEquals(res,tree.root?.value) //3 + assertEquals(res, tree.root?.value) //3 res = iterator.next() - assertEquals(res,tree.root?.right?.left?.left?.value) //4 + assertEquals(res, tree.root?.right?.left?.left?.value) //4 res = iterator.next() - assertEquals(res,tree.root?.right?.left?.value) //5 + assertEquals(res, tree.root?.right?.left?.value) //5 res = iterator.next() - assertEquals(res,tree.root?.right?.left?.right?.value) //6 + assertEquals(res, tree.root?.right?.left?.right?.value) //6 res = iterator.next() - assertEquals(res,tree.root?.right?.value) //7 + assertEquals(res, tree.root?.right?.value) //7 res = iterator.next() - assertEquals(res,tree.root?.right?.right?.left?.value) //8 + assertEquals(res, tree.root?.right?.right?.left?.value) //8 res = iterator.next() - assertEquals(res,tree.root?.right?.right?.value) //9 + assertEquals(res, tree.root?.right?.right?.value) //9 res = iterator.next() - assertEquals(res,tree.root?.right?.right?.right?.value) //10 + assertEquals(res, tree.root?.right?.right?.right?.value) //10 } @Test @@ -132,36 +132,36 @@ class InOrderIteratorTest { val iterator = tree.iterator() var res = iterator.next() - assertEquals(res,tree.root?.left?.left?.value) //0 + assertEquals(res, tree.root?.left?.left?.value) //0 res = iterator.next() - assertEquals(res,tree.root?.left?.value) //1 + assertEquals(res, tree.root?.left?.value) //1 res = iterator.next() - assertEquals(res,tree.root?.left?.right?.value) //2 + assertEquals(res, tree.root?.left?.right?.value) //2 res = iterator.next() - assertEquals(res,tree.root?.value) //3 + assertEquals(res, tree.root?.value) //3 res = iterator.next() - assertEquals(res,tree.root?.right?.left?.value) //4 + assertEquals(res, tree.root?.right?.left?.value) //4 res = iterator.next() - assertEquals(res,tree.root?.right?.value) //5 + assertEquals(res, tree.root?.right?.value) //5 res = iterator.next() - assertEquals(res,tree.root?.right?.right?.left?.value)//6 + assertEquals(res, tree.root?.right?.right?.left?.value)//6 res = iterator.next() - assertEquals(res,tree.root?.right?.right?.value) //7 + assertEquals(res, tree.root?.right?.right?.value) //7 res = iterator.next() - assertEquals(res,tree.root?.right?.right?.right?.left?.value) //8 + assertEquals(res, tree.root?.right?.right?.right?.left?.value) //8 res = iterator.next() - assertEquals(res,tree.root?.right?.right?.right?.value) //9 + assertEquals(res, tree.root?.right?.right?.right?.value) //9 res = iterator.next() - assertEquals(res,tree.root?.right?.right?.right?.right?.value) //10 + assertEquals(res, tree.root?.right?.right?.right?.right?.value) //10 } } \ No newline at end of file diff --git a/app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt b/app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt index 028c509..d0dec5e 100644 --- a/app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt +++ b/app/src/test/kotlin/app/model/bst/utils/InvariantChecker.kt @@ -95,9 +95,9 @@ object InvariantChecker { } /** - * Checks that all nodes linked correctly. - * For example, that node.left.parent is the same as node. - **/ + * Checks that all nodes linked correctly. + * For example, that node.left.parent is the same as node. + **/ fun > isParentLinkedRight(tree: RBTree?): Boolean { fun helper(root: RedBlackTreeNode?): Boolean { From f4d7cc995b5f1723f6510d4e4d5d8da7bc5f67f7 Mon Sep 17 00:00:00 2001 From: Vadim Yakshigulov Date: Wed, 3 May 2023 01:11:30 +0300 Subject: [PATCH 118/125] feat: Add icons and title for dialog --- app/build.gradle.kts | 12 ++++++++++++ app/src/main/kotlin/app/App.kt | 4 +++- .../main/kotlin/app/view/TreeChoiceDialog.kt | 3 ++- app/src/main/resources/icon.icns | Bin 0 -> 493064 bytes app/src/main/resources/icon.ico | Bin 0 -> 96444 bytes app/src/main/resources/icon.png | Bin 0 -> 621405 bytes 6 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 app/src/main/resources/icon.icns create mode 100644 app/src/main/resources/icon.ico create mode 100644 app/src/main/resources/icon.png diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9da4d05..e24eb5f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -65,6 +65,18 @@ compose.desktop { targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) packageName = "trees-visualizer" packageVersion = "1.0.0" + licenseFile.set(project.file("../LICENSE")) + + macOS { + iconFile.set(project.file("src/main/resources/icon.icns")) + } + windows { + iconFile.set(project.file("src/main/resources/icon.ico")) + } + linux { + iconFile.set(project.file("src/main/resources/icon.png")) + } } + } } diff --git a/app/src/main/kotlin/app/App.kt b/app/src/main/kotlin/app/App.kt index 541d8d8..bcd49b1 100644 --- a/app/src/main/kotlin/app/App.kt +++ b/app/src/main/kotlin/app/App.kt @@ -3,6 +3,7 @@ package app import androidx.compose.material3.MaterialTheme import androidx.compose.ui.Alignment import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Window @@ -16,11 +17,12 @@ fun main() { application { Window( onCloseRequest = ::exitApplication, - title = "graph visualizer", + title = "Graph visualizer", state = rememberWindowState( position = WindowPosition(alignment = Alignment.Center), size = DpSize(800.dp, 800.dp), ), + icon = painterResource("icon.png") ) { window.minimumSize = Dimension(800, 800) MaterialTheme( diff --git a/app/src/main/kotlin/app/view/TreeChoiceDialog.kt b/app/src/main/kotlin/app/view/TreeChoiceDialog.kt index 0d505b5..7ede8d5 100644 --- a/app/src/main/kotlin/app/view/TreeChoiceDialog.kt +++ b/app/src/main/kotlin/app/view/TreeChoiceDialog.kt @@ -20,7 +20,8 @@ fun TreeChoiceDialog() { var chosenTreeEditor: TreeEditor<*, *> by remember { mutableStateOf(BSTreeEditor()) } if (showDialog) { Dialog( - onCloseRequest = { showDialog = false } + onCloseRequest = { showDialog = false }, + title = "Choose tree" ) { Column( modifier = Modifier.padding(16.dp), diff --git a/app/src/main/resources/icon.icns b/app/src/main/resources/icon.icns new file mode 100644 index 0000000000000000000000000000000000000000..388deeae98f4b2e4762c31952a4e27b3e1391166 GIT binary patch literal 493064 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

w-NvaX6^l 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 C@K^*^4rj9N@S9h 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 +10Mj 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ðqZ0`7?X*4e!yP{slEK3ZKDRogYCwfoaK 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 T#(Wa$00000NkvXXu0mjfw}8_6 literal 0 HcmV?d00001 diff --git a/app/src/main/resources/icon.png b/app/src/main/resources/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..50b5d5399dee9646faf177dcdd7d02d81dfbec60 GIT binary patch literal 621405 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