From 6c92c2820898952a00cd871ef23ea0033626d584 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 14:55:23 +0000 Subject: [PATCH 001/203] Setting up GitHub Classroom Feedback From 906ce55c3e6f62164a3d4e17d2d9923017203f40 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 20 Mar 2023 23:31:50 +0300 Subject: [PATCH 002/203] =?UTF-8?q?1.=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=B8=20=D0=BD=D0=B5=D0=BC=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B8=D0=BB=20.gi?= =?UTF-8?q?tignore=202.=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20REA?= =?UTF-8?q?DME.md=20(=D0=BD=D1=83=D0=B6=D0=BD=D0=BE=20=D0=B1=D1=83=D0=B4?= =?UTF-8?q?=D0=B5=D1=82=20=D1=81=D0=BE=D1=81=D1=82=D0=B0=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C)=203.=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20src?= =?UTF-8?q?=20c=20main=20=D0=B8=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 12 ++++++++++++ README.md | 2 ++ src/main/Main.kt | 5 +++++ 3 files changed, 19 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 src/main/Main.kt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4884e53 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +# idea +.idea +*.iws +*.iml +*.ipr +/out/ +/.idea/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..c3d524b --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# TODO +Заполнить README diff --git a/src/main/Main.kt b/src/main/Main.kt new file mode 100644 index 0000000..3b3bcba --- /dev/null +++ b/src/main/Main.kt @@ -0,0 +1,5 @@ +package src.main + +fun main() { + println("Hello World!") +} \ No newline at end of file From a39544627822ba7cee39d92a117362273abe795c Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 22 Mar 2023 08:34:35 +0300 Subject: [PATCH 003/203] Add a binaryNode class --- src/main/Main.kt | 2 +- src/nodes/binaryNode/binaryNode.kt | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/nodes/binaryNode/binaryNode.kt diff --git a/src/main/Main.kt b/src/main/Main.kt index 3b3bcba..5cf9f3b 100644 --- a/src/main/Main.kt +++ b/src/main/Main.kt @@ -1,4 +1,4 @@ -package src.main +package main fun main() { println("Hello World!") diff --git a/src/nodes/binaryNode/binaryNode.kt b/src/nodes/binaryNode/binaryNode.kt new file mode 100644 index 0000000..fbbd280 --- /dev/null +++ b/src/nodes/binaryNode/binaryNode.kt @@ -0,0 +1,16 @@ +package binaryNode + +class binaryNode, NodeType>(key : T, value : NodeType) : Comparable> { + + var key : T + var value : NodeType + + private var right : binaryNode? = null + private var left : binaryNode? = null + + init { + key.also { this.key = it } + value.also { this.value = it } + } + override fun compareTo(other: binaryNode): Int = this.key.compareTo(other.key) +} \ No newline at end of file From 6825a6fb2b4edbd28318142f6f878d5a86f18ed9 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 22 Mar 2023 23:04:03 +0300 Subject: [PATCH 004/203] feat: Add a search fun in BinaryNode --- src/nodes/BinaryNode/BinaryNode.kt | 27 +++++++++++++++++++++++++++ src/nodes/binaryNode/binaryNode.kt | 16 ---------------- 2 files changed, 27 insertions(+), 16 deletions(-) create mode 100644 src/nodes/BinaryNode/BinaryNode.kt delete mode 100644 src/nodes/binaryNode/binaryNode.kt diff --git a/src/nodes/BinaryNode/BinaryNode.kt b/src/nodes/BinaryNode/BinaryNode.kt new file mode 100644 index 0000000..76548a5 --- /dev/null +++ b/src/nodes/BinaryNode/BinaryNode.kt @@ -0,0 +1,27 @@ +package BinaryNode + +class BinaryNode, NodeType>(key : T, value : NodeType) : Comparable> { + + var key : T + var value : NodeType + + private var right : BinaryNode? = null + private var left : BinaryNode? = null + + init { + key.also { this.key = it } + value.also { this.value = it } + } + + fun search(key: T) : NodeType? = + when (this.compareTo(key)) { + 1 -> this.right?.search(key) + 0 -> this.value + -1 -> this.left?.search(key) + else -> null + } + + + override fun compareTo(other: BinaryNode): Int = this.key.compareTo(other.key) + fun compareTo(key: T): Int = this.key.compareTo(key) +} \ No newline at end of file diff --git a/src/nodes/binaryNode/binaryNode.kt b/src/nodes/binaryNode/binaryNode.kt deleted file mode 100644 index fbbd280..0000000 --- a/src/nodes/binaryNode/binaryNode.kt +++ /dev/null @@ -1,16 +0,0 @@ -package binaryNode - -class binaryNode, NodeType>(key : T, value : NodeType) : Comparable> { - - var key : T - var value : NodeType - - private var right : binaryNode? = null - private var left : binaryNode? = null - - init { - key.also { this.key = it } - value.also { this.value = it } - } - override fun compareTo(other: binaryNode): Int = this.key.compareTo(other.key) -} \ No newline at end of file From fe46e2bb61e60ec1c5315ce2e3337f3a696b4882 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 27 Mar 2023 13:08:46 +0300 Subject: [PATCH 005/203] =?UTF-8?q?=D0=9E=D0=B3=D1=80=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=87=D0=B8=D0=BB=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D1=8C=20?= =?UTF-8?q?=D0=B2=20key,=20value.=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20toString()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nodes/BinaryNode/BinaryNode.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/nodes/BinaryNode/BinaryNode.kt b/src/nodes/BinaryNode/BinaryNode.kt index 76548a5..6b43242 100644 --- a/src/nodes/BinaryNode/BinaryNode.kt +++ b/src/nodes/BinaryNode/BinaryNode.kt @@ -2,8 +2,8 @@ package BinaryNode class BinaryNode, NodeType>(key : T, value : NodeType) : Comparable> { - var key : T - var value : NodeType + var key : T private set + var value : NodeType private set private var right : BinaryNode? = null private var left : BinaryNode? = null @@ -21,7 +21,9 @@ class BinaryNode, NodeType>(key : T, value : NodeType) : Compar else -> null } - + override fun toString(): String { + return "<$key, $value>" + } override fun compareTo(other: BinaryNode): Int = this.key.compareTo(other.key) fun compareTo(key: T): Int = this.key.compareTo(key) } \ No newline at end of file From b0fc0915253e683cb635c876bafa1575bc58b8b5 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 20 Mar 2023 23:31:50 +0300 Subject: [PATCH 006/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20gitignore,=20readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 12 ++++++++++++ README.md | 2 ++ src/main/Main.kt | 5 +++++ 3 files changed, 19 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 src/main/Main.kt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4884e53 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +# idea +.idea +*.iws +*.iml +*.ipr +/out/ +/.idea/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..c3d524b --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# TODO +Заполнить README diff --git a/src/main/Main.kt b/src/main/Main.kt new file mode 100644 index 0000000..3b3bcba --- /dev/null +++ b/src/main/Main.kt @@ -0,0 +1,5 @@ +package src.main + +fun main() { + println("Hello World!") +} \ No newline at end of file From 8af1ee39c1d5ca36f7d4d51bc74fb32f56ff2aba Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 22 Mar 2023 08:34:35 +0300 Subject: [PATCH 007/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20BinaryNode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/Main.kt | 2 +- src/nodes/binaryNode/binaryNode.kt | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/nodes/binaryNode/binaryNode.kt diff --git a/src/main/Main.kt b/src/main/Main.kt index 3b3bcba..5cf9f3b 100644 --- a/src/main/Main.kt +++ b/src/main/Main.kt @@ -1,4 +1,4 @@ -package src.main +package main fun main() { println("Hello World!") diff --git a/src/nodes/binaryNode/binaryNode.kt b/src/nodes/binaryNode/binaryNode.kt new file mode 100644 index 0000000..fbbd280 --- /dev/null +++ b/src/nodes/binaryNode/binaryNode.kt @@ -0,0 +1,16 @@ +package binaryNode + +class binaryNode, NodeType>(key : T, value : NodeType) : Comparable> { + + var key : T + var value : NodeType + + private var right : binaryNode? = null + private var left : binaryNode? = null + + init { + key.also { this.key = it } + value.also { this.value = it } + } + override fun compareTo(other: binaryNode): Int = this.key.compareTo(other.key) +} \ No newline at end of file From a5fa62a0f967e5aa5ad0ebd015a822e74d26086f Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 22 Mar 2023 23:04:03 +0300 Subject: [PATCH 008/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8E=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=B8=D1=81=D0=BA=D0=B0=20=D0=B2=20BinaryNode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nodes/BinaryNode/BinaryNode.kt | 27 +++++++++++++++++++++++++++ src/nodes/binaryNode/binaryNode.kt | 16 ---------------- 2 files changed, 27 insertions(+), 16 deletions(-) create mode 100644 src/nodes/BinaryNode/BinaryNode.kt delete mode 100644 src/nodes/binaryNode/binaryNode.kt diff --git a/src/nodes/BinaryNode/BinaryNode.kt b/src/nodes/BinaryNode/BinaryNode.kt new file mode 100644 index 0000000..76548a5 --- /dev/null +++ b/src/nodes/BinaryNode/BinaryNode.kt @@ -0,0 +1,27 @@ +package BinaryNode + +class BinaryNode, NodeType>(key : T, value : NodeType) : Comparable> { + + var key : T + var value : NodeType + + private var right : BinaryNode? = null + private var left : BinaryNode? = null + + init { + key.also { this.key = it } + value.also { this.value = it } + } + + fun search(key: T) : NodeType? = + when (this.compareTo(key)) { + 1 -> this.right?.search(key) + 0 -> this.value + -1 -> this.left?.search(key) + else -> null + } + + + override fun compareTo(other: BinaryNode): Int = this.key.compareTo(other.key) + fun compareTo(key: T): Int = this.key.compareTo(key) +} \ No newline at end of file diff --git a/src/nodes/binaryNode/binaryNode.kt b/src/nodes/binaryNode/binaryNode.kt deleted file mode 100644 index fbbd280..0000000 --- a/src/nodes/binaryNode/binaryNode.kt +++ /dev/null @@ -1,16 +0,0 @@ -package binaryNode - -class binaryNode, NodeType>(key : T, value : NodeType) : Comparable> { - - var key : T - var value : NodeType - - private var right : binaryNode? = null - private var left : binaryNode? = null - - init { - key.also { this.key = it } - value.also { this.value = it } - } - override fun compareTo(other: binaryNode): Int = this.key.compareTo(other.key) -} \ No newline at end of file From 1ef503db6d16b38dbcf25696fedb8a751f472e7e Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 27 Mar 2023 13:08:46 +0300 Subject: [PATCH 009/203] =?UTF-8?q?=D0=9E=D0=B3=D1=80=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=87=D0=B8=D0=BB=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D1=8C=20?= =?UTF-8?q?=D0=B2=20key,=20value.=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20toString()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nodes/BinaryNode/BinaryNode.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/nodes/BinaryNode/BinaryNode.kt b/src/nodes/BinaryNode/BinaryNode.kt index 76548a5..6b43242 100644 --- a/src/nodes/BinaryNode/BinaryNode.kt +++ b/src/nodes/BinaryNode/BinaryNode.kt @@ -2,8 +2,8 @@ package BinaryNode class BinaryNode, NodeType>(key : T, value : NodeType) : Comparable> { - var key : T - var value : NodeType + var key : T private set + var value : NodeType private set private var right : BinaryNode? = null private var left : BinaryNode? = null @@ -21,7 +21,9 @@ class BinaryNode, NodeType>(key : T, value : NodeType) : Compar else -> null } - + override fun toString(): String { + return "<$key, $value>" + } override fun compareTo(other: BinaryNode): Int = this.key.compareTo(other.key) fun compareTo(key: T): Int = this.key.compareTo(key) } \ No newline at end of file From 623d30a1d659e827c7a4d3c72f4530975c90e26e Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 27 Mar 2023 13:17:00 +0300 Subject: [PATCH 010/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20BinaryTree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/trees/BinaryTree/BinaryTree.kt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/trees/BinaryTree/BinaryTree.kt diff --git a/src/trees/BinaryTree/BinaryTree.kt b/src/trees/BinaryTree/BinaryTree.kt new file mode 100644 index 0000000..4dbe02a --- /dev/null +++ b/src/trees/BinaryTree/BinaryTree.kt @@ -0,0 +1,4 @@ +package BinaryTree + +class BinaryTree { +} \ No newline at end of file From b6de7b553d49e8860c28027944f95ef494408fe1 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 27 Mar 2023 13:31:43 +0300 Subject: [PATCH 011/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20search,=20insert=20=D0=B2=20BinaryTree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nodes/{BinaryNode => }/BinaryNode.kt | 2 -- src/trees/BinaryTree/BinaryTree.kt | 13 ++++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) rename src/nodes/{BinaryNode => }/BinaryNode.kt (97%) diff --git a/src/nodes/BinaryNode/BinaryNode.kt b/src/nodes/BinaryNode.kt similarity index 97% rename from src/nodes/BinaryNode/BinaryNode.kt rename to src/nodes/BinaryNode.kt index 6b43242..52b5aaa 100644 --- a/src/nodes/BinaryNode/BinaryNode.kt +++ b/src/nodes/BinaryNode.kt @@ -1,5 +1,3 @@ -package BinaryNode - class BinaryNode, NodeType>(key : T, value : NodeType) : Comparable> { var key : T private set diff --git a/src/trees/BinaryTree/BinaryTree.kt b/src/trees/BinaryTree/BinaryTree.kt index 4dbe02a..4affa01 100644 --- a/src/trees/BinaryTree/BinaryTree.kt +++ b/src/trees/BinaryTree/BinaryTree.kt @@ -1,4 +1,15 @@ package BinaryTree -class BinaryTree { +import BinaryNode + +class BinaryTree, NodeType> { + private var root : BinaryNode? = null + fun search(key : T) : NodeType? = root!!.search(key) + fun insert(key : T, value : NodeType) { + if (root == null) + root = BinaryNode(key, value) + else { + TODO("insert fun") + } + } } \ No newline at end of file From 0f1a22febd50a200675be0d13640f5ce67fbb587 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 2 Apr 2023 00:58:55 +0300 Subject: [PATCH 012/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BE=D1=81=D0=BD=D0=BE=D0=B2=D0=BD=D1=8B=D0=B5=20?= =?UTF-8?q?=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B2=20BinaryNod?= =?UTF-8?q?e=20=D0=B8=20BinaryTree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nodes/BinaryNode.kt | 4 ++++ src/trees/BinaryTree/BinaryTree.kt | 1 + 2 files changed, 5 insertions(+) diff --git a/src/nodes/BinaryNode.kt b/src/nodes/BinaryNode.kt index 52b5aaa..f6940b7 100644 --- a/src/nodes/BinaryNode.kt +++ b/src/nodes/BinaryNode.kt @@ -19,6 +19,10 @@ class BinaryNode, NodeType>(key : T, value : NodeType) : Compar else -> null } + fun delete(key: T): Nothing = TODO("delete NODE fun") + + fun insert(key : T, value : NodeType): Nothing = TODO("insert NODE fun") + override fun toString(): String { return "<$key, $value>" } diff --git a/src/trees/BinaryTree/BinaryTree.kt b/src/trees/BinaryTree/BinaryTree.kt index 4affa01..fb0e964 100644 --- a/src/trees/BinaryTree/BinaryTree.kt +++ b/src/trees/BinaryTree/BinaryTree.kt @@ -5,6 +5,7 @@ import BinaryNode class BinaryTree, NodeType> { private var root : BinaryNode? = null fun search(key : T) : NodeType? = root!!.search(key) + fun delete(key: T): Nothing = TODO("delete fun") fun insert(key : T, value : NodeType) { if (root == null) root = BinaryNode(key, value) From 439fd83e6d7dff3a31327592bbfed2f8ec8df47e Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 3 Apr 2023 13:14:39 +0300 Subject: [PATCH 013/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20add=20=D0=B8=20search=20=D0=B2=20BinaryNode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nodes/BinaryNode.kt | 23 ++++++++++++++++++++--- src/trees/BinaryTree/BinaryTree.kt | 6 +++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/nodes/BinaryNode.kt b/src/nodes/BinaryNode.kt index f6940b7..9691849 100644 --- a/src/nodes/BinaryNode.kt +++ b/src/nodes/BinaryNode.kt @@ -12,16 +12,33 @@ class BinaryNode, NodeType>(key : T, value : NodeType) : Compar } fun search(key: T) : NodeType? = - when (this.compareTo(key)) { + when (key.compareTo(this.key)) { 1 -> this.right?.search(key) 0 -> this.value -1 -> this.left?.search(key) else -> null - } + } fun delete(key: T): Nothing = TODO("delete NODE fun") - fun insert(key : T, value : NodeType): Nothing = TODO("insert NODE fun") + @Throws(Exception::class) + fun insert(key : T, value : NodeType) { + val compare = key.compareTo(this.key) + + if (compare == 1) { + if (right == null) + right = BinaryNode(key, value) + else + right!!.insert(key, value) + } else if (compare == 0) { + throw Exception("Keys can't be equal") + } else { + if (left == null) + left = BinaryNode(key, value) + else + left!!.insert(key, value) + } + } override fun toString(): String { return "<$key, $value>" diff --git a/src/trees/BinaryTree/BinaryTree.kt b/src/trees/BinaryTree/BinaryTree.kt index fb0e964..440b8ee 100644 --- a/src/trees/BinaryTree/BinaryTree.kt +++ b/src/trees/BinaryTree/BinaryTree.kt @@ -4,13 +4,13 @@ import BinaryNode class BinaryTree, NodeType> { private var root : BinaryNode? = null - fun search(key : T) : NodeType? = root!!.search(key) + fun search(key : T) : NodeType? = root?.search(key) fun delete(key: T): Nothing = TODO("delete fun") - fun insert(key : T, value : NodeType) { + fun add(key : T, value : NodeType) { if (root == null) root = BinaryNode(key, value) else { - TODO("insert fun") + root!!.insert(key, value) } } } \ No newline at end of file From 78e9f810fb3e0be2179d0a023d4ddb83916435a9 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 5 Apr 2023 14:11:52 +0300 Subject: [PATCH 014/203] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BB=202=20=D1=81=D0=BB=D1=83=D1=87=D0=B0?= =?UTF-8?q?=D1=8F=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B8=D0=B7=203=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nodes/BinaryNode.kt | 43 +++++++++++++++++++++++++++--- src/trees/BinaryTree/BinaryTree.kt | 4 +-- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/nodes/BinaryNode.kt b/src/nodes/BinaryNode.kt index 9691849..3962d2c 100644 --- a/src/nodes/BinaryNode.kt +++ b/src/nodes/BinaryNode.kt @@ -1,14 +1,22 @@ -class BinaryNode, NodeType>(key : T, value : NodeType) : Comparable> { +class BinaryNode, NodeType>(key : T, value : NodeType, parent : BinaryNode?) : Comparable> { var key : T private set var value : NodeType private set +// private var parent : BinaryNode? = null + private var right : BinaryNode? = null private var left : BinaryNode? = null + var hasChildren: Boolean + get() = !(this.right == null && this.left == null) + private set + init { + hasChildren = false key.also { this.key = it } value.also { this.value = it } +// parent?.also { this.parent = it } } fun search(key: T) : NodeType? = @@ -19,22 +27,49 @@ class BinaryNode, NodeType>(key : T, value : NodeType) : Compar else -> null } - fun delete(key: T): Nothing = TODO("delete NODE fun") + fun delete(key: T) { + if (right?.key == key) { + if (!right!!.hasChildren) + right = null + else { + if (right!!.left == null && right!!.right != null) + right = right!!.right + else if (right!!.right == null && right!!.left != null) + right = right!!.left + else { + + } + } + + } + else if (left?.key == key) { + if (!left!!.hasChildren) + left = null + else { + + } + } else { + if (key.compareTo(this.key) == -1) + left?.delete(key) + else + right?.delete(key) + } + } @Throws(Exception::class) fun insert(key : T, value : NodeType) { val compare = key.compareTo(this.key) if (compare == 1) { if (right == null) - right = BinaryNode(key, value) + right = BinaryNode(key, value, this) else right!!.insert(key, value) } else if (compare == 0) { throw Exception("Keys can't be equal") } else { if (left == null) - left = BinaryNode(key, value) + left = BinaryNode(key, value, this) else left!!.insert(key, value) } diff --git a/src/trees/BinaryTree/BinaryTree.kt b/src/trees/BinaryTree/BinaryTree.kt index 440b8ee..00c31ec 100644 --- a/src/trees/BinaryTree/BinaryTree.kt +++ b/src/trees/BinaryTree/BinaryTree.kt @@ -5,10 +5,10 @@ import BinaryNode class BinaryTree, NodeType> { private var root : BinaryNode? = null fun search(key : T) : NodeType? = root?.search(key) - fun delete(key: T): Nothing = TODO("delete fun") + fun delete(key: T) = root?.delete(key) fun add(key : T, value : NodeType) { if (root == null) - root = BinaryNode(key, value) + root = BinaryNode(key, value, null) else { root!!.insert(key, value) } From 27ec63a02f7e370cbc375562876ca353f9f5ffb7 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 5 Apr 2023 14:23:59 +0300 Subject: [PATCH 015/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20private=20=D1=84=D1=83=D0=BD-=D1=8E=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20(?= =?UTF-8?q?=D1=82=D0=B0=D0=BA=20=D1=87=D0=B8=D1=82=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?=D1=83=D0=B4=D0=BE=D0=B1=D0=BD=D0=B5=D0=B5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nodes/BinaryNode.kt | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/nodes/BinaryNode.kt b/src/nodes/BinaryNode.kt index 3962d2c..838e34e 100644 --- a/src/nodes/BinaryNode.kt +++ b/src/nodes/BinaryNode.kt @@ -27,27 +27,25 @@ class BinaryNode, NodeType>(key : T, value : NodeType, parent : else -> null } - fun delete(key: T) { - if (right?.key == key) { - if (!right!!.hasChildren) - right = null - else { - if (right!!.left == null && right!!.right != null) - right = right!!.right - else if (right!!.right == null && right!!.left != null) - right = right!!.left - else { + private fun nodeRemove(node : BinaryNode?) : BinaryNode? { + if (!node!!.hasChildren) + return null - } - } + if (node!!.left != null || node!!.right == null) { + if (node!!.right == null && node!!.left != null) + return node!!.left + else { + TODO("остаточное условие") + } + } else + return node!!.right - } + } + fun delete(key: T) { + if (right?.key == key) + right = nodeRemove(right) else if (left?.key == key) { - if (!left!!.hasChildren) - left = null - else { - - } + left = nodeRemove(left) } else { if (key.compareTo(this.key) == -1) left?.delete(key) From c3c9d29ddf4ebf0d1b43dacbd7233439610a8f1a Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov <113210919+twotwozeronine@users.noreply.github.com> Date: Thu, 6 Apr 2023 15:41:41 +0300 Subject: [PATCH 016/203] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3ad65ee --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Pogorelov Ilya, Sokolovskiy Ilya, Zaytsev Dmitriy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From d2f9e1dc18be57e47f8e5c93eb34ed0391a9a41a Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 6 Apr 2023 18:01:01 +0300 Subject: [PATCH 017/203] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D0=B0=D0=BB=20remove=20=D0=B2=20BinaryNode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nodes/BinaryNode.kt | 55 +++++++++++++++++------------- src/trees/BinaryTree/BinaryTree.kt | 4 ++- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/nodes/BinaryNode.kt b/src/nodes/BinaryNode.kt index 838e34e..4b48ab7 100644 --- a/src/nodes/BinaryNode.kt +++ b/src/nodes/BinaryNode.kt @@ -27,33 +27,42 @@ class BinaryNode, NodeType>(key : T, value : NodeType, parent : else -> null } - private fun nodeRemove(node : BinaryNode?) : BinaryNode? { - if (!node!!.hasChildren) - return null + fun remove(root : BinaryNode?, key : T) : BinaryNode? { + if (root == null) + return null - if (node!!.left != null || node!!.right == null) { - if (node!!.right == null && node!!.left != null) - return node!!.left - else { - TODO("остаточное условие") - } - } else - return node!!.right + if (key == this.key) { // когда remove вызывается для удаляемой вершины + if (this.right == null && this.left == null) + return null + // Простой случай - если есть только 1 потомок + else if (this.left == null) + return this.right + else if (this.right == null) + return this.left + // Есть оба поддерева + else { + // Находим минимальное дерево + // Перенимаем его key и value + // Удаляем минимальное дерево + val minNode = findMin(this.right) + this.key = minNode!!.key + this.value = minNode.value + this.right = right!!.remove(this.right, minNode.key) + return this + } - } - fun delete(key: T) { - if (right?.key == key) - right = nodeRemove(right) - else if (left?.key == key) { - left = nodeRemove(left) - } else { - if (key.compareTo(this.key) == -1) - left?.delete(key) + } else { + // Замещаем поддеревья на минимальные + if (key < this.key) + this.left = left?.remove(left, key) else - right?.delete(key) - } - + this.right = right?.remove(right, key) + return root + } } + + private fun findMin(node: BinaryNode?): BinaryNode? = if (node?.left != null) findMin(node!!.left) else node + @Throws(Exception::class) fun insert(key : T, value : NodeType) { val compare = key.compareTo(this.key) diff --git a/src/trees/BinaryTree/BinaryTree.kt b/src/trees/BinaryTree/BinaryTree.kt index 00c31ec..3936570 100644 --- a/src/trees/BinaryTree/BinaryTree.kt +++ b/src/trees/BinaryTree/BinaryTree.kt @@ -5,7 +5,9 @@ import BinaryNode class BinaryTree, NodeType> { private var root : BinaryNode? = null fun search(key : T) : NodeType? = root?.search(key) - fun delete(key: T) = root?.delete(key) + fun remove(key: T) { + root = root?.remove(this.root, key) + } fun add(key : T, value : NodeType) { if (root == null) root = BinaryNode(key, value, null) From 7dbae5e7ae63ede115142f0cc3a3973e2d46e5f3 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 6 Apr 2023 18:47:53 +0300 Subject: [PATCH 018/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=80?= =?UTF-8?q?=D0=B8=D0=B8=20=D0=B8=20=D0=BF=D0=BE=D1=87=D0=B8=D1=81=D1=82?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BA=D0=BE=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/nodes/{ => BinaryNode}/BinaryNode.kt | 56 ++++++++++++------------ src/trees/BinaryTree/BinaryTree.kt | 16 +++---- 2 files changed, 37 insertions(+), 35 deletions(-) rename src/nodes/{ => BinaryNode}/BinaryNode.kt (61%) diff --git a/src/nodes/BinaryNode.kt b/src/nodes/BinaryNode/BinaryNode.kt similarity index 61% rename from src/nodes/BinaryNode.kt rename to src/nodes/BinaryNode/BinaryNode.kt index 4b48ab7..ab73d2e 100644 --- a/src/nodes/BinaryNode.kt +++ b/src/nodes/BinaryNode/BinaryNode.kt @@ -1,25 +1,25 @@ -class BinaryNode, NodeType>(key : T, value : NodeType, parent : BinaryNode?) : Comparable> { +package BinaryNode - var key : T private set - var value : NodeType private set +/** + * Класс узла для бинарного дерева. + * + * Позволяет рекурсивно реализовывать операции *поиска*, *удаления*, *добавления*. + * + * @property key ключ для поиска. + * @property value значение узла. + * @author Dmitriy Zaytsev + */ +open class BinaryNode, NodeType>(key: T, value: NodeType) : Comparable> { -// private var parent : BinaryNode? = null + open var key : T = key + protected set + open var value : NodeType = value + protected set - private var right : BinaryNode? = null - private var left : BinaryNode? = null + protected open var right : BinaryNode? = null + protected open var left : BinaryNode? = null - var hasChildren: Boolean - get() = !(this.right == null && this.left == null) - private set - - init { - hasChildren = false - key.also { this.key = it } - value.also { this.value = it } -// parent?.also { this.parent = it } - } - - fun search(key: T) : NodeType? = + open fun search(key: T) : NodeType? = when (key.compareTo(this.key)) { 1 -> this.right?.search(key) 0 -> this.value @@ -27,10 +27,9 @@ class BinaryNode, NodeType>(key : T, value : NodeType, parent : else -> null } - fun remove(root : BinaryNode?, key : T) : BinaryNode? { + open fun remove(root : BinaryNode?, key : T) : BinaryNode? { if (root == null) return null - if (key == this.key) { // когда remove вызывается для удаляемой вершины if (this.right == null && this.left == null) return null @@ -61,24 +60,28 @@ class BinaryNode, NodeType>(key : T, value : NodeType, parent : } } - private fun findMin(node: BinaryNode?): BinaryNode? = if (node?.left != null) findMin(node!!.left) else node + /** + * @param[node] Узел для которого ищется минимальный эл-т. + * @return Наименьший узел. + */ + private fun findMin(node: BinaryNode?): BinaryNode? = if (node?.left != null) findMin(node.left) else node @Throws(Exception::class) - fun insert(key : T, value : NodeType) { + open fun add(key : T, value : NodeType) { val compare = key.compareTo(this.key) if (compare == 1) { if (right == null) - right = BinaryNode(key, value, this) + right = BinaryNode(key, value) else - right!!.insert(key, value) + right!!.add(key, value) } else if (compare == 0) { throw Exception("Keys can't be equal") } else { if (left == null) - left = BinaryNode(key, value, this) + left = BinaryNode(key, value) else - left!!.insert(key, value) + left!!.add(key, value) } } @@ -86,5 +89,4 @@ class BinaryNode, NodeType>(key : T, value : NodeType, parent : return "<$key, $value>" } override fun compareTo(other: BinaryNode): Int = this.key.compareTo(other.key) - fun compareTo(key: T): Int = this.key.compareTo(key) } \ No newline at end of file diff --git a/src/trees/BinaryTree/BinaryTree.kt b/src/trees/BinaryTree/BinaryTree.kt index 3936570..69b5057 100644 --- a/src/trees/BinaryTree/BinaryTree.kt +++ b/src/trees/BinaryTree/BinaryTree.kt @@ -1,18 +1,18 @@ package BinaryTree -import BinaryNode +import BinaryNode.BinaryNode -class BinaryTree, NodeType> { - private var root : BinaryNode? = null - fun search(key : T) : NodeType? = root?.search(key) - fun remove(key: T) { +open class BinaryTree, NodeType> { + protected open var root : BinaryNode? = null + open fun search(key : T) : NodeType? = root?.search(key) + open fun remove(key: T) { root = root?.remove(this.root, key) } - fun add(key : T, value : NodeType) { + open fun add(key : T, value : NodeType) { if (root == null) - root = BinaryNode(key, value, null) + root = BinaryNode(key, value) else { - root!!.insert(key, value) + root!!.add(key, value) } } } \ No newline at end of file From 18960ebc355c4758b0a43b103b95a911c959a1bc Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 11 Apr 2023 14:35:16 +0300 Subject: [PATCH 019/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20gradle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitattributes | 9 + .gitignore | 6 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61608 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 244 +++++++++++++++++++++++ gradlew.bat | 92 +++++++++ lib/build.gradle | 39 ++++ lib/src/main/kotlin/trees/Library.kt | 10 + lib/src/test/kotlin/trees/LibraryTest.kt | 14 ++ settings.gradle | 11 + 10 files changed, 431 insertions(+) create mode 100644 .gitattributes create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 lib/build.gradle create mode 100644 lib/src/main/kotlin/trees/Library.kt create mode 100644 lib/src/test/kotlin/trees/LibraryTest.kt create mode 100644 settings.gradle diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..097f9f9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + diff --git a/.gitignore b/.gitignore index 4884e53..967fea9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,9 @@ target/ *.ipr /out/ /.idea/ + +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..ccebba7710deaf9f98673a68957ea02138b60d0a GIT binary patch literal 61608 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..bdc9a83 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..79a61d4 --- /dev/null +++ b/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/lib/build.gradle b/lib/build.gradle new file mode 100644 index 0000000..d1dd836 --- /dev/null +++ b/lib/build.gradle @@ -0,0 +1,39 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Kotlin library 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/8.0.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.8.10' + + // Apply the java-library plugin for API and implementation separation. + id 'java-library' +} + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() +} + +dependencies { + // Use the Kotlin JUnit 5 integration. + testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5' + + // Use the JUnit 5 integration. + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.1' + + // This dependency is exported to consumers, that is to say found on their compile classpath. + api 'org.apache.commons:commons-math3:3.6.1' + + // This dependency is used internally, and not exposed to consumers on their own compile classpath. + implementation 'com.google.guava:guava:31.1-jre' +} + +tasks.named('test') { + // Use JUnit Platform for unit tests. + useJUnitPlatform() +} diff --git a/lib/src/main/kotlin/trees/Library.kt b/lib/src/main/kotlin/trees/Library.kt new file mode 100644 index 0000000..d3a076e --- /dev/null +++ b/lib/src/main/kotlin/trees/Library.kt @@ -0,0 +1,10 @@ +/* + * This Kotlin source file was generated by the Gradle 'init' task. + */ +package trees + +class Library { + fun someLibraryMethod(): Boolean { + return true + } +} diff --git a/lib/src/test/kotlin/trees/LibraryTest.kt b/lib/src/test/kotlin/trees/LibraryTest.kt new file mode 100644 index 0000000..5db0da8 --- /dev/null +++ b/lib/src/test/kotlin/trees/LibraryTest.kt @@ -0,0 +1,14 @@ +/* + * This Kotlin source file was generated by the Gradle 'init' task. + */ +package trees + +import kotlin.test.Test +import kotlin.test.assertTrue + +class LibraryTest { + @Test fun someLibraryMethodReturnsTrue() { + val classUnderTest = Library() + assertTrue(classUnderTest.someLibraryMethod(), "someLibraryMethod should return 'true'") + } +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..5986231 --- /dev/null +++ b/settings.gradle @@ -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/8.0.2/userguide/multi_project_builds.html + */ + +rootProject.name = 'trees' +include('lib') From bec1445fc4907c2d68b2caec85723b47e9c5cf20 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 11 Apr 2023 14:36:40 +0300 Subject: [PATCH 020/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20=D0=B8=D0=B7=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/build.gradle | 20 ------------------- .../kotlin}/nodes/BinaryNode/BinaryNode.kt | 0 .../kotlin}/trees/BinaryTree/BinaryTree.kt | 0 lib/src/main/kotlin/trees/Library.kt | 10 ---------- lib/src/test/kotlin/trees/LibraryTest.kt | 14 ------------- settings.gradle | 9 --------- src/main/Main.kt | 5 ----- 7 files changed, 58 deletions(-) rename {src => lib/src/main/kotlin}/nodes/BinaryNode/BinaryNode.kt (100%) rename {src => lib/src/main/kotlin}/trees/BinaryTree/BinaryTree.kt (100%) delete mode 100644 lib/src/main/kotlin/trees/Library.kt delete mode 100644 lib/src/test/kotlin/trees/LibraryTest.kt delete mode 100644 src/main/Main.kt diff --git a/lib/build.gradle b/lib/build.gradle index d1dd836..0084590 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -1,39 +1,19 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * This generated file contains a sample Kotlin library 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/8.0.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.8.10' - - // Apply the java-library plugin for API and implementation separation. id 'java-library' } repositories { - // Use Maven Central for resolving dependencies. mavenCentral() } dependencies { - // Use the Kotlin JUnit 5 integration. testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5' - - // Use the JUnit 5 integration. testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.1' - - // This dependency is exported to consumers, that is to say found on their compile classpath. api 'org.apache.commons:commons-math3:3.6.1' - - // This dependency is used internally, and not exposed to consumers on their own compile classpath. implementation 'com.google.guava:guava:31.1-jre' } tasks.named('test') { - // Use JUnit Platform for unit tests. useJUnitPlatform() } diff --git a/src/nodes/BinaryNode/BinaryNode.kt b/lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt similarity index 100% rename from src/nodes/BinaryNode/BinaryNode.kt rename to lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt diff --git a/src/trees/BinaryTree/BinaryTree.kt b/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt similarity index 100% rename from src/trees/BinaryTree/BinaryTree.kt rename to lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt diff --git a/lib/src/main/kotlin/trees/Library.kt b/lib/src/main/kotlin/trees/Library.kt deleted file mode 100644 index d3a076e..0000000 --- a/lib/src/main/kotlin/trees/Library.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This Kotlin source file was generated by the Gradle 'init' task. - */ -package trees - -class Library { - fun someLibraryMethod(): Boolean { - return true - } -} diff --git a/lib/src/test/kotlin/trees/LibraryTest.kt b/lib/src/test/kotlin/trees/LibraryTest.kt deleted file mode 100644 index 5db0da8..0000000 --- a/lib/src/test/kotlin/trees/LibraryTest.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This Kotlin source file was generated by the Gradle 'init' task. - */ -package trees - -import kotlin.test.Test -import kotlin.test.assertTrue - -class LibraryTest { - @Test fun someLibraryMethodReturnsTrue() { - val classUnderTest = Library() - assertTrue(classUnderTest.someLibraryMethod(), "someLibraryMethod should return 'true'") - } -} diff --git a/settings.gradle b/settings.gradle index 5986231..0e6e81e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,11 +1,2 @@ -/* - * 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/8.0.2/userguide/multi_project_builds.html - */ - rootProject.name = 'trees' include('lib') diff --git a/src/main/Main.kt b/src/main/Main.kt deleted file mode 100644 index 5cf9f3b..0000000 --- a/src/main/Main.kt +++ /dev/null @@ -1,5 +0,0 @@ -package main - -fun main() { - println("Hello World!") -} \ No newline at end of file From af072b8f190fdd6b142e857b61f1718a7a768b4a Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 11 Apr 2023 14:50:23 +0300 Subject: [PATCH 021/203] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 967fea9..a3faa49 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ target/ # Ignore Gradle build output directory build +/gradle/ From fc721790beeb8e6a6f4ec7471174aa29fffd07c7 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 11 Apr 2023 18:37:36 +0300 Subject: [PATCH 022/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20App.kt=20=D0=B2=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/build.gradle | 24 ++++++++++++++++++++++++ App/src/main/kotlin/app/App.kt | 9 +++++++++ settings.gradle | 4 ++-- 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 App/build.gradle create mode 100644 App/src/main/kotlin/app/App.kt diff --git a/App/build.gradle b/App/build.gradle new file mode 100644 index 0000000..fea29ad --- /dev/null +++ b/App/build.gradle @@ -0,0 +1,24 @@ +plugins { + id 'org.jetbrains.kotlin.jvm' version '1.8.10' + id 'application' +} + +application { + mainClass = 'app.AppKt' +} + +repositories { + mavenCentral() +} + +dependencies { + implementation project(path: ':lib') + testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5' + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.1' + api 'org.apache.commons:commons-math3:3.6.1' + implementation 'com.google.guava:guava:31.1-jre' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt new file mode 100644 index 0000000..c9ce7b3 --- /dev/null +++ b/App/src/main/kotlin/app/App.kt @@ -0,0 +1,9 @@ +package app + +import BinaryTree.BinaryTree + +fun main() { + val tree = BinaryTree() + tree.add(100, "Hello World!") + println(tree.search(100)) +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 0e6e81e..ed4a47b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ -rootProject.name = 'trees' -include('lib') +rootProject.name = 'trees-10' +include('lib', "App") From 896bbd2a3a32df79b3284010a1e993e4f7c0e9fe Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 12 Apr 2023 10:55:14 +0300 Subject: [PATCH 023/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BF=D0=B0=D0=BF=D0=BA=D1=83=20=D1=81=20=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D0=BC=D0=B8=20=D0=B2=20lib?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/build.gradle | 7 +++++++ lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt | 5 +++++ 2 files changed, 12 insertions(+) create mode 100644 lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt diff --git a/lib/build.gradle b/lib/build.gradle index 0084590..6650895 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -16,4 +16,11 @@ dependencies { tasks.named('test') { useJUnitPlatform() + beforeTest { descriptor -> + logger.lifecycle("Running test: " + descriptor) + } + onOutput { descriptor, event -> + logger.lifecycle("Test " + descriptor + " message: " + event.message ) + } + failFast = true } diff --git a/lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt b/lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt new file mode 100644 index 0000000..2064ba2 --- /dev/null +++ b/lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt @@ -0,0 +1,5 @@ +package trees.BinaryTree + +import org.junit.jupiter.api.Assertions.* + +class BinaryTreeTest \ No newline at end of file From 41ee39808e9f56211a61e341c08fb06684117244 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 12 Apr 2023 11:00:20 +0300 Subject: [PATCH 024/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=BD=D0=B0=20add?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/trees/BinaryTree/BinaryTreeTest.kt | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt b/lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt index 2064ba2..c4b92da 100644 --- a/lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt +++ b/lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt @@ -1,5 +1,38 @@ package trees.BinaryTree +import BinaryTree.BinaryTree import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.time.Duration.ofMillis +import kotlin.random.Random -class BinaryTreeTest \ No newline at end of file +class BinaryTreeTest { + + @Nested + inner class `Add check` { + @Test + fun `Simple add`() { + val tree = BinaryTree() + val list = listOf(100, 120, 10, -30) + for (item in list) + tree.add(item, item) + } + @Test + fun `Equal keys add`() { + val tree = BinaryTree() + tree.add(100, "root") + assertThrows { tree.add(100, "abc") } + } + @Test + fun `Multiply add`() { + assertTimeout(ofMillis(1000)) { + val tree = BinaryTree() + val list : List = (List(100000) { Random.nextInt(1, 100000) }).distinct().toMutableList() + for (item in list) + tree.add(item, 0) + } + } + } +} \ No newline at end of file From c7450bd001c0f98b5b24d0bf1cb5217eeacb06c7 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 12 Apr 2023 14:28:47 +0300 Subject: [PATCH 025/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D1=8F=D1=82?= =?UTF-8?q?=D1=8C=20null-=D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=20=D0=B2=20BinaryNode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt | 6 +++--- lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt b/lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt index ab73d2e..2f3fa22 100644 --- a/lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt +++ b/lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt @@ -9,11 +9,11 @@ package BinaryNode * @property value значение узла. * @author Dmitriy Zaytsev */ -open class BinaryNode, NodeType>(key: T, value: NodeType) : Comparable> { +open class BinaryNode, NodeType>(key: T, value: NodeType?) : Comparable> { open var key : T = key protected set - open var value : NodeType = value + open var value : NodeType? = value protected set protected open var right : BinaryNode? = null @@ -67,7 +67,7 @@ open class BinaryNode, NodeType>(key: T, value: NodeType) : Com private fun findMin(node: BinaryNode?): BinaryNode? = if (node?.left != null) findMin(node.left) else node @Throws(Exception::class) - open fun add(key : T, value : NodeType) { + open fun add(key : T, value : NodeType?) { val compare = key.compareTo(this.key) if (compare == 1) { diff --git a/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt b/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt index 69b5057..d9c5888 100644 --- a/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt +++ b/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt @@ -8,11 +8,12 @@ open class BinaryTree, NodeType> { open fun remove(key: T) { root = root?.remove(this.root, key) } - open fun add(key : T, value : NodeType) { + open fun add(key : T, value : NodeType?) { if (root == null) root = BinaryNode(key, value) else { root!!.add(key, value) } } + open fun add(key : T) = this.add(key, null) } \ No newline at end of file From 6356cd52ad66edaf2498ac61fa787578eca2c0ca Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 12 Apr 2023 14:44:42 +0300 Subject: [PATCH 026/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D1=8F=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BC=D0=B0=D1=81=D1=81=D0=B8=D0=B2=D1=8B=20=D0=BA?= =?UTF-8?q?=D0=BB=D1=8E=D1=87=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt b/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt index d9c5888..1408aff 100644 --- a/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt +++ b/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt @@ -16,4 +16,9 @@ open class BinaryTree, NodeType> { } } open fun add(key : T) = this.add(key, null) + open fun add(keys : Array) { + for (item in keys) + this.add(item) + } + } \ No newline at end of file From ff995b36b3decab20ee058e77e11ae0190c0b486 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 12 Apr 2023 14:47:54 +0300 Subject: [PATCH 027/203] =?UTF-8?q?=D0=9D=D0=B5=D0=BC=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8=D0=BB=20=D1=84?= =?UTF-8?q?=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20add?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt b/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt index 1408aff..baa5596 100644 --- a/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt +++ b/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt @@ -8,17 +8,16 @@ open class BinaryTree, NodeType> { open fun remove(key: T) { root = root?.remove(this.root, key) } - open fun add(key : T, value : NodeType?) { + open fun add(key : T, value : NodeType? = null) { if (root == null) root = BinaryNode(key, value) else { root!!.add(key, value) } } - open fun add(key : T) = this.add(key, null) - open fun add(keys : Array) { - for (item in keys) - this.add(item) + open fun add(keys : Array, values : Array? = null) { + for (i in 0..keys.count()) + this.add(keys[i], values?.get(i)) } } \ No newline at end of file From 1c8e1725ea634fe5c063b08ea25fa0e628bc8f2d Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 12 Apr 2023 18:44:51 +0300 Subject: [PATCH 028/203] =?UTF-8?q?=D0=9F=D1=80=D0=B8=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B8=20=D1=8D=D0=BB-?= =?UTF-8?q?=D0=B0=20=D1=81=20=D1=83=D0=B6=D0=B5=20=D1=81=D1=83=D1=89=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B2=D1=83=D1=8E=D1=89=D0=B8=D0=BC=20=D0=BA=D0=BB?= =?UTF-8?q?=D1=8E=D1=87=D0=BE=D0=BC=20value=20=D0=B7=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=8F=D0=B5=D1=82=D1=81=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt | 2 +- lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt b/lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt index 2f3fa22..82eb4b8 100644 --- a/lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt +++ b/lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt @@ -76,7 +76,7 @@ open class BinaryNode, NodeType>(key: T, value: NodeType?) : Co else right!!.add(key, value) } else if (compare == 0) { - throw Exception("Keys can't be equal") + this.value = value } else { if (left == null) left = BinaryNode(key, value) diff --git a/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt b/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt index baa5596..b0485d8 100644 --- a/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt +++ b/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt @@ -15,9 +15,5 @@ open class BinaryTree, NodeType> { root!!.add(key, value) } } - open fun add(keys : Array, values : Array? = null) { - for (i in 0..keys.count()) - this.add(keys[i], values?.get(i)) - } } \ No newline at end of file From a6d3fe61ee0696ed0ff9df2a9bc9a18b5ada86d0 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 12 Apr 2023 18:54:28 +0300 Subject: [PATCH 029/203] =?UTF-8?q?=D0=94=D0=BE=D0=BF=D0=B8=D1=81=D0=B0?= =?UTF-8?q?=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?BinaryTree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/build.gradle | 2 +- .../kotlin/trees/BinaryTree/BinaryTreeTest.kt | 89 +++++++++++++++++-- 2 files changed, 85 insertions(+), 6 deletions(-) diff --git a/lib/build.gradle b/lib/build.gradle index 6650895..8400d90 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -17,7 +17,7 @@ dependencies { tasks.named('test') { useJUnitPlatform() beforeTest { descriptor -> - logger.lifecycle("Running test: " + descriptor) + logger.lifecycle("Running test: " + descriptor.getDisplayName()) } onOutput { descriptor, event -> logger.lifecycle("Test " + descriptor + " message: " + event.message ) diff --git a/lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt b/lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt index c4b92da..b44bcf8 100644 --- a/lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt +++ b/lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt @@ -2,36 +2,115 @@ package trees.BinaryTree import BinaryTree.BinaryTree import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.api.function.Executable import java.time.Duration.ofMillis import kotlin.random.Random class BinaryTreeTest { + + @Nested + inner class `Remove check` { + + /** + * Добавляет последовательно массив из ключей с null value + */ + private fun , NodeType> BinaryTree.addGroup(keys : Array) { + for (item in keys) + this.add(item) + } + @Test + @DisplayName("Root remove") + fun `Root remove`() { + val tree = BinaryTree() + tree.add(100, "root") + tree.remove(100) + assertEquals(null, tree.search(100)) + } + @Test + @DisplayName("Simple element remove") + fun `Simple element remove`() { + val tree = BinaryTree() + tree.add(8, "root") + tree.add(10, "a") + tree.add(14, "b") + tree.add(13) + tree.remove(13) + assertAll("elements", + Executable { assertEquals("root", tree.search(8)) }, + Executable { assertEquals("a", tree.search(10)) }, + Executable { assertEquals("b", tree.search(14)) }, + Executable { assertEquals(null, tree.search(13)) } + ) + } + @Test + @DisplayName("Element with one child node remove") + fun `Element with one child node remove`() { + val tree = BinaryTree() + tree.add(8, "root") + tree.add(10, "a") + tree.add(14) + tree.add(13, "c") + tree.remove(14) + assertAll("elements", + Executable { assertEquals("root", tree.search(8)) }, + Executable { assertEquals("a", tree.search(10)) }, + Executable { assertEquals("c", tree.search(13)) }, + Executable { assertEquals(null, tree.search(14)) } + ) + } + @Test + @DisplayName("Element with two child nodes remove") + fun `Element with two child nodes remove`() { + val tree = BinaryTree() + tree.addGroup(arrayOf(8, 10, 14, 13, 3, 1, 6, 4, 7)) + tree.add(8, "root") + tree.add(4, "a") + tree.add(1, "b") + tree.add(6, "c") + tree.add(7, "d") + + tree.remove(3) + assertAll("elements", + Executable { assertEquals("a", tree.search(4)) }, + Executable { assertEquals("b", tree.search(1)) }, + Executable { assertEquals(null, tree.search(3)) }, + Executable { assertEquals("c", tree.search(6)) }, + Executable { assertEquals("d", tree.search(7)) }, + Executable { assertEquals("root", tree.search(8)) } + ) + } + } @Nested inner class `Add check` { @Test + @DisplayName("Simple add") fun `Simple add`() { - val tree = BinaryTree() - val list = listOf(100, 120, 10, -30) - for (item in list) - tree.add(item, item) + val tree = BinaryTree() + tree.add(30, "root") + assertEquals("root", tree.search(30)) } @Test + @DisplayName("Equal keys add") fun `Equal keys add`() { val tree = BinaryTree() + tree.add(100, "abc") tree.add(100, "root") - assertThrows { tree.add(100, "abc") } + assertEquals("root", tree.search(100)) } @Test + @DisplayName("Multiply add") fun `Multiply add`() { assertTimeout(ofMillis(1000)) { val tree = BinaryTree() val list : List = (List(100000) { Random.nextInt(1, 100000) }).distinct().toMutableList() for (item in list) tree.add(item, 0) + assertEquals(tree.search(list.last()), 0) } } } From 524c0aca1f3ebdd271702b52bfc26f8f7e4d7959 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 13 Apr 2023 13:14:25 +0300 Subject: [PATCH 030/203] =?UTF-8?q?=D0=9F=D0=BE=D1=87=D0=B8=D1=81=D1=82?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20BinaryNode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/{BinaryNode => }/BinaryNode.kt | 6 +----- lib/src/main/kotlin/trees/{BinaryTree => }/BinaryTree.kt | 0 .../test/kotlin/trees/{BinaryTree => }/BinaryTreeTest.kt | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) rename lib/src/main/kotlin/nodes/{BinaryNode => }/BinaryNode.kt (93%) rename lib/src/main/kotlin/trees/{BinaryTree => }/BinaryTree.kt (100%) rename lib/src/test/kotlin/trees/{BinaryTree => }/BinaryTreeTest.kt (99%) diff --git a/lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt b/lib/src/main/kotlin/nodes/BinaryNode.kt similarity index 93% rename from lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt rename to lib/src/main/kotlin/nodes/BinaryNode.kt index 82eb4b8..b8eeeb4 100644 --- a/lib/src/main/kotlin/nodes/BinaryNode/BinaryNode.kt +++ b/lib/src/main/kotlin/nodes/BinaryNode.kt @@ -9,7 +9,7 @@ package BinaryNode * @property value значение узла. * @author Dmitriy Zaytsev */ -open class BinaryNode, NodeType>(key: T, value: NodeType?) : Comparable> { +open class BinaryNode, NodeType>(key: T, value: NodeType?) { open var key : T = key protected set @@ -85,8 +85,4 @@ open class BinaryNode, NodeType>(key: T, value: NodeType?) : Co } } - override fun toString(): String { - return "<$key, $value>" - } - override fun compareTo(other: BinaryNode): Int = this.key.compareTo(other.key) } \ No newline at end of file diff --git a/lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt b/lib/src/main/kotlin/trees/BinaryTree.kt similarity index 100% rename from lib/src/main/kotlin/trees/BinaryTree/BinaryTree.kt rename to lib/src/main/kotlin/trees/BinaryTree.kt diff --git a/lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt b/lib/src/test/kotlin/trees/BinaryTreeTest.kt similarity index 99% rename from lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt rename to lib/src/test/kotlin/trees/BinaryTreeTest.kt index b44bcf8..deded72 100644 --- a/lib/src/test/kotlin/trees/BinaryTree/BinaryTreeTest.kt +++ b/lib/src/test/kotlin/trees/BinaryTreeTest.kt @@ -1,4 +1,4 @@ -package trees.BinaryTree +package trees import BinaryTree.BinaryTree import org.junit.jupiter.api.Assertions.* From 7b1e1d73e006e9e2cb79dcd4ec48cea636b4960b Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 15 Apr 2023 20:59:05 +0300 Subject: [PATCH 031/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20workflow=20=D1=84=D0=B0=D0=B9=D0=BB=20c=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BF=D1=83=D1=81=D0=BA=D0=BE=D0=BC=20=D0=B8=20=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=D0=BC=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/gradle.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/gradle.yml diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 0000000..a5fa514 --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,22 @@ +name: Gradle Build&Test +on: [push, pull_request] +jobs: + gradle: + + runs-on: ubuntu-latest + steps: + + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 11 + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + + - name: Build + run: ./gradlew build + + - name: Test + run: ./gradlew test From 2dd9e4764d8b1f248ba4bee8eaf681be5e7bdc84 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 16 Apr 2023 23:49:53 +0300 Subject: [PATCH 032/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5=D0=B9=D1=81?= =?UTF-8?q?=20ITree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/BinaryNode.kt | 2 +- lib/src/main/kotlin/trees/BinaryTree.kt | 2 +- lib/src/main/kotlin/trees/ITree.kt | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 lib/src/main/kotlin/trees/ITree.kt diff --git a/lib/src/main/kotlin/nodes/BinaryNode.kt b/lib/src/main/kotlin/nodes/BinaryNode.kt index b8eeeb4..b9beb50 100644 --- a/lib/src/main/kotlin/nodes/BinaryNode.kt +++ b/lib/src/main/kotlin/nodes/BinaryNode.kt @@ -1,4 +1,4 @@ -package BinaryNode +package nodes /** * Класс узла для бинарного дерева. diff --git a/lib/src/main/kotlin/trees/BinaryTree.kt b/lib/src/main/kotlin/trees/BinaryTree.kt index b0485d8..bb71e08 100644 --- a/lib/src/main/kotlin/trees/BinaryTree.kt +++ b/lib/src/main/kotlin/trees/BinaryTree.kt @@ -1,4 +1,4 @@ -package BinaryTree +package trees import BinaryNode.BinaryNode diff --git a/lib/src/main/kotlin/trees/ITree.kt b/lib/src/main/kotlin/trees/ITree.kt new file mode 100644 index 0000000..ed91a87 --- /dev/null +++ b/lib/src/main/kotlin/trees/ITree.kt @@ -0,0 +1,8 @@ +package trees + +interface ITree, NodeType> { + fun search(key : T) : NodeType? + fun remove(key : T) + fun add(key : T, value : NodeType? = null) + +} \ No newline at end of file From 7388c74742c90655369c3ee543e4e72ed15427fb Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 16 Apr 2023 23:50:59 +0300 Subject: [PATCH 033/203] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BB=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84?= =?UTF-8?q?=D0=B5=D0=B9=D1=81=20=D0=B2=20BinaryNode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/trees/BinaryTree.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/src/main/kotlin/trees/BinaryTree.kt b/lib/src/main/kotlin/trees/BinaryTree.kt index bb71e08..4156584 100644 --- a/lib/src/main/kotlin/trees/BinaryTree.kt +++ b/lib/src/main/kotlin/trees/BinaryTree.kt @@ -1,14 +1,14 @@ package trees -import BinaryNode.BinaryNode +import nodes.BinaryNode -open class BinaryTree, NodeType> { +open class BinaryTree, NodeType> : ITree { protected open var root : BinaryNode? = null - open fun search(key : T) : NodeType? = root?.search(key) - open fun remove(key: T) { + override fun search(key : T) : NodeType? = root?.search(key) + override fun remove(key: T) { root = root?.remove(this.root, key) } - open fun add(key : T, value : NodeType? = null) { + override fun add(key : T, value : NodeType?) { if (root == null) root = BinaryNode(key, value) else { From 6f58fb52c47ceaed6a35a454ad2a3709cdf8f1f8 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 16 Apr 2023 23:54:24 +0300 Subject: [PATCH 034/203] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BB=20=D0=BF=D0=B0=D0=BA=D0=B5?= =?UTF-8?q?=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/BinaryTreeTest.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/src/test/kotlin/trees/BinaryTreeTest.kt b/lib/src/test/kotlin/trees/BinaryTreeTest.kt index deded72..ba71b15 100644 --- a/lib/src/test/kotlin/trees/BinaryTreeTest.kt +++ b/lib/src/test/kotlin/trees/BinaryTreeTest.kt @@ -1,11 +1,10 @@ package trees -import BinaryTree.BinaryTree +import trees.BinaryTree import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.function.Executable import java.time.Duration.ofMillis import kotlin.random.Random From 4e18a036a50c857e85953f452d3d5d99838ad1c3 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 16 Apr 2023 23:58:46 +0300 Subject: [PATCH 035/203] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA=D1=83=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index c9ce7b3..ed1beeb 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -1,6 +1,6 @@ package app -import BinaryTree.BinaryTree +import trees.BinaryTree fun main() { val tree = BinaryTree() From b402256432805bcb8c326528adbc4506922f3c53 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 17 Apr 2023 00:42:14 +0300 Subject: [PATCH 036/203] =?UTF-8?q?=D0=97=D0=B0=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5=D0=B9=D1=81?= =?UTF-8?q?=20=D0=BD=D0=B0=20=D0=B0=D0=B1=D1=81=D1=82=D1=80=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BD=D1=8B=D0=B5=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D1=8B?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D0=BD=D0=BE=D0=B4=20=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B2=D1=8C=D0=B5=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/AbstractNode.kt | 11 ++++++ lib/src/main/kotlin/nodes/BinaryNode.kt | 22 +++++------- lib/src/main/kotlin/trees/AbstractTree.kt | 10 ++++++ lib/src/main/kotlin/trees/BinaryTree.kt | 14 ++++---- lib/src/main/kotlin/trees/ITree.kt | 8 ----- lib/src/test/kotlin/trees/BinaryTreeTest.kt | 37 ++++++++++----------- 6 files changed, 53 insertions(+), 49 deletions(-) create mode 100644 lib/src/main/kotlin/nodes/AbstractNode.kt create mode 100644 lib/src/main/kotlin/trees/AbstractTree.kt delete mode 100644 lib/src/main/kotlin/trees/ITree.kt diff --git a/lib/src/main/kotlin/nodes/AbstractNode.kt b/lib/src/main/kotlin/nodes/AbstractNode.kt new file mode 100644 index 0000000..78c46be --- /dev/null +++ b/lib/src/main/kotlin/nodes/AbstractNode.kt @@ -0,0 +1,11 @@ +package nodes + +abstract class AbstractNode, V, NodeType : AbstractNode>() { + abstract var key : K + protected set + abstract var value : V? + protected set + + abstract var right : NodeType? + abstract var left : NodeType? +} \ No newline at end of file diff --git a/lib/src/main/kotlin/nodes/BinaryNode.kt b/lib/src/main/kotlin/nodes/BinaryNode.kt index b9beb50..83cd129 100644 --- a/lib/src/main/kotlin/nodes/BinaryNode.kt +++ b/lib/src/main/kotlin/nodes/BinaryNode.kt @@ -9,25 +9,20 @@ package nodes * @property value значение узла. * @author Dmitriy Zaytsev */ -open class BinaryNode, NodeType>(key: T, value: NodeType?) { +open class BinaryNode, V>(override var key: K, override var value: V?) : AbstractNode>() { - open var key : T = key - protected set - open var value : NodeType? = value - protected set + override var right : BinaryNode? = null + override var left : BinaryNode? = null - protected open var right : BinaryNode? = null - protected open var left : BinaryNode? = null - - open fun search(key: T) : NodeType? = + open fun search(key: K) : BinaryNode? = when (key.compareTo(this.key)) { 1 -> this.right?.search(key) - 0 -> this.value + 0 -> this -1 -> this.left?.search(key) else -> null } - open fun remove(root : BinaryNode?, key : T) : BinaryNode? { + open fun remove(root : BinaryNode?, key : K) : BinaryNode? { if (root == null) return null if (key == this.key) { // когда remove вызывается для удаляемой вершины @@ -64,10 +59,9 @@ open class BinaryNode, NodeType>(key: T, value: NodeType?) { * @param[node] Узел для которого ищется минимальный эл-т. * @return Наименьший узел. */ - private fun findMin(node: BinaryNode?): BinaryNode? = if (node?.left != null) findMin(node.left) else node + private fun findMin(node: BinaryNode?): BinaryNode? = if (node?.left != null) findMin(node.left) else node - @Throws(Exception::class) - open fun add(key : T, value : NodeType?) { + open fun add(key : K, value : V?) { val compare = key.compareTo(this.key) if (compare == 1) { diff --git a/lib/src/main/kotlin/trees/AbstractTree.kt b/lib/src/main/kotlin/trees/AbstractTree.kt new file mode 100644 index 0000000..8c2ae4f --- /dev/null +++ b/lib/src/main/kotlin/trees/AbstractTree.kt @@ -0,0 +1,10 @@ +package trees + +import nodes.AbstractNode + +abstract class AbstractTree, V, NodeType : AbstractNode> { + protected abstract var root : NodeType? + abstract fun search(key : K) : NodeType? + abstract fun add(key : K, value : V? = null) + abstract fun remove(key : K) +} \ No newline at end of file diff --git a/lib/src/main/kotlin/trees/BinaryTree.kt b/lib/src/main/kotlin/trees/BinaryTree.kt index 4156584..648b0b5 100644 --- a/lib/src/main/kotlin/trees/BinaryTree.kt +++ b/lib/src/main/kotlin/trees/BinaryTree.kt @@ -2,18 +2,16 @@ package trees import nodes.BinaryNode -open class BinaryTree, NodeType> : ITree { - protected open var root : BinaryNode? = null - override fun search(key : T) : NodeType? = root?.search(key) - override fun remove(key: T) { +open class BinaryTree, V> : AbstractTree>() { + override var root : BinaryNode? = null + override fun search(key : K) : BinaryNode? = root?.search(key) + override fun remove(key: K) { root = root?.remove(this.root, key) } - override fun add(key : T, value : NodeType?) { + override fun add(key : K, value : V?) { if (root == null) root = BinaryNode(key, value) - else { + else root!!.add(key, value) - } } - } \ No newline at end of file diff --git a/lib/src/main/kotlin/trees/ITree.kt b/lib/src/main/kotlin/trees/ITree.kt deleted file mode 100644 index ed91a87..0000000 --- a/lib/src/main/kotlin/trees/ITree.kt +++ /dev/null @@ -1,8 +0,0 @@ -package trees - -interface ITree, NodeType> { - fun search(key : T) : NodeType? - fun remove(key : T) - fun add(key : T, value : NodeType? = null) - -} \ No newline at end of file diff --git a/lib/src/test/kotlin/trees/BinaryTreeTest.kt b/lib/src/test/kotlin/trees/BinaryTreeTest.kt index ba71b15..2f2e83f 100644 --- a/lib/src/test/kotlin/trees/BinaryTreeTest.kt +++ b/lib/src/test/kotlin/trees/BinaryTreeTest.kt @@ -1,6 +1,5 @@ package trees -import trees.BinaryTree import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested @@ -28,7 +27,7 @@ class BinaryTreeTest { val tree = BinaryTree() tree.add(100, "root") tree.remove(100) - assertEquals(null, tree.search(100)) + assertEquals(null, tree.search(100)?.value) } @Test @DisplayName("Simple element remove") @@ -40,10 +39,10 @@ class BinaryTreeTest { tree.add(13) tree.remove(13) assertAll("elements", - Executable { assertEquals("root", tree.search(8)) }, - Executable { assertEquals("a", tree.search(10)) }, - Executable { assertEquals("b", tree.search(14)) }, - Executable { assertEquals(null, tree.search(13)) } + Executable { assertEquals("root", tree.search(8)?.value) }, + Executable { assertEquals("a", tree.search(10)?.value) }, + Executable { assertEquals("b", tree.search(14)?.value) }, + Executable { assertEquals(null, tree.search(13)?.value) } ) } @Test @@ -56,10 +55,10 @@ class BinaryTreeTest { tree.add(13, "c") tree.remove(14) assertAll("elements", - Executable { assertEquals("root", tree.search(8)) }, - Executable { assertEquals("a", tree.search(10)) }, - Executable { assertEquals("c", tree.search(13)) }, - Executable { assertEquals(null, tree.search(14)) } + Executable { assertEquals("root", tree.search(8)?.value) }, + Executable { assertEquals("a", tree.search(10)?.value) }, + Executable { assertEquals("c", tree.search(13)?.value) }, + Executable { assertEquals(null, tree.search(14)?.value) } ) } @Test @@ -75,12 +74,12 @@ class BinaryTreeTest { tree.remove(3) assertAll("elements", - Executable { assertEquals("a", tree.search(4)) }, - Executable { assertEquals("b", tree.search(1)) }, - Executable { assertEquals(null, tree.search(3)) }, - Executable { assertEquals("c", tree.search(6)) }, - Executable { assertEquals("d", tree.search(7)) }, - Executable { assertEquals("root", tree.search(8)) } + Executable { assertEquals("a", tree.search(4)?.value) }, + Executable { assertEquals("b", tree.search(1)?.value) }, + Executable { assertEquals(null, tree.search(3)?.value) }, + Executable { assertEquals("c", tree.search(6)?.value) }, + Executable { assertEquals("d", tree.search(7)?.value) }, + Executable { assertEquals("root", tree.search(8)?.value) } ) } } @@ -91,7 +90,7 @@ class BinaryTreeTest { fun `Simple add`() { val tree = BinaryTree() tree.add(30, "root") - assertEquals("root", tree.search(30)) + assertEquals("root", tree.search(30)?.value) } @Test @DisplayName("Equal keys add") @@ -99,7 +98,7 @@ class BinaryTreeTest { val tree = BinaryTree() tree.add(100, "abc") tree.add(100, "root") - assertEquals("root", tree.search(100)) + assertEquals("root", tree.search(100)?.value) } @Test @DisplayName("Multiply add") @@ -109,7 +108,7 @@ class BinaryTreeTest { val list : List = (List(100000) { Random.nextInt(1, 100000) }).distinct().toMutableList() for (item in list) tree.add(item, 0) - assertEquals(tree.search(list.last()), 0) + assertEquals(tree.search(list.last())?.value, 0) } } } From b798d9ba8b1a36c78bf4373bcc6f44beb14c2997 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 17 Apr 2023 22:58:21 +0300 Subject: [PATCH 037/203] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20!!=20?= =?UTF-8?q?=D0=B8=D0=B7=20=D0=BA=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/BinaryNode.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/src/main/kotlin/nodes/BinaryNode.kt b/lib/src/main/kotlin/nodes/BinaryNode.kt index 83cd129..2cd4a87 100644 --- a/lib/src/main/kotlin/nodes/BinaryNode.kt +++ b/lib/src/main/kotlin/nodes/BinaryNode.kt @@ -39,9 +39,11 @@ open class BinaryNode, V>(override var key: K, override var val // Перенимаем его key и value // Удаляем минимальное дерево val minNode = findMin(this.right) - this.key = minNode!!.key - this.value = minNode.value - this.right = right!!.remove(this.right, minNode.key) + minNode?.let { + this.key = it.key + this.value = it.value + } + this.right = right?.remove(right, key) return this } @@ -68,14 +70,14 @@ open class BinaryNode, V>(override var key: K, override var val if (right == null) right = BinaryNode(key, value) else - right!!.add(key, value) + right?.add(key, value) } else if (compare == 0) { this.value = value } else { if (left == null) left = BinaryNode(key, value) else - left!!.add(key, value) + left?.add(key, value) } } From d4c509896d1558db0184802425692e8f70784bc8 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 18 Apr 2023 00:30:14 +0300 Subject: [PATCH 038/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=85=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=BD=D0=BE=D0=B4=20=D0=B2=20=D0=B1=D0=B0=D0=B7=D0=B5=20=D0=B4?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20(SQLite)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + lib/build.gradle | 4 ++ lib/src/main/kotlin/databases/BinaryBase.kt | 48 +++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 lib/src/main/kotlin/databases/BinaryBase.kt diff --git a/.gitignore b/.gitignore index a3faa49..b1c583d 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ target/ # Ignore Gradle build output directory build /gradle/ +/App/test.db diff --git a/lib/build.gradle b/lib/build.gradle index 8400d90..0552a08 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -3,6 +3,7 @@ plugins { id 'java-library' } + repositories { mavenCentral() } @@ -12,6 +13,9 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.1' api 'org.apache.commons:commons-math3:3.6.1' implementation 'com.google.guava:guava:31.1-jre' + + implementation("org.xerial:sqlite-jdbc:3.32.3.2") + implementation("io.github.microutils:kotlin-logging-jvm:2.0.6") } tasks.named('test') { diff --git a/lib/src/main/kotlin/databases/BinaryBase.kt b/lib/src/main/kotlin/databases/BinaryBase.kt new file mode 100644 index 0000000..f2f2ea9 --- /dev/null +++ b/lib/src/main/kotlin/databases/BinaryBase.kt @@ -0,0 +1,48 @@ +package databases + +import nodes.BinaryNode +import java.io.Closeable +import java.sql.DriverManager +import java.sql.SQLException + +data class Node(val binNode: NodeType, val x: Int, val y : Int) +class BinaryBase (path: String): Closeable { + + private val connection = DriverManager.getConnection("jdbc:sqlite:$path") + ?: throw SQLException("Cannot connect to database") + private val createBaseStatement by lazy {connection.prepareStatement("CREATE TABLE if not exists BinaryNodes (x int, y int, key int, value varchar(255));")} + private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO BinaryNodes (x, y, key, value) VALUES (?, ?, ?, ?);") } + private val getNodeByKey by lazy { connection.prepareStatement("SELECT x, y, value FROM BinaryNodes WHERE BinaryNodes.key = ?;") } + private val removeNodeByKey by lazy { connection.prepareStatement("DELETE FROM BinaryNodes WHERE key=?;") } + fun create() = createBaseStatement.execute() + + fun removeNode(key : Int) { + removeNodeByKey.setInt(1, key) + removeNodeByKey.execute() + } + fun addNode(node : Node>) { + addNodeStatement.setInt(1, node.x) + addNodeStatement.setInt(2, node.y) + addNodeStatement.setInt(3, node.binNode.key) + addNodeStatement.setString(4, node.binNode.value ?: "empty") + + addNodeStatement.execute() + } + fun search(key: Int) : Node>? { + getNodeByKey.setInt(1, key) + val res = getNodeByKey.executeQuery() + if (res.isClosed) + return null + + return Node(BinaryNode(key, res.getString("value")), res.getInt("x"), res.getInt("y")) + } + override fun close() { + createBaseStatement.close() + addNodeStatement.close() + getNodeByKey.close() + removeNodeByKey.close() + + connection.close() + } + +} \ No newline at end of file From 60c5f845fa98abcf174cd6d4791091d9926880a1 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 18 Apr 2023 00:47:14 +0300 Subject: [PATCH 039/203] =?UTF-8?q?=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D0=BD=D0=B5=D0=BB=D1=8C=D0=B7=D1=8F=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D1=8F=D1=82=D1=8C=20=D0=BE=D0=B4=D0=B8=D0=BD=D0=B0?= =?UTF-8?q?=D0=BA=D0=BE=D0=B2=D1=8B=D0=B5=20=D0=BD=D0=BE=D0=B4=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/{ => bin}/BinaryBase.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) rename lib/src/main/kotlin/databases/{ => bin}/BinaryBase.kt (93%) diff --git a/lib/src/main/kotlin/databases/BinaryBase.kt b/lib/src/main/kotlin/databases/bin/BinaryBase.kt similarity index 93% rename from lib/src/main/kotlin/databases/BinaryBase.kt rename to lib/src/main/kotlin/databases/bin/BinaryBase.kt index f2f2ea9..57f93ec 100644 --- a/lib/src/main/kotlin/databases/BinaryBase.kt +++ b/lib/src/main/kotlin/databases/bin/BinaryBase.kt @@ -1,4 +1,4 @@ -package databases +package databases.bin import nodes.BinaryNode import java.io.Closeable @@ -14,13 +14,16 @@ class BinaryBase (path: String): Closeable { private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO BinaryNodes (x, y, key, value) VALUES (?, ?, ?, ?);") } private val getNodeByKey by lazy { connection.prepareStatement("SELECT x, y, value FROM BinaryNodes WHERE BinaryNodes.key = ?;") } private val removeNodeByKey by lazy { connection.prepareStatement("DELETE FROM BinaryNodes WHERE key=?;") } - fun create() = createBaseStatement.execute() + fun open() = createBaseStatement.execute() fun removeNode(key : Int) { removeNodeByKey.setInt(1, key) removeNodeByKey.execute() } fun addNode(node : Node>) { + if (search(node.binNode.key) != null) + return + addNodeStatement.setInt(1, node.x) addNodeStatement.setInt(2, node.y) addNodeStatement.setInt(3, node.binNode.key) From 60312f04369d98e94150c37d402fc49399813e8f Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Tue, 18 Apr 2023 02:12:19 +0300 Subject: [PATCH 040/203] Add RBTree Node class --- lib/src/main/kotlin/nodes/RBTNode.kt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 lib/src/main/kotlin/nodes/RBTNode.kt diff --git a/lib/src/main/kotlin/nodes/RBTNode.kt b/lib/src/main/kotlin/nodes/RBTNode.kt new file mode 100644 index 0000000..27c279a --- /dev/null +++ b/lib/src/main/kotlin/nodes/RBTNode.kt @@ -0,0 +1,21 @@ +import nodes + +package RBTNode + +class RBNode, V>(override var key: K, override var value: V?) : + AbstractNode>() { + + override var right: RBNode? = null + override var left: RBNode? = null + var color: Color = Color.BLACK + private set + + fun flipColor() { + color = when (color) { + Color.RED -> Color.BLACK + Color.BLACK -> Color.RED + } + } +} + +enum class Color { RED, BLACK } From 378c877ba6aad9f5990c735299b9edf0e9f4aa82 Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Wed, 19 Apr 2023 04:15:22 +0300 Subject: [PATCH 041/203] Changed RBTNode, created RBTree --- lib/src/main/kotlin/nodes/RBTNode.kt | 3 +- lib/src/main/kotlin/trees/RBTree.kt | 233 +++++++++++++++++++++++++++ 2 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 lib/src/main/kotlin/trees/RBTree.kt diff --git a/lib/src/main/kotlin/nodes/RBTNode.kt b/lib/src/main/kotlin/nodes/RBTNode.kt index 27c279a..d98b124 100644 --- a/lib/src/main/kotlin/nodes/RBTNode.kt +++ b/lib/src/main/kotlin/nodes/RBTNode.kt @@ -7,8 +7,9 @@ class RBNode, V>(override var key: K, override var value: V?) override var right: RBNode? = null override var left: RBNode? = null + + var parent: RBNode? = null var color: Color = Color.BLACK - private set fun flipColor() { color = when (color) { diff --git a/lib/src/main/kotlin/trees/RBTree.kt b/lib/src/main/kotlin/trees/RBTree.kt new file mode 100644 index 0000000..fc87da5 --- /dev/null +++ b/lib/src/main/kotlin/trees/RBTree.kt @@ -0,0 +1,233 @@ +package RBTree + +import RBTNode +import AbstractTree + + +class RBTree, V> : AbstractTree>() { + override var root: RBNode? = null + + override fun search(key: K): RBNode? { + var node = root + while (node != null) { + when { + key < node.key -> node = node.left + key > node.key -> node = node.right + else -> return node //when found - return node + } + } + return null + } + + override fun add(key: K, value: V?) { + val newNode = RBNode(key, value) + if (root == null) { // if there is no root, make the node - new root + root = newNode + root?.color = Color.BLACK + return + } + + var node = root + var parent: RBNode? = null + while (node != null) { //move down the tree + parent = node + node = if (key < node.key) node.left else node.right + } + + newNode.color = Color.RED + newNode.parent = parent + + if (key < parent?.key ?: throw NullPointerException("Parent is null")) { //move up the tree, find needed place + parent.left = newNode + } else { + parent.right = newNode + } + + fixInsert(newNode) + } + + override fun remove(key: K) { + val node = search(key) ?: return //check if node is real + removeNode(node) + } + + private fun removeNode(node: RBNode) { + var replacementNode = when { + node.left == null -> node.right + node.right == null -> node.left + else -> { + var successor = node.right + while (successor?.left != null) { + successor = successor.left + } + if (successor?.parent != node) { + transplant(successor ?: throw IllegalArgumentException("Node cannot be null"), successor.right) + successor.right = node.right + successor.right?.parent = successor + } + transplant(node, successor ?: throw IllegalArgumentException("Node cannot be null")) + successor.left = node.left + successor.left?.parent = successor + successor.color = node.color + successor + } + } + + if (node.color == Color.BLACK) { + fixDelete(replacementNode) + } + + if (node.parent == null) { + root = replacementNode + } else if (node == (node.parent as RBNode).left) { + (node.parent as RBNode).left = replacementNode + } else { + (node.parent as RBNode).right = replacementNode + } + + replacementNode?.parent = node.parent + } + + private fun fixInsert(node: RBNode) { + var newNode = node + while (newNode.parent?.color == Color.RED) { + if (newNode.parent == newNode.parent?.parent?.left) { + val uncle = newNode.parent?.parent?.right + if (uncle?.color == Color.RED) { + newNode.parent?.color = Color.BLACK + uncle.color = Color.BLACK + newNode.parent?.parent?.color = Color.RED + newNode = newNode.parent?.parent ?: throw IllegalArgumentException("Node cannot be null") + } else { + if (newNode == newNode.parent?.right) { + newNode = newNode.parent ?: throw IllegalArgumentException("Node cannot be null") + leftRotate(newNode) + } + newNode.parent?.color = Color.BLACK + newNode.parent?.parent?.color = Color.RED + newNode.parent?.parent?.let { rightRotate(it) } ?: throw IllegalArgumentException("Node cannot be null") + } + } else { + val uncle = newNode.parent?.parent?.left + if (uncle?.color == Color.RED) { + newNode.parent?.color = Color.BLACK + uncle.color = Color.BLACK + newNode.parent?.parent?.color = Color.RED + newNode = newNode.parent?.parent ?: throw IllegalArgumentException("Node cannot be null") + } else { + if (newNode == newNode.parent?.left) { + newNode = newNode.parent ?: throw IllegalArgumentException("Node cannot be null") + rightRotate(newNode) + } + newNode.parent?.color = Color.BLACK + newNode.parent?.parent?.color = Color.RED + newNode.parent?.parent?.let { leftRotate(it) } ?: throw IllegalArgumentException("Node cannot be null") + } + } + } + root?.color = Color.BLACK + } + + private fun fixDelete(node: RBNode?) { + var currentNode = node + while (currentNode != root && currentNode?.color == Color.BLACK) { + if (currentNode == currentNode.parent?.left) { + var sibling = currentNode.parent?.right + if (sibling?.color == Color.RED) { + sibling.color = Color.BLACK + currentNode.parent?.color = Color.RED + leftRotate(currentNode.parent!!) + sibling = currentNode.parent?.right + } + if (sibling?.left?.color == Color.BLACK && sibling.right?.color == Color.BLACK) { + sibling.color = Color.RED + currentNode = currentNode.parent + } else { + if (sibling?.right?.color == Color.BLACK) { + sibling.left?.color = Color.BLACK + sibling.color = Color.RED + rightRotate(sibling) + sibling = currentNode.parent?.right + } + sibling?.color = currentNode.parent?.color ?: throw IllegalStateException("Parent color is null") + currentNode.parent?.color = Color.BLACK + sibling?.right?.color = Color.BLACK + leftRotate(currentNode.parent!!) ?: throw IllegalStateException("Left rotate failed") + currentNode = root + } + } else { + var sibling = currentNode.parent?.left + if (sibling?.color == Color.RED) { + sibling.color = Color.BLACK + currentNode.parent?.color = Color.RED + rightRotate(currentNode.parent!!) + sibling = currentNode.parent?.left + } + if (sibling?.right?.color == Color.BLACK && sibling.left?.color == Color.BLACK) { + sibling.color = Color.RED + currentNode = currentNode.parent + } else { + if (sibling?.left?.color == Color.BLACK) { + sibling.right?.color = Color.BLACK + sibling.color = Color.RED + leftRotate(sibling) + sibling = currentNode.parent?.left + } + sibling?.color = currentNode.parent?.color ?: throw IllegalStateException("Parent color is null") + currentNode.parent?.color = Color.BLACK + sibling?.left?.color = Color.BLACK + rightRotate(currentNode.parent!!) ?: throw IllegalStateException("Right rotate failed") + currentNode = root + } + } + } + currentNode?.color = Color.BLACK + } + + private fun leftRotate(node: RBNode) { + val rightChild = node.right ?: throw IllegalStateException("Right child is null") + node.right = rightChild.left + if (rightChild.left != null) { + rightChild.left!!.parent = node + } + rightChild.parent = node.parent + if (node.parent == null) { + root = rightChild + } else if (node == node.parent!!.left) { + node.parent!!.left = rightChild + } else { + node.parent!!.right = rightChild + } + rightChild.left = node + node.parent = rightChild + } + + private fun rightRotate(node: RBNode) { + val leftChild = node.left ?: throw IllegalStateException("Left child is null") + node.left = leftChild.right + if (leftChild.right != null) { + leftChild.right!!.parent = node + } + leftChild.parent = node.parent + if (node.parent == null) { + root = leftChild + } else if (node == node.parent!!.right) { + node.parent!!.right = leftChild + } else { + node.parent!!.left = leftChild + } + leftChild.right = node + node.parent = leftChild + } + + private fun transplant(u: RBNode?, v: RBNode?) { + if (u?.parent == null) { + root = v ?: throw IllegalStateException("Node v is null") + } else if (u == u.parent!!.left) { + u.parent!!.left = v ?: throw IllegalStateException("Node v is null") + } else { + u.parent!!.right = v ?: throw IllegalStateException("Node v is null") + } + v?.parent = u?.parent + } +} \ No newline at end of file From 0e001685ae91d370119d4c26961f40566670af44 Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov <113210919+twotwozeronine@users.noreply.github.com> Date: Wed, 19 Apr 2023 06:48:06 +0300 Subject: [PATCH 042/203] Create README.md --- README.md | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c3d524b..4c0ab6f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,34 @@ -# TODO -Заполнить README +# Описание проекта TREES-10 + +Этот проект содержит реализации трех типов деревьев: бинарное дерево поиска, AVL-дерево и красно-черное дерево. Все три типа деревьев наследуются из абстрактного класса AbstractTree, а их узлы наследуются из абстрактного класса AbstractNode. Система сборки - Gradle + +# Бинарное дерево поиска + +Бинарное дерево поиска - это структура данных, в которой каждый узел имеет не более двух потомков, и ключи в левом поддереве меньше, чем ключ в корне, а ключи в правом поддереве больше, чем ключ в корне. Бинарное дерево поиска реализовано в классе BinaryTree. + +# AVL-дерево + +AVL-дерево - это сбалансированное бинарное дерево поиска, в котором для каждого узла высота левого и правого поддеревьев различается не более чем на 1. AVL-дерево реализовано в классе AVLTree. + +# Красно-черное дерево + +Красно-черное дерево - это сбалансированное бинарное дерево поиска, в котором каждый узел имеет цвет - красный или черный. Каждый путь от корня до листа содержит одинаковое количество черных узлов. Красно-черное дерево реализовано в классе RBTree. + +# Сохранение деревьев + +Для сохранения деревьев мы используем три различных базы данных: SQLite, Neo4j и JSON. Бинарное дерево поиска сохраняется в SQLite, AVL-дерево сохраняется в Neo4j, RBTree сохраняется в JSON + +# Тестирование деревьев + +Тестирование каждого дерева проходит с помощью фреймворка JUnit. + +# Методы + +Чтобы пользоваться деревьями, необходимо использовать следующие команды: + +``` +val tree = \необходимое дерево\ +add.tree(key, value) //добавление элемента по ключу +remove.tree(key) //удаление элемента с заданным ключом +search.tree(key) //поиск элемента по заданному ключу +``` From 17cc27b8328a95cf7dd45c43f0732c26729263de Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Wed, 19 Apr 2023 08:33:59 +0300 Subject: [PATCH 043/203] Added tests for RBTree --- lib/src/test/kotlin/trees/RBTreeTest.kt | 69 +++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 lib/src/test/kotlin/trees/RBTreeTest.kt diff --git a/lib/src/test/kotlin/trees/RBTreeTest.kt b/lib/src/test/kotlin/trees/RBTreeTest.kt new file mode 100644 index 0000000..f549247 --- /dev/null +++ b/lib/src/test/kotlin/trees/RBTreeTest.kt @@ -0,0 +1,69 @@ +import org.junit.Assert.* +import org.junit.Test +import RBTree + +class RBTreeTest { + @Test + fun testAdd() { + val tree = RBTree() + tree.add(1, "one") + tree.add(2, "two") + tree.add(3, "three") + assertEquals("one", tree.search(1)) + assertEquals("two", tree.search(2)) + assertEquals("three", tree.search(3)) + } + + @Test + fun testSearch() { + val tree = RBTree() + tree.add(1, "one") + tree.add(2, "two") + tree.add(3, "three") + assertEquals("one", tree.search(1)) + assertEquals("two", tree.search(2)) + assertEquals("three", tree.search(3)) + assertNull(tree.search(4)) + } + + @Test + fun testRemove() { + val tree = RBTree() + tree.add(1, "one") + tree.add(2, "two") + tree.add(3, "three") + tree.remove(2) + assertEquals("one", tree.search(1)) + assertNull(tree.search(2)) + assertEquals("three", tree.search(3)) + } + + @Test + fun testAddSearchRemove() { + val tree = RBTree() + tree.add(1, "one") + tree.add(2, "two") + tree.add(3, "three") + assertEquals("one", tree.search(1)) + assertEquals("two", tree.search(2)) + assertEquals("three", tree.search(3)) + tree.remove(2) + assertEquals("one", tree.search(1)) + assertNull(tree.search(2)) + assertEquals("three", tree.search(3)) + tree.add(4, "four") + assertEquals("four", tree.search(4)) + assertNull(tree.search(2)) + } + + @Test + fun testAddMany() { + val tree = RBTree() + for (i in 1..1000) { + tree.add(i, i.toString()) + } + for (i in 1..1000) { + assertEquals(i.toString(), tree.search(i)) + } + } +} \ No newline at end of file From b0ceb2a391e1003b81963769f743b5fb1633af18 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 19 Apr 2023 08:48:54 +0300 Subject: [PATCH 044/203] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE?= =?UTF-8?q?=D0=BA,=20=D1=87=D0=B8=D1=81=D1=82=D0=BA=D0=B0=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/RBTNode.kt | 4 +-- lib/src/main/kotlin/trees/RBTree.kt | 25 ++++++++-------- lib/src/test/kotlin/trees/RBTreeTest.kt | 40 +++++++++++++------------ 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/lib/src/main/kotlin/nodes/RBTNode.kt b/lib/src/main/kotlin/nodes/RBTNode.kt index d98b124..2fb596d 100644 --- a/lib/src/main/kotlin/nodes/RBTNode.kt +++ b/lib/src/main/kotlin/nodes/RBTNode.kt @@ -1,6 +1,4 @@ -import nodes - -package RBTNode +package nodes class RBNode, V>(override var key: K, override var value: V?) : AbstractNode>() { diff --git a/lib/src/main/kotlin/trees/RBTree.kt b/lib/src/main/kotlin/trees/RBTree.kt index fc87da5..48d6976 100644 --- a/lib/src/main/kotlin/trees/RBTree.kt +++ b/lib/src/main/kotlin/trees/RBTree.kt @@ -1,8 +1,7 @@ -package RBTree - -import RBTNode -import AbstractTree +package trees +import nodes.Color +import nodes.RBNode class RBTree, V> : AbstractTree>() { override var root: RBNode? = null @@ -10,9 +9,9 @@ class RBTree, V> : AbstractTree>() { override fun search(key: K): RBNode? { var node = root while (node != null) { - when { - key < node.key -> node = node.left - key > node.key -> node = node.right + node = when { + key < node.key -> node.left + key > node.key -> node.right else -> return node //when found - return node } } @@ -37,7 +36,7 @@ class RBTree, V> : AbstractTree>() { newNode.color = Color.RED newNode.parent = parent - if (key < parent?.key ?: throw NullPointerException("Parent is null")) { //move up the tree, find needed place + if (key < (parent?.key ?: throw NullPointerException("Parent is null"))) { //move up the tree, find needed place parent.left = newNode } else { parent.right = newNode @@ -52,7 +51,7 @@ class RBTree, V> : AbstractTree>() { } private fun removeNode(node: RBNode) { - var replacementNode = when { + val replacementNode = when { node.left == null -> node.right node.right == null -> node.left else -> { @@ -65,7 +64,7 @@ class RBTree, V> : AbstractTree>() { successor.right = node.right successor.right?.parent = successor } - transplant(node, successor ?: throw IllegalArgumentException("Node cannot be null")) + transplant(node, successor) successor.left = node.left successor.left?.parent = successor successor.color = node.color @@ -152,7 +151,7 @@ class RBTree, V> : AbstractTree>() { sibling?.color = currentNode.parent?.color ?: throw IllegalStateException("Parent color is null") currentNode.parent?.color = Color.BLACK sibling?.right?.color = Color.BLACK - leftRotate(currentNode.parent!!) ?: throw IllegalStateException("Left rotate failed") + leftRotate(currentNode.parent!!) currentNode = root } } else { @@ -176,7 +175,7 @@ class RBTree, V> : AbstractTree>() { sibling?.color = currentNode.parent?.color ?: throw IllegalStateException("Parent color is null") currentNode.parent?.color = Color.BLACK sibling?.left?.color = Color.BLACK - rightRotate(currentNode.parent!!) ?: throw IllegalStateException("Right rotate failed") + rightRotate(currentNode.parent!!) currentNode = root } } @@ -228,6 +227,6 @@ class RBTree, V> : AbstractTree>() { } else { u.parent!!.right = v ?: throw IllegalStateException("Node v is null") } - v?.parent = u?.parent + v.parent = u?.parent } } \ No newline at end of file diff --git a/lib/src/test/kotlin/trees/RBTreeTest.kt b/lib/src/test/kotlin/trees/RBTreeTest.kt index f549247..92ca78d 100644 --- a/lib/src/test/kotlin/trees/RBTreeTest.kt +++ b/lib/src/test/kotlin/trees/RBTreeTest.kt @@ -1,6 +1,8 @@ -import org.junit.Assert.* -import org.junit.Test -import RBTree + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Test +import trees.RBTree class RBTreeTest { @Test @@ -9,9 +11,9 @@ class RBTreeTest { tree.add(1, "one") tree.add(2, "two") tree.add(3, "three") - assertEquals("one", tree.search(1)) - assertEquals("two", tree.search(2)) - assertEquals("three", tree.search(3)) + assertEquals("one", tree.search(1)?.value) + assertEquals("two", tree.search(2)?.value) + assertEquals("three", tree.search(3)?.value) } @Test @@ -20,9 +22,9 @@ class RBTreeTest { tree.add(1, "one") tree.add(2, "two") tree.add(3, "three") - assertEquals("one", tree.search(1)) - assertEquals("two", tree.search(2)) - assertEquals("three", tree.search(3)) + assertEquals("one", tree.search(1)?.value) + assertEquals("two", tree.search(2)?.value) + assertEquals("three", tree.search(3)?.value) assertNull(tree.search(4)) } @@ -33,9 +35,9 @@ class RBTreeTest { tree.add(2, "two") tree.add(3, "three") tree.remove(2) - assertEquals("one", tree.search(1)) - assertNull(tree.search(2)) - assertEquals("three", tree.search(3)) + assertEquals("one", tree.search(1)?.value) + assertNull(tree.search(2)?.value) + assertEquals("three", tree.search(3)?.value) } @Test @@ -44,15 +46,15 @@ class RBTreeTest { tree.add(1, "one") tree.add(2, "two") tree.add(3, "three") - assertEquals("one", tree.search(1)) - assertEquals("two", tree.search(2)) - assertEquals("three", tree.search(3)) + assertEquals("one", tree.search(1)?.value) + assertEquals("two", tree.search(2)?.value) + assertEquals("three", tree.search(3)?.value) tree.remove(2) - assertEquals("one", tree.search(1)) + assertEquals("one", tree.search(1)?.value) assertNull(tree.search(2)) - assertEquals("three", tree.search(3)) + assertEquals("three", tree.search(3)?.value) tree.add(4, "four") - assertEquals("four", tree.search(4)) + assertEquals("four", tree.search(4)?.value) assertNull(tree.search(2)) } @@ -63,7 +65,7 @@ class RBTreeTest { tree.add(i, i.toString()) } for (i in 1..1000) { - assertEquals(i.toString(), tree.search(i)) + assertEquals(i.toString(), tree.search(i)?.value) } } } \ No newline at end of file From 761f63d6408ba8cb29e860b1d01dc4621f456166 Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Wed, 19 Apr 2023 09:06:54 +0300 Subject: [PATCH 045/203] Deleted !! --- lib/src/main/kotlin/trees/RBTree.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/src/main/kotlin/trees/RBTree.kt b/lib/src/main/kotlin/trees/RBTree.kt index 48d6976..618edb1 100644 --- a/lib/src/main/kotlin/trees/RBTree.kt +++ b/lib/src/main/kotlin/trees/RBTree.kt @@ -135,7 +135,7 @@ class RBTree, V> : AbstractTree>() { if (sibling?.color == Color.RED) { sibling.color = Color.BLACK currentNode.parent?.color = Color.RED - leftRotate(currentNode.parent!!) + currentNode.parent?.let { leftRotate(it) } sibling = currentNode.parent?.right } if (sibling?.left?.color == Color.BLACK && sibling.right?.color == Color.BLACK) { @@ -145,13 +145,13 @@ class RBTree, V> : AbstractTree>() { if (sibling?.right?.color == Color.BLACK) { sibling.left?.color = Color.BLACK sibling.color = Color.RED - rightRotate(sibling) + sibling?.let { rightRotate(it) } sibling = currentNode.parent?.right } sibling?.color = currentNode.parent?.color ?: throw IllegalStateException("Parent color is null") currentNode.parent?.color = Color.BLACK sibling?.right?.color = Color.BLACK - leftRotate(currentNode.parent!!) + currentNode.parent?.let { leftRotate(it) } currentNode = root } } else { @@ -159,7 +159,7 @@ class RBTree, V> : AbstractTree>() { if (sibling?.color == Color.RED) { sibling.color = Color.BLACK currentNode.parent?.color = Color.RED - rightRotate(currentNode.parent!!) + currentNode.parent?.let { rightRotate(it) } sibling = currentNode.parent?.left } if (sibling?.right?.color == Color.BLACK && sibling.left?.color == Color.BLACK) { @@ -169,13 +169,13 @@ class RBTree, V> : AbstractTree>() { if (sibling?.left?.color == Color.BLACK) { sibling.right?.color = Color.BLACK sibling.color = Color.RED - leftRotate(sibling) + sibling?.let { leftRotate(it) } sibling = currentNode.parent?.left } sibling?.color = currentNode.parent?.color ?: throw IllegalStateException("Parent color is null") currentNode.parent?.color = Color.BLACK sibling?.left?.color = Color.BLACK - rightRotate(currentNode.parent!!) + currentNode.parent?.let { rightRotate(it) } currentNode = root } } @@ -183,6 +183,7 @@ class RBTree, V> : AbstractTree>() { currentNode?.color = Color.BLACK } + private fun leftRotate(node: RBNode) { val rightChild = node.right ?: throw IllegalStateException("Right child is null") node.right = rightChild.left From ce02ca9fab4d8e40c8ef8d2e3e4086376bc9d08a Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Wed, 19 Apr 2023 09:18:01 +0300 Subject: [PATCH 046/203] Added DataBase --- .../main/kotlin/database/RBT/RBTDataBase.kt | 22 +++++++++++++++++++ lib/src/main/kotlin/trees/RBTree.kt | 14 ++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 lib/src/main/kotlin/database/RBT/RBTDataBase.kt diff --git a/lib/src/main/kotlin/database/RBT/RBTDataBase.kt b/lib/src/main/kotlin/database/RBT/RBTDataBase.kt new file mode 100644 index 0000000..f45572e --- /dev/null +++ b/lib/src/main/kotlin/database/RBT/RBTDataBase.kt @@ -0,0 +1,22 @@ +package DB + +import java.io.* + +class RBTreeSerializer { + fun serialize(tree: RBTree, filePath: String) { + val fileOutputStream = FileOutputStream(filePath) + val objectOutputStream = ObjectOutputStream(fileOutputStream) + objectOutputStream.writeObject(tree) + objectOutputStream.close() + fileOutputStream.close() + } + + fun deserialize(filePath: String): RBTree { + val fileInputStream = FileInputStream(filePath) + val objectInputStream = ObjectInputStream(fileInputStream) + val tree = objectInputStream.readObject() as RBTree + objectInputStream.close() + fileInputStream.close() + return tree + } +} diff --git a/lib/src/main/kotlin/trees/RBTree.kt b/lib/src/main/kotlin/trees/RBTree.kt index 618edb1..d1e4f35 100644 --- a/lib/src/main/kotlin/trees/RBTree.kt +++ b/lib/src/main/kotlin/trees/RBTree.kt @@ -2,6 +2,8 @@ package trees import nodes.Color import nodes.RBNode +import DB.RBTreeSerializer +import java.io.* class RBTree, V> : AbstractTree>() { override var root: RBNode? = null @@ -230,4 +232,16 @@ class RBTree, V> : AbstractTree>() { } v.parent = u?.parent } + + fun saveToFile(filePath: String) { + val serializer = RBTreeSerializer() + serializer.serialize(this, filePath) + } + + companion object { + fun loadFromFile(filePath: String): RBTree { + val serializer = RBTreeSerializer() + return serializer.deserialize(filePath) + } + } } \ No newline at end of file From 5814eac444a69eaa2d362202c1e87177dd37fe75 Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Sat, 15 Apr 2023 16:39:26 +0300 Subject: [PATCH 047/203] Add AVL node; Add insertion to AVL tree --- lib/src/main/kotlin/nodes/AVLNode.kt | 14 ++++ lib/src/main/kotlin/trees/AVLTree.kt | 102 +++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 lib/src/main/kotlin/nodes/AVLNode.kt create mode 100644 lib/src/main/kotlin/trees/AVLTree.kt diff --git a/lib/src/main/kotlin/nodes/AVLNode.kt b/lib/src/main/kotlin/nodes/AVLNode.kt new file mode 100644 index 0000000..59ea8f6 --- /dev/null +++ b/lib/src/main/kotlin/nodes/AVLNode.kt @@ -0,0 +1,14 @@ +package nodes + +import nodes.BinaryNode + +class AVLNode, V>(key: K, value: V){ + var height: Int = 1 + open var key : K = key + protected set + open var value : V? = value + protected set + + open var right : AVLNode? = null + open var left : AVLNode? = null +} \ No newline at end of file diff --git a/lib/src/main/kotlin/trees/AVLTree.kt b/lib/src/main/kotlin/trees/AVLTree.kt new file mode 100644 index 0000000..78e2369 --- /dev/null +++ b/lib/src/main/kotlin/trees/AVLTree.kt @@ -0,0 +1,102 @@ +package trees + +import nodes.AVLNode +import kotlin.math.max + +class AVLTree, V> { + var root: AVLNode? = null + + + fun add(key: K, value: V) { + root = insert(root , key , value) + } + + fun delete(node: AVLNode) { + + } + + + //Called on node to insert a key value pair under it. + private fun insert(node: AVLNode? , key: K, value: V): AVLNode { + if (node == null) { + return AVLNode(key, value) + } + + var delta: Int = key.compareTo(node.key) + + if (delta < 0) { + node.left = insert(node.left , key , value) + } else if(delta > 0) { + node.right = insert(node.right , key , value) + } else { + //Duplicate key + } + + return rebalance(node) ?: throw Exception("Rebalance returned a null value") + } + + private fun rebalance(node: AVLNode): AVLNode? { + node.height = 1 + max(getHeight(node.left) , getHeight(node.right)) + + val balance: Int = getBalance(node) + val leftBalance: Int = getBalance(node.left) + val rightBalance: Int = getBalance(node.right) + + if (balance > 1 && leftBalance >= 0) { + return rotateRight(node) + } + if (balance > 1 && leftBalance < 0) { + node.left = rotateLeft(node.left) + return rotateRight(node) + } + if (balance < -1 && rightBalance <= 0) { + return rotateLeft(node) + } + if (balance < -1 && rightBalance > 0) { + node.right = rotateRight(node.right) + return rotateLeft(node) + } + + return node + } + + private fun getBalance(node: AVLNode?): Int { + if (node == null) { + return 0 + } + return getHeight(node.left) - getHeight(node.right) + } + + private fun getHeight(node: AVLNode?): Int { + if (node == null) { + return 0 + } + return node.height + } + + private fun rotateRight(node: AVLNode?): AVLNode? { + val x = node?.left + val b = x?.right + + x?.right = node + node?.left = b + + node?.height = 1 + max(getHeight(node?.left) , getHeight(node?.right)) + x?.height = 1 + max(getHeight(x?.left) , getHeight(x?.right)) + + return x + } + + private fun rotateLeft(node: AVLNode?): AVLNode? { + val y = node?.right + val b = y?.left + + y?.left = node + node?.right = b + + node?.height = 1 + max(getHeight(node?.left) , getHeight(node?.right)) + y?.height = 1 + max(getHeight(y?.left) , getHeight(y?.right)) + + return y + } +} \ No newline at end of file From 498e949319f0675917e29e98b35bd97eeb3bc218 Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Tue, 18 Apr 2023 20:35:15 +0300 Subject: [PATCH 048/203] Add deletion in AVL tree --- lib/src/main/kotlin/trees/AVLTree.kt | 31 +++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/src/main/kotlin/trees/AVLTree.kt b/lib/src/main/kotlin/trees/AVLTree.kt index 78e2369..d28e0b2 100644 --- a/lib/src/main/kotlin/trees/AVLTree.kt +++ b/lib/src/main/kotlin/trees/AVLTree.kt @@ -11,12 +11,35 @@ class AVLTree, V> { root = insert(root , key , value) } - fun delete(node: AVLNode) { - + fun remove(key: K) { + root = delete(root, key) } + fun delete(node: AVLNode?, key: K): AVLNode? { + if (node == null) { + return null + } + + if (key < node.key) { + node.left = delete(node.left , key) + } else if (key > node.key) { + node.right = delete(node.right , key) + } else { + if (node.left == null) { + return node.right + } else if (node.right == null) { + return node.left + } + + val temp = findMin(node) + node.value = temp.value + node.right = delete(node.right, temp.key) + + } + + return rebalance(node) ?: throw Exception("Rebalance returned a null value") + } - //Called on node to insert a key value pair under it. private fun insert(node: AVLNode? , key: K, value: V): AVLNode { if (node == null) { return AVLNode(key, value) @@ -35,6 +58,8 @@ class AVLTree, V> { return rebalance(node) ?: throw Exception("Rebalance returned a null value") } + private fun findMin(node: AVLNode): AVLNode = if (node.left != null) findMin(node.left!!) else node + private fun rebalance(node: AVLNode): AVLNode? { node.height = 1 + max(getHeight(node.left) , getHeight(node.right)) From 7c762cfdb9cf7614ec8fdb5095a8a0b374a82cdf Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Wed, 19 Apr 2023 08:19:14 +0300 Subject: [PATCH 049/203] Add tests --- lib/src/main/kotlin/nodes/AVLNode.kt | 12 +- lib/src/main/kotlin/nodes/AbstractNode.kt | 2 +- lib/src/main/kotlin/trees/AVLTree.kt | 34 +++-- lib/src/test/kotlin/trees/AVLTreeTest.kt | 145 ++++++++++++++++++++++ 4 files changed, 176 insertions(+), 17 deletions(-) create mode 100644 lib/src/test/kotlin/trees/AVLTreeTest.kt diff --git a/lib/src/main/kotlin/nodes/AVLNode.kt b/lib/src/main/kotlin/nodes/AVLNode.kt index 59ea8f6..ace5632 100644 --- a/lib/src/main/kotlin/nodes/AVLNode.kt +++ b/lib/src/main/kotlin/nodes/AVLNode.kt @@ -2,13 +2,9 @@ package nodes import nodes.BinaryNode -class AVLNode, V>(key: K, value: V){ - var height: Int = 1 - open var key : K = key - protected set - open var value : V? = value - protected set +class AVLNode, V>(override var key: K, override var value: V?) : AbstractNode>(){ + override var right : AVLNode? = null + override var left : AVLNode? = null - open var right : AVLNode? = null - open var left : AVLNode? = null + var height: Int = 1 } \ No newline at end of file diff --git a/lib/src/main/kotlin/nodes/AbstractNode.kt b/lib/src/main/kotlin/nodes/AbstractNode.kt index 78c46be..bd81ac0 100644 --- a/lib/src/main/kotlin/nodes/AbstractNode.kt +++ b/lib/src/main/kotlin/nodes/AbstractNode.kt @@ -4,7 +4,7 @@ abstract class AbstractNode, V, NodeType : AbstractNode, V> { - var root: AVLNode? = null +class AVLTree, V> : AbstractTree>() { + override var root: AVLNode? = null - fun add(key: K, value: V) { + override fun add(key: K, value: V?) { root = insert(root , key , value) } - fun remove(key: K) { + override fun remove(key: K) { root = delete(root, key) } - fun delete(node: AVLNode?, key: K): AVLNode? { + override fun search(key: K): AVLNode? { + return searchNode(root, key) + } + + private fun searchNode(node: AVLNode?, key: K): AVLNode? { + if (node == null) { + return null + } + + if (key < node.key) { + return searchNode(node.left, key) + } else if (key > node.key) { + return searchNode(node.right, key) + } else { + return node + } + } + + private fun delete(node: AVLNode?, key: K): AVLNode? { if (node == null) { return null } @@ -40,12 +58,12 @@ class AVLTree, V> { return rebalance(node) ?: throw Exception("Rebalance returned a null value") } - private fun insert(node: AVLNode? , key: K, value: V): AVLNode { + private fun insert(node: AVLNode? , key: K, value: V?): AVLNode { if (node == null) { - return AVLNode(key, value) + return AVLNode(key, value) } - var delta: Int = key.compareTo(node.key) + val delta: Int = key.compareTo(node.key) if (delta < 0) { node.left = insert(node.left , key , value) diff --git a/lib/src/test/kotlin/trees/AVLTreeTest.kt b/lib/src/test/kotlin/trees/AVLTreeTest.kt new file mode 100644 index 0000000..bf6a8bc --- /dev/null +++ b/lib/src/test/kotlin/trees/AVLTreeTest.kt @@ -0,0 +1,145 @@ +package trees + +import nodes.AVLNode +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.function.Executable +import java.time.Duration.ofMillis +import kotlin.math.abs +import kotlin.random.Random + +class AVLTreeTest { + private fun getBalance(node: AVLNode?): Int { + if (node == null) { + return 0 + } + return getHeight(node.left) - getHeight(node.right) + } + + private fun getHeight(node: AVLNode?): Int { + if (node == null) { + return 0 + } + return node.height + } + + fun invariantCheck(node: AVLNode?): Boolean { + if (node == null) { + return true + } + return abs(getBalance(node)) <= 1 && invariantCheck(node.left) && invariantCheck(node.right) + } + + @Nested + inner class `Remove check` { + @Test + @DisplayName("Root remove") + fun `Root remove`() { + val tree = AVLTree() + tree.add(100, "root") + tree.remove(100) + assertEquals(null, tree.search(100)?.value) + } + @Test + @DisplayName("Simple element remove") + fun `Simple element remove`() { + val tree = AVLTree() + tree.add(8, "root") + tree.add(10, "a") + tree.add(14, "b") + tree.add(13) + tree.remove(13) + assertAll("elements", + Executable { assertEquals("root", tree.search(8)?.value) }, + Executable { assertEquals("a", tree.search(10)?.value) }, + Executable { assertEquals("b", tree.search(14)?.value) }, + Executable { assertEquals(null, tree.search(13)?.value) }, + Executable { assertEquals(true, invariantCheck(tree.search(10))) } + ) + } + @Test + @DisplayName("Element with one child node remove") + fun `Element with one child node remove`() { + val tree = AVLTree() + tree.add(8, "root") + tree.add(10, "a") + tree.add(14) + tree.add(13, "c") + tree.remove(14) + assertAll("elements", + Executable { assertEquals("root", tree.search(8)?.value) }, + Executable { assertEquals("a", tree.search(10)?.value) }, + Executable { assertEquals("c", tree.search(13)?.value) }, + Executable { assertEquals(null, tree.search(14)?.value) }, + Executable { assertEquals(true, invariantCheck(tree.search(10))) } + ) + } + @Test + @DisplayName("Element with two child nodes remove") + fun `Element with two child nodes remove`() { + val tree = AVLTree() + tree.add(8, "root") + tree.add(4, "a") + tree.add(1, "b") + tree.add(6, "c") + tree.add(7, "d") + + tree.remove(3) + assertAll("elements", + Executable { assertEquals("a", tree.search(4)?.value) }, + Executable { assertEquals("b", tree.search(1)?.value) }, + Executable { assertEquals(null, tree.search(3)?.value) }, + Executable { assertEquals("c", tree.search(6)?.value) }, + Executable { assertEquals("d", tree.search(7)?.value) }, + Executable { assertEquals("root", tree.search(8)?.value) }, + Executable { assertEquals(true, invariantCheck(tree.search(4))) } + ) + } + } + @Nested + inner class `Add check` { + @Test + @DisplayName("Simple add") + fun `Simple add`() { + val tree = AVLTree() + tree.add(30, "root") + assertEquals("root", tree.search(30)?.value) + } + + @Test + @DisplayName("Left rotation on add") + fun `Left rotation on add`() { + val tree = AVLTree() + tree.add(1, "root") + tree.add(2, "a") + tree.add(3, "b") + assertEquals("root", tree.search(2)?.left?.value) + assertEquals(true, invariantCheck(tree.search(2))) + } + + @Test + @DisplayName("Right rotation on add") + fun `Right rotation on add`() { + val tree = AVLTree() + tree.add(3, "root") + tree.add(2, "a") + tree.add(1, "b") + assertEquals("root", tree.search(2)?.right?.value) + assertEquals(true, invariantCheck(tree.search(2))) + } + + @Test + @DisplayName("Multiply add") + fun `Multiply add`() { + assertTimeout(ofMillis(1000)) { + val tree = AVLTree() + val list : List = (List(100000) { Random.nextInt(1, 100000) }).distinct().toMutableList() + for (item in list) + tree.add(item, 0) + assertEquals(tree.search(list.last())?.value, 0) + } + } + } +} \ No newline at end of file From ea29182576ec085033b662b93227c3ea1461262c Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Wed, 19 Apr 2023 09:25:15 +0300 Subject: [PATCH 050/203] Add database --- lib/src/main/kotlin/databases/bin/AVLBase.kt | 50 ++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 lib/src/main/kotlin/databases/bin/AVLBase.kt diff --git a/lib/src/main/kotlin/databases/bin/AVLBase.kt b/lib/src/main/kotlin/databases/bin/AVLBase.kt new file mode 100644 index 0000000..0484d5c --- /dev/null +++ b/lib/src/main/kotlin/databases/bin/AVLBase.kt @@ -0,0 +1,50 @@ +package databases.bin + +import nodes.AVLNode +import java.io.Closeable +import java.sql.DriverManager +import java.sql.SQLException + +class AVLBase (path: String): Closeable { + + private val connection = DriverManager.getConnection("jdbc:sqlite:$path") + ?: throw SQLException("Cannot connect to database") + private val createBaseStatement by lazy {connection.prepareStatement("CREATE TABLE if not exists BinaryNodes (x int, y int, key int, value varchar(255));")} + private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO BinaryNodes (x, y, key, value) VALUES (?, ?, ?, ?);") } + private val getNodeByKey by lazy { connection.prepareStatement("SELECT x, y, value FROM BinaryNodes WHERE BinaryNodes.key = ?;") } + private val removeNodeByKey by lazy { connection.prepareStatement("DELETE FROM BinaryNodes WHERE key=?;") } + fun open() = createBaseStatement.execute() + + fun removeNode(key : Int) { + removeNodeByKey.setInt(1, key) + removeNodeByKey.execute() + } + fun addNode(node : Node>) { + if (search(node.binNode.key) != null) + return + + addNodeStatement.setInt(1, node.x) + addNodeStatement.setInt(2, node.y) + addNodeStatement.setInt(3, node.binNode.key) + addNodeStatement.setString(4, node.binNode.value ?: "empty") + + addNodeStatement.execute() + } + fun search(key: Int) : Node>? { + getNodeByKey.setInt(1, key) + val res = getNodeByKey.executeQuery() + if (res.isClosed) + return null + + return Node(AVLNode(key, res.getString("value")), res.getInt("x"), res.getInt("y")) + } + override fun close() { + createBaseStatement.close() + addNodeStatement.close() + getNodeByKey.close() + removeNodeByKey.close() + + connection.close() + } + +} \ No newline at end of file From ac5ba5f8df807b33d707cd5c77493271c37feae4 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 17:43:44 +0300 Subject: [PATCH 051/203] =?UTF-8?q?=D0=92=D1=81=D0=B5=20=D0=B1=D0=B0=D0=B7?= =?UTF-8?q?=D1=8B=20=D0=B4=D0=BE=D0=BB=D0=B6=D0=BD=D1=8B=20=D0=BB=D0=B5?= =?UTF-8?q?=D0=B6=D0=B0=D1=82=D1=8C=20=D0=B2=20=D0=BF=D0=B0=D0=BF=D0=BA?= =?UTF-8?q?=D0=B5=20databases.=20=D0=A4=D0=B0=D0=B9=D0=BB=20=D1=81=20?= =?UTF-8?q?=D0=B1=D0=B4=20=D0=B1=D0=B8=D0=BD=D0=B0=D1=80=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=B0=20=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=BB=20=D0=BD=D0=B0=D0=B7=D1=8B=D0=B2=D0=B0=D1=82=D1=8C?= =?UTF-8?q?=D1=81=D1=8F=20"BinTreeBase"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/databases/{bin/BinaryBase.kt => BinTreeBase.kt} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename lib/src/main/kotlin/databases/{bin/BinaryBase.kt => BinTreeBase.kt} (98%) diff --git a/lib/src/main/kotlin/databases/bin/BinaryBase.kt b/lib/src/main/kotlin/databases/BinTreeBase.kt similarity index 98% rename from lib/src/main/kotlin/databases/bin/BinaryBase.kt rename to lib/src/main/kotlin/databases/BinTreeBase.kt index 57f93ec..43be0d1 100644 --- a/lib/src/main/kotlin/databases/bin/BinaryBase.kt +++ b/lib/src/main/kotlin/databases/BinTreeBase.kt @@ -1,4 +1,4 @@ -package databases.bin +package databases import nodes.BinaryNode import java.io.Closeable From b85198a52762aee4fe3636361d3eb8770b2a7fff Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 17:56:34 +0300 Subject: [PATCH 052/203] =?UTF-8?q?=D0=A2=D0=B8=D0=BF=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B4=D0=B0=D0=B2=D0=B0=D0=B5=D0=BC=D0=BE=D0=B9=20=D0=B2?= =?UTF-8?q?=20=D0=B0=D0=B1=D1=81=D1=82=D1=80=D0=B0=D0=BA=D1=82=D0=BD=D1=8B?= =?UTF-8?q?=D0=B5=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D1=8B=20=D0=BD=D0=BE?= =?UTF-8?q?=D0=B4=D1=8B=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=81=D1=82=D0=BE=20node,=20=D0=B0=20=D0=BD=D0=B5?= =?UTF-8?q?=20NodeType?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/AbstractNode.kt | 6 +++--- lib/src/main/kotlin/trees/AbstractTree.kt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/src/main/kotlin/nodes/AbstractNode.kt b/lib/src/main/kotlin/nodes/AbstractNode.kt index 78c46be..180892e 100644 --- a/lib/src/main/kotlin/nodes/AbstractNode.kt +++ b/lib/src/main/kotlin/nodes/AbstractNode.kt @@ -1,11 +1,11 @@ package nodes -abstract class AbstractNode, V, NodeType : AbstractNode>() { +abstract class AbstractNode, V, node : AbstractNode>() { abstract var key : K protected set abstract var value : V? protected set - abstract var right : NodeType? - abstract var left : NodeType? + abstract var right : node? + abstract var left : node? } \ No newline at end of file diff --git a/lib/src/main/kotlin/trees/AbstractTree.kt b/lib/src/main/kotlin/trees/AbstractTree.kt index 8c2ae4f..15be086 100644 --- a/lib/src/main/kotlin/trees/AbstractTree.kt +++ b/lib/src/main/kotlin/trees/AbstractTree.kt @@ -2,9 +2,9 @@ package trees import nodes.AbstractNode -abstract class AbstractTree, V, NodeType : AbstractNode> { - protected abstract var root : NodeType? - abstract fun search(key : K) : NodeType? +abstract class AbstractTree, V, node : AbstractNode> { + protected abstract var root : node? + abstract fun search(key : K) : node? abstract fun add(key : K, value : V? = null) abstract fun remove(key : K) } \ No newline at end of file From c8f049beb73c57557c6a7e04f75d0cfdbb51f7f3 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 18:25:48 +0300 Subject: [PATCH 053/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20TreeException,?= =?UTF-8?q?=20=D0=BD=D0=B5=D0=BE=D0=B1=D1=85=D0=BE=D0=B4=D0=B8=D0=BC=D1=8B?= =?UTF-8?q?=D0=B9=20=D0=B4=D0=BB=D1=8F=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D0=B9,=20=D1=81=D0=B2=D1=8F=D0=B7?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D1=81=20=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B2=D1=8C=D1=8F=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/exceptions/TreeExceptions.kt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 lib/src/main/kotlin/exceptions/TreeExceptions.kt diff --git a/lib/src/main/kotlin/exceptions/TreeExceptions.kt b/lib/src/main/kotlin/exceptions/TreeExceptions.kt new file mode 100644 index 0000000..84dea91 --- /dev/null +++ b/lib/src/main/kotlin/exceptions/TreeExceptions.kt @@ -0,0 +1,6 @@ +package exceptions + +/** + * Общий класс для всех исключений, связанных с деревьями + * */ +open class TreeException(message: String, cause: Throwable? = null) : Exception(message, cause) \ No newline at end of file From ee1077de587f7d1f4f456c4511dabf39e81c9db7 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 18:29:22 +0300 Subject: [PATCH 054/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=B4=D0=B2=D0=B0=20=D0=BA=D0=BB=D0=B0?= =?UTF-8?q?=D1=81=D1=81=D0=B0=20(NodeNotFound,=20NodeAlreadyExists)=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=B2=D1=8B=D0=B1=D1=80=D0=B0=D1=81=D1=8B?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D1=81=D0=BE=D0=BE=D1=82=D0=B2?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=B2=D1=83=D1=8E=D1=89=D0=B8=D1=85=20=D0=B8?= =?UTF-8?q?=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/exceptions/TreeExceptions.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/src/main/kotlin/exceptions/TreeExceptions.kt b/lib/src/main/kotlin/exceptions/TreeExceptions.kt index 84dea91..5d06be0 100644 --- a/lib/src/main/kotlin/exceptions/TreeExceptions.kt +++ b/lib/src/main/kotlin/exceptions/TreeExceptions.kt @@ -3,4 +3,8 @@ package exceptions /** * Общий класс для всех исключений, связанных с деревьями * */ -open class TreeException(message: String, cause: Throwable? = null) : Exception(message, cause) \ No newline at end of file +open class TreeException(message: String) : Exception(message) + +class NodeNotFound() : TreeException("Подходящий узел дерева не найден") + +class NodeAlreadyExists() : TreeException("Такой узел дерева уже существует") From 331ee429519cea31ace6fe0b990097655f6f20bc Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 18:41:45 +0300 Subject: [PATCH 055/203] =?UTF-8?q?=D0=A1=D0=BE=D0=BE=D0=B1=D1=89=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D1=83=20=D0=BD=D0=BE=D0=B2=D1=8B=D1=85=20?= =?UTF-8?q?=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B9=20?= =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D1=8B=20=D0=BD=D0=B0?= =?UTF-8?q?=20=D0=B1=D0=BE=D0=BB=D0=B5=D0=B5=20=D0=BF=D0=BE=D0=BD=D1=8F?= =?UTF-8?q?=D1=82=D0=BD=D1=8B=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/exceptions/TreeExceptions.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/main/kotlin/exceptions/TreeExceptions.kt b/lib/src/main/kotlin/exceptions/TreeExceptions.kt index 5d06be0..f21ae80 100644 --- a/lib/src/main/kotlin/exceptions/TreeExceptions.kt +++ b/lib/src/main/kotlin/exceptions/TreeExceptions.kt @@ -5,6 +5,6 @@ package exceptions * */ open class TreeException(message: String) : Exception(message) -class NodeNotFound() : TreeException("Подходящий узел дерева не найден") +class NodeNotFound() : TreeException("Подходящий для выполнения операции узел дерева не найден") -class NodeAlreadyExists() : TreeException("Такой узел дерева уже существует") +class NodeAlreadyExists() : TreeException("Узел дерева с таким ключом уже существует") From 6ec2e7525016b03bf84dc53a2da2d04b1330bdc8 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 18:42:30 +0300 Subject: [PATCH 056/203] =?UTF-8?q?=D0=9F=D1=80=D0=B8=20=D0=BF=D0=BE=D0=BF?= =?UTF-8?q?=D1=8B=D1=82=D0=BA=D0=B5=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BD=D0=B5=D1=81=D1=83=D1=89=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=B2=D1=83=D1=8E=D1=89=D0=B5=D0=B9=20=D0=BD=D0=BE=D0=B4=D1=8B?= =?UTF-8?q?=20=D0=B2=D1=8B=D0=B1=D1=80=D0=B0=D1=81=D1=8B=D0=B2=D0=B0=D0=B5?= =?UTF-8?q?=D1=82=D1=81=D1=8F=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/BinaryNode.kt | 50 +++++++++++++++---------- lib/src/main/kotlin/trees/BinaryTree.kt | 3 ++ 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/lib/src/main/kotlin/nodes/BinaryNode.kt b/lib/src/main/kotlin/nodes/BinaryNode.kt index 2cd4a87..f7e3eba 100644 --- a/lib/src/main/kotlin/nodes/BinaryNode.kt +++ b/lib/src/main/kotlin/nodes/BinaryNode.kt @@ -1,5 +1,7 @@ package nodes +import exceptions.NodeNotFound + /** * Класс узла для бинарного дерева. * @@ -9,50 +11,53 @@ package nodes * @property value значение узла. * @author Dmitriy Zaytsev */ -open class BinaryNode, V>(override var key: K, override var value: V?) : AbstractNode>() { +open class BinaryNode, V>(override var key: K, override var value: V?) : + AbstractNode>() { - override var right : BinaryNode? = null - override var left : BinaryNode? = null + override var right: BinaryNode? = null + override var left: BinaryNode? = null - open fun search(key: K) : BinaryNode? = + open fun search(key: K): BinaryNode? = when (key.compareTo(this.key)) { 1 -> this.right?.search(key) 0 -> this -1 -> this.left?.search(key) else -> null - } + } - open fun remove(root : BinaryNode?, key : K) : BinaryNode? { - if (root == null) - return null + open fun remove(root: BinaryNode?, key: K): BinaryNode? { if (key == this.key) { // когда remove вызывается для удаляемой вершины - if (this.right == null && this.left == null) - return null + if (right == null && left == null) + return null // просто стираем ноду + // Простой случай - если есть только 1 потомок - else if (this.left == null) - return this.right - else if (this.right == null) - return this.left - // Есть оба поддерева + else if (left == null) + return right + else if (right == null) + return left + + // Случай где есть два потомка else { // Находим минимальное дерево + val minNode = findMin(right) // Перенимаем его key и value - // Удаляем минимальное дерево - val minNode = findMin(this.right) minNode?.let { this.key = it.key this.value = it.value } + // Удаляем минимальное дерево this.right = right?.remove(right, key) return this } } else { - // Замещаем поддеревья на минимальные + // Идём дальше по дереву искать что удалить if (key < this.key) this.left = left?.remove(left, key) + ?: throw NodeNotFound() else this.right = right?.remove(right, key) + ?: throw NodeNotFound() return root } } @@ -61,9 +66,14 @@ open class BinaryNode, V>(override var key: K, override var val * @param[node] Узел для которого ищется минимальный эл-т. * @return Наименьший узел. */ - private fun findMin(node: BinaryNode?): BinaryNode? = if (node?.left != null) findMin(node.left) else node + private fun findMin(node: BinaryNode?): BinaryNode? { + return if (node?.left != null) + findMin(node.left) + else + node + } - open fun add(key : K, value : V?) { + open fun add(key: K, value: V?) { val compare = key.compareTo(this.key) if (compare == 1) { diff --git a/lib/src/main/kotlin/trees/BinaryTree.kt b/lib/src/main/kotlin/trees/BinaryTree.kt index 648b0b5..52001bd 100644 --- a/lib/src/main/kotlin/trees/BinaryTree.kt +++ b/lib/src/main/kotlin/trees/BinaryTree.kt @@ -1,11 +1,14 @@ package trees +import exceptions.NodeNotFound import nodes.BinaryNode open class BinaryTree, V> : AbstractTree>() { override var root : BinaryNode? = null override fun search(key : K) : BinaryNode? = root?.search(key) override fun remove(key: K) { + if (root == null) + throw NodeNotFound() root = root?.remove(this.root, key) } override fun add(key : K, value : V?) { From eb3d49fd1034d931c6b424457af80e19da8fb491 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 18:48:37 +0300 Subject: [PATCH 057/203] =?UTF-8?q?=D0=9F=D1=80=D0=B8=20=D0=BF=D0=BE=D0=B8?= =?UTF-8?q?=D1=81=D0=BA=D0=B5=20=D0=BD=D0=B5=D1=81=D1=83=D1=89=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D1=83=D1=8E=D1=89=D0=B5=D0=B9=20=D0=BD=D0=BE=D0=B4?= =?UTF-8?q?=D1=8B=20=D0=B2=D1=8B=D0=B1=D1=80=D0=B0=D1=81=D1=8B=D0=B2=D0=B0?= =?UTF-8?q?=D0=B5=D1=82=D1=81=D1=8F=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/trees/BinaryTree.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/src/main/kotlin/trees/BinaryTree.kt b/lib/src/main/kotlin/trees/BinaryTree.kt index 52001bd..90d44aa 100644 --- a/lib/src/main/kotlin/trees/BinaryTree.kt +++ b/lib/src/main/kotlin/trees/BinaryTree.kt @@ -6,10 +6,9 @@ import nodes.BinaryNode open class BinaryTree, V> : AbstractTree>() { override var root : BinaryNode? = null override fun search(key : K) : BinaryNode? = root?.search(key) + ?: throw NodeNotFound() override fun remove(key: K) { - if (root == null) - throw NodeNotFound() - root = root?.remove(this.root, key) + root = root?.remove(this.root, key) ?: throw NodeNotFound() } override fun add(key : K, value : V?) { if (root == null) From d71863cc32a13f12b4815223d023e462f9fbd1a2 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 18:53:12 +0300 Subject: [PATCH 058/203] =?UTF-8?q?(!)=20AbstractNode,=20AbstractTree:=20?= =?UTF-8?q?=D1=81=D0=B2=D0=BE=D0=B9=D1=81=D1=82=D0=B2=D0=B0=20key,=20value?= =?UTF-8?q?=20=D0=B8=20root=20=D0=B1=D0=BE=D0=BB=D1=8C=D1=88=D0=B5=20?= =?UTF-8?q?=D0=BD=D0=B5=20=D1=82=D1=80=D0=B5=D0=B1=D1=83=D1=8E=D1=82=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=BE=D0=BF=D1=80=D0=B5=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B2=20=D0=BA=D0=BB=D0=B0?= =?UTF-8?q?=D1=81=D1=81=D0=B0=D1=85=20(=D0=B1=D0=BE=D0=BB=D1=8C=D1=88?= =?UTF-8?q?=D0=B5=20=D0=BD=D0=B5=20abstract)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/AbstractNode.kt | 10 +++++----- lib/src/main/kotlin/trees/AbstractTree.kt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/src/main/kotlin/nodes/AbstractNode.kt b/lib/src/main/kotlin/nodes/AbstractNode.kt index 180892e..7487337 100644 --- a/lib/src/main/kotlin/nodes/AbstractNode.kt +++ b/lib/src/main/kotlin/nodes/AbstractNode.kt @@ -1,11 +1,11 @@ package nodes abstract class AbstractNode, V, node : AbstractNode>() { - abstract var key : K - protected set - abstract var value : V? + lateinit var key : K protected set + var value : V? = null + protected set - abstract var right : node? - abstract var left : node? + var right : node? = null + var left : node? = null } \ No newline at end of file diff --git a/lib/src/main/kotlin/trees/AbstractTree.kt b/lib/src/main/kotlin/trees/AbstractTree.kt index 15be086..432aa6e 100644 --- a/lib/src/main/kotlin/trees/AbstractTree.kt +++ b/lib/src/main/kotlin/trees/AbstractTree.kt @@ -3,7 +3,7 @@ package trees import nodes.AbstractNode abstract class AbstractTree, V, node : AbstractNode> { - protected abstract var root : node? + protected var root : node? = null abstract fun search(key : K) : node? abstract fun add(key : K, value : V? = null) abstract fun remove(key : K) From 67527166a8abfa17118e27bae45082381eba3072 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 18:55:59 +0300 Subject: [PATCH 059/203] =?UTF-8?q?(!)=20AbstractNode:=20=D1=83=20Abstract?= =?UTF-8?q?Node=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D1=81=D0=B2?= =?UTF-8?q?=D0=BE=D0=B9=20=D0=BA=D0=BE=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80,=20key=20=D0=B8=20value=20=D0=BE=D0=BF=D1=80?= =?UTF-8?q?=D0=B5=D0=B4=D0=B5=D0=BB=D1=8F=D1=8E=D1=82=D1=81=D1=8F=20=D0=B2?= =?UTF-8?q?=20=D0=BD=D1=91=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/AbstractNode.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/main/kotlin/nodes/AbstractNode.kt b/lib/src/main/kotlin/nodes/AbstractNode.kt index 7487337..0a6506d 100644 --- a/lib/src/main/kotlin/nodes/AbstractNode.kt +++ b/lib/src/main/kotlin/nodes/AbstractNode.kt @@ -1,9 +1,9 @@ package nodes -abstract class AbstractNode, V, node : AbstractNode>() { - lateinit var key : K +abstract class AbstractNode, V, node : AbstractNode>(key: K, value : V?) { + var key : K = key protected set - var value : V? = null + var value : V? = value protected set var right : node? = null From f3ee36321f5622dc5238b4f0552ee2f4e9c353d6 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 18:58:14 +0300 Subject: [PATCH 060/203] =?UTF-8?q?=D0=92=D0=BD=D0=B5=D1=81=D0=B5=D0=BD?= =?UTF-8?q?=D1=8B=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=20=D0=B2=20=D1=81=D0=B2=D1=8F=D0=B7=D0=B8=20=D1=81=20=D0=BE?= =?UTF-8?q?=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC=20?= =?UTF-8?q?=D0=B0=D0=B1=D1=81=D1=82=D1=80=D0=B0=D0=BA=D1=82=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/BinaryNode.kt | 33 ++++++++++--------------- lib/src/main/kotlin/trees/BinaryTree.kt | 6 ++--- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/lib/src/main/kotlin/nodes/BinaryNode.kt b/lib/src/main/kotlin/nodes/BinaryNode.kt index f7e3eba..902e67f 100644 --- a/lib/src/main/kotlin/nodes/BinaryNode.kt +++ b/lib/src/main/kotlin/nodes/BinaryNode.kt @@ -11,12 +11,8 @@ import exceptions.NodeNotFound * @property value значение узла. * @author Dmitriy Zaytsev */ -open class BinaryNode, V>(override var key: K, override var value: V?) : - AbstractNode>() { - - override var right: BinaryNode? = null - override var left: BinaryNode? = null - +open class BinaryNode, V>(key: K, value: V?) : + AbstractNode>(key, value) { open fun search(key: K): BinaryNode? = when (key.compareTo(this.key)) { 1 -> this.right?.search(key) @@ -24,7 +20,6 @@ open class BinaryNode, V>(override var key: K, override var va -1 -> this.left?.search(key) else -> null } - open fun remove(root: BinaryNode?, key: K): BinaryNode? { if (key == this.key) { // когда remove вызывается для удаляемой вершины if (right == null && left == null) @@ -61,18 +56,6 @@ open class BinaryNode, V>(override var key: K, override var va return root } } - - /** - * @param[node] Узел для которого ищется минимальный эл-т. - * @return Наименьший узел. - */ - private fun findMin(node: BinaryNode?): BinaryNode? { - return if (node?.left != null) - findMin(node.left) - else - node - } - open fun add(key: K, value: V?) { val compare = key.compareTo(this.key) @@ -91,4 +74,14 @@ open class BinaryNode, V>(override var key: K, override var va } } -} \ No newline at end of file + /** + * @param[node] Узел для которого ищется минимальный эл-т. + * @return Наименьший узел. + */ + private fun findMin(node: BinaryNode?): BinaryNode? { + return if (node?.left != null) + findMin(node.left) + else + node + } +} diff --git a/lib/src/main/kotlin/trees/BinaryTree.kt b/lib/src/main/kotlin/trees/BinaryTree.kt index 90d44aa..eaa09f0 100644 --- a/lib/src/main/kotlin/trees/BinaryTree.kt +++ b/lib/src/main/kotlin/trees/BinaryTree.kt @@ -4,16 +4,16 @@ import exceptions.NodeNotFound import nodes.BinaryNode open class BinaryTree, V> : AbstractTree>() { - override var root : BinaryNode? = null override fun search(key : K) : BinaryNode? = root?.search(key) ?: throw NodeNotFound() override fun remove(key: K) { - root = root?.remove(this.root, key) ?: throw NodeNotFound() + root = root?.remove(this.root, key) + ?: throw NodeNotFound() } override fun add(key : K, value : V?) { if (root == null) root = BinaryNode(key, value) else - root!!.add(key, value) + root?.add(key, value) } } \ No newline at end of file From 318fa6c03d969ac0fcf2e8b038e56a70f4a98692 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 19:01:50 +0300 Subject: [PATCH 061/203] =?UTF-8?q?=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B8=20=D0=BD=D0=BE=D0=B4=D1=8B=20=D1=81=20=D1=83?= =?UTF-8?q?=D0=B6=D0=B5=20=D1=81=D1=83=D1=89=D0=B5=D1=81=D1=82=D0=B2=D1=83?= =?UTF-8?q?=D1=8E=D1=89=D0=B8=D0=BC=20=D0=B2=20=D0=B4=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=B2=D0=B5=20=D0=BA=D0=BB=D1=8E=D1=87=D0=BE=D0=BC=20=D0=B2?= =?UTF-8?q?=D1=8B=D0=B1=D1=80=D0=B0=D1=81=D1=8B=D0=B2=D0=B0=D0=B5=D1=82?= =?UTF-8?q?=D1=81=D1=8F=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/BinaryNode.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/src/main/kotlin/nodes/BinaryNode.kt b/lib/src/main/kotlin/nodes/BinaryNode.kt index 902e67f..79608aa 100644 --- a/lib/src/main/kotlin/nodes/BinaryNode.kt +++ b/lib/src/main/kotlin/nodes/BinaryNode.kt @@ -1,5 +1,6 @@ package nodes +import exceptions.NodeAlreadyExists import exceptions.NodeNotFound /** @@ -20,6 +21,7 @@ open class BinaryNode, V>(key: K, value: V?) : -1 -> this.left?.search(key) else -> null } + open fun remove(root: BinaryNode?, key: K): BinaryNode? { if (key == this.key) { // когда remove вызывается для удаляемой вершины if (right == null && left == null) @@ -56,6 +58,7 @@ open class BinaryNode, V>(key: K, value: V?) : return root } } + open fun add(key: K, value: V?) { val compare = key.compareTo(this.key) @@ -64,9 +67,10 @@ open class BinaryNode, V>(key: K, value: V?) : right = BinaryNode(key, value) else right?.add(key, value) - } else if (compare == 0) { - this.value = value - } else { + } else if (compare == 0) + // Попытка добавления новой ноды с уже существующим в дереве ключом + throw NodeAlreadyExists() + else { if (left == null) left = BinaryNode(key, value) else From f31c2772fd07a195ddd1739956e26858733e15eb Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 19:12:36 +0300 Subject: [PATCH 062/203] =?UTF-8?q?=D0=9E=D1=82=20BinaryNode=20=D0=B8=20Bi?= =?UTF-8?q?naryTree=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BD=D0=B5?= =?UTF-8?q?=D0=BB=D1=8C=D0=B7=D1=8F=20=D0=BD=D0=B0=D1=81=D0=BB=D0=B5=D0=B4?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=D1=81=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/BinaryNode.kt | 8 ++++---- lib/src/main/kotlin/trees/BinaryTree.kt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/src/main/kotlin/nodes/BinaryNode.kt b/lib/src/main/kotlin/nodes/BinaryNode.kt index 79608aa..3645ad9 100644 --- a/lib/src/main/kotlin/nodes/BinaryNode.kt +++ b/lib/src/main/kotlin/nodes/BinaryNode.kt @@ -12,9 +12,9 @@ import exceptions.NodeNotFound * @property value значение узла. * @author Dmitriy Zaytsev */ -open class BinaryNode, V>(key: K, value: V?) : +class BinaryNode, V>(key: K, value: V?) : AbstractNode>(key, value) { - open fun search(key: K): BinaryNode? = + fun search(key: K): BinaryNode? = when (key.compareTo(this.key)) { 1 -> this.right?.search(key) 0 -> this @@ -22,7 +22,7 @@ open class BinaryNode, V>(key: K, value: V?) : else -> null } - open fun remove(root: BinaryNode?, key: K): BinaryNode? { + fun remove(root: BinaryNode?, key: K): BinaryNode? { if (key == this.key) { // когда remove вызывается для удаляемой вершины if (right == null && left == null) return null // просто стираем ноду @@ -59,7 +59,7 @@ open class BinaryNode, V>(key: K, value: V?) : } } - open fun add(key: K, value: V?) { + fun add(key: K, value: V?) { val compare = key.compareTo(this.key) if (compare == 1) { diff --git a/lib/src/main/kotlin/trees/BinaryTree.kt b/lib/src/main/kotlin/trees/BinaryTree.kt index eaa09f0..ceb5634 100644 --- a/lib/src/main/kotlin/trees/BinaryTree.kt +++ b/lib/src/main/kotlin/trees/BinaryTree.kt @@ -3,7 +3,7 @@ package trees import exceptions.NodeNotFound import nodes.BinaryNode -open class BinaryTree, V> : AbstractTree>() { +class BinaryTree, V> : AbstractTree>() { override fun search(key : K) : BinaryNode? = root?.search(key) ?: throw NodeNotFound() override fun remove(key: K) { From 8aea8d604978346b2759744d388c85866383dc33 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 19:16:23 +0300 Subject: [PATCH 063/203] =?UTF-8?q?BinaryTree.search=20=D0=B1=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D1=88=D0=B5=20=D0=BD=D0=B5=20=D0=BC=D0=BE=D0=B6=D0=B5?= =?UTF-8?q?=D1=82=20=D0=B2=D0=B5=D1=80=D0=BD=D1=83=D1=82=D1=8C=20null=20(?= =?UTF-8?q?=D0=BB=D0=B8=D0=B1=D0=BE=20=D0=BD=D0=BE=D0=B4=D0=B0,=20=D0=BB?= =?UTF-8?q?=D0=B8=D0=B1=D0=BE=20Exception)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/BinaryNode.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/src/main/kotlin/nodes/BinaryNode.kt b/lib/src/main/kotlin/nodes/BinaryNode.kt index 3645ad9..60c17b4 100644 --- a/lib/src/main/kotlin/nodes/BinaryNode.kt +++ b/lib/src/main/kotlin/nodes/BinaryNode.kt @@ -21,7 +21,6 @@ class BinaryNode, V>(key: K, value: V?) : -1 -> this.left?.search(key) else -> null } - fun remove(root: BinaryNode?, key: K): BinaryNode? { if (key == this.key) { // когда remove вызывается для удаляемой вершины if (right == null && left == null) @@ -58,7 +57,6 @@ class BinaryNode, V>(key: K, value: V?) : return root } } - fun add(key: K, value: V?) { val compare = key.compareTo(this.key) From 60acdf76f72d746d7414a2a70af955f7f408d6ab Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 19:17:36 +0300 Subject: [PATCH 064/203] =?UTF-8?q?=D0=9A=D0=BB=D0=B0=D1=81=D1=81=D1=8B=20?= =?UTF-8?q?=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B9=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D1=8C=D0=B5?= =?UTF-8?q?=D0=B2=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=D1=8E=D1=82=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20NodeNotFoundException,=20NodeAlreadyExistsException?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/exceptions/TreeExceptions.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/main/kotlin/exceptions/TreeExceptions.kt b/lib/src/main/kotlin/exceptions/TreeExceptions.kt index f21ae80..e4c480f 100644 --- a/lib/src/main/kotlin/exceptions/TreeExceptions.kt +++ b/lib/src/main/kotlin/exceptions/TreeExceptions.kt @@ -5,6 +5,6 @@ package exceptions * */ open class TreeException(message: String) : Exception(message) -class NodeNotFound() : TreeException("Подходящий для выполнения операции узел дерева не найден") +class NodeNotFoundException() : TreeException("Подходящий для выполнения операции узел дерева не найден") -class NodeAlreadyExists() : TreeException("Узел дерева с таким ключом уже существует") +class NodeAlreadyExistsException() : TreeException("Узел дерева с таким ключом уже существует") From 0a754326a28fa32aba49c10ecc4bedcc90797c72 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 19:43:02 +0300 Subject: [PATCH 065/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=20=D1=81=D0=BE?= =?UTF-8?q?=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=BE=20=D1=81?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=BE=D1=8F=D0=BD=D0=B8=D0=B8=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=85=D0=BE=D0=B6=D0=B4=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/build.gradle | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/build.gradle b/lib/build.gradle index 0552a08..b7728d8 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -12,7 +12,6 @@ dependencies { testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5' testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.1' api 'org.apache.commons:commons-math3:3.6.1' - implementation 'com.google.guava:guava:31.1-jre' implementation("org.xerial:sqlite-jdbc:3.32.3.2") implementation("io.github.microutils:kotlin-logging-jvm:2.0.6") @@ -20,11 +19,7 @@ dependencies { tasks.named('test') { useJUnitPlatform() - beforeTest { descriptor -> - logger.lifecycle("Running test: " + descriptor.getDisplayName()) + testLogging { + events "PASSED", "SKIPPED", "FAILED" } - onOutput { descriptor, event -> - logger.lifecycle("Test " + descriptor + " message: " + event.message ) - } - failFast = true } From fc50363c82403ce9673bee819e8c91e34f8c4ecd Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 20:16:25 +0300 Subject: [PATCH 066/203] =?UTF-8?q?=D0=9D=D0=BE=D0=B4=D1=8B=20=D1=82=D0=B5?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=20?= =?UTF-8?q?=D1=81=D1=80=D0=B0=D0=B2=D0=BD=D0=B8=D0=B2=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?=D0=BC=D0=B5=D0=B6=D0=B4=D1=83=20=D1=81=D0=BE=D0=B1=D0=BE=D0=B9?= =?UTF-8?q?=20(=D0=BF=D0=BE=20key)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/AbstractNode.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/src/main/kotlin/nodes/AbstractNode.kt b/lib/src/main/kotlin/nodes/AbstractNode.kt index 0a6506d..190a6b0 100644 --- a/lib/src/main/kotlin/nodes/AbstractNode.kt +++ b/lib/src/main/kotlin/nodes/AbstractNode.kt @@ -1,11 +1,14 @@ package nodes -abstract class AbstractNode, V, node : AbstractNode>(key: K, value : V?) { - var key : K = key +abstract class AbstractNode, V, node : AbstractNode>(key: K, value: V?) : + Comparable> { + var key: K = key protected set - var value : V? = value - protected set + var value: V? = value + protected set + + var right: node? = null + var left: node? = null - var right : node? = null - var left : node? = null + override fun compareTo(other: AbstractNode): Int = this.key.compareTo(other.key) } \ No newline at end of file From b767b0234c998b361666b9b105c751a675495768 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 20:32:15 +0300 Subject: [PATCH 067/203] =?UTF-8?q?root=20=D1=81=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BC=D0=BE=D0=B4=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=82?= =?UTF-8?q?=D0=BE=D1=80=20=D0=B4=D0=BE=D1=81=D1=82=D1=83=D0=BF=D0=B0=20?= =?UTF-8?q?=D0=BD=D0=B0=20internal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/trees/AbstractTree.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/main/kotlin/trees/AbstractTree.kt b/lib/src/main/kotlin/trees/AbstractTree.kt index 432aa6e..6eaf77f 100644 --- a/lib/src/main/kotlin/trees/AbstractTree.kt +++ b/lib/src/main/kotlin/trees/AbstractTree.kt @@ -3,7 +3,7 @@ package trees import nodes.AbstractNode abstract class AbstractTree, V, node : AbstractNode> { - protected var root : node? = null + internal var root : node? = null abstract fun search(key : K) : node? abstract fun add(key : K, value : V? = null) abstract fun remove(key : K) From 202b719c0a55148026dde37c4cc2af60249d20d6 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 22:33:52 +0300 Subject: [PATCH 068/203] =?UTF-8?q?=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20=D0=B1?= =?UTF-8?q?=D0=B8=D0=BD=D0=B0=D1=80=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B4=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B2=D0=B0=20=D0=BD=D0=B5=20=D0=B8=D1=81=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=D0=B7=D1=83=D1=8E=D1=82=20=D1=84-=D0=B8?= =?UTF-8?q?=D0=B8=20=D1=81=D0=B0=D0=BC=D0=BE=D0=B3=D0=BE=20=D0=B4=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B2=D0=B0=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8=20(=D1=80=D0=B5=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D1=8B=20=D0=BD=D0=B5?= =?UTF-8?q?=D1=81=D0=BA=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE=20=D0=B2=D1=81=D0=BF?= =?UTF-8?q?=D0=BE=D0=BC=D0=BE=D0=B3=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D1=8B=D1=85=20=D1=84-=D0=B8=D0=B9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/BinaryTreeTest.kt | 152 ++++++++++++++------ 1 file changed, 107 insertions(+), 45 deletions(-) diff --git a/lib/src/test/kotlin/trees/BinaryTreeTest.kt b/lib/src/test/kotlin/trees/BinaryTreeTest.kt index 2f2e83f..607b1d7 100644 --- a/lib/src/test/kotlin/trees/BinaryTreeTest.kt +++ b/lib/src/test/kotlin/trees/BinaryTreeTest.kt @@ -1,5 +1,7 @@ package trees +import exceptions.NodeAlreadyExistsException +import nodes.BinaryNode import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested @@ -7,109 +9,169 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.function.Executable import java.time.Duration.ofMillis import kotlin.random.Random +import kotlin.test.BeforeTest class BinaryTreeTest { + private lateinit var tree: BinaryTree + + @BeforeTest + fun init() { + tree = BinaryTree() + } @Nested inner class `Remove check` { - /** - * Добавляет последовательно массив из ключей с null value - */ - private fun , NodeType> BinaryTree.addGroup(keys : Array) { - for (item in keys) - this.add(item) - } @Test @DisplayName("Root remove") fun `Root remove`() { - val tree = BinaryTree() tree.add(100, "root") + tree.remove(100) - assertEquals(null, tree.search(100)?.value) + + assertFalse(tree.nodeExists(100, null)) } + @Test - @DisplayName("Simple element remove") - fun `Simple element remove`() { - val tree = BinaryTree() + @DisplayName("Remove node without children") + fun `Remove node without children`() { tree.add(8, "root") tree.add(10, "a") tree.add(14, "b") tree.add(13) + tree.remove(13) + + // Проверка что каждый assertEquals не выбрасывает исключений + // В случае исключения выведется сообщение о нём assertAll("elements", - Executable { assertEquals("root", tree.search(8)?.value) }, - Executable { assertEquals("a", tree.search(10)?.value) }, - Executable { assertEquals("b", tree.search(14)?.value) }, - Executable { assertEquals(null, tree.search(13)?.value) } + Executable { assertTrue(tree.nodeExists(8, "root")) }, + Executable { assertTrue(tree.nodeExists(10, "a")) }, + Executable { assertTrue(tree.nodeExists(14, "b")) }, + Executable { assertFalse(tree.nodeExists(13, null)) }, + Executable { assertTrue(tree.root?.childrenCheck() ?: false) } ) } + @Test @DisplayName("Element with one child node remove") fun `Element with one child node remove`() { - val tree = BinaryTree() tree.add(8, "root") tree.add(10, "a") tree.add(14) tree.add(13, "c") + tree.remove(14) + assertAll("elements", - Executable { assertEquals("root", tree.search(8)?.value) }, - Executable { assertEquals("a", tree.search(10)?.value) }, - Executable { assertEquals("c", tree.search(13)?.value) }, - Executable { assertEquals(null, tree.search(14)?.value) } + Executable { assertTrue(tree.nodeExists(8, "root"))}, + Executable { assertTrue(tree.nodeExists(10, "a")) }, + Executable { assertTrue(tree.nodeExists(13, "c")) }, + Executable { assertFalse(tree.nodeExists(14, null)) }, + Executable { assertTrue(tree.root?.childrenCheck() ?: false) } ) } + @Test @DisplayName("Element with two child nodes remove") fun `Element with two child nodes remove`() { - val tree = BinaryTree() - tree.addGroup(arrayOf(8, 10, 14, 13, 3, 1, 6, 4, 7)) tree.add(8, "root") - tree.add(4, "a") + tree.add(10, "a") + tree.add(14) + tree.add(13) + tree.add(3, "abc") tree.add(1, "b") tree.add(6, "c") + tree.add(4) tree.add(7, "d") tree.remove(3) + assertAll("elements", - Executable { assertEquals("a", tree.search(4)?.value) }, - Executable { assertEquals("b", tree.search(1)?.value) }, - Executable { assertEquals(null, tree.search(3)?.value) }, - Executable { assertEquals("c", tree.search(6)?.value) }, - Executable { assertEquals("d", tree.search(7)?.value) }, - Executable { assertEquals("root", tree.search(8)?.value) } + Executable { assertTrue(tree.nodeExists(10, "a")) }, + Executable { assertTrue(tree.nodeExists(1, "b")) }, + Executable { assertFalse(tree.nodeExists(3, "abc")) }, + Executable { assertTrue(tree.nodeExists(6, "c")) }, + Executable { assertTrue(tree.nodeExists(7, "d")) }, + Executable { assertTrue(tree.nodeExists(8, "root")) }, + Executable { assertTrue(tree.root?.childrenCheck() ?: false) } ) } } + @Nested - inner class `Add check` { + inner class `Add Check` { @Test - @DisplayName("Simple add") - fun `Simple add`() { - val tree = BinaryTree() + @DisplayName("Root add") + fun `Root add`() { tree.add(30, "root") - assertEquals("root", tree.search(30)?.value) + + assertTrue(tree.nodeExists(30, "root")) } + @Test @DisplayName("Equal keys add") fun `Equal keys add`() { - val tree = BinaryTree() - tree.add(100, "abc") + tree.add(100) + + assertThrows(NodeAlreadyExistsException::class.java) {tree.add(100)} + } + + @Test + @DisplayName("Add to different nodes") + fun `Add to different subtrees`() { tree.add(100, "root") - assertEquals("root", tree.search(100)?.value) + tree.add(150, "root -> right") + tree.add(80, "root -> left") + + assertAll("elements", + Executable { assertTrue(tree.nodeExists(100, "root")) }, + Executable { assertTrue(tree.nodeExists(150, "root -> right")) }, + Executable { assertTrue(tree.nodeExists(80, "root -> left")) }, + Executable { assertTrue(tree.root?.childrenCheck() ?: false)} + ) } @Test - @DisplayName("Multiply add") - fun `Multiply add`() { + @DisplayName("Add a large number of elements") + fun `Add a large number of elements`() { assertTimeout(ofMillis(1000)) { - val tree = BinaryTree() - val list : List = (List(100000) { Random.nextInt(1, 100000) }).distinct().toMutableList() + val list: List = (List(100000) { Random.nextInt(1, 100000) }).distinct().toMutableList() + for (item in list) - tree.add(item, 0) - assertEquals(tree.search(list.last())?.value, 0) + tree.add(item, "a") } } } -} \ No newline at end of file + + /** + * Проверка на то, что левый узел меньше, а правый больше + * @return True - узлы размещены как положено + * */ + fun , V> BinaryNode.childrenCheck(): Boolean = + (this.left == null || this.left?.compareTo(this) == -1) + && (this.right == null || this.right?.compareTo(this) == 1) + + /** + * Выполняет рекурсивный поиск ноды + * (нужна чтобы тесты не опирались на ф-ию поиска класса BinaryNode) + */ + private fun , V> BinaryNode.recursiveSearch(key: K): BinaryNode? = + when (key.compareTo(this.key)) { + 1 -> this.right?.search(key) + 0 -> this + -1 -> this.left?.search(key) + else -> null + } + + /*** + * Проверяет ноду на существование + * @return True - найден узел с совпадающим ключом и значением + */ + fun , V> BinaryTree.nodeExists(key: K, value: V?): Boolean { + if (this.root == null) + return false + val searchRes = this.root?.recursiveSearch(key) + return searchRes != null && searchRes.value == value + } +} From 0606d50b17c0728eea7a2cd185519210dceb3f53 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 22:39:31 +0300 Subject: [PATCH 069/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D1=82=D0=B5=D1=81=D1=82=20=D0=BD=D0=B0=20=D1=83?= =?UTF-8?q?=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B5=D1=81?= =?UTF-8?q?=D1=83=D1=89=D0=B5=D1=81=D1=82=D0=B2=D1=83=D1=8E=D1=89=D0=B5?= =?UTF-8?q?=D0=B3=D0=BE=20=D0=BA=D0=BE=D1=80=D0=BD=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/BinaryTreeTest.kt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/src/test/kotlin/trees/BinaryTreeTest.kt b/lib/src/test/kotlin/trees/BinaryTreeTest.kt index 607b1d7..6e9e102 100644 --- a/lib/src/test/kotlin/trees/BinaryTreeTest.kt +++ b/lib/src/test/kotlin/trees/BinaryTreeTest.kt @@ -1,6 +1,7 @@ package trees import exceptions.NodeAlreadyExistsException +import exceptions.NodeNotFoundException import nodes.BinaryNode import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName @@ -34,7 +35,7 @@ class BinaryTreeTest { } @Test - @DisplayName("Remove node without children") + @DisplayName("Node without children remove") fun `Remove node without children`() { tree.add(8, "root") tree.add(10, "a") @@ -73,6 +74,12 @@ class BinaryTreeTest { ) } + @Test + @DisplayName("Non-existent element remove") + fun `Non-existent element remove`() { + assertThrows(NodeNotFoundException::class.java) {tree.remove(100)} + } + @Test @DisplayName("Element with two child nodes remove") fun `Element with two child nodes remove`() { @@ -133,7 +140,7 @@ class BinaryTreeTest { ) } @Test - @DisplayName("Add a large number of elements") + @DisplayName("Large number of elements add") fun `Add a large number of elements`() { assertTimeout(ofMillis(1000)) { val list: List = (List(100000) { Random.nextInt(1, 100000) }).distinct().toMutableList() From 6e0fa9c92c0fc1ee00d447c88f207e78929dd3af Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 22:53:27 +0300 Subject: [PATCH 070/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D0=BD=D0=BE=D0=B2=D0=BE=D0=B5=20=D0=B8?= =?UTF-8?q?=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20NullNo?= =?UTF-8?q?deException?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/exceptions/TreeExceptions.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/main/kotlin/exceptions/TreeExceptions.kt b/lib/src/main/kotlin/exceptions/TreeExceptions.kt index e4c480f..b2190f2 100644 --- a/lib/src/main/kotlin/exceptions/TreeExceptions.kt +++ b/lib/src/main/kotlin/exceptions/TreeExceptions.kt @@ -8,3 +8,5 @@ open class TreeException(message: String) : Exception(message) class NodeNotFoundException() : TreeException("Подходящий для выполнения операции узел дерева не найден") class NodeAlreadyExistsException() : TreeException("Узел дерева с таким ключом уже существует") + +class NullNodeException() : TreeException("Узел дерева принял значение null") \ No newline at end of file From fed4618a0a11abbf016ad63f279893529ffbc0d6 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 22:55:05 +0300 Subject: [PATCH 071/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BF=D0=BE=D0=BA=D1=80=D1=8B=D1=82=D0=B8=D0=B5=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=B0=D0=BC=D0=B8=20=D1=81=D0=B8=D1=82?= =?UTF-8?q?=D1=83=D0=B0=D1=86=D0=B8=D0=B8=20=D1=81=20=D1=83=D0=B4=D0=B0?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC=20=D0=BD=D0=B5=D1=81=D1=83?= =?UTF-8?q?=D1=89=D0=B5=D1=81=D1=82=D0=B2=D1=83=D1=8E=D1=89=D0=B5=D0=B3?= =?UTF-8?q?=D0=BE=20=D1=8D=D0=BB-=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/BinaryTreeTest.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/src/test/kotlin/trees/BinaryTreeTest.kt b/lib/src/test/kotlin/trees/BinaryTreeTest.kt index 6e9e102..75041da 100644 --- a/lib/src/test/kotlin/trees/BinaryTreeTest.kt +++ b/lib/src/test/kotlin/trees/BinaryTreeTest.kt @@ -77,6 +77,16 @@ class BinaryTreeTest { @Test @DisplayName("Non-existent element remove") fun `Non-existent element remove`() { + tree.add(100) + tree.add(120) + tree.add(130) + tree.add(109) + assertThrows(NodeNotFoundException::class.java) {tree.remove(150)} + } + + @Test + @DisplayName("Non-existent root remove") + fun `Non-existent root remove`() { assertThrows(NodeNotFoundException::class.java) {tree.remove(100)} } From 925544c96dfdba742f562358ae1a29df792f558f Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 23:03:29 +0300 Subject: [PATCH 072/203] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D1=83=20=D1=81?= =?UTF-8?q?=D0=B2=D1=8F=D0=B7=D0=B0=D0=BD=D0=BD=D1=83=D1=8E=20=D1=81=20?= =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC=20=D0=BD?= =?UTF-8?q?=D0=BE=D0=B4=D1=8B=20=D1=81=20=D0=B4=D0=B2=D1=83=D0=BC=D1=8F=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D1=8C=D1=8F?= =?UTF-8?q?=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/BinaryNode.kt | 21 ++++++++++++--------- lib/src/main/kotlin/trees/BinaryTree.kt | 9 +++++---- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/lib/src/main/kotlin/nodes/BinaryNode.kt b/lib/src/main/kotlin/nodes/BinaryNode.kt index 60c17b4..a51d311 100644 --- a/lib/src/main/kotlin/nodes/BinaryNode.kt +++ b/lib/src/main/kotlin/nodes/BinaryNode.kt @@ -1,7 +1,8 @@ package nodes -import exceptions.NodeAlreadyExists -import exceptions.NodeNotFound +import exceptions.NodeAlreadyExistsException +import exceptions.NodeNotFoundException +import exceptions.NullNodeException /** * Класс узла для бинарного дерева. @@ -35,28 +36,30 @@ class BinaryNode, V>(key: K, value: V?) : // Случай где есть два потомка else { // Находим минимальное дерево - val minNode = findMin(right) + val minNode = findMin(right) ?: throw NullNodeException() + // Перенимаем его key и value - minNode?.let { + minNode.let { this.key = it.key this.value = it.value + // Удаляем минимальное дерево + this.right = right?.remove(right, it.key) } - // Удаляем минимальное дерево - this.right = right?.remove(right, key) return this } } else { + if (left == null && right == null) + throw NodeNotFoundException() // Идём дальше по дереву искать что удалить if (key < this.key) this.left = left?.remove(left, key) - ?: throw NodeNotFound() else this.right = right?.remove(right, key) - ?: throw NodeNotFound() return root } } + fun add(key: K, value: V?) { val compare = key.compareTo(this.key) @@ -67,7 +70,7 @@ class BinaryNode, V>(key: K, value: V?) : right?.add(key, value) } else if (compare == 0) // Попытка добавления новой ноды с уже существующим в дереве ключом - throw NodeAlreadyExists() + throw NodeAlreadyExistsException() else { if (left == null) left = BinaryNode(key, value) diff --git a/lib/src/main/kotlin/trees/BinaryTree.kt b/lib/src/main/kotlin/trees/BinaryTree.kt index ceb5634..b334103 100644 --- a/lib/src/main/kotlin/trees/BinaryTree.kt +++ b/lib/src/main/kotlin/trees/BinaryTree.kt @@ -1,14 +1,15 @@ package trees -import exceptions.NodeNotFound +import exceptions.NodeNotFoundException import nodes.BinaryNode class BinaryTree, V> : AbstractTree>() { - override fun search(key : K) : BinaryNode? = root?.search(key) - ?: throw NodeNotFound() + override fun search(key : K) : BinaryNode = root?.search(key) + ?: throw NodeNotFoundException() override fun remove(key: K) { + if (root == null) + throw NodeNotFoundException() root = root?.remove(this.root, key) - ?: throw NodeNotFound() } override fun add(key : K, value : V?) { if (root == null) From 7b5aae91d88501d5882576552111db9adc01e671 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 20 Apr 2023 23:12:15 +0300 Subject: [PATCH 073/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2=D0=BE?= =?UTF-8?q?=D0=B5=20=D0=BF=D0=BE=D0=BA=D1=80=D1=8B=D1=82=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=84-=D0=B8=D0=B8=20=D0=BF=D0=BE=D0=B8?= =?UTF-8?q?=D1=81=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/BinaryTreeTest.kt | 35 ++++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/lib/src/test/kotlin/trees/BinaryTreeTest.kt b/lib/src/test/kotlin/trees/BinaryTreeTest.kt index 75041da..209a692 100644 --- a/lib/src/test/kotlin/trees/BinaryTreeTest.kt +++ b/lib/src/test/kotlin/trees/BinaryTreeTest.kt @@ -21,6 +21,30 @@ class BinaryTreeTest { tree = BinaryTree() } + @Nested + inner class `Search check` { + @Test + @DisplayName("Existing elements search") + fun `Existing elements search`() { + tree.add(100, "root") + tree.add(150, "root -> right") + tree.add(50, "root -> left") + tree.add(30, "root -> left -> left") + + assertAll( + Executable { assertEquals("root", tree.search(100).value) }, + Executable { assertEquals("root -> right", tree.search(150).value) }, + Executable { assertEquals("root -> left", tree.search(50).value) }, + Executable { assertEquals("root -> left -> left", tree.search(30).value) }) + } + + @Test + @DisplayName("Not-existent elements search") + fun `Not-existent elements search`() { + assertThrows(NodeNotFoundException::class.java) { tree.search(100) } + } + } + @Nested inner class `Remove check` { @@ -66,7 +90,7 @@ class BinaryTreeTest { tree.remove(14) assertAll("elements", - Executable { assertTrue(tree.nodeExists(8, "root"))}, + Executable { assertTrue(tree.nodeExists(8, "root")) }, Executable { assertTrue(tree.nodeExists(10, "a")) }, Executable { assertTrue(tree.nodeExists(13, "c")) }, Executable { assertFalse(tree.nodeExists(14, null)) }, @@ -81,13 +105,13 @@ class BinaryTreeTest { tree.add(120) tree.add(130) tree.add(109) - assertThrows(NodeNotFoundException::class.java) {tree.remove(150)} + assertThrows(NodeNotFoundException::class.java) { tree.remove(150) } } @Test @DisplayName("Non-existent root remove") fun `Non-existent root remove`() { - assertThrows(NodeNotFoundException::class.java) {tree.remove(100)} + assertThrows(NodeNotFoundException::class.java) { tree.remove(100) } } @Test @@ -132,7 +156,7 @@ class BinaryTreeTest { fun `Equal keys add`() { tree.add(100) - assertThrows(NodeAlreadyExistsException::class.java) {tree.add(100)} + assertThrows(NodeAlreadyExistsException::class.java) { tree.add(100) } } @Test @@ -146,9 +170,10 @@ class BinaryTreeTest { Executable { assertTrue(tree.nodeExists(100, "root")) }, Executable { assertTrue(tree.nodeExists(150, "root -> right")) }, Executable { assertTrue(tree.nodeExists(80, "root -> left")) }, - Executable { assertTrue(tree.root?.childrenCheck() ?: false)} + Executable { assertTrue(tree.root?.childrenCheck() ?: false) } ) } + @Test @DisplayName("Large number of elements add") fun `Add a large number of elements`() { From bd322cde77cb1423c470a12fc0a66633eea0106a Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Fri, 21 Apr 2023 16:30:25 +0300 Subject: [PATCH 074/203] =?UTF-8?q?=D0=97=D0=B0=D0=BF=D1=83=D1=81=D0=BA=20?= =?UTF-8?q?actions=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D1=82=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=BA=D0=BE=20=D0=BF=D1=80=D0=B8=20=D0=BF=D1=83?= =?UTF-8?q?=D1=88=D0=B5=20=D0=B8=20=D1=81=D1=80=D0=B0=D0=B7=D1=83=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=B4=D0=B2=D1=83=D1=85=20=D1=81=D0=B8=D1=81=D1=82?= =?UTF-8?q?=D0=B5=D0=BC=D0=B0=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/gradle.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index a5fa514..f194536 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -1,9 +1,9 @@ name: Gradle Build&Test -on: [push, pull_request] +on: [push] jobs: gradle: - runs-on: ubuntu-latest + runs-on: [ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v3 @@ -17,6 +17,3 @@ jobs: - name: Build run: ./gradlew build - - - name: Test - run: ./gradlew test From 040e919bf52aa3f997930b136acece554c732e06 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Fri, 21 Apr 2023 17:18:31 +0300 Subject: [PATCH 075/203] =?UTF-8?q?=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?actions=20=D0=B7=D0=B0=D0=BF=D1=83=D1=81=D0=BA=D0=B0=D1=8E?= =?UTF-8?q?=D1=82=D1=81=D1=8F=20=D1=81=D1=80=D0=B0=D0=B7=D1=83=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D1=82=D1=80=D1=91=D1=85=20=D1=81=D0=B8=D1=81=D1=82?= =?UTF-8?q?=D0=B5=D0=BC=D0=B0=D1=85.=20Actions=20=D1=81=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=B0=D1=82=D1=8B=D0=B2=D0=B0=D0=B5=D1=82=20=D1=82=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=BA=D0=BE=20=D0=BF=D1=80=D0=B8=20=D0=BF=D1=83=D1=88?= =?UTF-8?q?=D0=B5=20=D0=BD=D0=B5=20=D0=B2=20main=20=D0=B8=D0=BB=D0=B8=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=20=D0=BF=D1=83=D0=BB-=D1=80=D0=B5=D0=BA?= =?UTF-8?q?=D0=B2=D0=B5=D1=81=D1=82=D0=B5=20=D0=B2=20main?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/gradle.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index f194536..be39008 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -1,9 +1,19 @@ name: Gradle Build&Test -on: [push] +on: + push: + branches-gnore: + - main + pull_request: + branches: + - main jobs: gradle: - runs-on: [ubuntu-latest, windows-latest] + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: - uses: actions/checkout@v3 From c049d48ef3bbe73417e20ae27fd27c05fdecdeca Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Fri, 21 Apr 2023 17:32:07 +0300 Subject: [PATCH 076/203] =?UTF-8?q?=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=20=D0=BD=D0=BE=D1=80=D0=BC?= =?UTF-8?q?=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE=20=D0=B1=D0=B8=D0=BB=D0=B4=D0=B8?= =?UTF-8?q?=D1=82=D1=81=D1=8F=20(=D0=B2=D0=BD=D0=B5=D1=81=D0=B5=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20-=20=D1=8D=D1=82=D0=BE=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=BE=20=D0=B7=D0=B0=D0=B3=D0=BB=D1=83=D1=88=D0=BA?= =?UTF-8?q?=D0=B8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/database/RBT/RBTDataBase.kt | 9 +++++---- lib/src/main/kotlin/trees/RBTree.kt | 5 ++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/src/main/kotlin/database/RBT/RBTDataBase.kt b/lib/src/main/kotlin/database/RBT/RBTDataBase.kt index f45572e..e557082 100644 --- a/lib/src/main/kotlin/database/RBT/RBTDataBase.kt +++ b/lib/src/main/kotlin/database/RBT/RBTDataBase.kt @@ -1,9 +1,10 @@ -package DB +package database.RBT +import trees.RBTree import java.io.* class RBTreeSerializer { - fun serialize(tree: RBTree, filePath: String) { + fun serialize(tree: RBTree<*, *>, filePath: String) { val fileOutputStream = FileOutputStream(filePath) val objectOutputStream = ObjectOutputStream(fileOutputStream) objectOutputStream.writeObject(tree) @@ -11,10 +12,10 @@ class RBTreeSerializer { fileOutputStream.close() } - fun deserialize(filePath: String): RBTree { + fun deserialize(filePath: String): RBTree<*, *> { val fileInputStream = FileInputStream(filePath) val objectInputStream = ObjectInputStream(fileInputStream) - val tree = objectInputStream.readObject() as RBTree + val tree = objectInputStream.readObject() as RBTree<*, *> objectInputStream.close() fileInputStream.close() return tree diff --git a/lib/src/main/kotlin/trees/RBTree.kt b/lib/src/main/kotlin/trees/RBTree.kt index d1e4f35..554823a 100644 --- a/lib/src/main/kotlin/trees/RBTree.kt +++ b/lib/src/main/kotlin/trees/RBTree.kt @@ -2,8 +2,7 @@ package trees import nodes.Color import nodes.RBNode -import DB.RBTreeSerializer -import java.io.* +import database.RBT.RBTreeSerializer class RBTree, V> : AbstractTree>() { override var root: RBNode? = null @@ -239,7 +238,7 @@ class RBTree, V> : AbstractTree>() { } companion object { - fun loadFromFile(filePath: String): RBTree { + fun loadFromFile(filePath: String): RBTree<*, *> { val serializer = RBTreeSerializer() return serializer.deserialize(filePath) } From add28848153cc78fcf89107dbca5a417522602b2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaytsev <113129532+d-zaytsev@users.noreply.github.com> Date: Fri, 21 Apr 2023 17:35:41 +0300 Subject: [PATCH 077/203] Merge pull request #17 from spbu-coding-2022/fixes/build-fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Исправление ошибок, мешающих сборке проекта --- .../main/kotlin/database/RBT/RBTDataBase.kt | 23 ++ lib/src/main/kotlin/trees/RBTree.kt | 246 ++++++++++++++++++ 2 files changed, 269 insertions(+) create mode 100644 lib/src/main/kotlin/database/RBT/RBTDataBase.kt create mode 100644 lib/src/main/kotlin/trees/RBTree.kt diff --git a/lib/src/main/kotlin/database/RBT/RBTDataBase.kt b/lib/src/main/kotlin/database/RBT/RBTDataBase.kt new file mode 100644 index 0000000..e557082 --- /dev/null +++ b/lib/src/main/kotlin/database/RBT/RBTDataBase.kt @@ -0,0 +1,23 @@ +package database.RBT + +import trees.RBTree +import java.io.* + +class RBTreeSerializer { + fun serialize(tree: RBTree<*, *>, filePath: String) { + val fileOutputStream = FileOutputStream(filePath) + val objectOutputStream = ObjectOutputStream(fileOutputStream) + objectOutputStream.writeObject(tree) + objectOutputStream.close() + fileOutputStream.close() + } + + fun deserialize(filePath: String): RBTree<*, *> { + val fileInputStream = FileInputStream(filePath) + val objectInputStream = ObjectInputStream(fileInputStream) + val tree = objectInputStream.readObject() as RBTree<*, *> + objectInputStream.close() + fileInputStream.close() + return tree + } +} diff --git a/lib/src/main/kotlin/trees/RBTree.kt b/lib/src/main/kotlin/trees/RBTree.kt new file mode 100644 index 0000000..554823a --- /dev/null +++ b/lib/src/main/kotlin/trees/RBTree.kt @@ -0,0 +1,246 @@ +package trees + +import nodes.Color +import nodes.RBNode +import database.RBT.RBTreeSerializer + +class RBTree, V> : AbstractTree>() { + override var root: RBNode? = null + + override fun search(key: K): RBNode? { + var node = root + while (node != null) { + node = when { + key < node.key -> node.left + key > node.key -> node.right + else -> return node //when found - return node + } + } + return null + } + + override fun add(key: K, value: V?) { + val newNode = RBNode(key, value) + if (root == null) { // if there is no root, make the node - new root + root = newNode + root?.color = Color.BLACK + return + } + + var node = root + var parent: RBNode? = null + while (node != null) { //move down the tree + parent = node + node = if (key < node.key) node.left else node.right + } + + newNode.color = Color.RED + newNode.parent = parent + + if (key < (parent?.key ?: throw NullPointerException("Parent is null"))) { //move up the tree, find needed place + parent.left = newNode + } else { + parent.right = newNode + } + + fixInsert(newNode) + } + + override fun remove(key: K) { + val node = search(key) ?: return //check if node is real + removeNode(node) + } + + private fun removeNode(node: RBNode) { + val replacementNode = when { + node.left == null -> node.right + node.right == null -> node.left + else -> { + var successor = node.right + while (successor?.left != null) { + successor = successor.left + } + if (successor?.parent != node) { + transplant(successor ?: throw IllegalArgumentException("Node cannot be null"), successor.right) + successor.right = node.right + successor.right?.parent = successor + } + transplant(node, successor) + successor.left = node.left + successor.left?.parent = successor + successor.color = node.color + successor + } + } + + if (node.color == Color.BLACK) { + fixDelete(replacementNode) + } + + if (node.parent == null) { + root = replacementNode + } else if (node == (node.parent as RBNode).left) { + (node.parent as RBNode).left = replacementNode + } else { + (node.parent as RBNode).right = replacementNode + } + + replacementNode?.parent = node.parent + } + + private fun fixInsert(node: RBNode) { + var newNode = node + while (newNode.parent?.color == Color.RED) { + if (newNode.parent == newNode.parent?.parent?.left) { + val uncle = newNode.parent?.parent?.right + if (uncle?.color == Color.RED) { + newNode.parent?.color = Color.BLACK + uncle.color = Color.BLACK + newNode.parent?.parent?.color = Color.RED + newNode = newNode.parent?.parent ?: throw IllegalArgumentException("Node cannot be null") + } else { + if (newNode == newNode.parent?.right) { + newNode = newNode.parent ?: throw IllegalArgumentException("Node cannot be null") + leftRotate(newNode) + } + newNode.parent?.color = Color.BLACK + newNode.parent?.parent?.color = Color.RED + newNode.parent?.parent?.let { rightRotate(it) } ?: throw IllegalArgumentException("Node cannot be null") + } + } else { + val uncle = newNode.parent?.parent?.left + if (uncle?.color == Color.RED) { + newNode.parent?.color = Color.BLACK + uncle.color = Color.BLACK + newNode.parent?.parent?.color = Color.RED + newNode = newNode.parent?.parent ?: throw IllegalArgumentException("Node cannot be null") + } else { + if (newNode == newNode.parent?.left) { + newNode = newNode.parent ?: throw IllegalArgumentException("Node cannot be null") + rightRotate(newNode) + } + newNode.parent?.color = Color.BLACK + newNode.parent?.parent?.color = Color.RED + newNode.parent?.parent?.let { leftRotate(it) } ?: throw IllegalArgumentException("Node cannot be null") + } + } + } + root?.color = Color.BLACK + } + + private fun fixDelete(node: RBNode?) { + var currentNode = node + while (currentNode != root && currentNode?.color == Color.BLACK) { + if (currentNode == currentNode.parent?.left) { + var sibling = currentNode.parent?.right + if (sibling?.color == Color.RED) { + sibling.color = Color.BLACK + currentNode.parent?.color = Color.RED + currentNode.parent?.let { leftRotate(it) } + sibling = currentNode.parent?.right + } + if (sibling?.left?.color == Color.BLACK && sibling.right?.color == Color.BLACK) { + sibling.color = Color.RED + currentNode = currentNode.parent + } else { + if (sibling?.right?.color == Color.BLACK) { + sibling.left?.color = Color.BLACK + sibling.color = Color.RED + sibling?.let { rightRotate(it) } + sibling = currentNode.parent?.right + } + sibling?.color = currentNode.parent?.color ?: throw IllegalStateException("Parent color is null") + currentNode.parent?.color = Color.BLACK + sibling?.right?.color = Color.BLACK + currentNode.parent?.let { leftRotate(it) } + currentNode = root + } + } else { + var sibling = currentNode.parent?.left + if (sibling?.color == Color.RED) { + sibling.color = Color.BLACK + currentNode.parent?.color = Color.RED + currentNode.parent?.let { rightRotate(it) } + sibling = currentNode.parent?.left + } + if (sibling?.right?.color == Color.BLACK && sibling.left?.color == Color.BLACK) { + sibling.color = Color.RED + currentNode = currentNode.parent + } else { + if (sibling?.left?.color == Color.BLACK) { + sibling.right?.color = Color.BLACK + sibling.color = Color.RED + sibling?.let { leftRotate(it) } + sibling = currentNode.parent?.left + } + sibling?.color = currentNode.parent?.color ?: throw IllegalStateException("Parent color is null") + currentNode.parent?.color = Color.BLACK + sibling?.left?.color = Color.BLACK + currentNode.parent?.let { rightRotate(it) } + currentNode = root + } + } + } + currentNode?.color = Color.BLACK + } + + + private fun leftRotate(node: RBNode) { + val rightChild = node.right ?: throw IllegalStateException("Right child is null") + node.right = rightChild.left + if (rightChild.left != null) { + rightChild.left!!.parent = node + } + rightChild.parent = node.parent + if (node.parent == null) { + root = rightChild + } else if (node == node.parent!!.left) { + node.parent!!.left = rightChild + } else { + node.parent!!.right = rightChild + } + rightChild.left = node + node.parent = rightChild + } + + private fun rightRotate(node: RBNode) { + val leftChild = node.left ?: throw IllegalStateException("Left child is null") + node.left = leftChild.right + if (leftChild.right != null) { + leftChild.right!!.parent = node + } + leftChild.parent = node.parent + if (node.parent == null) { + root = leftChild + } else if (node == node.parent!!.right) { + node.parent!!.right = leftChild + } else { + node.parent!!.left = leftChild + } + leftChild.right = node + node.parent = leftChild + } + + private fun transplant(u: RBNode?, v: RBNode?) { + if (u?.parent == null) { + root = v ?: throw IllegalStateException("Node v is null") + } else if (u == u.parent!!.left) { + u.parent!!.left = v ?: throw IllegalStateException("Node v is null") + } else { + u.parent!!.right = v ?: throw IllegalStateException("Node v is null") + } + v.parent = u?.parent + } + + fun saveToFile(filePath: String) { + val serializer = RBTreeSerializer() + serializer.serialize(this, filePath) + } + + companion object { + fun loadFromFile(filePath: String): RBTree<*, *> { + val serializer = RBTreeSerializer() + return serializer.deserialize(filePath) + } + } +} \ No newline at end of file From adac63f78b130e16a2646524db42c4a32c75b596 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 22 Apr 2023 13:05:25 +0300 Subject: [PATCH 078/203] =?UTF-8?q?=D0=94=D0=BB=D1=8F=20=D0=B1=D0=B4=20?= =?UTF-8?q?=D0=B1=D0=B8=D0=BD=D0=B0=D1=80=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B2=D0=B0=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA?= =?UTF-8?q?=D0=B0=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BE=D1=82?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D0=BF=D0=B0=D0=BA?= =?UTF-8?q?=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/databases/{ => binTree}/BinTreeBase.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) rename lib/src/main/kotlin/databases/{ => binTree}/BinTreeBase.kt (90%) diff --git a/lib/src/main/kotlin/databases/BinTreeBase.kt b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt similarity index 90% rename from lib/src/main/kotlin/databases/BinTreeBase.kt rename to lib/src/main/kotlin/databases/binTree/BinTreeBase.kt index 43be0d1..68fc088 100644 --- a/lib/src/main/kotlin/databases/BinTreeBase.kt +++ b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt @@ -1,14 +1,15 @@ -package databases +package databases.binTree import nodes.BinaryNode +import trees.BinaryTree import java.io.Closeable import java.sql.DriverManager import java.sql.SQLException data class Node(val binNode: NodeType, val x: Int, val y : Int) -class BinaryBase (path: String): Closeable { +class BinaryBase (dbPath: String): Closeable { - private val connection = DriverManager.getConnection("jdbc:sqlite:$path") + private val connection = DriverManager.getConnection("jdbc:sqlite:$dbPath") ?: throw SQLException("Cannot connect to database") private val createBaseStatement by lazy {connection.prepareStatement("CREATE TABLE if not exists BinaryNodes (x int, y int, key int, value varchar(255));")} private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO BinaryNodes (x, y, key, value) VALUES (?, ?, ?, ?);") } @@ -16,6 +17,10 @@ class BinaryBase (path: String): Closeable { private val removeNodeByKey by lazy { connection.prepareStatement("DELETE FROM BinaryNodes WHERE key=?;") } fun open() = createBaseStatement.execute() + fun saveBinaryTree(tree: BinaryTree) { +// if (tree.root)ы + } + fun removeNode(key : Int) { removeNodeByKey.setInt(1, key) removeNodeByKey.execute() From b145bcd04af4348e9d15bebcf34fed6303c447a6 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 22 Apr 2023 13:16:32 +0300 Subject: [PATCH 079/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20(WrappedBinNode?= =?UTF-8?q?)=20=D0=B4=D0=BB=D1=8F=20=D1=85=D1=80=D0=B0=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BD=D0=BE=D0=B4=20=D1=81=D0=BE=D0=B2=D0=BC?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=BD=D0=BE=20=D1=81=20=D0=B8=D1=85=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BE=D1=80=D0=B4=D0=B8=D0=BD=D0=B0=D1=82=D0=B0=D0=BC?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt new file mode 100644 index 0000000..4d30430 --- /dev/null +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt @@ -0,0 +1,9 @@ +package databases.binTree + +import nodes.AbstractNode +import nodes.BinaryNode + +class WrappedBinNode, V>(key: K, value: V?, var x: Double = 0.0, var y: Double = 0.0) : + AbstractNode>(key, value) { + +} \ No newline at end of file From f094e2f50aca181210e0f445610eb86835714e44 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 22 Apr 2023 13:21:35 +0300 Subject: [PATCH 080/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20WrappedBinTree,?= =?UTF-8?q?=20=D0=BD=D0=B5=D0=BE=D0=B1=D1=85=D0=BE=D0=B4=D0=B8=D0=BC=D1=8B?= =?UTF-8?q?=D0=B9=20=D0=B4=D0=BB=D1=8F=20=D1=81=D0=BE=D1=85=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B1=D0=B8=D0=BD=D0=B0=D1=80?= =?UTF-8?q?=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=B0?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA=D0=B0=20=D0=B2=20=D0=B1=D0=B0?= =?UTF-8?q?=D0=B7=D1=83=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../databases/binTree/WrappedBinNode.kt | 2 +- .../databases/binTree/WrappedBinTree.kt | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt index 4d30430..c58a21f 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt @@ -4,6 +4,6 @@ import nodes.AbstractNode import nodes.BinaryNode class WrappedBinNode, V>(key: K, value: V?, var x: Double = 0.0, var y: Double = 0.0) : - AbstractNode>(key, value) { + AbstractNode>(key, value) { } \ No newline at end of file diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt new file mode 100644 index 0000000..b9899d9 --- /dev/null +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -0,0 +1,20 @@ +package databases.binTree + +import trees.AbstractTree +import trees.BinaryTree + +data class Node(val binNode: NodeType, val x: Double, val y: Double) + +class WrappedBinTree, V> : AbstractTree>() { + override fun search(key: K): WrappedBinNode? { + TODO("Not yet implemented") + } + + override fun add(key: K, value: V?) { + TODO("Not yet implemented") + } + + override fun remove(key: K) { + TODO("Not yet implemented") + } +} \ No newline at end of file From 08fecd5b47a46bceee50de7f5dde689f13869247 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 22 Apr 2023 13:58:09 +0300 Subject: [PATCH 081/203] =?UTF-8?q?=D0=9A=D0=BB=D0=B0=D1=81=D1=81=20Wrappe?= =?UTF-8?q?dBinTree=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=B7=D0=B2=D0=BE=D0=BB=D1=8F=D0=B5=D1=82=20=D1=85=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=82=D1=8C=20=D0=B1=D0=B8=D0=BD=D0=B0=D1=80=D0=BD?= =?UTF-8?q?=D1=8B=D0=B5=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D1=8C=D1=8F=20?= =?UTF-8?q?=D1=81=D0=BE=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BD=D0=BE=20=D1=81?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BE=D1=80=D0=B4=D0=B8=D0=BD=D0=B0=D1=82=D0=B0?= =?UTF-8?q?=D0=BC=D0=B8=20=D0=BA=D0=B0=D0=B6=D0=B4=D0=BE=D0=B9=20=D0=BD?= =?UTF-8?q?=D0=BE=D0=B4=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/databases/binTree/BinTreeBase.kt | 110 +++++++++--------- .../databases/binTree/WrappedBinTree.kt | 32 +++-- 2 files changed, 79 insertions(+), 63 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt index 68fc088..2ba2a54 100644 --- a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt +++ b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt @@ -1,56 +1,54 @@ -package databases.binTree - -import nodes.BinaryNode -import trees.BinaryTree -import java.io.Closeable -import java.sql.DriverManager -import java.sql.SQLException - -data class Node(val binNode: NodeType, val x: Int, val y : Int) -class BinaryBase (dbPath: String): Closeable { - - private val connection = DriverManager.getConnection("jdbc:sqlite:$dbPath") - ?: throw SQLException("Cannot connect to database") - private val createBaseStatement by lazy {connection.prepareStatement("CREATE TABLE if not exists BinaryNodes (x int, y int, key int, value varchar(255));")} - private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO BinaryNodes (x, y, key, value) VALUES (?, ?, ?, ?);") } - private val getNodeByKey by lazy { connection.prepareStatement("SELECT x, y, value FROM BinaryNodes WHERE BinaryNodes.key = ?;") } - private val removeNodeByKey by lazy { connection.prepareStatement("DELETE FROM BinaryNodes WHERE key=?;") } - fun open() = createBaseStatement.execute() - - fun saveBinaryTree(tree: BinaryTree) { -// if (tree.root)ы - } - - fun removeNode(key : Int) { - removeNodeByKey.setInt(1, key) - removeNodeByKey.execute() - } - fun addNode(node : Node>) { - if (search(node.binNode.key) != null) - return - - addNodeStatement.setInt(1, node.x) - addNodeStatement.setInt(2, node.y) - addNodeStatement.setInt(3, node.binNode.key) - addNodeStatement.setString(4, node.binNode.value ?: "empty") - - addNodeStatement.execute() - } - fun search(key: Int) : Node>? { - getNodeByKey.setInt(1, key) - val res = getNodeByKey.executeQuery() - if (res.isClosed) - return null - - return Node(BinaryNode(key, res.getString("value")), res.getInt("x"), res.getInt("y")) - } - override fun close() { - createBaseStatement.close() - addNodeStatement.close() - getNodeByKey.close() - removeNodeByKey.close() - - connection.close() - } - -} \ No newline at end of file +//package databases.binTree +// +//import nodes.BinaryNode +//import trees.BinaryTree +//import java.io.Closeable +//import java.sql.DriverManager +//import java.sql.SQLException +//class BinaryBase (dbPath: String): Closeable { +// +// private val connection = DriverManager.getConnection("jdbc:sqlite:$dbPath") +// ?: throw SQLException("Cannot connect to database") +// private val createBaseStatement by lazy {connection.prepareStatement("CREATE TABLE if not exists BinaryNodes (x int, y int, key int, value varchar(255));")} +// private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO BinaryNodes (x, y, key, value) VALUES (?, ?, ?, ?);") } +// private val getNodeByKey by lazy { connection.prepareStatement("SELECT x, y, value FROM BinaryNodes WHERE BinaryNodes.key = ?;") } +// private val removeNodeByKey by lazy { connection.prepareStatement("DELETE FROM BinaryNodes WHERE key=?;") } +// fun open() = createBaseStatement.execute() +// +// fun saveBinaryTree(tree: BinaryTree) { +//// if (tree.root)ы +// } +// +// fun removeNode(key : Int) { +// removeNodeByKey.setInt(1, key) +// removeNodeByKey.execute() +// } +// fun addNode(node : Node>) { +// if (search(node.binNode.key) != null) +// return +// +// addNodeStatement.setInt(1, node.x) +// addNodeStatement.setInt(2, node.y) +// addNodeStatement.setInt(3, node.binNode.key) +// addNodeStatement.setString(4, node.binNode.value ?: "empty") +// +// addNodeStatement.execute() +// } +// fun search(key: Int) : Node>? { +// getNodeByKey.setInt(1, key) +// val res = getNodeByKey.executeQuery() +// if (res.isClosed) +// return null +// +// return Node(BinaryNode(key, res.getString("value")), res.getInt("x"), res.getInt("y")) +// } +// override fun close() { +// createBaseStatement.close() +// addNodeStatement.close() +// getNodeByKey.close() +// removeNodeByKey.close() +// +// connection.close() +// } +// +//} \ No newline at end of file diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index b9899d9..b4d3ce4 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -1,20 +1,38 @@ package databases.binTree +import exceptions.NullNodeException +import nodes.BinaryNode import trees.AbstractTree import trees.BinaryTree data class Node(val binNode: NodeType, val x: Double, val y: Double) -class WrappedBinTree, V> : AbstractTree>() { - override fun search(key: K): WrappedBinNode? { - TODO("Not yet implemented") +class WrappedBinTree, V>() { + + private var wrappedNodesList : MutableList> = mutableListOf() + + var tree : BinaryTree + get() = getTree() + set(value) = addTree(value) + private fun addTree(tree: BinaryTree) { + if (tree.root == null) + return + + addNode(tree.root ?: throw NullNodeException()) } - override fun add(key: K, value: V?) { - TODO("Not yet implemented") + private fun getTree() : BinaryTree { + val resBinTree = BinaryTree() + for (item in wrappedNodesList) + resBinTree.add(item.key, item.value) + return resBinTree } - override fun remove(key: K) { - TODO("Not yet implemented") + private fun addNode(node: BinaryNode) { + this.wrappedNodesList.add(WrappedBinNode(node.key, node.value)) + if (node.left != null) + addNode(node.left ?: throw NullNodeException()) + if (node.right != null) + addNode(node.right ?: throw NullNodeException()) } } \ No newline at end of file From 93c96dd3c7bec16a24d5649abd6e61d37dc9a1c0 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 22 Apr 2023 14:31:44 +0300 Subject: [PATCH 082/203] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20WrappedBi?= =?UTF-8?q?nTree,=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D1=8F=D1=8E=D1=89?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=81=D0=BE=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D0=B8=D0=B5=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B2=20=D0=BD=D0=B5?= =?UTF-8?q?=D0=B3=D0=BE=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=B0=20=D1=81=20?= =?UTF-8?q?=D0=B2=D1=8B=D0=B3=D1=80=D1=83=D0=B6=D0=B5=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../databases/binTree/WrappedBinTree.kt | 7 +- .../databases/binTree/WrappedBinTreeTest.kt | 97 +++++++++++++++++++ lib/src/test/kotlin/trees/BinaryTreeTest.kt | 4 +- 3 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index b4d3ce4..e0880d4 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -11,17 +11,14 @@ class WrappedBinTree, V>() { private var wrappedNodesList : MutableList> = mutableListOf() - var tree : BinaryTree - get() = getTree() - set(value) = addTree(value) - private fun addTree(tree: BinaryTree) { + fun addTree(tree: BinaryTree) { if (tree.root == null) return addNode(tree.root ?: throw NullNodeException()) } - private fun getTree() : BinaryTree { + fun getTree() : BinaryTree { val resBinTree = BinaryTree() for (item in wrappedNodesList) resBinTree.add(item.key, item.value) diff --git a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt new file mode 100644 index 0000000..3bd1745 --- /dev/null +++ b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt @@ -0,0 +1,97 @@ +package databases.binTree + +import org.junit.jupiter.api.Assertions.* +import trees.BinaryTree +import nodes.BinaryNode +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import kotlin.random.Random +import kotlin.test.BeforeTest + +class WrappedBinTreeTest { + + private lateinit var binTree: BinaryTree + private lateinit var wrappedTree: WrappedBinTree + + @BeforeTest + fun init() { + binTree = BinaryTree() + wrappedTree = WrappedBinTree() + } + + @Nested + inner class `Equivalence check` { + @Test + @DisplayName("Existing elements search") + fun `Root equivalence check`() { + binTree.add(100, "root") + wrappedTree.addTree(binTree) + + assertTrue(binTree.equalCheck(wrappedTree.getTree())) + } + + @Test + @DisplayName("Tree with one subtree equivalence check") + fun `Tree with one subtree equivalence check`() { + binTree.add(100, "root") + binTree.add(120, "a") + binTree.add(130, "b") + binTree.add(140, "c") + binTree.add(125, "d") + binTree.add(160, "e") + wrappedTree.addTree(binTree) + + assertTrue(binTree.equalCheck(wrappedTree.getTree())) + } + + @Test + @DisplayName("Tree with one subtree equivalence check") + fun `Tree with two subtrees equivalence check`() { + binTree.add(100, "root") + binTree.add(150) + binTree.add(160) + binTree.add(110) + binTree.add(50) + binTree.add(-100) + binTree.add(89) + + wrappedTree.addTree(binTree) + + assertTrue(binTree.equalCheck(wrappedTree.getTree())) + } + + @Test + @DisplayName("Random tree equivalence check") + fun `Random tree equivalence check`() { + val list: List = (List(100000) { Random.nextInt(1, 100000) }).distinct().toMutableList() + + for (item in list) + binTree.add(item) + + wrappedTree.addTree(binTree) + + assertTrue(binTree.equalCheck(wrappedTree.getTree())) + + } + } + + /** + * Сравнивает переданные ноды по всем параметрам (рекурсивно обходит детей) + * @return True - ноды полностью совпадают + */ + private fun , V> BinaryNode?.nodesEqualCheck(other: BinaryNode?): Boolean { + return (this == null && other == null) || + ((other?.key == this?.key) && + (other?.value == this?.value) && + (this?.left.nodesEqualCheck(other?.left)) && + (this?.right.nodesEqualCheck(other?.right))) + } + + /** + * Сравнивает деревья между собой + * @return True - деревья полностью схожи (включая расположение детей) + */ + fun , V> BinaryTree.equalCheck(other: BinaryTree): Boolean = + this.root.nodesEqualCheck(other.root) +} \ No newline at end of file diff --git a/lib/src/test/kotlin/trees/BinaryTreeTest.kt b/lib/src/test/kotlin/trees/BinaryTreeTest.kt index 209a692..bfcb229 100644 --- a/lib/src/test/kotlin/trees/BinaryTreeTest.kt +++ b/lib/src/test/kotlin/trees/BinaryTreeTest.kt @@ -190,7 +190,7 @@ class BinaryTreeTest { * Проверка на то, что левый узел меньше, а правый больше * @return True - узлы размещены как положено * */ - fun , V> BinaryNode.childrenCheck(): Boolean = + private fun , V> BinaryNode.childrenCheck(): Boolean = (this.left == null || this.left?.compareTo(this) == -1) && (this.right == null || this.right?.compareTo(this) == 1) @@ -210,7 +210,7 @@ class BinaryTreeTest { * Проверяет ноду на существование * @return True - найден узел с совпадающим ключом и значением */ - fun , V> BinaryTree.nodeExists(key: K, value: V?): Boolean { + private fun , V> BinaryTree.nodeExists(key: K, value: V?): Boolean { if (this.root == null) return false val searchRes = this.root?.recursiveSearch(key) From b51f99ad82a8bed378c208e1599d02990d35c203 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 22 Apr 2023 14:39:27 +0300 Subject: [PATCH 083/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=8C=20=D0=BC=D0=B5=D0=BD=D1=8F=D1=82=D1=8C?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BE=D1=80=D0=B4=D0=B8=D0=BD=D0=B0=D1=82=D1=8B?= =?UTF-8?q?=20=D1=83=20=D0=BD=D0=BE=D0=B4=20=D0=B2=20WrappedBinTree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../databases/binTree/WrappedBinTree.kt | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index e0880d4..a1ff2d3 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -1,5 +1,6 @@ package databases.binTree +import exceptions.NodeNotFoundException import exceptions.NullNodeException import nodes.BinaryNode import trees.AbstractTree @@ -9,8 +10,7 @@ data class Node(val binNode: NodeType, val x: Double, val y: Double) class WrappedBinTree, V>() { - private var wrappedNodesList : MutableList> = mutableListOf() - + private var wrappedNodesList: MutableList> = mutableListOf() fun addTree(tree: BinaryTree) { if (tree.root == null) return @@ -18,13 +18,35 @@ class WrappedBinTree, V>() { addNode(tree.root ?: throw NullNodeException()) } - fun getTree() : BinaryTree { + fun getTree(): BinaryTree { val resBinTree = BinaryTree() for (item in wrappedNodesList) resBinTree.add(item.key, item.value) return resBinTree } + fun setCoordinate(key: K, x: Double, y: Double) { + for (item in wrappedNodesList) { + if (item.key == key) { + item.x = x + item.y = y + return + } + } + + // Если ключ не совпадает ни с одной вершиной из имеющихся + throw NodeNotFoundException() + } + + fun getWrappedNode(key: K): WrappedBinNode { + for (item in wrappedNodesList) + if (item.key == key) + return item + + // Если ключ не совпадает ни с одной вершиной из имеющихся + throw NodeNotFoundException() + } + private fun addNode(node: BinaryNode) { this.wrappedNodesList.add(WrappedBinNode(node.key, node.value)) if (node.left != null) From 93f2b883df637cc7e9b9909ab1da700e1c2f8204 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 22 Apr 2023 14:47:19 +0300 Subject: [PATCH 084/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BF=D0=BE=D0=BA=D1=80=D1=8B=D1=82=D0=B8=D0=B5=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=B0=D0=BC=D0=B8=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=BE=D0=B2=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BA=D0=BE=D0=BE?= =?UTF-8?q?=D1=80=D0=B4=D0=B8=D0=BD=D0=B0=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../databases/binTree/WrappedBinTree.kt | 1 - .../databases/binTree/WrappedBinTreeTest.kt | 29 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index a1ff2d3..6b8a2b3 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -37,7 +37,6 @@ class WrappedBinTree, V>() { // Если ключ не совпадает ни с одной вершиной из имеющихся throw NodeNotFoundException() } - fun getWrappedNode(key: K): WrappedBinNode { for (item in wrappedNodesList) if (item.key == key) diff --git a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt index 3bd1745..05273ea 100644 --- a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt +++ b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt @@ -1,11 +1,13 @@ package databases.binTree +import exceptions.NodeNotFoundException import org.junit.jupiter.api.Assertions.* import trees.BinaryTree import nodes.BinaryNode import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test +import org.junit.jupiter.api.function.Executable import kotlin.random.Random import kotlin.test.BeforeTest @@ -76,6 +78,33 @@ class WrappedBinTreeTest { } } + @Nested + inner class `Coordinates check` { + @Test + @DisplayName("Coordinate change check") + fun `Coordinate change check`() { + binTree.add(100, "root") + + wrappedTree.addTree(binTree) + wrappedTree.setCoordinate(100, 10.0, -10.0) + + assertAll("elements", + Executable { assertTrue(wrappedTree.getWrappedNode(100).x == 10.0)}, + Executable { assertTrue(wrappedTree.getWrappedNode(100).y == -10.0)} + ) + } + + @Test + @DisplayName("Coordinate change check") + fun `Non-existent coordinate change`() { + binTree.add(100, "root") + + wrappedTree.addTree(binTree) + + assertThrows(NodeNotFoundException::class.java) { wrappedTree.setCoordinate(150, 10.0, -10.0) } + } + + } /** * Сравнивает переданные ноды по всем параметрам (рекурсивно обходит детей) * @return True - ноды полностью совпадают From 417e50a68969350c8895f181ae690354aafa7cd4 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 22 Apr 2023 14:50:04 +0300 Subject: [PATCH 085/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=20=D0=B4=D0=BB=D1=8F=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8=20=D0=BA=D0=BE=D1=80?= =?UTF-8?q?=D1=80=D0=B5=D0=BA=D1=82=D0=BD=D0=BE=D1=81=D1=82=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B2=D0=B0=20=D1=81=20=D0=BD=D1=83=D0=BB?= =?UTF-8?q?=D0=B5=D0=B2=D1=8B=D0=BC=20=D0=BA=D0=BE=D1=80=D0=BD=D0=B5=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/kotlin/databases/binTree/WrappedBinTreeTest.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt index 05273ea..349ad4c 100644 --- a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt +++ b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt @@ -76,6 +76,15 @@ class WrappedBinTreeTest { assertTrue(binTree.equalCheck(wrappedTree.getTree())) } + + @Test + @DisplayName("Null-root tree equivalence check") + fun `Null-root tree equivalence check`() { + wrappedTree.addTree(binTree) + + assertTrue(binTree.equalCheck(wrappedTree.getTree())) + + } } @Nested From ab50d0eabd7318ecdee0f695d483f333f186a629 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 22 Apr 2023 20:18:19 +0300 Subject: [PATCH 086/203] =?UTF-8?q?=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=B0=20WrappedBinTree?= =?UTF-8?q?=20=D0=BD=D0=B5=D0=BE=D0=B1=D1=85=D0=BE=D0=B4=D0=B8=D0=BC=D0=BE?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=D0=B0=D1=82=D1=8C=20=D0=B5?= =?UTF-8?q?=D0=BC=D1=83=20=D0=B1=D0=B8=D0=BD=D0=B0=D1=80=D0=BD=D0=BE=D0=B5?= =?UTF-8?q?=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=BE.=20=D0=92=D0=BE=D1=81?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=B8=D1=82=D1=8C=20=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B2=D0=BE=20=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE?= =?UTF-8?q?=20=D0=BE=D0=B1=D1=80=D0=B0=D1=82=D0=B8=D0=B2=D1=88=D0=B8=D1=81?= =?UTF-8?q?=D1=8C=20=D0=BA=20=D1=81=D0=B2=D0=BE=D0=B9=D1=81=D1=82=D0=B2?= =?UTF-8?q?=D1=83=20binaryTree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../databases/binTree/WrappedBinTree.kt | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index 6b8a2b3..f288521 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -3,27 +3,30 @@ package databases.binTree import exceptions.NodeNotFoundException import exceptions.NullNodeException import nodes.BinaryNode -import trees.AbstractTree import trees.BinaryTree data class Node(val binNode: NodeType, val x: Double, val y: Double) -class WrappedBinTree, V>() { +class WrappedBinTree, V>(tree: BinaryTree) { - private var wrappedNodesList: MutableList> = mutableListOf() - fun addTree(tree: BinaryTree) { - if (tree.root == null) - return - - addNode(tree.root ?: throw NullNodeException()) + // Добавление бинарного деерва + init { + addNode(tree.root) } - fun getTree(): BinaryTree { - val resBinTree = BinaryTree() - for (item in wrappedNodesList) - resBinTree.add(item.key, item.value) - return resBinTree - } + // Список с расширенными нодами + private var wrappedNodesList: MutableList> = mutableListOf() + + /** + * Позволяет получить бинарное дерево + */ + val binaryTree: BinaryTree + get() { + val resBinTree = BinaryTree() + for (item in wrappedNodesList) + resBinTree.add(item.key, item.value) + return resBinTree + } fun setCoordinate(key: K, x: Double, y: Double) { for (item in wrappedNodesList) { @@ -37,6 +40,7 @@ class WrappedBinTree, V>() { // Если ключ не совпадает ни с одной вершиной из имеющихся throw NodeNotFoundException() } + fun getWrappedNode(key: K): WrappedBinNode { for (item in wrappedNodesList) if (item.key == key) @@ -46,11 +50,14 @@ class WrappedBinTree, V>() { throw NodeNotFoundException() } - private fun addNode(node: BinaryNode) { + private fun addNode(node: BinaryNode?) { + if (node == null) + return this.wrappedNodesList.add(WrappedBinNode(node.key, node.value)) if (node.left != null) addNode(node.left ?: throw NullNodeException()) if (node.right != null) addNode(node.right ?: throw NullNodeException()) } + } \ No newline at end of file From 8d3717f342f7ade2c37f64df750f30acd6ae824d Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 22 Apr 2023 20:34:39 +0300 Subject: [PATCH 087/203] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B8=20=D0=B2=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=B0=D1=85=20=D0=B8=D0=B7-=D0=B7?= =?UTF-8?q?=D0=B0=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9?= =?UTF-8?q?=20WrappedBinTree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../databases/binTree/WrappedBinTree.kt | 20 +++++++------- .../databases/binTree/WrappedBinTreeTest.kt | 26 +++++++++---------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index f288521..7c603f5 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -9,18 +9,20 @@ data class Node(val binNode: NodeType, val x: Double, val y: Double) class WrappedBinTree, V>(tree: BinaryTree) { - // Добавление бинарного деерва - init { - addNode(tree.root) - } - // Список с расширенными нодами private var wrappedNodesList: MutableList> = mutableListOf() + // Добавление бинарного дерева + init { + + if (tree.root != null) + addNode(tree.root ?: throw NullNodeException()) + } + /** - * Позволяет получить бинарное дерево + * Позволяет получить сохранённое в классе бинарное дерево */ - val binaryTree: BinaryTree + val binaryTree: BinaryTree get() { val resBinTree = BinaryTree() for (item in wrappedNodesList) @@ -50,9 +52,7 @@ class WrappedBinTree, V>(tree: BinaryTree) { throw NodeNotFoundException() } - private fun addNode(node: BinaryNode?) { - if (node == null) - return + private fun addNode(node: BinaryNode) { this.wrappedNodesList.add(WrappedBinNode(node.key, node.value)) if (node.left != null) addNode(node.left ?: throw NullNodeException()) diff --git a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt index 349ad4c..d4cf0e9 100644 --- a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt +++ b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt @@ -19,7 +19,6 @@ class WrappedBinTreeTest { @BeforeTest fun init() { binTree = BinaryTree() - wrappedTree = WrappedBinTree() } @Nested @@ -28,9 +27,9 @@ class WrappedBinTreeTest { @DisplayName("Existing elements search") fun `Root equivalence check`() { binTree.add(100, "root") - wrappedTree.addTree(binTree) + wrappedTree = WrappedBinTree(binTree) - assertTrue(binTree.equalCheck(wrappedTree.getTree())) + assertTrue(binTree.equalCheck(wrappedTree.binaryTree)) } @Test @@ -42,9 +41,9 @@ class WrappedBinTreeTest { binTree.add(140, "c") binTree.add(125, "d") binTree.add(160, "e") - wrappedTree.addTree(binTree) + wrappedTree = WrappedBinTree(binTree) - assertTrue(binTree.equalCheck(wrappedTree.getTree())) + assertTrue(binTree.equalCheck(wrappedTree.binaryTree)) } @Test @@ -58,9 +57,9 @@ class WrappedBinTreeTest { binTree.add(-100) binTree.add(89) - wrappedTree.addTree(binTree) + wrappedTree = WrappedBinTree(binTree) - assertTrue(binTree.equalCheck(wrappedTree.getTree())) + assertTrue(binTree.equalCheck(wrappedTree.binaryTree)) } @Test @@ -71,19 +70,18 @@ class WrappedBinTreeTest { for (item in list) binTree.add(item) - wrappedTree.addTree(binTree) + wrappedTree = WrappedBinTree(binTree) - assertTrue(binTree.equalCheck(wrappedTree.getTree())) + assertTrue(binTree.equalCheck(wrappedTree.binaryTree)) } @Test @DisplayName("Null-root tree equivalence check") fun `Null-root tree equivalence check`() { - wrappedTree.addTree(binTree) - - assertTrue(binTree.equalCheck(wrappedTree.getTree())) + wrappedTree = WrappedBinTree(binTree) + assertTrue(binTree.equalCheck(wrappedTree.binaryTree)) } } @@ -94,7 +92,7 @@ class WrappedBinTreeTest { fun `Coordinate change check`() { binTree.add(100, "root") - wrappedTree.addTree(binTree) + wrappedTree = WrappedBinTree(binTree) wrappedTree.setCoordinate(100, 10.0, -10.0) assertAll("elements", @@ -108,7 +106,7 @@ class WrappedBinTreeTest { fun `Non-existent coordinate change`() { binTree.add(100, "root") - wrappedTree.addTree(binTree) + wrappedTree = WrappedBinTree(binTree) assertThrows(NodeNotFoundException::class.java) { wrappedTree.setCoordinate(150, 10.0, -10.0) } } From 73036ffc58ec74a54b775b2d3f474d92fe44d55b Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 22 Apr 2023 20:35:21 +0300 Subject: [PATCH 088/203] =?UTF-8?q?=D0=A3=D0=B4=D0=B0=D0=BB=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D1=83=D0=B6=D0=BD=D1=8B=D0=B9=20=D1=82=D0=B5?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D1=8C=20=D0=B4=D0=B0=D1=82=D0=B0=20=D0=BA?= =?UTF-8?q?=D0=BB=D0=B0=D1=81=D1=81=20Node?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index 7c603f5..fe7ca84 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -4,9 +4,6 @@ import exceptions.NodeNotFoundException import exceptions.NullNodeException import nodes.BinaryNode import trees.BinaryTree - -data class Node(val binNode: NodeType, val x: Double, val y: Double) - class WrappedBinTree, V>(tree: BinaryTree) { // Список с расширенными нодами From 1ed1cd87c56684784aa148e9488d458511666d8f Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Sun, 23 Apr 2023 00:06:51 +0300 Subject: [PATCH 089/203] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20imp?= =?UTF-8?q?ort=20=D0=B8=20package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/RBTNode.kt | 4 +++- lib/src/main/kotlin/trees/RBTree.kt | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/src/main/kotlin/nodes/RBTNode.kt b/lib/src/main/kotlin/nodes/RBTNode.kt index 2fb596d..a6ca369 100644 --- a/lib/src/main/kotlin/nodes/RBTNode.kt +++ b/lib/src/main/kotlin/nodes/RBTNode.kt @@ -1,4 +1,6 @@ -package nodes +package RBnode + +import nodes.AbstractNode class RBNode, V>(override var key: K, override var value: V?) : AbstractNode>() { diff --git a/lib/src/main/kotlin/trees/RBTree.kt b/lib/src/main/kotlin/trees/RBTree.kt index 554823a..46e73e0 100644 --- a/lib/src/main/kotlin/trees/RBTree.kt +++ b/lib/src/main/kotlin/trees/RBTree.kt @@ -1,7 +1,7 @@ package trees -import nodes.Color -import nodes.RBNode +import RBnode.Color +import RBnode.RBNode import database.RBT.RBTreeSerializer class RBTree, V> : AbstractTree>() { From ff5f34093cd946fd8aae536c4fe9aa857322e5a3 Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Sun, 23 Apr 2023 01:15:23 +0300 Subject: [PATCH 090/203] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D1=81=D0=B8=D0=BD=D1=82=D0=B0=D0=BA=D1=81=D0=B8?= =?UTF-8?q?=D1=87=D0=B5=D1=81=D0=BA=D1=83=D1=8E=20=D0=BE=D1=88=D0=B8=D0=B1?= =?UTF-8?q?=D0=BA=D1=83=20gnore=20->=20ignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/gradle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index be39008..7fcb440 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -1,7 +1,7 @@ name: Gradle Build&Test on: push: - branches-gnore: + branches-ignore: - main pull_request: branches: From 18ba24ecef3267082f1bd3c6e324f7cadd157c17 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 23 Apr 2023 01:15:26 +0300 Subject: [PATCH 091/203] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BE=D0=BF=D0=B5=D1=87=D0=B0=D1=82=D0=BA=D1=83?= =?UTF-8?q?=20=D0=B2=20workflow=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/gradle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index be39008..7fcb440 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -1,7 +1,7 @@ name: Gradle Build&Test on: push: - branches-gnore: + branches-ignore: - main pull_request: branches: From aa2653a1a3523b0f68d0fd9a06560bd45cd0a4a0 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 23 Apr 2023 01:19:27 +0300 Subject: [PATCH 092/203] =?UTF-8?q?WrappedBinNode=20=D1=82=D0=B5=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D1=8C=20=D0=BF=D1=80=D0=BE=D1=81=D1=82=D0=BE=20?= =?UTF-8?q?=D0=B4=D0=B0=D1=82=D0=B0=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81,=20?= =?UTF-8?q?=D0=BD=D0=B5=D1=82=20=D0=BD=D0=B8=D0=BA=D0=B0=D0=BA=D0=B8=D1=85?= =?UTF-8?q?=20=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D1=85=20=D1=81=D0=B2=D0=BE?= =?UTF-8?q?=D0=B9=D1=81=D1=82=D0=B2=20=D0=B8=20=D0=BC=D0=B5=D1=82=D0=BE?= =?UTF-8?q?=D0=B4=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt index c58a21f..f2701f4 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt @@ -1,9 +1,2 @@ package databases.binTree - -import nodes.AbstractNode -import nodes.BinaryNode - -class WrappedBinNode, V>(key: K, value: V?, var x: Double = 0.0, var y: Double = 0.0) : - AbstractNode>(key, value) { - -} \ No newline at end of file +data class WrappedBinNode, V>(var key: K, var value: V?, var x: Double = 0.0, var y: Double = 0.0) \ No newline at end of file From 17a807ff4bf99f48bb538b133eb0c83cc690efaf Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 23 Apr 2023 01:23:52 +0300 Subject: [PATCH 093/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=B2=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BF=D1=83=D1=81=D1=82=D0=BE=D0=B9=20WrappedBinTree,?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B8=D0=BC=D0=B5=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BB=20=D0=BD=D0=B5=D0=BA=D0=BE=D1=82=D0=BE=D1=80=D1=8B?= =?UTF-8?q?=D0=B5=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/databases/binTree/WrappedBinTree.kt | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index fe7ca84..22ab1d1 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -4,14 +4,13 @@ import exceptions.NodeNotFoundException import exceptions.NullNodeException import nodes.BinaryNode import trees.BinaryTree -class WrappedBinTree, V>(tree: BinaryTree) { +class WrappedBinTree, V>() { // Список с расширенными нодами private var wrappedNodesList: MutableList> = mutableListOf() // Добавление бинарного дерева - init { - + constructor(tree : BinaryTree) : this() { if (tree.root != null) addNode(tree.root ?: throw NullNodeException()) } @@ -19,8 +18,7 @@ class WrappedBinTree, V>(tree: BinaryTree) { /** * Позволяет получить сохранённое в классе бинарное дерево */ - val binaryTree: BinaryTree - get() { + fun getBinaryTree(): BinaryTree { val resBinTree = BinaryTree() for (item in wrappedNodesList) resBinTree.add(item.key, item.value) @@ -40,14 +38,7 @@ class WrappedBinTree, V>(tree: BinaryTree) { throw NodeNotFoundException() } - fun getWrappedNode(key: K): WrappedBinNode { - for (item in wrappedNodesList) - if (item.key == key) - return item - - // Если ключ не совпадает ни с одной вершиной из имеющихся - throw NodeNotFoundException() - } + fun getWrappedNodesArray(key: K): Array> = wrappedNodesList.toTypedArray() private fun addNode(node: BinaryNode) { this.wrappedNodesList.add(WrappedBinNode(node.key, node.value)) From 1de406709f3ba5b7ccc1da3f142c51444f5a2c97 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 23 Apr 2023 01:31:50 +0300 Subject: [PATCH 094/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20add=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BD=D0=BE=D0=B4=D1=8B=20=D0=B2=20=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B2=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../databases/binTree/WrappedBinTree.kt | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index 22ab1d1..a3c99da 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -4,26 +4,46 @@ import exceptions.NodeNotFoundException import exceptions.NullNodeException import nodes.BinaryNode import trees.BinaryTree + class WrappedBinTree, V>() { // Список с расширенными нодами private var wrappedNodesList: MutableList> = mutableListOf() // Добавление бинарного дерева - constructor(tree : BinaryTree) : this() { + constructor(tree: BinaryTree) : this() { if (tree.root != null) - addNode(tree.root ?: throw NullNodeException()) + addNodeToWrappedList(tree.root ?: throw NullNodeException()) } /** * Позволяет получить сохранённое в классе бинарное дерево */ fun getBinaryTree(): BinaryTree { - val resBinTree = BinaryTree() - for (item in wrappedNodesList) - resBinTree.add(item.key, item.value) - return resBinTree - } + val resBinTree = BinaryTree() + for (item in wrappedNodesList) + resBinTree.add(item.key, item.value) + return resBinTree + } + + /** + * Позволяет добавить новую ноду в дерево + */ + fun add(key: K, value: V?) { + val newTree = getBinaryTree() + newTree.add(key, value) + wrappedNodesList.clear() + + newTree.root?.let { addNodeToWrappedList(it) } + } + + fun add(node: BinaryNode) = add(node.key, node.value) + fun add(node: WrappedBinNode) { + add(node.key, node.value) + setCoordinate(node.key, node.x, node.y) + } + + fun getWrappedNodesArray(key: K): Array> = wrappedNodesList.toTypedArray() fun setCoordinate(key: K, x: Double, y: Double) { for (item in wrappedNodesList) { @@ -38,14 +58,12 @@ class WrappedBinTree, V>() { throw NodeNotFoundException() } - fun getWrappedNodesArray(key: K): Array> = wrappedNodesList.toTypedArray() - - private fun addNode(node: BinaryNode) { + private fun addNodeToWrappedList(node: BinaryNode) { this.wrappedNodesList.add(WrappedBinNode(node.key, node.value)) if (node.left != null) - addNode(node.left ?: throw NullNodeException()) + addNodeToWrappedList(node.left ?: throw NullNodeException()) if (node.right != null) - addNode(node.right ?: throw NullNodeException()) + addNodeToWrappedList(node.right ?: throw NullNodeException()) } } \ No newline at end of file From 21b6000eddb767206dd4bb05a984aefbd9ed0859 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 23 Apr 2023 01:34:41 +0300 Subject: [PATCH 095/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8E=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=20=D0=BD=D0=BE=D0=B4=D1=8B=20=D0=B8=D0=B7=20=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B2=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index a3c99da..9528b7d 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -32,17 +32,24 @@ class WrappedBinTree, V>() { fun add(key: K, value: V?) { val newTree = getBinaryTree() newTree.add(key, value) + wrappedNodesList.clear() newTree.root?.let { addNodeToWrappedList(it) } } - fun add(node: BinaryNode) = add(node.key, node.value) fun add(node: WrappedBinNode) { add(node.key, node.value) setCoordinate(node.key, node.x, node.y) } + fun remove(key: K) { + val newTree = getBinaryTree() + newTree.remove(key) + wrappedNodesList.clear() + + newTree.root?.let { addNodeToWrappedList(it) } + } fun getWrappedNodesArray(key: K): Array> = wrappedNodesList.toTypedArray() fun setCoordinate(key: K, x: Double, y: Double) { From 8beb7158a7695f2226dcdb57c21fac5a715beee5 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 23 Apr 2023 01:37:11 +0300 Subject: [PATCH 096/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8E=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=B8=D1=81=D0=BA=D0=B0=20=D0=BD=D0=BE=D0=B4=D1=8B=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D0=BA=D0=BB=D1=8E=D1=87=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index 9528b7d..9246437 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -50,6 +50,12 @@ class WrappedBinTree, V>() { newTree.root?.let { addNodeToWrappedList(it) } } + fun search(key: K): WrappedBinNode { + for (item in wrappedNodesList) + if (item.key == key) + return item + throw NodeNotFoundException() + } fun getWrappedNodesArray(key: K): Array> = wrappedNodesList.toTypedArray() fun setCoordinate(key: K, x: Double, y: Double) { From 6ce2b24d846396523dd5a7f1278a790a398836bd Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 23 Apr 2023 01:54:07 +0300 Subject: [PATCH 097/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D1=8F=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BD=D0=BE=D0=B4=D1=8B=20=D1=81=20null-value?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index 9246437..2515f4a 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -29,7 +29,7 @@ class WrappedBinTree, V>() { /** * Позволяет добавить новую ноду в дерево */ - fun add(key: K, value: V?) { + fun add(key: K, value: V? = null) { val newTree = getBinaryTree() newTree.add(key, value) @@ -58,7 +58,7 @@ class WrappedBinTree, V>() { } fun getWrappedNodesArray(key: K): Array> = wrappedNodesList.toTypedArray() - fun setCoordinate(key: K, x: Double, y: Double) { + fun setCoordinate(key: K, x: Double = 0.0, y: Double = 0.0) { for (item in wrappedNodesList) { if (item.key == key) { item.x = x From 72f0519c169eb0916b91d1cc7eb6baafe73785ce Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 23 Apr 2023 01:56:39 +0300 Subject: [PATCH 098/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BF=D0=BE=D0=BA=D1=80=D1=8B=D1=82=D0=B8=D0=B5=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=B0=D0=BC=D0=B8=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B9=20search,=20add,?= =?UTF-8?q?=20remove?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../databases/binTree/WrappedBinTreeTest.kt | 101 ++++++++++++++++-- 1 file changed, 94 insertions(+), 7 deletions(-) diff --git a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt index d4cf0e9..ee6ee60 100644 --- a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt +++ b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt @@ -29,7 +29,7 @@ class WrappedBinTreeTest { binTree.add(100, "root") wrappedTree = WrappedBinTree(binTree) - assertTrue(binTree.equalCheck(wrappedTree.binaryTree)) + assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) } @Test @@ -43,7 +43,7 @@ class WrappedBinTreeTest { binTree.add(160, "e") wrappedTree = WrappedBinTree(binTree) - assertTrue(binTree.equalCheck(wrappedTree.binaryTree)) + assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) } @Test @@ -59,7 +59,7 @@ class WrappedBinTreeTest { wrappedTree = WrappedBinTree(binTree) - assertTrue(binTree.equalCheck(wrappedTree.binaryTree)) + assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) } @Test @@ -72,7 +72,7 @@ class WrappedBinTreeTest { wrappedTree = WrappedBinTree(binTree) - assertTrue(binTree.equalCheck(wrappedTree.binaryTree)) + assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) } @@ -81,7 +81,7 @@ class WrappedBinTreeTest { fun `Null-root tree equivalence check`() { wrappedTree = WrappedBinTree(binTree) - assertTrue(binTree.equalCheck(wrappedTree.binaryTree)) + assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) } } @@ -96,8 +96,8 @@ class WrappedBinTreeTest { wrappedTree.setCoordinate(100, 10.0, -10.0) assertAll("elements", - Executable { assertTrue(wrappedTree.getWrappedNode(100).x == 10.0)}, - Executable { assertTrue(wrappedTree.getWrappedNode(100).y == -10.0)} + Executable { assertTrue(wrappedTree.search(100).x == 10.0)}, + Executable { assertTrue(wrappedTree.search(100).y == -10.0)} ) } @@ -112,6 +112,93 @@ class WrappedBinTreeTest { } } + + @Nested + inner class `Add test` { + @Test + @DisplayName("One element add test") + fun `One element add test`() { + wrappedTree = WrappedBinTree() + + binTree.add(100) + wrappedTree.add(100) + + assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) + } + + @Test + @DisplayName("Random tree add check") + fun `Random tree add check`() { + wrappedTree = WrappedBinTree() + + val list: List = (List(100) { Random.nextInt(1, 100000) }).distinct().toMutableList() + + for (item in list) { + wrappedTree.add(item) + binTree.add(item) + } + + assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) + } + } + + @Nested + inner class `Remove test` { + @Test + @DisplayName("One element add test") + fun `One element remove test`() { + binTree.add(100) + wrappedTree = WrappedBinTree(binTree) + binTree.remove(100) + wrappedTree.remove(100) + + assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) + } + + @Test + @DisplayName("Random tree add check") + fun `Random tree remove check`() { + binTree.add(100) + binTree.add(200) + binTree.add(150) + binTree.add(10) + binTree.add(220) + binTree.add(-100) + binTree.add(89) + binTree.add(-50) + binTree.add(-34) + + wrappedTree = WrappedBinTree(binTree) + + wrappedTree.remove(100) + binTree.remove(100) + + assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) + } + } + + @Nested + inner class `Search test` { + @Test + @DisplayName("Existent element search") + fun `Existent element search`() { + binTree.add(100) + + wrappedTree = WrappedBinTree(binTree) + wrappedTree.setCoordinate(100, 10.0) + + assertEquals(10.0, wrappedTree.search(100).x) + } + + @Test + @DisplayName("Non-existent element search") + fun `Non-existent element search`() { + wrappedTree = WrappedBinTree() + + assertThrows(NodeNotFoundException::class.java){ wrappedTree.search(100).x} + } + } + /** * Сравнивает переданные ноды по всем параметрам (рекурсивно обходит детей) * @return True - ноды полностью совпадают From 8c20ba31d2e4ca318e9b83c1e39c554bcd416372 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 23 Apr 2023 22:01:39 +0300 Subject: [PATCH 099/203] =?UTF-8?q?=D0=94=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D0=B8=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20(=D0=BF=D0=BE?= =?UTF-8?q?=D0=BA=D1=80=D1=8B=D1=82=D0=B8=D0=B5=20=D0=BD=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=BD=D0=B4=D0=B0=D1=80=D1=82=D0=BD=D1=8B=D1=85=20=D1=81?= =?UTF-8?q?=D0=BB=D1=83=D1=87=D0=B0=D0=B5=D0=B2=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20/=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../databases/binTree/WrappedBinTreeTest.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt index ee6ee60..834cc8f 100644 --- a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt +++ b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt @@ -1,5 +1,6 @@ package databases.binTree +import exceptions.NodeAlreadyExistsException import exceptions.NodeNotFoundException import org.junit.jupiter.api.Assertions.* import trees.BinaryTree @@ -126,6 +127,15 @@ class WrappedBinTreeTest { assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) } + @Test + @DisplayName("One element add test") + fun `Already existent element add test`() { + wrappedTree = WrappedBinTree() + wrappedTree.add(100, "root") + + assertThrows(NodeAlreadyExistsException::class.java) { wrappedTree.add(100, "root") } + } + @Test @DisplayName("Random tree add check") fun `Random tree add check`() { @@ -155,6 +165,14 @@ class WrappedBinTreeTest { assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) } + @Test + @DisplayName("Non-existent element remove test") + fun `Non-existent element remove test`() { + wrappedTree = WrappedBinTree() + + assertThrows(NodeNotFoundException::class.java) {wrappedTree.remove(100)} + } + @Test @DisplayName("Random tree add check") fun `Random tree remove check`() { From 037ee3857c363c45809b3e913355125d8488be72 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 23 Apr 2023 22:06:14 +0300 Subject: [PATCH 100/203] =?UTF-8?q?=D0=9A=D0=BB=D0=B0=D1=81=D1=81=20BinTre?= =?UTF-8?q?eBase=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D1=91=D0=BD=20?= =?UTF-8?q?=D1=81=20=D1=83=D1=87=D1=91=D1=82=D0=BE=D0=BC=20=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=BE=D0=B9=20=D0=B0=D1=80=D1=85=D0=B8=D1=82=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D1=83=D1=80=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/databases/binTree/BinTreeBase.kt | 103 +++++++++--------- 1 file changed, 49 insertions(+), 54 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt index 2ba2a54..5082b5a 100644 --- a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt +++ b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt @@ -1,54 +1,49 @@ -//package databases.binTree -// -//import nodes.BinaryNode -//import trees.BinaryTree -//import java.io.Closeable -//import java.sql.DriverManager -//import java.sql.SQLException -//class BinaryBase (dbPath: String): Closeable { -// -// private val connection = DriverManager.getConnection("jdbc:sqlite:$dbPath") -// ?: throw SQLException("Cannot connect to database") -// private val createBaseStatement by lazy {connection.prepareStatement("CREATE TABLE if not exists BinaryNodes (x int, y int, key int, value varchar(255));")} -// private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO BinaryNodes (x, y, key, value) VALUES (?, ?, ?, ?);") } -// private val getNodeByKey by lazy { connection.prepareStatement("SELECT x, y, value FROM BinaryNodes WHERE BinaryNodes.key = ?;") } -// private val removeNodeByKey by lazy { connection.prepareStatement("DELETE FROM BinaryNodes WHERE key=?;") } -// fun open() = createBaseStatement.execute() -// -// fun saveBinaryTree(tree: BinaryTree) { -//// if (tree.root)ы -// } -// -// fun removeNode(key : Int) { -// removeNodeByKey.setInt(1, key) -// removeNodeByKey.execute() -// } -// fun addNode(node : Node>) { -// if (search(node.binNode.key) != null) -// return -// -// addNodeStatement.setInt(1, node.x) -// addNodeStatement.setInt(2, node.y) -// addNodeStatement.setInt(3, node.binNode.key) -// addNodeStatement.setString(4, node.binNode.value ?: "empty") -// -// addNodeStatement.execute() -// } -// fun search(key: Int) : Node>? { -// getNodeByKey.setInt(1, key) -// val res = getNodeByKey.executeQuery() -// if (res.isClosed) -// return null -// -// return Node(BinaryNode(key, res.getString("value")), res.getInt("x"), res.getInt("y")) -// } -// override fun close() { -// createBaseStatement.close() -// addNodeStatement.close() -// getNodeByKey.close() -// removeNodeByKey.close() -// -// connection.close() -// } -// -//} \ No newline at end of file +package databases.binTree + +import nodes.BinaryNode +import trees.BinaryTree +import java.io.Closeable +import java.sql.DriverManager +import java.sql.SQLException +class BinaryBase (dbPath: String): Closeable { + + private val connection = DriverManager.getConnection("jdbc:sqlite:$dbPath") + ?: throw SQLException("Cannot connect to database") + private val createBaseStatement by lazy {connection.prepareStatement("CREATE TABLE if not exists BinaryNodes (key int, value varchar(255), x double, y double);")} + private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO BinaryNodes (key, value, x, y) VALUES (?, ?, ?, ?);") } + private val getNodeByKey by lazy { connection.prepareStatement("SELECT x, y, value FROM BinaryNodes WHERE BinaryNodes.key = ?;") } + private val removeNodeByKey by lazy { connection.prepareStatement("DELETE FROM BinaryNodes WHERE key=?;") } + fun open() = createBaseStatement.execute() + fun removeNode(key : Int) { + removeNodeByKey.setInt(1, key) + removeNodeByKey.execute() + } + fun addNode(node : WrappedBinNode) { + if (search(node.key) != null) + return + + addNodeStatement.setInt(1, node.key) + addNodeStatement.setString(2, node.value ?: "empty") + addNodeStatement.setDouble(3, node.x) + addNodeStatement.setDouble(4, node.y) + + addNodeStatement.execute() + } + fun search(key: Int) : WrappedBinNode? { + getNodeByKey.setInt(1, key) + val res = getNodeByKey.executeQuery() + if (res.isClosed) + return null + + return WrappedBinNode(key, res.getString("value"), res.getDouble("x"), res.getDouble("y")) + } + override fun close() { + createBaseStatement.close() + addNodeStatement.close() + getNodeByKey.close() + removeNodeByKey.close() + + connection.close() + } + +} \ No newline at end of file From 8e2e7c106d405b62abbbcb47062a2326ffdd9832 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 23 Apr 2023 22:14:09 +0300 Subject: [PATCH 101/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=8C=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D1=8F=D1=82=D1=8C=20=D0=B1=D0=B8=D0=BD=D0=B0=D1=80=D0=BD=D0=BE?= =?UTF-8?q?=D0=B5=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=BE=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=B8=D1=81=D0=BA=D0=B0=20=D0=B2=20=D0=B1=D0=B4=20=D1=81=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BC=D0=BE=D1=89=D1=8C=D1=8E=20=D1=84=D1=83=D0=BD?= =?UTF-8?q?=D0=BA=D1=86=D0=B8=D0=B8=20saveTree,=20=D0=BB=D0=B8=D0=B1=D0=BE?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/databases/binTree/BinTreeBase.kt | 14 +++++++++++++- .../kotlin/databases/binTree/WrappedBinTree.kt | 6 +++--- .../kotlin/databases/binTree/WrappedBinTreeTest.kt | 6 +++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt index 5082b5a..8e52e89 100644 --- a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt +++ b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt @@ -14,11 +14,17 @@ class BinaryBase (dbPath: String): Closeable { private val getNodeByKey by lazy { connection.prepareStatement("SELECT x, y, value FROM BinaryNodes WHERE BinaryNodes.key = ?;") } private val removeNodeByKey by lazy { connection.prepareStatement("DELETE FROM BinaryNodes WHERE key=?;") } fun open() = createBaseStatement.execute() + + fun saveTree(tree: WrappedBinTree) { + for (node in tree.getWrappedNodesArray()) + addNode(node) + } + fun saveTree(tree: BinaryTree) = saveTree(WrappedBinTree(tree)) fun removeNode(key : Int) { removeNodeByKey.setInt(1, key) removeNodeByKey.execute() } - fun addNode(node : WrappedBinNode) { + private fun addNode(node : WrappedBinNode) { if (search(node.key) != null) return @@ -37,6 +43,12 @@ class BinaryBase (dbPath: String): Closeable { return WrappedBinNode(key, res.getString("value"), res.getDouble("x"), res.getDouble("y")) } + constructor(dbPath: String, tree: WrappedBinTree) : this(dbPath) { + saveTree(tree) + } + constructor(dbPath: String, tree: BinaryTree) : this(dbPath) { + saveTree(tree) + } override fun close() { createBaseStatement.close() addNodeStatement.close() diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index 2515f4a..b315522 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -40,7 +40,7 @@ class WrappedBinTree, V>() { fun add(node: BinaryNode) = add(node.key, node.value) fun add(node: WrappedBinNode) { add(node.key, node.value) - setCoordinate(node.key, node.x, node.y) + setNodeCoordinate(node.key, node.x, node.y) } fun remove(key: K) { val newTree = getBinaryTree() @@ -56,9 +56,9 @@ class WrappedBinTree, V>() { return item throw NodeNotFoundException() } - fun getWrappedNodesArray(key: K): Array> = wrappedNodesList.toTypedArray() + fun getWrappedNodesArray(): Array> = wrappedNodesList.toTypedArray() - fun setCoordinate(key: K, x: Double = 0.0, y: Double = 0.0) { + fun setNodeCoordinate(key: K, x: Double = 0.0, y: Double = 0.0) { for (item in wrappedNodesList) { if (item.key == key) { item.x = x diff --git a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt index 834cc8f..d11414f 100644 --- a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt +++ b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt @@ -94,7 +94,7 @@ class WrappedBinTreeTest { binTree.add(100, "root") wrappedTree = WrappedBinTree(binTree) - wrappedTree.setCoordinate(100, 10.0, -10.0) + wrappedTree.setNodeCoordinate(100, 10.0, -10.0) assertAll("elements", Executable { assertTrue(wrappedTree.search(100).x == 10.0)}, @@ -109,7 +109,7 @@ class WrappedBinTreeTest { wrappedTree = WrappedBinTree(binTree) - assertThrows(NodeNotFoundException::class.java) { wrappedTree.setCoordinate(150, 10.0, -10.0) } + assertThrows(NodeNotFoundException::class.java) { wrappedTree.setNodeCoordinate(150, 10.0, -10.0) } } } @@ -203,7 +203,7 @@ class WrappedBinTreeTest { binTree.add(100) wrappedTree = WrappedBinTree(binTree) - wrappedTree.setCoordinate(100, 10.0) + wrappedTree.setNodeCoordinate(100, 10.0) assertEquals(10.0, wrappedTree.search(100).x) } From 6df3039ecf701363f9aff2876eb05fb88e283802 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 23 Apr 2023 22:30:39 +0300 Subject: [PATCH 102/203] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20=D0=BB?= =?UTF-8?q?=D0=B8=D1=88=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B3?= =?UTF-8?q?=D1=80=D1=83=D0=B7=D0=BA=D0=B8=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4?= =?UTF-8?q?=D0=B0=20add?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/databases/binTree/WrappedBinTree.kt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index b315522..4f4285d 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -29,18 +29,16 @@ class WrappedBinTree, V>() { /** * Позволяет добавить новую ноду в дерево */ - fun add(key: K, value: V? = null) { + fun add(key: K, value: V? = null, x: Double = 0.0, y: Double = 0.0) { val newTree = getBinaryTree() newTree.add(key, value) wrappedNodesList.clear() - newTree.root?.let { addNodeToWrappedList(it) } - } - fun add(node: BinaryNode) = add(node.key, node.value) - fun add(node: WrappedBinNode) { - add(node.key, node.value) - setNodeCoordinate(node.key, node.x, node.y) + newTree.root?.let { + addNodeToWrappedList(it) + setNodeCoordinate(key, x, y) + } } fun remove(key: K) { val newTree = getBinaryTree() From 246a1f94a3a4029f496fc16f202feb90092c83eb Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 23 Apr 2023 22:33:51 +0300 Subject: [PATCH 103/203] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BB=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=B4=D0=BE=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D0=B2=D0=B0=D1=82=D1=8C=20=D0=B1=D0=B8=D0=BD=D0=B0=D1=80=D0=BD?= =?UTF-8?q?=D0=BE=D0=B5=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=BE=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=B8=D1=81=D0=BA=D0=B0=20=D0=B8=D0=B7=20=D0=B1=D0=B0?= =?UTF-8?q?=D0=B7=D1=8B=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/databases/binTree/BinTreeBase.kt | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt index 8e52e89..7d0ad4f 100644 --- a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt +++ b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt @@ -1,33 +1,50 @@ package databases.binTree -import nodes.BinaryNode import trees.BinaryTree import java.io.Closeable import java.sql.DriverManager import java.sql.SQLException -class BinaryBase (dbPath: String): Closeable { + +class BinaryBase(dbPath: String) : Closeable { private val connection = DriverManager.getConnection("jdbc:sqlite:$dbPath") ?: throw SQLException("Cannot connect to database") - private val createBaseStatement by lazy {connection.prepareStatement("CREATE TABLE if not exists BinaryNodes (key int, value varchar(255), x double, y double);")} + private val createBaseStatement by lazy { connection.prepareStatement("CREATE TABLE if not exists BinaryNodes (key int, value varchar(255), x double, y double);") } private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO BinaryNodes (key, value, x, y) VALUES (?, ?, ?, ?);") } - private val getNodeByKey by lazy { connection.prepareStatement("SELECT x, y, value FROM BinaryNodes WHERE BinaryNodes.key = ?;") } - private val removeNodeByKey by lazy { connection.prepareStatement("DELETE FROM BinaryNodes WHERE key=?;") } + private val getNodesStatement by lazy { connection.prepareStatement("SELECT key, value, x, y, value FROM BinaryNodes") } fun open() = createBaseStatement.execute() fun saveTree(tree: WrappedBinTree) { for (node in tree.getWrappedNodesArray()) addNode(node) } + fun saveTree(tree: BinaryTree) = saveTree(WrappedBinTree(tree)) - fun removeNode(key : Int) { - removeNodeByKey.setInt(1, key) - removeNodeByKey.execute() + fun getWrappedBinTree(): WrappedBinTree { + val tree = WrappedBinTree() + + val stateRes = getNodesStatement.executeQuery() + + while (!stateRes.isClosed && stateRes.next()) { + tree.add(stateRes.getInt(1), stateRes.getString(2), stateRes.getDouble(3), stateRes.getDouble(4)) + } + + return tree } - private fun addNode(node : WrappedBinNode) { - if (search(node.key) != null) - return + fun getBinaryTree(): BinaryTree { + val tree = BinaryTree() + + val stateRes = getNodesStatement.executeQuery() + + while (!stateRes.isClosed && stateRes.next()) { + tree.add(stateRes.getInt(1), stateRes.getString(2)) + } + + return tree + } + + private fun addNode(node: WrappedBinNode) { addNodeStatement.setInt(1, node.key) addNodeStatement.setString(2, node.value ?: "empty") addNodeStatement.setDouble(3, node.x) @@ -35,25 +52,18 @@ class BinaryBase (dbPath: String): Closeable { addNodeStatement.execute() } - fun search(key: Int) : WrappedBinNode? { - getNodeByKey.setInt(1, key) - val res = getNodeByKey.executeQuery() - if (res.isClosed) - return null - return WrappedBinNode(key, res.getString("value"), res.getDouble("x"), res.getDouble("y")) - } constructor(dbPath: String, tree: WrappedBinTree) : this(dbPath) { saveTree(tree) } + constructor(dbPath: String, tree: BinaryTree) : this(dbPath) { saveTree(tree) } + override fun close() { createBaseStatement.close() addNodeStatement.close() - getNodeByKey.close() - removeNodeByKey.close() connection.close() } From c319aa7949a01291db313d36e80439509222b72b Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 24 Apr 2023 10:03:19 +0300 Subject: [PATCH 104/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D1=81=D0=B5=D1=80=D0=B8=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20value,=20=D1=83=D0=B4=D0=B0?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/databases/binTree/BinTreeBase.kt | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt index 7d0ad4f..9a00c34 100644 --- a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt +++ b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt @@ -5,7 +5,12 @@ import java.io.Closeable import java.sql.DriverManager import java.sql.SQLException -class BinaryBase(dbPath: String) : Closeable { + +class BinaryBase ( + dbPath: String, + private val serializeValue: (value: V?) -> String, + private val deserializeValue: (strValue: String) -> V +) : Closeable { private val connection = DriverManager.getConnection("jdbc:sqlite:$dbPath") ?: throw SQLException("Cannot connect to database") @@ -13,54 +18,46 @@ class BinaryBase(dbPath: String) : Closeable { private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO BinaryNodes (key, value, x, y) VALUES (?, ?, ?, ?);") } private val getNodesStatement by lazy { connection.prepareStatement("SELECT key, value, x, y, value FROM BinaryNodes") } fun open() = createBaseStatement.execute() - - fun saveTree(tree: WrappedBinTree) { + fun saveTree(tree: WrappedBinTree) { for (node in tree.getWrappedNodesArray()) addNode(node) } - fun saveTree(tree: BinaryTree) = saveTree(WrappedBinTree(tree)) - fun getWrappedBinTree(): WrappedBinTree { - val tree = WrappedBinTree() + fun saveTree(tree: BinaryTree) = saveTree(WrappedBinTree(tree)) + fun getWrappedBinTree(): WrappedBinTree { + val tree = WrappedBinTree() val stateRes = getNodesStatement.executeQuery() while (!stateRes.isClosed && stateRes.next()) { - tree.add(stateRes.getInt(1), stateRes.getString(2), stateRes.getDouble(3), stateRes.getDouble(4)) + tree.add(stateRes.getInt(1), deserializeValue(stateRes.getString(2)), stateRes.getDouble(3), stateRes.getDouble(4)) } return tree } - fun getBinaryTree(): BinaryTree { - val tree = BinaryTree() + fun getBinaryTree(): BinaryTree { + val tree = BinaryTree() val stateRes = getNodesStatement.executeQuery() while (!stateRes.isClosed && stateRes.next()) { - tree.add(stateRes.getInt(1), stateRes.getString(2)) + tree.add(stateRes.getInt(1), deserializeValue(stateRes.getString(2))) } return tree } - private fun addNode(node: WrappedBinNode) { + private fun addNode(node: WrappedBinNode) { + addNodeStatement.setInt(1, node.key) - addNodeStatement.setString(2, node.value ?: "empty") + addNodeStatement.setString(2, serializeValue(node.value) ?: "empty") addNodeStatement.setDouble(3, node.x) addNodeStatement.setDouble(4, node.y) addNodeStatement.execute() } - constructor(dbPath: String, tree: WrappedBinTree) : this(dbPath) { - saveTree(tree) - } - - constructor(dbPath: String, tree: BinaryTree) : this(dbPath) { - saveTree(tree) - } - override fun close() { createBaseStatement.close() addNodeStatement.close() From 69cb6df0b0fed325648f243f9dc769ea57185dce Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 24 Apr 2023 10:06:20 +0300 Subject: [PATCH 105/203] =?UTF-8?q?=D0=9C=D0=B5=D1=82=D0=BE=D0=B4=20open?= =?UTF-8?q?=20=D1=83=D0=B1=D1=80=D0=B0=D0=BB=20=D0=B8=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BE=D1=82=D0=BA=D1=80=D1=8B=D1=82?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B1=D0=B4=20=D0=B2=20=D0=BA=D0=BE=D0=BD=D1=81?= =?UTF-8?q?=D1=82=D1=80=D1=83=D0=BA=D1=82=D0=BE=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/binTree/BinTreeBase.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt index 9a00c34..8068071 100644 --- a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt +++ b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt @@ -6,7 +6,7 @@ import java.sql.DriverManager import java.sql.SQLException -class BinaryBase ( +class BinTreeBase ( dbPath: String, private val serializeValue: (value: V?) -> String, private val deserializeValue: (strValue: String) -> V @@ -17,7 +17,9 @@ class BinaryBase ( private val createBaseStatement by lazy { connection.prepareStatement("CREATE TABLE if not exists BinaryNodes (key int, value varchar(255), x double, y double);") } private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO BinaryNodes (key, value, x, y) VALUES (?, ?, ?, ?);") } private val getNodesStatement by lazy { connection.prepareStatement("SELECT key, value, x, y, value FROM BinaryNodes") } - fun open() = createBaseStatement.execute() + init { + createBaseStatement.execute() + } fun saveTree(tree: WrappedBinTree) { for (node in tree.getWrappedNodesArray()) addNode(node) From b9d1d6b17a2cf99129856807f71f88beea55f810 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 24 Apr 2023 10:14:27 +0300 Subject: [PATCH 106/203] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20=D0=B2?= =?UTF-8?q?=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20?= =?UTF-8?q?=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D1=8F=D1=82=D1=8C=20=D0=BD?= =?UTF-8?q?=D0=B5=20WrappedBinTree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/databases/binTree/BinTreeBase.kt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt index 8068071..79dd2c0 100644 --- a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt +++ b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt @@ -6,9 +6,9 @@ import java.sql.DriverManager import java.sql.SQLException -class BinTreeBase ( +class BinTreeBase( dbPath: String, - private val serializeValue: (value: V?) -> String, + private val serializeValue: (value: V?) -> String = { value -> value.toString() }, private val deserializeValue: (strValue: String) -> V ) : Closeable { @@ -17,22 +17,27 @@ class BinTreeBase ( private val createBaseStatement by lazy { connection.prepareStatement("CREATE TABLE if not exists BinaryNodes (key int, value varchar(255), x double, y double);") } private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO BinaryNodes (key, value, x, y) VALUES (?, ?, ?, ?);") } private val getNodesStatement by lazy { connection.prepareStatement("SELECT key, value, x, y, value FROM BinaryNodes") } + init { createBaseStatement.execute() } + fun saveTree(tree: WrappedBinTree) { for (node in tree.getWrappedNodesArray()) addNode(node) } - - fun saveTree(tree: BinaryTree) = saveTree(WrappedBinTree(tree)) fun getWrappedBinTree(): WrappedBinTree { val tree = WrappedBinTree() val stateRes = getNodesStatement.executeQuery() while (!stateRes.isClosed && stateRes.next()) { - tree.add(stateRes.getInt(1), deserializeValue(stateRes.getString(2)), stateRes.getDouble(3), stateRes.getDouble(4)) + tree.add( + stateRes.getInt(1), + deserializeValue(stateRes.getString(2)), + stateRes.getDouble(3), + stateRes.getDouble(4) + ) } return tree From a6a35f3e1d98e14ba06a99591450ec41ad7aac41 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 24 Apr 2023 10:34:45 +0300 Subject: [PATCH 107/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=8C=20=D0=BE=D1=87=D0=B8=D1=89=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B1=D0=B0=D0=B7=D1=83=20=D0=B4=D0=B0=D0=BD=D0=BD?= =?UTF-8?q?=D1=8B=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/databases/binTree/BinTreeBase.kt | 29 +++++++++---------- .../databases/binTree/WrappedBinTree.kt | 3 +- .../databases/binTree/WrappedBinTreeTest.kt | 8 ++--- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt index 79dd2c0..5f7ff2e 100644 --- a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt +++ b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt @@ -11,12 +11,17 @@ class BinTreeBase( private val serializeValue: (value: V?) -> String = { value -> value.toString() }, private val deserializeValue: (strValue: String) -> V ) : Closeable { + object DbConstants { + const val DB_NAME = "BinaryNodes" + } private val connection = DriverManager.getConnection("jdbc:sqlite:$dbPath") ?: throw SQLException("Cannot connect to database") - private val createBaseStatement by lazy { connection.prepareStatement("CREATE TABLE if not exists BinaryNodes (key int, value varchar(255), x double, y double);") } - private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO BinaryNodes (key, value, x, y) VALUES (?, ?, ?, ?);") } - private val getNodesStatement by lazy { connection.prepareStatement("SELECT key, value, x, y, value FROM BinaryNodes") } + private val createBaseStatement by lazy { connection.prepareStatement("CREATE TABLE if not exists ${DbConstants.DB_NAME} (key int, value varchar(255), x double, y double);") } + private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO ${DbConstants.DB_NAME} (key, value, x, y) VALUES (?, ?, ?, ?);") } + private val getNodesStatement by lazy { connection.prepareStatement("SELECT key, value, x, y, value FROM ${DbConstants.DB_NAME}") } + private val dropDatabaseStatement by lazy { connection.prepareStatement("DELETE FROM ${DbConstants.DB_NAME};") } + init { createBaseStatement.execute() @@ -26,6 +31,10 @@ class BinTreeBase( for (node in tree.getWrappedNodesArray()) addNode(node) } + + fun clear() { + dropDatabaseStatement.execute() + } fun getWrappedBinTree(): WrappedBinTree { val tree = WrappedBinTree() @@ -43,22 +52,10 @@ class BinTreeBase( return tree } - fun getBinaryTree(): BinaryTree { - val tree = BinaryTree() - - val stateRes = getNodesStatement.executeQuery() - - while (!stateRes.isClosed && stateRes.next()) { - tree.add(stateRes.getInt(1), deserializeValue(stateRes.getString(2))) - } - - return tree - } - private fun addNode(node: WrappedBinNode) { addNodeStatement.setInt(1, node.key) - addNodeStatement.setString(2, serializeValue(node.value) ?: "empty") + addNodeStatement.setString(2, serializeValue(node.value)) addNodeStatement.setDouble(3, node.x) addNodeStatement.setDouble(4, node.y) diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt index 4f4285d..44cb0bd 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt @@ -48,14 +48,13 @@ class WrappedBinTree, V>() { newTree.root?.let { addNodeToWrappedList(it) } } - fun search(key: K): WrappedBinNode { + fun getWrappedNode(key: K): WrappedBinNode { for (item in wrappedNodesList) if (item.key == key) return item throw NodeNotFoundException() } fun getWrappedNodesArray(): Array> = wrappedNodesList.toTypedArray() - fun setNodeCoordinate(key: K, x: Double = 0.0, y: Double = 0.0) { for (item in wrappedNodesList) { if (item.key == key) { diff --git a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt index d11414f..8904603 100644 --- a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt +++ b/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt @@ -97,8 +97,8 @@ class WrappedBinTreeTest { wrappedTree.setNodeCoordinate(100, 10.0, -10.0) assertAll("elements", - Executable { assertTrue(wrappedTree.search(100).x == 10.0)}, - Executable { assertTrue(wrappedTree.search(100).y == -10.0)} + Executable { assertTrue(wrappedTree.getWrappedNode(100).x == 10.0)}, + Executable { assertTrue(wrappedTree.getWrappedNode(100).y == -10.0)} ) } @@ -205,7 +205,7 @@ class WrappedBinTreeTest { wrappedTree = WrappedBinTree(binTree) wrappedTree.setNodeCoordinate(100, 10.0) - assertEquals(10.0, wrappedTree.search(100).x) + assertEquals(10.0, wrappedTree.getWrappedNode(100).x) } @Test @@ -213,7 +213,7 @@ class WrappedBinTreeTest { fun `Non-existent element search`() { wrappedTree = WrappedBinTree() - assertThrows(NodeNotFoundException::class.java){ wrappedTree.search(100).x} + assertThrows(NodeNotFoundException::class.java){ wrappedTree.getWrappedNode(100).x} } } From 8d9672fa50246b9e316bd3e392020e78f1c20fbe Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 24 Apr 2023 10:44:14 +0300 Subject: [PATCH 108/203] =?UTF-8?q?=D0=9C=D0=B5=D1=82=D0=BE=D0=B4=20close(?= =?UTF-8?q?)=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20private=20=D0=B8=20?= =?UTF-8?q?=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D1=83=D0=B5=D1=82?= =?UTF-8?q?=D1=81=D1=8F=20=D0=BF=D1=80=D0=B8=20=D1=81=D0=BE=D1=85=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D0=B8=20=D0=BD=D0=BE=D0=B2=D0=BE?= =?UTF-8?q?=D0=B3=D0=BE=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/binTree/BinTreeBase.kt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt index 5f7ff2e..b5ef22b 100644 --- a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt +++ b/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt @@ -28,13 +28,11 @@ class BinTreeBase( } fun saveTree(tree: WrappedBinTree) { + clear() for (node in tree.getWrappedNodesArray()) addNode(node) } - fun clear() { - dropDatabaseStatement.execute() - } fun getWrappedBinTree(): WrappedBinTree { val tree = WrappedBinTree() @@ -51,7 +49,6 @@ class BinTreeBase( return tree } - private fun addNode(node: WrappedBinNode) { addNodeStatement.setInt(1, node.key) @@ -62,9 +59,15 @@ class BinTreeBase( addNodeStatement.execute() } + private fun clear() { + dropDatabaseStatement.execute() + } + override fun close() { createBaseStatement.close() addNodeStatement.close() + getNodesStatement.close() + dropDatabaseStatement.close() connection.close() } From 1c086b875c45d0649e938b6edfd7aa1b3687a05e Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 24 Apr 2023 14:28:57 +0300 Subject: [PATCH 109/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BD=D0=B5=D1=81=D0=BA=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE?= =?UTF-8?q?=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B9=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D1=82=D0=B5=D1=81=D1=82=D0=B0=20=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D0=BB=20=D0=BA=D1=80=D0=B0=D1=81=D0=BD=D0=BE-?= =?UTF-8?q?=D1=87=D1=91=D1=80=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B2=D0=B0.=20=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=BD=D0=B0=20=D1=84=D1=83?= =?UTF-8?q?=D0=BD=D0=BA=D1=86=D0=B8=D1=8E=20search?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/RBTreeTest.kt | 172 ++++++++++++++++-------- 1 file changed, 115 insertions(+), 57 deletions(-) diff --git a/lib/src/test/kotlin/trees/RBTreeTest.kt b/lib/src/test/kotlin/trees/RBTreeTest.kt index 92ca78d..ff70382 100644 --- a/lib/src/test/kotlin/trees/RBTreeTest.kt +++ b/lib/src/test/kotlin/trees/RBTreeTest.kt @@ -1,71 +1,129 @@ - -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNull +import exceptions.NodeAlreadyExistsException +import exceptions.NodeNotFoundException +import exceptions.NullNodeException +import exceptions.TreeException +import nodes.BinaryNode +import nodes.Color +import nodes.RBNode +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test +import org.junit.jupiter.api.function.Executable import trees.RBTree +import java.time.Duration.ofMillis +import kotlin.random.Random +import kotlin.test.BeforeTest class RBTreeTest { - @Test - fun testAdd() { - val tree = RBTree() - tree.add(1, "one") - tree.add(2, "two") - tree.add(3, "three") - assertEquals("one", tree.search(1)?.value) - assertEquals("two", tree.search(2)?.value) - assertEquals("three", tree.search(3)?.value) + + private lateinit var tree : RBTree + @BeforeTest + fun init() { + tree = RBTree() } + + @Nested + inner class `Search check` { + @Test + @DisplayName("Existing elements search") + fun `Existing elements search`() { + tree.add(100, "root") + tree.add(150, "root -> right") + tree.add(50, "root -> left") + tree.add(30, "root -> left -> left") - @Test - fun testSearch() { - val tree = RBTree() - tree.add(1, "one") - tree.add(2, "two") - tree.add(3, "three") - assertEquals("one", tree.search(1)?.value) - assertEquals("two", tree.search(2)?.value) - assertEquals("three", tree.search(3)?.value) - assertNull(tree.search(4)) + assertEquals("root -> left -> left", tree.search(30)?.value) + } + + @Test + @DisplayName("Not-existent elements search") + fun `Not-existent elements search`() { + assertThrows(NodeNotFoundException::class.java) { tree.search(100) } + } } - @Test - fun testRemove() { - val tree = RBTree() - tree.add(1, "one") - tree.add(2, "two") - tree.add(3, "three") - tree.remove(2) - assertEquals("one", tree.search(1)?.value) - assertNull(tree.search(2)?.value) - assertEquals("three", tree.search(3)?.value) + @Nested + inner class `Add check` { + } - @Test - fun testAddSearchRemove() { - val tree = RBTree() - tree.add(1, "one") - tree.add(2, "two") - tree.add(3, "three") - assertEquals("one", tree.search(1)?.value) - assertEquals("two", tree.search(2)?.value) - assertEquals("three", tree.search(3)?.value) - tree.remove(2) - assertEquals("one", tree.search(1)?.value) - assertNull(tree.search(2)) - assertEquals("three", tree.search(3)?.value) - tree.add(4, "four") - assertEquals("four", tree.search(4)?.value) - assertNull(tree.search(2)) + /** + * Проверка дерева на соответствие правилам красно-чёрных деревьев + * @return True - узлы размещены как положено + * */ + private fun , V> RBTree.rulesCheck(): Boolean { + + if (this.root?.childrenCheck() == false) + throw TreeException("Неверное расположение узлов, key слева должен быть меньше, а key справа - больше") + if (this.root?.color != Color.BLACK) + throw TreeException("root у RBTree не можешь быть красным") + if (this.root?.checkEndNodesColor() == false) + throw TreeException("Конечные узлы RBTree не могут быть красными") + if (this.root?.checkEndNodesColor() == false) + throw TreeException("У красного узла родительский узел может быть только чёрным") + + this.root?.getBlackNodesCount() // Если что само выбросит исключение + + return true } - @Test - fun testAddMany() { - val tree = RBTree() - for (i in 1..1000) { - tree.add(i, i.toString()) - } - for (i in 1..1000) { - assertEquals(i.toString(), tree.search(i)?.value) - } + /** + * Проверка на то, что левый узел меньше, а правый больше + * @return True - узлы размещены как положено + * */ + private fun , V> RBNode.childrenCheck(): Boolean = + (this.left == null || this.left?.compareTo(this) == -1) + && (this.right == null || this.right?.compareTo(this) == 1) + && (this.right == null || right?.childrenCheck() == true) + && (this.left == null || left?.childrenCheck() == true) + + /** + * Проверяет, что у каждого красного узла родительский узел - чёрный + * @return True - условие верно + */ + private fun , V> RBNode.checkNodeParentColor(): Boolean { + return if (this.color == Color.RED && this.parent?.color != Color.BLACK) + false + else + (this.right == null || this.right?.checkEndNodesColor() == true) && + (this.left == null || this.left?.checkEndNodesColor() == true) + } + + /** + * @return Число чёрных нод на пути из ноды в лист + */ + private fun , V> RBNode.getBlackNodesCount(count: Int = 0): Int { + var mCount = count + if (this.color == Color.BLACK) + mCount++ + var leftCount = 0 + var rightCount = 0 + if (this.left != null) + leftCount += this.left?.getBlackNodesCount() ?: throw NullNodeException() + if (this.right != null) + rightCount += this.right?.getBlackNodesCount() ?: throw NullNodeException() + + // Теперь смотрим, выполняется ли условие + if (leftCount != rightCount) + throw TreeException("У RBTree не может быть разного количества чёрных узлов у поддеревьев") + + mCount += leftCount + rightCount + + return mCount } + + /** + * Проверяет что конечные узлы чёрные + * @return True - всё верно + */ + private fun , V> RBNode.checkEndNodesColor(): Boolean { + return if (this.right == null && this.left == null && this.color == Color.BLACK) + true + else + (this.right == null || this.right?.checkEndNodesColor() == true) && + (this.left == null || this.right?.checkEndNodesColor() == true) + } + } \ No newline at end of file From 05d4b22cb50c4ced4f4d9944ddac8a44e1444fb9 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 24 Apr 2023 14:49:27 +0300 Subject: [PATCH 110/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B2=20=D0=BA?= =?UTF-8?q?=D1=80=D0=B0=D1=81=D0=BD=D0=BE-=D1=87=D1=91=D1=80=D0=BD=D0=BE?= =?UTF-8?q?=D0=B5=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=B0=20(=D0=BF=D0=BE?= =?UTF-8?q?=D0=BA=D1=80=D1=8B=D1=82=D0=B8=D0=B5=20=D0=BD=D0=B5=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D0=BD=D0=BE=D0=B5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/RBTreeTest.kt | 54 +++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/lib/src/test/kotlin/trees/RBTreeTest.kt b/lib/src/test/kotlin/trees/RBTreeTest.kt index ff70382..112a0af 100644 --- a/lib/src/test/kotlin/trees/RBTreeTest.kt +++ b/lib/src/test/kotlin/trees/RBTreeTest.kt @@ -18,12 +18,13 @@ import kotlin.test.BeforeTest class RBTreeTest { - private lateinit var tree : RBTree + private lateinit var tree: RBTree + @BeforeTest fun init() { tree = RBTree() } - + @Nested inner class `Search check` { @Test @@ -46,7 +47,54 @@ class RBTreeTest { @Nested inner class `Add check` { + @Test + @DisplayName("Root element add") + fun `Root element add`() { + tree.add(100) + + assertTrue(tree.rulesCheck()) + } + @Test + @DisplayName("Small tree create test") + fun `Small tree create test`() { + tree.add(100) + tree.add(150) + tree.add(10) + tree.add(0) + + assertTrue(tree.rulesCheck()) + } + + @Test + @DisplayName("Add to different subtrees") + fun `Add to different subtrees`() { + tree.add(100, "root") + tree.add(150) + tree.add(125) + tree.add(200) + tree.add(50) + tree.add(25) + tree.add(60) + + assertTrue(tree.rulesCheck()) + } + + @Test + @DisplayName("Equal keys add") + fun `Equals keys add`() { + tree.add(100) + + assertThrows(NodeAlreadyExistsException::class.java) { tree.add(100) } + } + + @Test + @DisplayName("Equal keys add") + fun `Equal keys add`() { + tree.add(100) + + assertThrows(NodeAlreadyExistsException::class.java) { tree.add(100) } + } } /** @@ -107,7 +155,7 @@ class RBTreeTest { // Теперь смотрим, выполняется ли условие if (leftCount != rightCount) - throw TreeException("У RBTree не может быть разного количества чёрных узлов у поддеревьев") + throw TreeException("Узел [${this.key}, ${this.value}] содержит разное кол-во чёрных узлов в левом [$leftCount] и правом [$rightCount] поддереве") mCount += leftCount + rightCount From dd05925f75f301ee41dcf08c8d8b2fca25b66584 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 24 Apr 2023 15:27:40 +0300 Subject: [PATCH 111/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20add,=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D1=84-=D0=B8=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D0=BA=D0=B8=20=D1=81=D1=83=D1=89=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D1=88=D0=B8=D0=BD=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/RBTreeTest.kt | 69 +++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/lib/src/test/kotlin/trees/RBTreeTest.kt b/lib/src/test/kotlin/trees/RBTreeTest.kt index 112a0af..26201d9 100644 --- a/lib/src/test/kotlin/trees/RBTreeTest.kt +++ b/lib/src/test/kotlin/trees/RBTreeTest.kt @@ -2,17 +2,14 @@ import exceptions.NodeAlreadyExistsException import exceptions.NodeNotFoundException import exceptions.NullNodeException import exceptions.TreeException -import nodes.BinaryNode import nodes.Color import nodes.RBNode -import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.junit.jupiter.api.function.Executable import trees.RBTree -import java.time.Duration.ofMillis import kotlin.random.Random import kotlin.test.BeforeTest @@ -80,6 +77,39 @@ class RBTreeTest { assertTrue(tree.rulesCheck()) } + @Test + @DisplayName("Random elements add") + fun `Random elements add`() { + val list: List = (List(100000) { Random.nextInt(1, 100000) }).distinct().toMutableList() + + for (item in list) + tree.add(item, "a") + + assertTrue(tree.rulesCheck()) + } + + @Test + @DisplayName("Add elements existence check") + fun `Add elements existence check`() { + tree.add(100, "root") + tree.add(150) + tree.add(125) + tree.add(200) + tree.add(50) + tree.add(25) + tree.add(60) + + assertAll( + Executable { assertTrue(tree.nodeExists(100, "root")) }, + Executable { assertTrue(tree.nodeExists(150, null)) }, + Executable { assertTrue(tree.nodeExists(125, null)) }, + Executable { assertTrue(tree.nodeExists(200, null)) }, + Executable { assertTrue(tree.nodeExists(50, null)) }, + Executable { assertTrue(tree.nodeExists(25, null)) }, + Executable { assertTrue(tree.nodeExists(60, null)) } + ) + } + @Test @DisplayName("Equal keys add") fun `Equals keys add`() { @@ -97,6 +127,39 @@ class RBTreeTest { } } + @Nested + inner class `Remove check` { + @Test + fun `Root element del`() { + tree.add(100) + + + } + } + + /*** + * Проверяет ноду на существование + * @return True - найден узел с совпадающим ключом и значением + */ + private fun , V> RBTree.nodeExists(key: K, value: V?): Boolean { + if (this.root == null) + return false + val searchRes = this.root?.recursiveSearch(key) + return searchRes != null && searchRes.value == value + } + + /** + * Выполняет рекурсивный поиск ноды + * (нужна чтобы тесты не опирались на ф-ию поиска класса BinaryNode) + */ + private fun , V> RBNode.recursiveSearch(key: K): RBNode? = + when (key.compareTo(this.key)) { + 1 -> this.right?.recursiveSearch(key) + 0 -> this + -1 -> this.left?.recursiveSearch(key) + else -> null + } + /** * Проверка дерева на соответствие правилам красно-чёрных деревьев * @return True - узлы размещены как положено From 8a7b2e668ceb5c054cc008e1409a87e71b63ba5a Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Mon, 24 Apr 2023 20:01:27 +0300 Subject: [PATCH 112/203] =?UTF-8?q?=D0=9F=D0=BE=D0=BC=D0=B5=D0=BD=D1=8F?= =?UTF-8?q?=D0=BB=20=D0=BC=D0=BE=D0=B4=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=82?= =?UTF-8?q?=D0=BE=D1=80=20=D0=B2=D0=B8=D0=B4=D0=B8=D0=BC=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B8=20'set'=20=D1=83=20'value'=20=D0=B2=20'AbstractNode'=20?= =?UTF-8?q?=D0=BD=D0=B0=20internal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/bin/AVLBase.kt | 50 -------------------- lib/src/main/kotlin/nodes/AbstractNode.kt | 2 +- 2 files changed, 1 insertion(+), 51 deletions(-) delete mode 100644 lib/src/main/kotlin/databases/bin/AVLBase.kt diff --git a/lib/src/main/kotlin/databases/bin/AVLBase.kt b/lib/src/main/kotlin/databases/bin/AVLBase.kt deleted file mode 100644 index 0484d5c..0000000 --- a/lib/src/main/kotlin/databases/bin/AVLBase.kt +++ /dev/null @@ -1,50 +0,0 @@ -package databases.bin - -import nodes.AVLNode -import java.io.Closeable -import java.sql.DriverManager -import java.sql.SQLException - -class AVLBase (path: String): Closeable { - - private val connection = DriverManager.getConnection("jdbc:sqlite:$path") - ?: throw SQLException("Cannot connect to database") - private val createBaseStatement by lazy {connection.prepareStatement("CREATE TABLE if not exists BinaryNodes (x int, y int, key int, value varchar(255));")} - private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO BinaryNodes (x, y, key, value) VALUES (?, ?, ?, ?);") } - private val getNodeByKey by lazy { connection.prepareStatement("SELECT x, y, value FROM BinaryNodes WHERE BinaryNodes.key = ?;") } - private val removeNodeByKey by lazy { connection.prepareStatement("DELETE FROM BinaryNodes WHERE key=?;") } - fun open() = createBaseStatement.execute() - - fun removeNode(key : Int) { - removeNodeByKey.setInt(1, key) - removeNodeByKey.execute() - } - fun addNode(node : Node>) { - if (search(node.binNode.key) != null) - return - - addNodeStatement.setInt(1, node.x) - addNodeStatement.setInt(2, node.y) - addNodeStatement.setInt(3, node.binNode.key) - addNodeStatement.setString(4, node.binNode.value ?: "empty") - - addNodeStatement.execute() - } - fun search(key: Int) : Node>? { - getNodeByKey.setInt(1, key) - val res = getNodeByKey.executeQuery() - if (res.isClosed) - return null - - return Node(AVLNode(key, res.getString("value")), res.getInt("x"), res.getInt("y")) - } - override fun close() { - createBaseStatement.close() - addNodeStatement.close() - getNodeByKey.close() - removeNodeByKey.close() - - connection.close() - } - -} \ No newline at end of file diff --git a/lib/src/main/kotlin/nodes/AbstractNode.kt b/lib/src/main/kotlin/nodes/AbstractNode.kt index 6372770..20df1ea 100644 --- a/lib/src/main/kotlin/nodes/AbstractNode.kt +++ b/lib/src/main/kotlin/nodes/AbstractNode.kt @@ -6,7 +6,7 @@ abstract class AbstractNode, V, node : AbstractNode Date: Mon, 24 Apr 2023 20:07:12 +0300 Subject: [PATCH 113/203] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20overri?= =?UTF-8?q?de-=D1=8B=20=D0=BF=D1=80=D0=B0=D0=B2=D0=BE=D0=B3=D0=BE=20=D0=B8?= =?UTF-8?q?=20=D0=BB=D0=B5=D0=B2=D0=BE=D0=B3=D0=BE=20=D0=BF=D0=BE=D0=B4?= =?UTF-8?q?=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=B0=20AVL=20=D0=BD=D0=BE=D0=B4?= =?UTF-8?q?=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/AVLNode.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/src/main/kotlin/nodes/AVLNode.kt b/lib/src/main/kotlin/nodes/AVLNode.kt index ace5632..6ff70bd 100644 --- a/lib/src/main/kotlin/nodes/AVLNode.kt +++ b/lib/src/main/kotlin/nodes/AVLNode.kt @@ -1,10 +1,5 @@ package nodes -import nodes.BinaryNode - -class AVLNode, V>(override var key: K, override var value: V?) : AbstractNode>(){ - override var right : AVLNode? = null - override var left : AVLNode? = null - +class AVLNode, V>(key: K, value: V?) : AbstractNode>(key, value){ var height: Int = 1 -} \ No newline at end of file +} From c1070e41b8254e955ffd21f83fdf92c1096479ae Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Mon, 24 Apr 2023 20:15:50 +0300 Subject: [PATCH 114/203] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=20=D0=B2=D1=81=D0=BF=D0=BE=D0=BC=D0=BE?= =?UTF-8?q?=D0=B3=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D1=84?= =?UTF-8?q?=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B2=20=D0=BE=D1=81?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=BD=D1=8B=D0=B5,=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B5=20?= =?UTF-8?q?=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BE?= =?UTF-8?q?=D0=B1=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=D1=85,=20=D0=BF=D0=BE=D0=B4=D1=81=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=B4=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=20=D0=B2=20'AbstractTree'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/trees/AVLTree.kt | 132 ++++++++++++++------------- 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/lib/src/main/kotlin/trees/AVLTree.kt b/lib/src/main/kotlin/trees/AVLTree.kt index fba5659..a9ad49b 100644 --- a/lib/src/main/kotlin/trees/AVLTree.kt +++ b/lib/src/main/kotlin/trees/AVLTree.kt @@ -1,82 +1,81 @@ package trees +import exceptions.NodeAlreadyExistsException +import exceptions.NullNodeException import nodes.AVLNode import kotlin.math.max class AVLTree, V> : AbstractTree>() { - override var root: AVLNode? = null - - override fun add(key: K, value: V?) { - root = insert(root , key , value) - } + fun addRecursive(node: AVLNode? , key: K, value: V?): AVLNode { + if (node == null) { + return AVLNode(key, value) + } - override fun remove(key: K) { - root = delete(root, key) - } + val delta: Int = key.compareTo(node.key) - override fun search(key: K): AVLNode? { - return searchNode(root, key) - } + if (delta < 0) { + node.left = addRecursive(node.left , key , value) + } else if(delta > 0) { + node.right = addRecursive(node.right , key , value) + } else { + throw NodeAlreadyExistsException() + } - private fun searchNode(node: AVLNode?, key: K): AVLNode? { - if (node == null) { - return null + return rebalance(node) ?: throw NullNodeException() } - if (key < node.key) { - return searchNode(node.left, key) - } else if (key > node.key) { - return searchNode(node.right, key) - } else { - return node - } + root = addRecursive(root , key , value) } - private fun delete(node: AVLNode?, key: K): AVLNode? { - if (node == null) { - return null - } - - if (key < node.key) { - node.left = delete(node.left , key) - } else if (key > node.key) { - node.right = delete(node.right , key) - } else { - if (node.left == null) { - return node.right - } else if (node.right == null) { - return node.left + override fun remove(key: K) { + fun removeRecursive(node: AVLNode?, key: K): AVLNode? { + if (node == null) { + return null } - val temp = findMin(node) - node.value = temp.value - node.right = delete(node.right, temp.key) + if (key < node.key) { + node.left = removeRecursive(node.left , key) + } else if (key > node.key) { + node.right = removeRecursive(node.right , key) + } else { + if (node.left == null) { + return node.right + } else if (node.right == null) { + return node.left + } + + val minNode = findMin(node) ?: throw NullNodeException() + node.value = minNode.value + node.right = removeRecursive(node.right, minNode.key) + + } + return rebalance(node) ?: throw NullNodeException() } - return rebalance(node) ?: throw Exception("Rebalance returned a null value") + root = removeRecursive(root, key) } - private fun insert(node: AVLNode? , key: K, value: V?): AVLNode { - if (node == null) { - return AVLNode(key, value) - } - - val delta: Int = key.compareTo(node.key) + override fun search(key: K): AVLNode? { + fun searchRecursive(node: AVLNode?, key: K): AVLNode? { + if (node == null) { + return null + } - if (delta < 0) { - node.left = insert(node.left , key , value) - } else if(delta > 0) { - node.right = insert(node.right , key , value) - } else { - //Duplicate key + return if (key < node.key) { + searchRecursive(node.left, key) + } else if (key > node.key) { + searchRecursive(node.right, key) + } else { + node + } } - return rebalance(node) ?: throw Exception("Rebalance returned a null value") + return searchRecursive(root, key) } - private fun findMin(node: AVLNode): AVLNode = if (node.left != null) findMin(node.left!!) else node + private fun findMin(node: AVLNode?): AVLNode? = if (node?.left != null) findMin(node.left) else node private fun rebalance(node: AVLNode): AVLNode? { node.height = 1 + max(getHeight(node.left) , getHeight(node.right)) @@ -85,21 +84,24 @@ class AVLTree, V> : AbstractTree>() { val leftBalance: Int = getBalance(node.left) val rightBalance: Int = getBalance(node.right) - if (balance > 1 && leftBalance >= 0) { - return rotateRight(node) - } - if (balance > 1 && leftBalance < 0) { - node.left = rotateLeft(node.left) - return rotateRight(node) - } - if (balance < -1 && rightBalance <= 0) { - return rotateLeft(node) + if (balance > 1) { + return if (leftBalance >= 0) { + rotateRight(node) + } else{ + node.left = rotateLeft(node.left) + rotateRight(node) + } } - if (balance < -1 && rightBalance > 0) { - node.right = rotateRight(node.right) - return rotateLeft(node) + if (balance < -1) { + return if (rightBalance <= 0) { + rotateLeft(node) + } else { + node.right = rotateRight(node.right) + rotateLeft(node) + } } + return node } From aae36c5d14f9c657520b60a277cfaa6c95b171d8 Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Mon, 24 Apr 2023 20:29:51 +0300 Subject: [PATCH 115/203] =?UTF-8?q?=D0=92=D0=BD=D0=B5=D1=81=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B2=20=D1=81?= =?UTF-8?q?=D0=B2=D1=8F=D0=B7=D0=B8=20=D1=81=20=D1=81=D0=BE=D0=B7=D0=B4?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=B5=D0=BC=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81?= =?UTF-8?q?=D0=B0=20=D0=B4=D0=BB=D1=8F=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D0=B9,=20=D0=B0=20=D1=82=D0=B0=D0=BA?= =?UTF-8?q?=D0=B6=D0=B5=20=D0=B2=20=D1=81=D0=B2=D1=8F=D0=B7=D0=B8=20=D1=81?= =?UTF-8?q?=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=D0=BC?= =?UTF-8?q?=20=D0=B0=D0=B1=D1=81=D1=82=D1=80=D0=B0=D0=BA=D1=82=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=BE=D0=B2=20=D0=BD?= =?UTF-8?q?=D0=BE=D0=B4=D1=8B=20=D0=B8=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/gradle.yml | 2 +- lib/src/main/kotlin/nodes/RBTNode.kt | 7 ++--- lib/src/main/kotlin/trees/RBTree.kt | 40 ++++++++++++++-------------- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index be39008..7fcb440 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -1,7 +1,7 @@ name: Gradle Build&Test on: push: - branches-gnore: + branches-ignore: - main pull_request: branches: diff --git a/lib/src/main/kotlin/nodes/RBTNode.kt b/lib/src/main/kotlin/nodes/RBTNode.kt index a6ca369..d65ad55 100644 --- a/lib/src/main/kotlin/nodes/RBTNode.kt +++ b/lib/src/main/kotlin/nodes/RBTNode.kt @@ -2,11 +2,8 @@ package RBnode import nodes.AbstractNode -class RBNode, V>(override var key: K, override var value: V?) : - AbstractNode>() { - - override var right: RBNode? = null - override var left: RBNode? = null +class RBNode, V>(key: K, value: V?) : + AbstractNode>(key, value) { var parent: RBNode? = null var color: Color = Color.BLACK diff --git a/lib/src/main/kotlin/trees/RBTree.kt b/lib/src/main/kotlin/trees/RBTree.kt index 46e73e0..18f4436 100644 --- a/lib/src/main/kotlin/trees/RBTree.kt +++ b/lib/src/main/kotlin/trees/RBTree.kt @@ -2,11 +2,10 @@ package trees import RBnode.Color import RBnode.RBNode -import database.RBT.RBTreeSerializer +import exceptions.* -class RBTree, V> : AbstractTree>() { - override var root: RBNode? = null +class RBTree, V> : AbstractTree>() { override fun search(key: K): RBNode? { var node = root while (node != null) { @@ -20,6 +19,9 @@ class RBTree, V> : AbstractTree>() { } override fun add(key: K, value: V?) { + if (contains(key)) { // check if node with the same key already exists + throw NodeAlreadyExistsException() + } val newNode = RBNode(key, value) if (root == null) { // if there is no root, make the node - new root root = newNode @@ -47,7 +49,7 @@ class RBTree, V> : AbstractTree>() { } override fun remove(key: K) { - val node = search(key) ?: return //check if node is real + val node = search(key) ?: throw NodeNotFoundException() //check if node is real removeNode(node) } @@ -146,7 +148,7 @@ class RBTree, V> : AbstractTree>() { if (sibling?.right?.color == Color.BLACK) { sibling.left?.color = Color.BLACK sibling.color = Color.RED - sibling?.let { rightRotate(it) } + sibling.let { rightRotate(it) } sibling = currentNode.parent?.right } sibling?.color = currentNode.parent?.color ?: throw IllegalStateException("Parent color is null") @@ -170,7 +172,7 @@ class RBTree, V> : AbstractTree>() { if (sibling?.left?.color == Color.BLACK) { sibling.right?.color = Color.BLACK sibling.color = Color.RED - sibling?.let { leftRotate(it) } + sibling.let { leftRotate(it) } sibling = currentNode.parent?.left } sibling?.color = currentNode.parent?.color ?: throw IllegalStateException("Parent color is null") @@ -186,7 +188,7 @@ class RBTree, V> : AbstractTree>() { private fun leftRotate(node: RBNode) { - val rightChild = node.right ?: throw IllegalStateException("Right child is null") + val rightChild = node.right ?: throw NullNodeException() node.right = rightChild.left if (rightChild.left != null) { rightChild.left!!.parent = node @@ -223,24 +225,22 @@ class RBTree, V> : AbstractTree>() { private fun transplant(u: RBNode?, v: RBNode?) { if (u?.parent == null) { - root = v ?: throw IllegalStateException("Node v is null") + root = v ?: throw NullNodeException() } else if (u == u.parent!!.left) { - u.parent!!.left = v ?: throw IllegalStateException("Node v is null") + u.parent!!.left = v ?: throw NullNodeException() } else { - u.parent!!.right = v ?: throw IllegalStateException("Node v is null") + u.parent!!.right = v ?: throw NullNodeException() } v.parent = u?.parent } - - fun saveToFile(filePath: String) { - val serializer = RBTreeSerializer() - serializer.serialize(this, filePath) - } - - companion object { - fun loadFromFile(filePath: String): RBTree<*, *> { - val serializer = RBTreeSerializer() - return serializer.deserialize(filePath) + fun contains(key: K): Boolean { + var node = root + while (node != null) { + if (key == node.key) { + return true + } + node = if (key < node.key) node.left else node.right } + return false } } \ No newline at end of file From 0738a5ccf8b00a6e951aaef55c2dad072de92fcd Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 25 Apr 2023 00:29:44 +0300 Subject: [PATCH 116/203] =?UTF-8?q?=D0=9F=D0=BE=D0=BC=D0=B5=D0=BD=D1=8F?= =?UTF-8?q?=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20add=20(=D1=82?= =?UTF-8?q?=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BF=D0=BE=D0=BD=D1=8F=D1=82?= =?UTF-8?q?=D0=BD=D0=B5=D0=B5=20=D0=B3=D0=B4=D0=B5=20=D0=B8=D1=81=D0=BA?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D1=83)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/RBTreeTest.kt | 97 ++++++++++++++++++------- 1 file changed, 72 insertions(+), 25 deletions(-) diff --git a/lib/src/test/kotlin/trees/RBTreeTest.kt b/lib/src/test/kotlin/trees/RBTreeTest.kt index 26201d9..a0d1195 100644 --- a/lib/src/test/kotlin/trees/RBTreeTest.kt +++ b/lib/src/test/kotlin/trees/RBTreeTest.kt @@ -53,26 +53,55 @@ class RBTreeTest { } @Test - @DisplayName("Small tree create test") - fun `Small tree create test`() { - tree.add(100) - tree.add(150) - tree.add(10) - tree.add(0) + @DisplayName("Add one element to root") + fun `Add one element to root`() { + tree.add(1) + tree.add(2) assertTrue(tree.rulesCheck()) } @Test - @DisplayName("Add to different subtrees") - fun `Add to different subtrees`() { - tree.add(100, "root") - tree.add(150) - tree.add(125) - tree.add(200) - tree.add(50) - tree.add(25) - tree.add(60) + @DisplayName("Balance with three elements check") + fun `Balance with three elements check`() { + tree.add(1) + tree.add(2) + tree.add(3) + + assertTrue(tree.rulesCheck()) + } + @Test + @DisplayName("Balance and repaint simple check") + fun `Balance and repaint simple check`() { + tree.add(2) + tree.add(1) + tree.add(3) + tree.add(4) + + assertTrue(tree.rulesCheck()) + } + + @Test + @DisplayName("Complex rotate check") + fun `Complex rotate check`() { + tree.add(2) + tree.add(3) + tree.add(4) + tree.add(5) + tree.add(1) + + assertTrue(tree.rulesCheck()) + } + + @Test + @DisplayName("Complex rotate and repaint check") + fun `Complex rotate and repaint check`() { + tree.add(2) + tree.add(1) + tree.add(4) + tree.add(3) + tree.add(5) + tree.add(6) assertTrue(tree.rulesCheck()) } @@ -90,7 +119,7 @@ class RBTreeTest { @Test @DisplayName("Add elements existence check") - fun `Add elements existence check`() { + fun `New elements existence check`() { tree.add(100, "root") tree.add(150) tree.add(125) @@ -117,23 +146,41 @@ class RBTreeTest { assertThrows(NodeAlreadyExistsException::class.java) { tree.add(100) } } - - @Test - @DisplayName("Equal keys add") - fun `Equal keys add`() { - tree.add(100) - - assertThrows(NodeAlreadyExistsException::class.java) { tree.add(100) } - } } @Nested inner class `Remove check` { @Test fun `Root element del`() { - tree.add(100) + tree.add(100, "root") + tree.remove(100) + assertFalse(tree.nodeExists(100, "root")) + } + + @Test + fun `Node with no children del`() { + tree.add(100, "a") + tree.add(120, "b") + + tree.remove(120) + + assertTrue(tree.rulesCheck()) + } + + @Test + fun `Node with one children del`() { + tree.add(100, "a") + tree.add(120, "b") + + tree.remove(100) + + assertTrue(tree.rulesCheck()) + } + @Test + fun `Non-existent element del`() { + assertThrows(NodeNotFoundException::class.java ){ tree.remove(100) } } } From cfdd2e7b9f23f5e36aa034a3322059188052799b Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 25 Apr 2023 00:57:23 +0300 Subject: [PATCH 117/203] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BD=D1=91?= =?UTF-8?q?=D1=81=20=D0=B2=D1=81=D0=BF=D0=BE=D0=BC=D0=BE=D0=B3=D0=B0=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D1=84=D1=83=D0=BD=D0=BA?= =?UTF-8?q?=D1=86=D0=B8=D0=B8=20=D0=B2=D0=BD=D0=B8=D0=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/AVLTreeTest.kt | 54 ++++++++++++++---------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/lib/src/test/kotlin/trees/AVLTreeTest.kt b/lib/src/test/kotlin/trees/AVLTreeTest.kt index bf6a8bc..36d0afd 100644 --- a/lib/src/test/kotlin/trees/AVLTreeTest.kt +++ b/lib/src/test/kotlin/trees/AVLTreeTest.kt @@ -1,5 +1,6 @@ package trees +import exceptions.NodeAlreadyExistsException import nodes.AVLNode import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName @@ -11,27 +12,6 @@ import kotlin.math.abs import kotlin.random.Random class AVLTreeTest { - private fun getBalance(node: AVLNode?): Int { - if (node == null) { - return 0 - } - return getHeight(node.left) - getHeight(node.right) - } - - private fun getHeight(node: AVLNode?): Int { - if (node == null) { - return 0 - } - return node.height - } - - fun invariantCheck(node: AVLNode?): Boolean { - if (node == null) { - return true - } - return abs(getBalance(node)) <= 1 && invariantCheck(node.left) && invariantCheck(node.right) - } - @Nested inner class `Remove check` { @Test @@ -42,6 +22,12 @@ class AVLTreeTest { tree.remove(100) assertEquals(null, tree.search(100)?.value) } + @Test + @DisplayName("Non-existence element remove check") + fun `Non-existence element remove check`() { + assertThrows(NodeAlreadyExistsException::class.java) { tree.remove() } + } + @Test @DisplayName("Simple element remove") fun `Simple element remove`() { @@ -98,6 +84,7 @@ class AVLTreeTest { ) } } + @Nested inner class `Add check` { @Test @@ -107,7 +94,6 @@ class AVLTreeTest { tree.add(30, "root") assertEquals("root", tree.search(30)?.value) } - @Test @DisplayName("Left rotation on add") fun `Left rotation on add`() { @@ -141,5 +127,27 @@ class AVLTreeTest { assertEquals(tree.search(list.last())?.value, 0) } } + + } + + private fun getBalance(node: AVLNode?): Int { + if (node == null) { + return 0 + } + return getHeight(node.left) - getHeight(node.right) + } + + private fun getHeight(node: AVLNode?): Int { + if (node == null) { + return 0 + } + return node.height + } + + fun invariantCheck(node: AVLNode?): Boolean { + if (node == null) { + return true + } + return abs(getBalance(node)) <= 1 && invariantCheck(node.left) && invariantCheck(node.right) } -} \ No newline at end of file +} From a8b4b02bef1340015d5a43babc8a840d0155ad01 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 25 Apr 2023 00:59:50 +0300 Subject: [PATCH 118/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B8=D0=BD=D0=B8=D1=86=D0=B8=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8E=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=B0?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=20=D1=82=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/AVLTreeTest.kt | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/src/test/kotlin/trees/AVLTreeTest.kt b/lib/src/test/kotlin/trees/AVLTreeTest.kt index 36d0afd..ab310d3 100644 --- a/lib/src/test/kotlin/trees/AVLTreeTest.kt +++ b/lib/src/test/kotlin/trees/AVLTreeTest.kt @@ -10,14 +10,22 @@ import org.junit.jupiter.api.function.Executable import java.time.Duration.ofMillis import kotlin.math.abs import kotlin.random.Random +import kotlin.test.BeforeTest class AVLTreeTest { + + private lateinit var tree: AVLTree + @BeforeTest + fun init() { + tree = AVLTree() + } + + @Nested inner class `Remove check` { @Test @DisplayName("Root remove") fun `Root remove`() { - val tree = AVLTree() tree.add(100, "root") tree.remove(100) assertEquals(null, tree.search(100)?.value) @@ -31,7 +39,6 @@ class AVLTreeTest { @Test @DisplayName("Simple element remove") fun `Simple element remove`() { - val tree = AVLTree() tree.add(8, "root") tree.add(10, "a") tree.add(14, "b") @@ -48,7 +55,6 @@ class AVLTreeTest { @Test @DisplayName("Element with one child node remove") fun `Element with one child node remove`() { - val tree = AVLTree() tree.add(8, "root") tree.add(10, "a") tree.add(14) @@ -65,7 +71,6 @@ class AVLTreeTest { @Test @DisplayName("Element with two child nodes remove") fun `Element with two child nodes remove`() { - val tree = AVLTree() tree.add(8, "root") tree.add(4, "a") tree.add(1, "b") @@ -90,14 +95,12 @@ class AVLTreeTest { @Test @DisplayName("Simple add") fun `Simple add`() { - val tree = AVLTree() tree.add(30, "root") assertEquals("root", tree.search(30)?.value) } @Test @DisplayName("Left rotation on add") fun `Left rotation on add`() { - val tree = AVLTree() tree.add(1, "root") tree.add(2, "a") tree.add(3, "b") @@ -108,7 +111,6 @@ class AVLTreeTest { @Test @DisplayName("Right rotation on add") fun `Right rotation on add`() { - val tree = AVLTree() tree.add(3, "root") tree.add(2, "a") tree.add(1, "b") @@ -120,11 +122,10 @@ class AVLTreeTest { @DisplayName("Multiply add") fun `Multiply add`() { assertTimeout(ofMillis(1000)) { - val tree = AVLTree() val list : List = (List(100000) { Random.nextInt(1, 100000) }).distinct().toMutableList() for (item in list) - tree.add(item, 0) - assertEquals(tree.search(list.last())?.value, 0) + tree.add(item, "0") + assertEquals(tree.search(list.last())?.value, "0") } } From 9c255f0c2287ceef2bb2919177ed3b686b3e0c1d Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 25 Apr 2023 01:02:23 +0300 Subject: [PATCH 119/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BD=D0=B5=D1=81=D1=82=D0=B0=D0=BD=D0=B4=D0=B0=D1=80?= =?UTF-8?q?=D1=82=D0=BD=D1=8B=D0=B5=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=B4=D0=BB=D1=8F=20add=20=D0=B8=20remove?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/AVLTreeTest.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/src/test/kotlin/trees/AVLTreeTest.kt b/lib/src/test/kotlin/trees/AVLTreeTest.kt index ab310d3..241efce 100644 --- a/lib/src/test/kotlin/trees/AVLTreeTest.kt +++ b/lib/src/test/kotlin/trees/AVLTreeTest.kt @@ -1,6 +1,7 @@ package trees import exceptions.NodeAlreadyExistsException +import exceptions.NodeNotFoundException import nodes.AVLNode import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName @@ -33,7 +34,7 @@ class AVLTreeTest { @Test @DisplayName("Non-existence element remove check") fun `Non-existence element remove check`() { - assertThrows(NodeAlreadyExistsException::class.java) { tree.remove() } + assertThrows(NodeNotFoundException::class.java) { tree.remove(100) } } @Test @@ -98,6 +99,14 @@ class AVLTreeTest { tree.add(30, "root") assertEquals("root", tree.search(30)?.value) } + + @Test + @DisplayName("Non-existence element remove check") + fun `Non-existence element remove check`() { + tree.add(100) + + assertThrows(NodeAlreadyExistsException::class.java) { tree.add(100) } + } @Test @DisplayName("Left rotation on add") fun `Left rotation on add`() { From fd1d6bf702b25af57d5458812dc21fe659eb2901 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 25 Apr 2023 01:04:21 +0300 Subject: [PATCH 120/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2=20?= =?UTF-8?q?=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20search=20=D0=B8=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=BF=D0=B8=D1=81=D0=B0=D0=BB=20=D0=BE=D0=B4=D0=B8?= =?UTF-8?q?=D0=BD=20=D1=82=D0=B5=D1=81=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/AVLTreeTest.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/src/test/kotlin/trees/AVLTreeTest.kt b/lib/src/test/kotlin/trees/AVLTreeTest.kt index 241efce..3f17e39 100644 --- a/lib/src/test/kotlin/trees/AVLTreeTest.kt +++ b/lib/src/test/kotlin/trees/AVLTreeTest.kt @@ -140,6 +140,17 @@ class AVLTreeTest { } + @Nested + inner class `Search check` { + @Test + @DisplayName("Non-existence element search") + fun `Non-existence element search`() { + assertThrows(NodeNotFoundException::class.java) { + tree.search(100) + } + } + } + private fun getBalance(node: AVLNode?): Int { if (node == null) { return 0 From 631b4eafad1a19072598f6137045d3ab35cfa742 Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Wed, 26 Apr 2023 18:20:23 +0300 Subject: [PATCH 121/203] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D0=BA=D0=B8=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2=20RBTree,?= =?UTF-8?q?=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=B4=20RBTree,=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BD=D0=B5=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7?= =?UTF-8?q?=D1=83=D0=B5=D0=BC=D1=8B=D0=B9=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4?= =?UTF-8?q?=20=D0=B2=20RBTNode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/nodes/RBTNode.kt | 11 +---------- lib/src/main/kotlin/trees/RBTree.kt | 12 ++++++------ lib/src/test/kotlin/trees/RBTreeTest.kt | 16 ++++++++++------ 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/lib/src/main/kotlin/nodes/RBTNode.kt b/lib/src/main/kotlin/nodes/RBTNode.kt index d65ad55..adc9e96 100644 --- a/lib/src/main/kotlin/nodes/RBTNode.kt +++ b/lib/src/main/kotlin/nodes/RBTNode.kt @@ -1,19 +1,10 @@ -package RBnode - -import nodes.AbstractNode +package nodes class RBNode, V>(key: K, value: V?) : AbstractNode>(key, value) { var parent: RBNode? = null var color: Color = Color.BLACK - - fun flipColor() { - color = when (color) { - Color.RED -> Color.BLACK - Color.BLACK -> Color.RED - } - } } enum class Color { RED, BLACK } diff --git a/lib/src/main/kotlin/trees/RBTree.kt b/lib/src/main/kotlin/trees/RBTree.kt index 18f4436..4c115f5 100644 --- a/lib/src/main/kotlin/trees/RBTree.kt +++ b/lib/src/main/kotlin/trees/RBTree.kt @@ -1,12 +1,12 @@ package trees -import RBnode.Color -import RBnode.RBNode +import nodes.Color +import nodes.RBNode import exceptions.* class RBTree, V> : AbstractTree>() { - override fun search(key: K): RBNode? { + override fun search(key: K): RBNode { var node = root while (node != null) { node = when { @@ -15,7 +15,7 @@ class RBTree, V> : AbstractTree>() { else -> return node //when found - return node } } - return null + throw NodeNotFoundException() } override fun add(key: K, value: V?) { @@ -39,7 +39,7 @@ class RBTree, V> : AbstractTree>() { newNode.color = Color.RED newNode.parent = parent - if (key < (parent?.key ?: throw NullPointerException("Parent is null"))) { //move up the tree, find needed place + if (key < (parent?.key ?: throw NullNodeException())) { //move up the tree, find needed place parent.left = newNode } else { parent.right = newNode @@ -49,7 +49,7 @@ class RBTree, V> : AbstractTree>() { } override fun remove(key: K) { - val node = search(key) ?: throw NodeNotFoundException() //check if node is real + val node = search(key) //check if node is real removeNode(node) } diff --git a/lib/src/test/kotlin/trees/RBTreeTest.kt b/lib/src/test/kotlin/trees/RBTreeTest.kt index a0d1195..7ff3065 100644 --- a/lib/src/test/kotlin/trees/RBTreeTest.kt +++ b/lib/src/test/kotlin/trees/RBTreeTest.kt @@ -32,7 +32,7 @@ class RBTreeTest { tree.add(50, "root -> left") tree.add(30, "root -> left -> left") - assertEquals("root -> left -> left", tree.search(30)?.value) + assertEquals("root -> left -> left", tree.search(30).value) } @Test @@ -62,7 +62,7 @@ class RBTreeTest { } @Test - @DisplayName("Balance with three elements check") + @DisplayName("Balance with three elements add check") fun `Balance with three elements check`() { tree.add(1) tree.add(2) @@ -71,7 +71,7 @@ class RBTreeTest { assertTrue(tree.rulesCheck()) } @Test - @DisplayName("Balance and repaint simple check") + @DisplayName("Balance and repaint adding check") fun `Balance and repaint simple check`() { tree.add(2) tree.add(1) @@ -83,19 +83,23 @@ class RBTreeTest { @Test @DisplayName("Complex rotate check") - fun `Complex rotate check`() { + fun `Rotate check`() { tree.add(2) tree.add(3) tree.add(4) tree.add(5) tree.add(1) + tree.add(7) + tree.add(6) + tree.add(9) + assertTrue(tree.rulesCheck()) } @Test @DisplayName("Complex rotate and repaint check") - fun `Complex rotate and repaint check`() { + fun `Rotate and repaint check`() { tree.add(2) tree.add(1) tree.add(4) @@ -267,7 +271,7 @@ class RBTreeTest { if (leftCount != rightCount) throw TreeException("Узел [${this.key}, ${this.value}] содержит разное кол-во чёрных узлов в левом [$leftCount] и правом [$rightCount] поддереве") - mCount += leftCount + rightCount + mCount += leftCount return mCount } From 36a650d5d9ece9bf48f796d11704e47d2808acc5 Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Thu, 27 Apr 2023 02:45:50 +0300 Subject: [PATCH 122/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=80?= =?UTF-8?q?=D0=B8=D0=B8=20=D0=BA=20=D0=BA=D0=BE=D0=B4=D1=83=20RBTree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/trees/RBTree.kt | 70 ++++++++++++++--------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/lib/src/main/kotlin/trees/RBTree.kt b/lib/src/main/kotlin/trees/RBTree.kt index 4c115f5..eefa651 100644 --- a/lib/src/main/kotlin/trees/RBTree.kt +++ b/lib/src/main/kotlin/trees/RBTree.kt @@ -12,18 +12,18 @@ class RBTree, V> : AbstractTree>() { node = when { key < node.key -> node.left key > node.key -> node.right - else -> return node //when found - return node + else -> return node //когда нода найдена - возвращаем ее } } throw NodeNotFoundException() } override fun add(key: K, value: V?) { - if (contains(key)) { // check if node with the same key already exists + if (contains(key)) { // проверяем, существует ли нода с таким ключом, если да - выводим сообщение throw NodeAlreadyExistsException() } val newNode = RBNode(key, value) - if (root == null) { // if there is no root, make the node - new root + if (root == null) { // если нет корня - записываем в корень root = newNode root?.color = Color.BLACK return @@ -31,7 +31,7 @@ class RBTree, V> : AbstractTree>() { var node = root var parent: RBNode? = null - while (node != null) { //move down the tree + while (node != null) { //спускаемся вниз по дереву поэлементно до null-листа parent = node node = if (key < node.key) node.left else node.right } @@ -39,30 +39,30 @@ class RBTree, V> : AbstractTree>() { newNode.color = Color.RED newNode.parent = parent - if (key < (parent?.key ?: throw NullNodeException())) { //move up the tree, find needed place + if (key < (parent?.key ?: throw NullNodeException())) { //заменяем нужный null-лист элементом parent.left = newNode } else { parent.right = newNode } - fixInsert(newNode) + fixInsert(newNode) //проверяем на баланс } override fun remove(key: K) { - val node = search(key) //check if node is real + val node = search(key) //проверяем на существование ноду removeNode(node) } private fun removeNode(node: RBNode) { - val replacementNode = when { - node.left == null -> node.right + val replacementNode = when { //объявляем ноду, которая заменит удаяемую + node.left == null -> node.right //если один ребенок node.right == null -> node.left - else -> { + else -> { //если два ребенка var successor = node.right - while (successor?.left != null) { + while (successor?.left != null) { //ищем самого левого потомка правого ребенка удаляемой ноды successor = successor.left } - if (successor?.parent != node) { + if (successor?.parent != node) { //если у правого ребенка удаляемой ноды есть дети transplant(successor ?: throw IllegalArgumentException("Node cannot be null"), successor.right) successor.right = node.right successor.right?.parent = successor @@ -92,38 +92,38 @@ class RBTree, V> : AbstractTree>() { private fun fixInsert(node: RBNode) { var newNode = node - while (newNode.parent?.color == Color.RED) { - if (newNode.parent == newNode.parent?.parent?.left) { + while (newNode.parent?.color == Color.RED) { // балансируем, пока идут две красные ноды подряд + if (newNode.parent == newNode.parent?.parent?.left) { //если отец - левый сын дедушки val uncle = newNode.parent?.parent?.right if (uncle?.color == Color.RED) { newNode.parent?.color = Color.BLACK uncle.color = Color.BLACK newNode.parent?.parent?.color = Color.RED - newNode = newNode.parent?.parent ?: throw IllegalArgumentException("Node cannot be null") - } else { + newNode = newNode.parent?.parent ?: throw NullNodeException() + } else { // если дядя черный или его нет if (newNode == newNode.parent?.right) { - newNode = newNode.parent ?: throw IllegalArgumentException("Node cannot be null") + newNode = newNode.parent ?: throw NullNodeException() leftRotate(newNode) } newNode.parent?.color = Color.BLACK newNode.parent?.parent?.color = Color.RED - newNode.parent?.parent?.let { rightRotate(it) } ?: throw IllegalArgumentException("Node cannot be null") + newNode.parent?.parent?.let { rightRotate(it) } ?: throw NullNodeException() } - } else { + } else { //если отец - правый сын дедушки val uncle = newNode.parent?.parent?.left if (uncle?.color == Color.RED) { newNode.parent?.color = Color.BLACK uncle.color = Color.BLACK newNode.parent?.parent?.color = Color.RED - newNode = newNode.parent?.parent ?: throw IllegalArgumentException("Node cannot be null") - } else { + newNode = newNode.parent?.parent ?: throw NullNodeException() + } else { //если дядя черный или его нет if (newNode == newNode.parent?.left) { - newNode = newNode.parent ?: throw IllegalArgumentException("Node cannot be null") + newNode = newNode.parent ?: throw NullNodeException() rightRotate(newNode) } newNode.parent?.color = Color.BLACK newNode.parent?.parent?.color = Color.RED - newNode.parent?.parent?.let { leftRotate(it) } ?: throw IllegalArgumentException("Node cannot be null") + newNode.parent?.parent?.let { leftRotate(it) } ?: throw NullNodeException() } } } @@ -132,50 +132,50 @@ class RBTree, V> : AbstractTree>() { private fun fixDelete(node: RBNode?) { var currentNode = node - while (currentNode != root && currentNode?.color == Color.BLACK) { - if (currentNode == currentNode.parent?.left) { + while (currentNode != root && currentNode?.color == Color.BLACK) { //пока нода не корень и она черная + if (currentNode == currentNode.parent?.left) { //если нода - левый сын var sibling = currentNode.parent?.right - if (sibling?.color == Color.RED) { + if (sibling?.color == Color.RED) { //если брат - красный sibling.color = Color.BLACK currentNode.parent?.color = Color.RED currentNode.parent?.let { leftRotate(it) } sibling = currentNode.parent?.right } - if (sibling?.left?.color == Color.BLACK && sibling.right?.color == Color.BLACK) { + if (sibling?.left?.color == Color.BLACK && sibling.right?.color == Color.BLACK) { //если дети брата черные sibling.color = Color.RED currentNode = currentNode.parent } else { - if (sibling?.right?.color == Color.BLACK) { + if (sibling?.right?.color == Color.BLACK) { //левый сын брата красный, правый - черный sibling.left?.color = Color.BLACK sibling.color = Color.RED sibling.let { rightRotate(it) } sibling = currentNode.parent?.right } - sibling?.color = currentNode.parent?.color ?: throw IllegalStateException("Parent color is null") + sibling?.color = currentNode.parent?.color ?: throw TreeException("Parent color is null") currentNode.parent?.color = Color.BLACK sibling?.right?.color = Color.BLACK currentNode.parent?.let { leftRotate(it) } currentNode = root } - } else { + } else { //нода - правый сын var sibling = currentNode.parent?.left - if (sibling?.color == Color.RED) { + if (sibling?.color == Color.RED) { //если брат - красный sibling.color = Color.BLACK currentNode.parent?.color = Color.RED currentNode.parent?.let { rightRotate(it) } sibling = currentNode.parent?.left } - if (sibling?.right?.color == Color.BLACK && sibling.left?.color == Color.BLACK) { + if (sibling?.right?.color == Color.BLACK && sibling.left?.color == Color.BLACK) { //дети брата черные sibling.color = Color.RED currentNode = currentNode.parent } else { - if (sibling?.left?.color == Color.BLACK) { + if (sibling?.left?.color == Color.BLACK) { //левый сын брата черный, правый - красный sibling.right?.color = Color.BLACK sibling.color = Color.RED sibling.let { leftRotate(it) } sibling = currentNode.parent?.left } - sibling?.color = currentNode.parent?.color ?: throw IllegalStateException("Parent color is null") + sibling?.color = currentNode.parent?.color ?: throw TreeException("Parent color is null") currentNode.parent?.color = Color.BLACK sibling?.left?.color = Color.BLACK currentNode.parent?.let { rightRotate(it) } @@ -206,7 +206,7 @@ class RBTree, V> : AbstractTree>() { } private fun rightRotate(node: RBNode) { - val leftChild = node.left ?: throw IllegalStateException("Left child is null") + val leftChild = node.left ?: throw NullNodeException() node.left = leftChild.right if (leftChild.right != null) { leftChild.right!!.parent = node From 8f493b18311315fcf93fb908fbaa3dbfb3c243ea Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Thu, 27 Apr 2023 13:45:55 +0300 Subject: [PATCH 123/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8E=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=B8=D1=81=D0=BA=D0=B0=20=D0=B2=20=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=B0=D1=85=20AVL,=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=B8=D1=81=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BF=D1=80=D0=B8=20=D0=BF=D0=BE=D0=B8=D1=81?= =?UTF-8?q?=D0=BA=D0=B5=20/=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B5=D1=81=D1=83=D1=89=D0=B5=D1=81=D1=82=D0=B2?= =?UTF-8?q?=D1=83=D1=8E=D1=89=D0=B5=D0=B9=20=D0=BD=D0=BE=D0=B4=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/trees/AVLTree.kt | 7 +-- lib/src/test/kotlin/trees/AVLTreeTest.kt | 61 ++++++++++++++---------- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/lib/src/main/kotlin/trees/AVLTree.kt b/lib/src/main/kotlin/trees/AVLTree.kt index a9ad49b..94d64e5 100644 --- a/lib/src/main/kotlin/trees/AVLTree.kt +++ b/lib/src/main/kotlin/trees/AVLTree.kt @@ -1,6 +1,7 @@ package trees import exceptions.NodeAlreadyExistsException +import exceptions.NodeNotFoundException import exceptions.NullNodeException import nodes.AVLNode import kotlin.math.max @@ -31,7 +32,7 @@ class AVLTree, V> : AbstractTree>() { override fun remove(key: K) { fun removeRecursive(node: AVLNode?, key: K): AVLNode? { if (node == null) { - return null + throw NodeNotFoundException() } if (key < node.key) { @@ -57,7 +58,7 @@ class AVLTree, V> : AbstractTree>() { root = removeRecursive(root, key) } - override fun search(key: K): AVLNode? { + override fun search(key: K): AVLNode { fun searchRecursive(node: AVLNode?, key: K): AVLNode? { if (node == null) { return null @@ -72,7 +73,7 @@ class AVLTree, V> : AbstractTree>() { } } - return searchRecursive(root, key) + return searchRecursive(root, key) ?: throw NodeNotFoundException() } private fun findMin(node: AVLNode?): AVLNode? = if (node?.left != null) findMin(node.left) else node diff --git a/lib/src/test/kotlin/trees/AVLTreeTest.kt b/lib/src/test/kotlin/trees/AVLTreeTest.kt index 3f17e39..543cbbd 100644 --- a/lib/src/test/kotlin/trees/AVLTreeTest.kt +++ b/lib/src/test/kotlin/trees/AVLTreeTest.kt @@ -29,7 +29,7 @@ class AVLTreeTest { fun `Root remove`() { tree.add(100, "root") tree.remove(100) - assertEquals(null, tree.search(100)?.value) + assertEquals(null, tree.testSearch(100)?.value) } @Test @DisplayName("Non-existence element remove check") @@ -46,11 +46,11 @@ class AVLTreeTest { tree.add(13) tree.remove(13) assertAll("elements", - Executable { assertEquals("root", tree.search(8)?.value) }, - Executable { assertEquals("a", tree.search(10)?.value) }, - Executable { assertEquals("b", tree.search(14)?.value) }, - Executable { assertEquals(null, tree.search(13)?.value) }, - Executable { assertEquals(true, invariantCheck(tree.search(10))) } + Executable { assertEquals("root", tree.testSearch(8)?.value) }, + Executable { assertEquals("a", tree.testSearch(10)?.value) }, + Executable { assertEquals("b", tree.testSearch(14)?.value) }, + Executable { assertEquals(null, tree.testSearch(13)?.value) }, + Executable { assertEquals(true, invariantCheck(tree.testSearch(10))) } ) } @Test @@ -62,11 +62,11 @@ class AVLTreeTest { tree.add(13, "c") tree.remove(14) assertAll("elements", - Executable { assertEquals("root", tree.search(8)?.value) }, - Executable { assertEquals("a", tree.search(10)?.value) }, - Executable { assertEquals("c", tree.search(13)?.value) }, - Executable { assertEquals(null, tree.search(14)?.value) }, - Executable { assertEquals(true, invariantCheck(tree.search(10))) } + Executable { assertEquals("root", tree.testSearch(8)?.value) }, + Executable { assertEquals("a", tree.testSearch(10)?.value) }, + Executable { assertEquals("c", tree.testSearch(13)?.value) }, + Executable { assertEquals(null, tree.testSearch(14)?.value) }, + Executable { assertEquals(true, invariantCheck(tree.testSearch(10))) } ) } @Test @@ -77,16 +77,17 @@ class AVLTreeTest { tree.add(1, "b") tree.add(6, "c") tree.add(7, "d") + tree.add(3, "e") tree.remove(3) assertAll("elements", - Executable { assertEquals("a", tree.search(4)?.value) }, - Executable { assertEquals("b", tree.search(1)?.value) }, - Executable { assertEquals(null, tree.search(3)?.value) }, - Executable { assertEquals("c", tree.search(6)?.value) }, - Executable { assertEquals("d", tree.search(7)?.value) }, - Executable { assertEquals("root", tree.search(8)?.value) }, - Executable { assertEquals(true, invariantCheck(tree.search(4))) } + Executable { assertEquals("a", tree.testSearch(4)?.value) }, + Executable { assertEquals("b", tree.testSearch(1)?.value) }, + Executable { assertEquals(null, tree.testSearch(3)?.value) }, + Executable { assertEquals("c", tree.testSearch(6)?.value) }, + Executable { assertEquals("d", tree.testSearch(7)?.value) }, + Executable { assertEquals("root", tree.testSearch(8)?.value) }, + Executable { assertEquals(true, invariantCheck(tree.testSearch(4))) } ) } } @@ -97,7 +98,7 @@ class AVLTreeTest { @DisplayName("Simple add") fun `Simple add`() { tree.add(30, "root") - assertEquals("root", tree.search(30)?.value) + assertEquals("root", tree.testSearch(30)?.value) } @Test @@ -113,8 +114,8 @@ class AVLTreeTest { tree.add(1, "root") tree.add(2, "a") tree.add(3, "b") - assertEquals("root", tree.search(2)?.left?.value) - assertEquals(true, invariantCheck(tree.search(2))) + assertEquals("root", tree.testSearch(2)?.left?.value) + assertEquals(true, invariantCheck(tree.testSearch(2))) } @Test @@ -123,8 +124,8 @@ class AVLTreeTest { tree.add(3, "root") tree.add(2, "a") tree.add(1, "b") - assertEquals("root", tree.search(2)?.right?.value) - assertEquals(true, invariantCheck(tree.search(2))) + assertEquals("root", tree.testSearch(2)?.right?.value) + assertEquals(true, invariantCheck(tree.testSearch(2))) } @Test @@ -134,7 +135,7 @@ class AVLTreeTest { val list : List = (List(100000) { Random.nextInt(1, 100000) }).distinct().toMutableList() for (item in list) tree.add(item, "0") - assertEquals(tree.search(list.last())?.value, "0") + assertEquals(tree.testSearch(list.last())?.value, "0") } } @@ -151,6 +152,18 @@ class AVLTreeTest { } } + private fun, V> AVLTree.testSearch(key: K): AVLNode? { + fun , V> AVLNode.recursiveSearch(key: K): AVLNode? = + when (key.compareTo(this.key)) { + 1 -> this.right?.recursiveSearch(key) + 0 -> this + -1 -> this.left?.recursiveSearch(key) + else -> null + } + return this.root?.recursiveSearch(key) + } + + private fun getBalance(node: AVLNode?): Int { if (node == null) { return 0 From 958c88bfefb77ae4305afde0371ee416deb5d763 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 27 Apr 2023 21:38:08 +0300 Subject: [PATCH 124/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=20=D0=BD=D0=B0=20search=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20AVLTree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/AVLTreeTest.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/src/test/kotlin/trees/AVLTreeTest.kt b/lib/src/test/kotlin/trees/AVLTreeTest.kt index 543cbbd..b25d0a5 100644 --- a/lib/src/test/kotlin/trees/AVLTreeTest.kt +++ b/lib/src/test/kotlin/trees/AVLTreeTest.kt @@ -150,6 +150,14 @@ class AVLTreeTest { tree.search(100) } } + + @Test + @DisplayName("Existence element search") + fun `Existence element search`() { + tree.add(100, "root") + + assertEquals("root", tree.search(100).value) + } } private fun, V> AVLTree.testSearch(key: K): AVLNode? { @@ -163,7 +171,6 @@ class AVLTreeTest { return this.root?.recursiveSearch(key) } - private fun getBalance(node: AVLNode?): Int { if (node == null) { return 0 From 7500f9c100dabc06e3e66b2a04cb98e458ec5ec2 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 27 Apr 2023 21:41:55 +0300 Subject: [PATCH 125/203] =?UTF-8?q?=D0=A1=D0=BE=D0=BA=D1=80=D0=B0=D1=82?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=B4=D0=BB=D0=B8=D0=BD=D1=83=20=D0=B2=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D0=BC=D0=BE=D0=B3=D0=B0=D1=82=D0=B5=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=BE=D0=B2?= =?UTF-8?q?,=20=D0=BF=D0=BE=D1=87=D0=B8=D1=81=D1=82=D0=B8=D0=BB=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/AVLTreeTest.kt | 31 +++++++++++------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/lib/src/test/kotlin/trees/AVLTreeTest.kt b/lib/src/test/kotlin/trees/AVLTreeTest.kt index b25d0a5..36e141d 100644 --- a/lib/src/test/kotlin/trees/AVLTreeTest.kt +++ b/lib/src/test/kotlin/trees/AVLTreeTest.kt @@ -16,6 +16,7 @@ import kotlin.test.BeforeTest class AVLTreeTest { private lateinit var tree: AVLTree + @BeforeTest fun init() { tree = AVLTree() @@ -31,6 +32,7 @@ class AVLTreeTest { tree.remove(100) assertEquals(null, tree.testSearch(100)?.value) } + @Test @DisplayName("Non-existence element remove check") fun `Non-existence element remove check`() { @@ -53,6 +55,7 @@ class AVLTreeTest { Executable { assertEquals(true, invariantCheck(tree.testSearch(10))) } ) } + @Test @DisplayName("Element with one child node remove") fun `Element with one child node remove`() { @@ -69,6 +72,7 @@ class AVLTreeTest { Executable { assertEquals(true, invariantCheck(tree.testSearch(10))) } ) } + @Test @DisplayName("Element with two child nodes remove") fun `Element with two child nodes remove`() { @@ -108,6 +112,7 @@ class AVLTreeTest { assertThrows(NodeAlreadyExistsException::class.java) { tree.add(100) } } + @Test @DisplayName("Left rotation on add") fun `Left rotation on add`() { @@ -132,7 +137,7 @@ class AVLTreeTest { @DisplayName("Multiply add") fun `Multiply add`() { assertTimeout(ofMillis(1000)) { - val list : List = (List(100000) { Random.nextInt(1, 100000) }).distinct().toMutableList() + val list: List = (List(100000) { Random.nextInt(1, 100000) }).distinct().toMutableList() for (item in list) tree.add(item, "0") assertEquals(tree.testSearch(list.last())?.value, "0") @@ -160,7 +165,7 @@ class AVLTreeTest { } } - private fun, V> AVLTree.testSearch(key: K): AVLNode? { + private fun , V> AVLTree.testSearch(key: K): AVLNode? { fun , V> AVLNode.recursiveSearch(key: K): AVLNode? = when (key.compareTo(this.key)) { 1 -> this.right?.recursiveSearch(key) @@ -172,23 +177,15 @@ class AVLTreeTest { } private fun getBalance(node: AVLNode?): Int { - if (node == null) { - return 0 - } - return getHeight(node.left) - getHeight(node.right) - } - - private fun getHeight(node: AVLNode?): Int { - if (node == null) { - return 0 - } - return node.height + return if (node == null) + 0 + else getHeight(node.left) - getHeight(node.right) } + private fun getHeight(node: AVLNode?): Int = node?.height ?: 0 fun invariantCheck(node: AVLNode?): Boolean { - if (node == null) { - return true - } - return abs(getBalance(node)) <= 1 && invariantCheck(node.left) && invariantCheck(node.right) + return if (node == null) + true + else abs(getBalance(node)) <= 1 && invariantCheck(node.left) && invariantCheck(node.right) } } From d1d2c49f51724b5815728d43f47f4658c6049bc3 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 27 Apr 2023 21:46:31 +0300 Subject: [PATCH 126/203] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0?= =?UTF-8?q?=20=D0=B2=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B5=20recursiveSea?= =?UTF-8?q?rch=20=D0=B2=20BinaryTreeTest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/BinaryTreeTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/test/kotlin/trees/BinaryTreeTest.kt b/lib/src/test/kotlin/trees/BinaryTreeTest.kt index bfcb229..80adf4d 100644 --- a/lib/src/test/kotlin/trees/BinaryTreeTest.kt +++ b/lib/src/test/kotlin/trees/BinaryTreeTest.kt @@ -200,9 +200,9 @@ class BinaryTreeTest { */ private fun , V> BinaryNode.recursiveSearch(key: K): BinaryNode? = when (key.compareTo(this.key)) { - 1 -> this.right?.search(key) + 1 -> this.right?.recursiveSearch(key) 0 -> this - -1 -> this.left?.search(key) + -1 -> this.left?.recursiveSearch(key) else -> null } From 3a64223f7d916e5c85dbf44b966259e48b0944a1 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 27 Apr 2023 22:03:03 +0300 Subject: [PATCH 127/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=20=D0=BD=D0=B0=20remove=20?= =?UTF-8?q?=D0=B2=20RBTreeTest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/AVLTreeTest.kt | 1 - lib/src/test/kotlin/trees/RBTreeTest.kt | 30 ++++++++++++++++++------ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/lib/src/test/kotlin/trees/AVLTreeTest.kt b/lib/src/test/kotlin/trees/AVLTreeTest.kt index 36e141d..73c1606 100644 --- a/lib/src/test/kotlin/trees/AVLTreeTest.kt +++ b/lib/src/test/kotlin/trees/AVLTreeTest.kt @@ -22,7 +22,6 @@ class AVLTreeTest { tree = AVLTree() } - @Nested inner class `Remove check` { @Test diff --git a/lib/src/test/kotlin/trees/RBTreeTest.kt b/lib/src/test/kotlin/trees/RBTreeTest.kt index 7ff3065..4787b92 100644 --- a/lib/src/test/kotlin/trees/RBTreeTest.kt +++ b/lib/src/test/kotlin/trees/RBTreeTest.kt @@ -1,12 +1,9 @@ -import exceptions.NodeAlreadyExistsException -import exceptions.NodeNotFoundException -import exceptions.NullNodeException -import exceptions.TreeException -import nodes.Color -import nodes.RBNode +import exceptions.* +import nodes.* import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.RepeatedTest import org.junit.jupiter.api.Test import org.junit.jupiter.api.function.Executable import trees.RBTree @@ -70,6 +67,7 @@ class RBTreeTest { assertTrue(tree.rulesCheck()) } + @Test @DisplayName("Balance and repaint adding check") fun `Balance and repaint simple check`() { @@ -155,6 +153,7 @@ class RBTreeTest { @Nested inner class `Remove check` { @Test + @DisplayName("Root element del") fun `Root element del`() { tree.add(100, "root") @@ -164,6 +163,7 @@ class RBTreeTest { } @Test + @DisplayName("Node with no children del") fun `Node with no children del`() { tree.add(100, "a") tree.add(120, "b") @@ -174,6 +174,7 @@ class RBTreeTest { } @Test + @DisplayName("Node with one children del") fun `Node with one children del`() { tree.add(100, "a") tree.add(120, "b") @@ -182,9 +183,24 @@ class RBTreeTest { assertTrue(tree.rulesCheck()) } + + @Test + @DisplayName("Random tree element del") + @RepeatedTest(10) + fun `Random tree element del`() { + val list: List = (List(1000) { Random.nextInt(1, 100000) }).distinct().toMutableList() + + for (item in list) + tree.add(item, "a") + + tree.remove(list.asSequence().shuffled().first()) + + assertTrue(tree.rulesCheck()) + } @Test + @DisplayName("Non-existent element del") fun `Non-existent element del`() { - assertThrows(NodeNotFoundException::class.java ){ tree.remove(100) } + assertThrows(NodeNotFoundException::class.java) { tree.remove(100) } } } From 29f9fa9ae24715ca6b733a2cd846ed9d3f324d26 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 27 Apr 2023 22:28:10 +0300 Subject: [PATCH 128/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B4=D0=B2=D0=B0=20=D0=BD=D0=BE=D0=B2=D1=8B=D1=85=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=B0=20=D0=BD=D0=B0=20remove?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/test/kotlin/trees/RBTreeTest.kt | 47 +++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/lib/src/test/kotlin/trees/RBTreeTest.kt b/lib/src/test/kotlin/trees/RBTreeTest.kt index 4787b92..e9ab219 100644 --- a/lib/src/test/kotlin/trees/RBTreeTest.kt +++ b/lib/src/test/kotlin/trees/RBTreeTest.kt @@ -156,6 +156,8 @@ class RBTreeTest { @DisplayName("Root element del") fun `Root element del`() { tree.add(100, "root") + tree.add(120) + tree.add(50) tree.remove(100) @@ -184,6 +186,51 @@ class RBTreeTest { assertTrue(tree.rulesCheck()) } + @Test + @DisplayName("Black node simple remove test") + fun `Black node simple remove test`() { + tree.add(100, "P") + tree.add(120, "S") + tree.add(50, "Sl") + tree.add(125, "Sr") + tree.add(115, "Sr") + + tree.remove(120) + + assertTrue(tree.rulesCheck()) + } + @Test + @DisplayName("Red node with black children remove test") + fun `Red node with black children remove test`() { + tree.add(13) + tree.add(17) + tree.add(8) + tree.add(25) + tree.add(1) + tree.add(11) + tree.add(15) + tree.add(27) + + tree.remove(17) + + assertTrue(tree.rulesCheck()) + } + + @Test + @DisplayName("Black node with red children remove test") + fun `Black node with red children remove test`() { + tree.add(13) + tree.add(17) + tree.add(8) + tree.add(25) + tree.add(1) + tree.add(11) + + tree.remove(8) + + assertTrue(tree.rulesCheck()) + } + @Test @DisplayName("Random tree element del") @RepeatedTest(10) From 4024d0093bf9b0a091c415344a1fdb33d96f816e Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 27 Apr 2023 22:29:18 +0300 Subject: [PATCH 129/203] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=20=D0=B2=D1=81=D0=B5=20=D0=B1=D0=B0?= =?UTF-8?q?=D0=B7=D1=8B=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B2=20?= =?UTF-8?q?=D0=BE=D0=B4=D0=B8=D0=BD=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/{database/RBT => databases/RBTree}/RBTDataBase.kt | 2 +- lib/src/test/kotlin/trees/RBTreeTest.kt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) rename lib/src/main/kotlin/{database/RBT => databases/RBTree}/RBTDataBase.kt (96%) diff --git a/lib/src/main/kotlin/database/RBT/RBTDataBase.kt b/lib/src/main/kotlin/databases/RBTree/RBTDataBase.kt similarity index 96% rename from lib/src/main/kotlin/database/RBT/RBTDataBase.kt rename to lib/src/main/kotlin/databases/RBTree/RBTDataBase.kt index e557082..c1654a5 100644 --- a/lib/src/main/kotlin/database/RBT/RBTDataBase.kt +++ b/lib/src/main/kotlin/databases/RBTree/RBTDataBase.kt @@ -1,4 +1,4 @@ -package database.RBT +package databases.RBTree import trees.RBTree import java.io.* diff --git a/lib/src/test/kotlin/trees/RBTreeTest.kt b/lib/src/test/kotlin/trees/RBTreeTest.kt index e9ab219..6afad17 100644 --- a/lib/src/test/kotlin/trees/RBTreeTest.kt +++ b/lib/src/test/kotlin/trees/RBTreeTest.kt @@ -199,6 +199,7 @@ class RBTreeTest { assertTrue(tree.rulesCheck()) } + @Test @DisplayName("Red node with black children remove test") fun `Red node with black children remove test`() { @@ -244,6 +245,7 @@ class RBTreeTest { assertTrue(tree.rulesCheck()) } + @Test @DisplayName("Non-existent element del") fun `Non-existent element del`() { From 7ca01c1ea686c7ec065dbba1130ea0bc31ca926c Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Fri, 28 Apr 2023 23:08:28 +0300 Subject: [PATCH 130/203] =?UTF-8?q?=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D1=8B=20=D0=BE=D0=BA=D0=BD=D0=B0?= =?UTF-8?q?=20=D0=B8=20=D0=BC=D0=B5=D0=BD=D1=8E,=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=B8=D1=85=20=D0=B2=D1=8B=D0=B2?= =?UTF-8?q?=D0=BE=D0=B4=20=D0=BD=D0=B0=20=D1=8D=D0=BA=D1=80=D0=B0=D0=BD=20?= =?UTF-8?q?=D0=B2=20App?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/GUIClasses/FrameClass.kt | 45 +++++++++++++ App/src/main/kotlin/GUIClasses/MenuClass.kt | 69 ++++++++++++++++++++ App/src/main/kotlin/app/App.kt | 10 ++- lib/src/main/kotlin/trees/AVLTree.kt | 3 +- 4 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 App/src/main/kotlin/GUIClasses/FrameClass.kt create mode 100644 App/src/main/kotlin/GUIClasses/MenuClass.kt diff --git a/App/src/main/kotlin/GUIClasses/FrameClass.kt b/App/src/main/kotlin/GUIClasses/FrameClass.kt new file mode 100644 index 0000000..c35d13e --- /dev/null +++ b/App/src/main/kotlin/GUIClasses/FrameClass.kt @@ -0,0 +1,45 @@ +package Frame + +import javax.swing.* + +class Frame(name: String, width: Int, heidht: Int, locX: Int, locY: Int) : JFrame() { + init { + // Устанавливаем заголовок окна + title = name + + // Устанавливаем размер окна + setSize(width, heidht) + + // Устанавливаем положение окна на экране + setLocation(locX, locY) + + // Создаем панель с прокруткой + val scrollPane = JScrollPane() + + // Установка изображения + val icon = ImageIcon("tree.jpg").image + iconImage = icon + + // Создаем панель с компонентами + val panel = JPanel() + + // Добавляем панель на панель с прокруткой + scrollPane.setViewportView(panel) + + // Добавляем панель с прокруткой на окно + contentPane.add(scrollPane) + + // Устанавливаем режим прокрутки по вертикали и горизонтали + scrollPane.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED + scrollPane.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED + + //Запрет на форматирование окна + isResizable = false + + // Устанавливаем операцию закрытия окна + defaultCloseOperation = JFrame.EXIT_ON_CLOSE + + // Отображаем окно + isVisible = true + } +} diff --git a/App/src/main/kotlin/GUIClasses/MenuClass.kt b/App/src/main/kotlin/GUIClasses/MenuClass.kt new file mode 100644 index 0000000..298b1e3 --- /dev/null +++ b/App/src/main/kotlin/GUIClasses/MenuClass.kt @@ -0,0 +1,69 @@ +package Menu + +import java.awt.Color +import javax.swing.JMenu +import javax.swing.JMenuBar +import javax.swing.JMenuItem + +class MenuClass() : JMenuBar() { + init { + val menu = JMenu("Выбор Дерева") + val BinTree = JMenuItem("Binary Tree") + val AVLTree = JMenuItem("AVL-Tree") + val RBTree = JMenuItem("Red-black Tree") + + menu.add(BinTree) + menu.add(AVLTree) + menu.add(RBTree) + + add(menu) + + // Флаги выбранных элементов меню + var binTreeSelected = false + var avlTreeSelected = false + var rbTreeSelected = false + + // Обновляем цвета при выборе другого варианта + fun resetMenuItemsChoosing() { + BinTree.background = Color.WHITE + AVLTree.background = Color.WHITE + RBTree.background = Color.WHITE + + } + + // Функция для обновления видимости элементов меню + fun updateMenuItemsChoosing() { + if (binTreeSelected) {BinTree.background = Color.PINK} + if (avlTreeSelected) {AVLTree.background = Color.PINK} + if (rbTreeSelected) {RBTree.background = Color.PINK} + + } + + // Слушатель событий для элемента меню "Binary Tree" + BinTree.addActionListener { + resetMenuItemsChoosing() + binTreeSelected = true + avlTreeSelected = false + rbTreeSelected = false + updateMenuItemsChoosing() + } + + // Слушатель событий для элемента меню "AVL-Tree" + AVLTree.addActionListener { + resetMenuItemsChoosing() + binTreeSelected = false + avlTreeSelected = true + rbTreeSelected = false + updateMenuItemsChoosing() + } + + // Слушатель событий для элемента меню "Red-black Tree" + RBTree.addActionListener { + resetMenuItemsChoosing() + binTreeSelected = false + avlTreeSelected = false + rbTreeSelected = true + updateMenuItemsChoosing() + } + } +} \ No newline at end of file diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index ed1beeb..d779767 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -1,9 +1,13 @@ package app +import javax.swing.* import trees.BinaryTree +import Frame.* +import Menu.* fun main() { - val tree = BinaryTree() - tree.add(100, "Hello World!") - println(tree.search(100)) + val GraphFrame = Frame("Treeple",1000, 700, 360, 50) + val MenuFrame = Frame("Treeple Menu",300, 400, 50, 50) + + val menuBar = MenuClass() } \ No newline at end of file diff --git a/lib/src/main/kotlin/trees/AVLTree.kt b/lib/src/main/kotlin/trees/AVLTree.kt index a9ad49b..3b136bf 100644 --- a/lib/src/main/kotlin/trees/AVLTree.kt +++ b/lib/src/main/kotlin/trees/AVLTree.kt @@ -1,7 +1,6 @@ package trees -import exceptions.NodeAlreadyExistsException -import exceptions.NullNodeException +import exceptions.* import nodes.AVLNode import kotlin.math.max From df2bd2e18b5d81a18694ae2f1f34c7814e51628b Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 29 Apr 2023 01:45:54 +0300 Subject: [PATCH 131/203] =?UTF-8?q?(MenuClass):=20=D0=92=D1=8B=D0=BD=D0=B5?= =?UTF-8?q?=D1=81=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B8?= =?UTF-8?q?=D0=B7=20=D0=BA=D0=BE=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B0=20=D0=B2=20=D1=81=D0=B0=D0=BC=20=D0=BA=D0=BB?= =?UTF-8?q?=D0=B0=D1=81=D1=81=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE=D0=B2?= =?UTF-8?q?=D1=8B=D1=88=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=87=D0=B8=D1=82=D0=B0?= =?UTF-8?q?=D0=B5=D0=BC=D0=BE=D1=81=D1=82=D0=B8.=20=D0=A1=D0=BE=D0=BA?= =?UTF-8?q?=D1=80=D0=B0=D1=82=D0=B8=D0=BB=20=D0=BA=D0=BE=D0=BB-=D0=B2?= =?UTF-8?q?=D0=BE=20=D1=81=D1=82=D1=80=D0=BE=D0=BA=20=D0=BA=D0=BE=D0=B4?= =?UTF-8?q?=D0=B0,=20=D1=83=D0=B1=D1=80=D0=B0=D0=B2=20=D0=BF=D0=BE=D0=B2?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B5=D0=BD=D0=B8=D1=8F.=20=D0=A1=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B0=D0=BB=20=D0=BB=D0=BE=D0=BA=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D0=BF=D0=BE=D0=BB=D1=8F=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/GUIClasses/MenuClass.kt | 69 ------------------- App/src/main/kotlin/app/App.kt | 20 ++++-- .../FrameClass.kt => guiClasses/Frame.kt} | 8 +-- App/src/main/kotlin/guiClasses/MenuClass.kt | 49 +++++++++++++ 4 files changed, 67 insertions(+), 79 deletions(-) delete mode 100644 App/src/main/kotlin/GUIClasses/MenuClass.kt rename App/src/main/kotlin/{GUIClasses/FrameClass.kt => guiClasses/Frame.kt} (89%) create mode 100644 App/src/main/kotlin/guiClasses/MenuClass.kt diff --git a/App/src/main/kotlin/GUIClasses/MenuClass.kt b/App/src/main/kotlin/GUIClasses/MenuClass.kt deleted file mode 100644 index 298b1e3..0000000 --- a/App/src/main/kotlin/GUIClasses/MenuClass.kt +++ /dev/null @@ -1,69 +0,0 @@ -package Menu - -import java.awt.Color -import javax.swing.JMenu -import javax.swing.JMenuBar -import javax.swing.JMenuItem - -class MenuClass() : JMenuBar() { - init { - val menu = JMenu("Выбор Дерева") - val BinTree = JMenuItem("Binary Tree") - val AVLTree = JMenuItem("AVL-Tree") - val RBTree = JMenuItem("Red-black Tree") - - menu.add(BinTree) - menu.add(AVLTree) - menu.add(RBTree) - - add(menu) - - // Флаги выбранных элементов меню - var binTreeSelected = false - var avlTreeSelected = false - var rbTreeSelected = false - - // Обновляем цвета при выборе другого варианта - fun resetMenuItemsChoosing() { - BinTree.background = Color.WHITE - AVLTree.background = Color.WHITE - RBTree.background = Color.WHITE - - } - - // Функция для обновления видимости элементов меню - fun updateMenuItemsChoosing() { - if (binTreeSelected) {BinTree.background = Color.PINK} - if (avlTreeSelected) {AVLTree.background = Color.PINK} - if (rbTreeSelected) {RBTree.background = Color.PINK} - - } - - // Слушатель событий для элемента меню "Binary Tree" - BinTree.addActionListener { - resetMenuItemsChoosing() - binTreeSelected = true - avlTreeSelected = false - rbTreeSelected = false - updateMenuItemsChoosing() - } - - // Слушатель событий для элемента меню "AVL-Tree" - AVLTree.addActionListener { - resetMenuItemsChoosing() - binTreeSelected = false - avlTreeSelected = true - rbTreeSelected = false - updateMenuItemsChoosing() - } - - // Слушатель событий для элемента меню "Red-black Tree" - RBTree.addActionListener { - resetMenuItemsChoosing() - binTreeSelected = false - avlTreeSelected = false - rbTreeSelected = true - updateMenuItemsChoosing() - } - } -} \ No newline at end of file diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index d779767..995f5c4 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -1,13 +1,21 @@ package app -import javax.swing.* -import trees.BinaryTree -import Frame.* +import guiClasses.Frame import Menu.* +import java.awt.Container +import java.awt.EventQueue +import java.awt.LayoutManager +import javax.swing.GroupLayout +import javax.swing.JButton +import javax.swing.JPanel fun main() { - val GraphFrame = Frame("Treeple",1000, 700, 360, 50) - val MenuFrame = Frame("Treeple Menu",300, 400, 50, 50) + EventQueue.invokeLater { +// val treeFrame = Frame("Treeple",1000, 700, 360, 50) + val menuFrame = Frame("Treeple Menu",300, 400, 50, 50) - val menuBar = MenuClass() + val panel = JPanel() + panel.add(MenuClass()) + menuFrame.add(panel) + } } \ No newline at end of file diff --git a/App/src/main/kotlin/GUIClasses/FrameClass.kt b/App/src/main/kotlin/guiClasses/Frame.kt similarity index 89% rename from App/src/main/kotlin/GUIClasses/FrameClass.kt rename to App/src/main/kotlin/guiClasses/Frame.kt index c35d13e..e4188ea 100644 --- a/App/src/main/kotlin/GUIClasses/FrameClass.kt +++ b/App/src/main/kotlin/guiClasses/Frame.kt @@ -1,14 +1,14 @@ -package Frame +package guiClasses import javax.swing.* -class Frame(name: String, width: Int, heidht: Int, locX: Int, locY: Int) : JFrame() { +class Frame(name: String, width: Int, height: Int, locX: Int, locY: Int) : JFrame() { init { // Устанавливаем заголовок окна title = name // Устанавливаем размер окна - setSize(width, heidht) + setSize(width, height) // Устанавливаем положение окна на экране setLocation(locX, locY) @@ -37,7 +37,7 @@ class Frame(name: String, width: Int, heidht: Int, locX: Int, locY: Int) : JFram isResizable = false // Устанавливаем операцию закрытия окна - defaultCloseOperation = JFrame.EXIT_ON_CLOSE + defaultCloseOperation = EXIT_ON_CLOSE // Отображаем окно isVisible = true diff --git a/App/src/main/kotlin/guiClasses/MenuClass.kt b/App/src/main/kotlin/guiClasses/MenuClass.kt new file mode 100644 index 0000000..d74bd0b --- /dev/null +++ b/App/src/main/kotlin/guiClasses/MenuClass.kt @@ -0,0 +1,49 @@ +package Menu + +import java.awt.Color +import javax.swing.JMenu +import javax.swing.JMenuBar +import javax.swing.JMenuItem + +class MenuClass() : JMenuBar() { + + /** + * Визуально обозначает элементы как неактивные + * */ + private fun resetMenuItemsChoosing() { + menuItems.forEach { it.background = Color.WHITE } + } + + /** + * Визуально обозначает цветом переданный эл-т как выделенный + * */ + private fun updateMenuItemsChoosing(item: JMenuItem) { + item.background = Color.PINK + } + + private val menu = JMenu("Выбор Дерева") + private val menuItems = arrayOf(JMenuItem("Binary Tree"), JMenuItem("AVL-Tree"), JMenuItem("Red-black Tree")) + + init { + menuItems.forEach { menu.add(it) } + resetMenuItemsChoosing() + + // Слушатель событий для элемента меню "Binary Tree" + menuItems[0].addActionListener { + updateMenuItemsChoosing(menuItems[0]) + } + + // Слушатель событий для элемента меню "AVL-Tree" + menuItems[1].addActionListener { + updateMenuItemsChoosing(menuItems[1]) + } + + // Слушатель событий для элемента меню "Red-black Tree" + menuItems[2].addActionListener { + updateMenuItemsChoosing(menuItems[2]) + } + + add(menu) + } + +} \ No newline at end of file From 88694c7bc92592aaf440713191e8da8cd557b61c Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 29 Apr 2023 01:52:24 +0300 Subject: [PATCH 132/203] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=BA=D0=BE=D1=80=D1=80=D0=B5=D0=BA=D1=82=D0=BD=D0=BE=D0=B5=20?= =?UTF-8?q?=D0=BE=D1=82=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=B2=D1=8B=D0=B1=D1=80=D0=B0=D0=BD=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20MenuClass=20=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B2=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/guiClasses/MenuClass.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/App/src/main/kotlin/guiClasses/MenuClass.kt b/App/src/main/kotlin/guiClasses/MenuClass.kt index d74bd0b..b65c2e8 100644 --- a/App/src/main/kotlin/guiClasses/MenuClass.kt +++ b/App/src/main/kotlin/guiClasses/MenuClass.kt @@ -19,6 +19,7 @@ class MenuClass() : JMenuBar() { * */ private fun updateMenuItemsChoosing(item: JMenuItem) { item.background = Color.PINK + menuItems.filter { it != item }.forEach { it.background = Color.WHITE} } private val menu = JMenu("Выбор Дерева") From be0ff31e0e13ce4ba4833058b0ab73be3e2362ea Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 29 Apr 2023 02:01:00 +0300 Subject: [PATCH 133/203] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=BA=D0=B8=20=D0=B2=20Frame,=20=D0=BE=D1=82?= =?UTF-8?q?=D0=B2=D0=B5=D1=87=D0=B0=D1=8E=D1=89=D0=B8=D0=B5=20=D0=B7=D0=B0?= =?UTF-8?q?=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=B0=20JPanel?= =?UTF-8?q?=20=D0=B8=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BD=D1=91=D1=81=20=D0=B8?= =?UTF-8?q?=D1=85=20=D0=B2=20main=20(=D1=87=D1=82=D0=BE=D0=B1=D1=8B=20?= =?UTF-8?q?=D0=B8=D0=B7=D0=B1=D0=B5=D0=B6=D0=B0=D1=82=D1=8C=20=D0=BE=D1=88?= =?UTF-8?q?=D0=B8=D0=B1=D0=BE=D0=BA)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 32 +++++++++++++++++-------- App/src/main/kotlin/guiClasses/Frame.kt | 16 ------------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 995f5c4..d522fc2 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -2,20 +2,32 @@ package app import guiClasses.Frame import Menu.* -import java.awt.Container import java.awt.EventQueue -import java.awt.LayoutManager -import javax.swing.GroupLayout -import javax.swing.JButton -import javax.swing.JPanel +import javax.swing.* fun main() { EventQueue.invokeLater { -// val treeFrame = Frame("Treeple",1000, 700, 360, 50) - val menuFrame = Frame("Treeple Menu",300, 400, 50, 50) + val treeFrame = Frame("Treeple", 1000, 700, 360, 50) + val menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) - val panel = JPanel() - panel.add(MenuClass()) - menuFrame.add(panel) + // Создаем панель с компонентами + val treePanel = JPanel() + val menuPanel = JPanel() + + val scrollPane = JScrollPane() + // Добавляем панель на панель с прокруткой + scrollPane.setViewportView(treePanel) + + // Добавляем панель с прокруткой на окно + menuFrame.contentPane.add(scrollPane) + + // Устанавливаем режим прокрутки по вертикали и горизонтали + scrollPane.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED + scrollPane.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED + + menuPanel.add(MenuClass()) + + menuFrame.add(menuPanel) + treeFrame.add(treePanel) } } \ No newline at end of file diff --git a/App/src/main/kotlin/guiClasses/Frame.kt b/App/src/main/kotlin/guiClasses/Frame.kt index e4188ea..7831c83 100644 --- a/App/src/main/kotlin/guiClasses/Frame.kt +++ b/App/src/main/kotlin/guiClasses/Frame.kt @@ -13,26 +13,10 @@ class Frame(name: String, width: Int, height: Int, locX: Int, locY: Int) : JFram // Устанавливаем положение окна на экране setLocation(locX, locY) - // Создаем панель с прокруткой - val scrollPane = JScrollPane() - // Установка изображения val icon = ImageIcon("tree.jpg").image iconImage = icon - // Создаем панель с компонентами - val panel = JPanel() - - // Добавляем панель на панель с прокруткой - scrollPane.setViewportView(panel) - - // Добавляем панель с прокруткой на окно - contentPane.add(scrollPane) - - // Устанавливаем режим прокрутки по вертикали и горизонтали - scrollPane.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED - scrollPane.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED - //Запрет на форматирование окна isResizable = false From ff148597559ba09561a1683e1f05b51d0563b956 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 29 Apr 2023 12:43:22 +0300 Subject: [PATCH 134/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20KeyTextField=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=B2=D0=B2=D0=BE=D0=B4=D0=B0=20=D0=B7?= =?UTF-8?q?=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/guiClasses/KeyTextField.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 App/src/main/kotlin/guiClasses/KeyTextField.kt diff --git a/App/src/main/kotlin/guiClasses/KeyTextField.kt b/App/src/main/kotlin/guiClasses/KeyTextField.kt new file mode 100644 index 0000000..ba41f2e --- /dev/null +++ b/App/src/main/kotlin/guiClasses/KeyTextField.kt @@ -0,0 +1,16 @@ +package guiClasses + +import java.awt.Font +import javax.swing.JTextField + +class KeyTextField() : JTextField() { + + private val textField = JTextField("Key") + init { + textField.columns = 6 + textField.toolTipText = "key" + + add(textField) + + } +} \ No newline at end of file From 170c629bc6d3cfdd7f406fdcf0e7fee0de968b71 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 29 Apr 2023 13:40:01 +0300 Subject: [PATCH 135/203] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=D1=8C=D0=BD=D0=BE=D0=B5=20?= =?UTF-8?q?=D1=80=D0=B0=D1=81=D0=BF=D0=BE=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BE=D0=BA=20=D0=B8=20?= =?UTF-8?q?TextFields=20=D0=BD=D0=B0=20menuFrame?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 99 +++++++++++++++---- .../main/kotlin/guiClasses/KeyTextField.kt | 7 +- 2 files changed, 84 insertions(+), 22 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index d522fc2..690cdff 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -2,32 +2,91 @@ package app import guiClasses.Frame import Menu.* -import java.awt.EventQueue +import guiClasses.KeyTextField import javax.swing.* -fun main() { - EventQueue.invokeLater { - val treeFrame = Frame("Treeple", 1000, 700, 360, 50) - val menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) +private fun treeFrameInit() { + val treeFrame = Frame("Treeple", 1000, 700, 360, 50) + + // Создаем панель с компонентами + val treePanel = JPanel() + + val scrollPane = JScrollPane() + // Добавляем панель на панель с прокруткой + scrollPane.setViewportView(treePanel) + + // Добавляем панель с прокруткой на окно + treeFrame.contentPane.add(scrollPane) + + // Устанавливаем режим прокрутки по вертикали и горизонтали + scrollPane.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED + scrollPane.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED + + treeFrame.add(treePanel) +} + +private fun menuFrameInit() { + val menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) - // Создаем панель с компонентами - val treePanel = JPanel() - val menuPanel = JPanel() + val addButton = JButton("Add") + val addTextField = KeyTextField() - val scrollPane = JScrollPane() - // Добавляем панель на панель с прокруткой - scrollPane.setViewportView(treePanel) + val removeButton = JButton("remove") + val removeTextField = KeyTextField() - // Добавляем панель с прокруткой на окно - menuFrame.contentPane.add(scrollPane) + val searchButton = JButton("search") + val searchTextField = KeyTextField() - // Устанавливаем режим прокрутки по вертикали и горизонтали - scrollPane.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED - scrollPane.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED + val treeMenu = MenuClass() - menuPanel.add(MenuClass()) + // contentPane - контейнер для компонентов + val layout = GroupLayout(menuFrame.contentPane) + menuFrame.contentPane.layout = layout - menuFrame.add(menuPanel) - treeFrame.add(treePanel) - } + layout.autoCreateContainerGaps = true + layout.autoCreateGaps = true + + layout.setHorizontalGroup( + layout.createSequentialGroup() // Последовательные группы + .addGroup( // Группа с кнопками + // GroupLayout.Alignment.LEADING - выравнивание по левому краю в горизонтальном измерении + layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(addButton) + .addComponent(removeButton) + .addComponent(searchButton) + ) + .addGroup( // Группа с TextFields + layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(addTextField) + .addComponent(removeTextField) + .addComponent(searchTextField) + ) + ) + + layout.setVerticalGroup( + layout.createSequentialGroup() + .addGroup( + layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(addButton) + .addComponent(addTextField) + ) + + .addGroup( + layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(removeButton) + .addComponent(removeTextField) + ) + + .addGroup( + layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(searchButton) + .addComponent(searchTextField) + ) + + ) +} + +fun main() { + treeFrameInit() + menuFrameInit() } \ No newline at end of file diff --git a/App/src/main/kotlin/guiClasses/KeyTextField.kt b/App/src/main/kotlin/guiClasses/KeyTextField.kt index ba41f2e..78b576a 100644 --- a/App/src/main/kotlin/guiClasses/KeyTextField.kt +++ b/App/src/main/kotlin/guiClasses/KeyTextField.kt @@ -1,14 +1,17 @@ package guiClasses import java.awt.Font +import java.awt.event.ActionListener import javax.swing.JTextField class KeyTextField() : JTextField() { private val textField = JTextField("Key") init { - textField.columns = 6 - textField.toolTipText = "key" + textField.also { + addActionListener { + text = "" } + } add(textField) From fd96360eb7bad2b423618b4e38777c0fdf636f71 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 29 Apr 2023 13:45:50 +0300 Subject: [PATCH 136/203] =?UTF-8?q?Frame=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D1=8C=20resizable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/guiClasses/Frame.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/App/src/main/kotlin/guiClasses/Frame.kt b/App/src/main/kotlin/guiClasses/Frame.kt index 7831c83..de9c787 100644 --- a/App/src/main/kotlin/guiClasses/Frame.kt +++ b/App/src/main/kotlin/guiClasses/Frame.kt @@ -1,5 +1,6 @@ package guiClasses +import java.awt.Dimension import javax.swing.* class Frame(name: String, width: Int, height: Int, locX: Int, locY: Int) : JFrame() { @@ -9,6 +10,7 @@ class Frame(name: String, width: Int, height: Int, locX: Int, locY: Int) : JFram // Устанавливаем размер окна setSize(width, height) + minimumSize = Dimension(width, height) // Устанавливаем положение окна на экране setLocation(locX, locY) @@ -17,9 +19,6 @@ class Frame(name: String, width: Int, height: Int, locX: Int, locY: Int) : JFram val icon = ImageIcon("tree.jpg").image iconImage = icon - //Запрет на форматирование окна - isResizable = false - // Устанавливаем операцию закрытия окна defaultCloseOperation = EXIT_ON_CLOSE From 1f0153faca3c5b5b9bc245e0d3cfe655a09f8357 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sat, 29 Apr 2023 14:33:14 +0300 Subject: [PATCH 137/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D1=83=20save?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 41 +++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 690cdff..453dbc5 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -31,12 +31,14 @@ private fun menuFrameInit() { val addButton = JButton("Add") val addTextField = KeyTextField() - val removeButton = JButton("remove") + val removeButton = JButton("Remove") val removeTextField = KeyTextField() - val searchButton = JButton("search") + val searchButton = JButton("Find") val searchTextField = KeyTextField() + val saveButton = JButton("Save") + val treeMenu = MenuClass() // contentPane - контейнер для компонентов @@ -47,20 +49,24 @@ private fun menuFrameInit() { layout.autoCreateGaps = true layout.setHorizontalGroup( - layout.createSequentialGroup() // Последовательные группы - .addGroup( // Группа с кнопками - // GroupLayout.Alignment.LEADING - выравнивание по левому краю в горизонтальном измерении - layout.createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(addButton) - .addComponent(removeButton) - .addComponent(searchButton) - ) - .addGroup( // Группа с TextFields - layout.createParallelGroup(GroupLayout.Alignment.LEADING) - .addComponent(addTextField) - .addComponent(removeTextField) - .addComponent(searchTextField) + layout.createParallelGroup(GroupLayout.Alignment.CENTER) + .addGroup( // Группа с кнопками и TextFields + layout.createSequentialGroup() + .addGroup( // Группа с кнопками + // GroupLayout.Alignment.LEADING - выравнивание по левому краю в горизонтальном измерении + layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(addButton) + .addComponent(removeButton) + .addComponent(searchButton) + ) + .addGroup( // Группа с TextFields + layout.createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(addTextField) + .addComponent(removeTextField) + .addComponent(searchTextField) + ) ) + .addComponent(saveButton) ) layout.setVerticalGroup( @@ -83,6 +89,11 @@ private fun menuFrameInit() { .addComponent(searchTextField) ) + .addGroup( + layout.createSequentialGroup() + .addComponent(saveButton) + ) + ) } From a1637fe089e1768a967bf11f1a94846ff999fb74 Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Sat, 29 Apr 2023 16:52:42 +0300 Subject: [PATCH 138/203] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20package=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=B0=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BC=D0=B5=D0=BD=D1=8E,=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=B2=D0=B5=D0=BB=20=D0=BC=D0=B5=D0=BD=D1=8E=20=D0=B2=20=D0=BE?= =?UTF-8?q?=D0=BA=D0=BD=D0=BE=20=D0=BF=D1=80=D0=BE=D0=B3=D1=80=D0=B0=D0=BC?= =?UTF-8?q?=D0=BC=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 7 ++++--- App/src/main/kotlin/guiClasses/MenuClass.kt | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 453dbc5..b056b0f 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -1,8 +1,6 @@ package app -import guiClasses.Frame -import Menu.* -import guiClasses.KeyTextField +import guiClasses.* import javax.swing.* private fun treeFrameInit() { @@ -41,6 +39,9 @@ private fun menuFrameInit() { val treeMenu = MenuClass() + menuFrame.jMenuBar = treeMenu + + // contentPane - контейнер для компонентов val layout = GroupLayout(menuFrame.contentPane) menuFrame.contentPane.layout = layout diff --git a/App/src/main/kotlin/guiClasses/MenuClass.kt b/App/src/main/kotlin/guiClasses/MenuClass.kt index b65c2e8..09effa9 100644 --- a/App/src/main/kotlin/guiClasses/MenuClass.kt +++ b/App/src/main/kotlin/guiClasses/MenuClass.kt @@ -1,4 +1,4 @@ -package Menu +package guiClasses import java.awt.Color import javax.swing.JMenu From f30438ad6aaa9459d610cc9717d1c3a8bea4fc31 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 30 Apr 2023 19:40:14 +0300 Subject: [PATCH 139/203] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=B2=20gradle:=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20=D1=84=D0=B0=D0=B9=D0=BB=20gra?= =?UTF-8?q?dle.properties=20=D1=81=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D0=BC=D0=B8=20(=D0=B2=D0=B5=D1=80=D1=81?= =?UTF-8?q?=D0=B8=D1=8F=D0=BC=D0=B8=20=D0=B1=D0=B8=D0=B1=D0=BB=D0=B8=D0=BE?= =?UTF-8?q?=D1=82=D0=B5=D0=BA=20=D0=B8=20=D1=82=D0=B4),=20=D1=83=D0=B1?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D1=8B=20=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=20=D0=B7=D0=B0=D0=B2=D0=B8=D1=81=D0=B8=D0=BC=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B8=20=D0=B8=D0=B7=20build.gradle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/build.gradle | 8 +++----- gradle.properties | 2 ++ lib/build.gradle | 7 ++----- 3 files changed, 7 insertions(+), 10 deletions(-) create mode 100644 gradle.properties diff --git a/App/build.gradle b/App/build.gradle index fea29ad..783940d 100644 --- a/App/build.gradle +++ b/App/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'org.jetbrains.kotlin.jvm' version '1.8.10' + id 'org.jetbrains.kotlin.jvm' version "${KOTLIN_JVM_VERSION}" id 'application' } @@ -13,10 +13,8 @@ repositories { dependencies { implementation project(path: ':lib') - testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5' - testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.1' - api 'org.apache.commons:commons-math3:3.6.1' - implementation 'com.google.guava:guava:31.1-jre' + + testImplementation "${KOTLIN_TEST_JUNIT}" } tasks.named('test') { diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..77b36bc --- /dev/null +++ b/gradle.properties @@ -0,0 +1,2 @@ +KOTLIN_JVM_VERSION=1.8.10 +KOTLIN_TEST_JUNIT=org.jetbrains.kotlin:kotlin-test-junit5 diff --git a/lib/build.gradle b/lib/build.gradle index b7728d8..e7603eb 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'org.jetbrains.kotlin.jvm' version '1.8.10' + id 'org.jetbrains.kotlin.jvm' version "${KOTLIN_JVM_VERSION}" id 'java-library' } @@ -9,12 +9,9 @@ repositories { } dependencies { - testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5' - testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.1' - api 'org.apache.commons:commons-math3:3.6.1' + testImplementation "${KOTLIN_TEST_JUNIT}" implementation("org.xerial:sqlite-jdbc:3.32.3.2") - implementation("io.github.microutils:kotlin-logging-jvm:2.0.6") } tasks.named('test') { From 44d508503590b758c80ea254a987185cb35efc8e Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 30 Apr 2023 19:43:11 +0300 Subject: [PATCH 140/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20serialization=20=D0=B2=20=D0=B7=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=81=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D0=B8,=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B8=D0=BC=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=B0?= =?UTF-8?q?=D0=BA=D0=B5=D1=82=D0=BE=D0=B2=20=D1=81=20=D0=B1=D0=B0=D0=B7?= =?UTF-8?q?=D0=B0=D0=BC=D0=B8=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20(?= =?UTF-8?q?=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BF=D0=BE=D0=BD=D1=8F?= =?UTF-8?q?=D1=82=D0=BD=D0=BE,=20=D0=B3=D0=B4=D0=B5=20=D0=BA=D0=B0=D0=BA?= =?UTF-8?q?=D0=BE=D0=B9=20=D1=81=D0=BF=D0=BE=D1=81=D0=BE=D0=B1=20=D1=85?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/build.gradle | 2 ++ lib/src/main/kotlin/databases/{RBTree => json}/RBTDataBase.kt | 2 +- .../main/kotlin/databases/{binTree => sqlite}/BinTreeBase.kt | 3 +-- .../kotlin/databases/{binTree => sqlite}/WrappedBinNode.kt | 2 +- .../kotlin/databases/{binTree => sqlite}/WrappedBinTree.kt | 2 +- .../kotlin/databases/{binTree => sqlite}/WrappedBinTreeTest.kt | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) rename lib/src/main/kotlin/databases/{RBTree => json}/RBTDataBase.kt (96%) rename lib/src/main/kotlin/databases/{binTree => sqlite}/BinTreeBase.kt (97%) rename lib/src/main/kotlin/databases/{binTree => sqlite}/WrappedBinNode.kt (81%) rename lib/src/main/kotlin/databases/{binTree => sqlite}/WrappedBinTree.kt (98%) rename lib/src/test/kotlin/databases/{binTree => sqlite}/WrappedBinTreeTest.kt (99%) diff --git a/lib/build.gradle b/lib/build.gradle index e7603eb..795544a 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -1,5 +1,6 @@ plugins { id 'org.jetbrains.kotlin.jvm' version "${KOTLIN_JVM_VERSION}" + id 'org.jetbrains.kotlin.plugin.serialization' version "${KOTLIN_JVM_VERSION}" id 'java-library' } @@ -10,6 +11,7 @@ repositories { dependencies { testImplementation "${KOTLIN_TEST_JUNIT}" + implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0' implementation("org.xerial:sqlite-jdbc:3.32.3.2") } diff --git a/lib/src/main/kotlin/databases/RBTree/RBTDataBase.kt b/lib/src/main/kotlin/databases/json/RBTDataBase.kt similarity index 96% rename from lib/src/main/kotlin/databases/RBTree/RBTDataBase.kt rename to lib/src/main/kotlin/databases/json/RBTDataBase.kt index c1654a5..7ddac3d 100644 --- a/lib/src/main/kotlin/databases/RBTree/RBTDataBase.kt +++ b/lib/src/main/kotlin/databases/json/RBTDataBase.kt @@ -1,4 +1,4 @@ -package databases.RBTree +package databases.json import trees.RBTree import java.io.* diff --git a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt b/lib/src/main/kotlin/databases/sqlite/BinTreeBase.kt similarity index 97% rename from lib/src/main/kotlin/databases/binTree/BinTreeBase.kt rename to lib/src/main/kotlin/databases/sqlite/BinTreeBase.kt index b5ef22b..3a00a7b 100644 --- a/lib/src/main/kotlin/databases/binTree/BinTreeBase.kt +++ b/lib/src/main/kotlin/databases/sqlite/BinTreeBase.kt @@ -1,6 +1,5 @@ -package databases.binTree +package databases.sqlite -import trees.BinaryTree import java.io.Closeable import java.sql.DriverManager import java.sql.SQLException diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt b/lib/src/main/kotlin/databases/sqlite/WrappedBinNode.kt similarity index 81% rename from lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt rename to lib/src/main/kotlin/databases/sqlite/WrappedBinNode.kt index f2701f4..717a2fd 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinNode.kt +++ b/lib/src/main/kotlin/databases/sqlite/WrappedBinNode.kt @@ -1,2 +1,2 @@ -package databases.binTree +package databases.sqlite data class WrappedBinNode, V>(var key: K, var value: V?, var x: Double = 0.0, var y: Double = 0.0) \ No newline at end of file diff --git a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt b/lib/src/main/kotlin/databases/sqlite/WrappedBinTree.kt similarity index 98% rename from lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt rename to lib/src/main/kotlin/databases/sqlite/WrappedBinTree.kt index 44cb0bd..66909ad 100644 --- a/lib/src/main/kotlin/databases/binTree/WrappedBinTree.kt +++ b/lib/src/main/kotlin/databases/sqlite/WrappedBinTree.kt @@ -1,4 +1,4 @@ -package databases.binTree +package databases.sqlite import exceptions.NodeNotFoundException import exceptions.NullNodeException diff --git a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt b/lib/src/test/kotlin/databases/sqlite/WrappedBinTreeTest.kt similarity index 99% rename from lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt rename to lib/src/test/kotlin/databases/sqlite/WrappedBinTreeTest.kt index 8904603..4a2d8c1 100644 --- a/lib/src/test/kotlin/databases/binTree/WrappedBinTreeTest.kt +++ b/lib/src/test/kotlin/databases/sqlite/WrappedBinTreeTest.kt @@ -1,4 +1,4 @@ -package databases.binTree +package databases.sqlite import exceptions.NodeAlreadyExistsException import exceptions.NodeNotFoundException From 50959b783009abf00c980d60d9c429ee7dd51660 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 30 Apr 2023 20:04:20 +0300 Subject: [PATCH 141/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D1=8B=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D1=81=D0=B5=D1=80=D0=B8=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=B8=20=D0=BA=D1=87=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/build.gradle | 1 + lib/src/main/kotlin/databases/json/JsonRBNode.kt | 11 +++++++++++ lib/src/main/kotlin/databases/json/JsonRBTree.kt | 5 +++++ 3 files changed, 17 insertions(+) create mode 100644 lib/src/main/kotlin/databases/json/JsonRBNode.kt create mode 100644 lib/src/main/kotlin/databases/json/JsonRBTree.kt diff --git a/lib/build.gradle b/lib/build.gradle index 795544a..d5c6619 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -11,6 +11,7 @@ repositories { dependencies { testImplementation "${KOTLIN_TEST_JUNIT}" + implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0' implementation("org.xerial:sqlite-jdbc:3.32.3.2") diff --git a/lib/src/main/kotlin/databases/json/JsonRBNode.kt b/lib/src/main/kotlin/databases/json/JsonRBNode.kt new file mode 100644 index 0000000..2d73853 --- /dev/null +++ b/lib/src/main/kotlin/databases/json/JsonRBNode.kt @@ -0,0 +1,11 @@ +package databases.json + +import kotlinx.serialization.Serializable + +@Serializable +data class JsonRBNode( + val value: String, + val key: Int, + val left: JsonRBNode?, + val right: JsonRBNode? +) \ No newline at end of file diff --git a/lib/src/main/kotlin/databases/json/JsonRBTree.kt b/lib/src/main/kotlin/databases/json/JsonRBTree.kt new file mode 100644 index 0000000..b2f4154 --- /dev/null +++ b/lib/src/main/kotlin/databases/json/JsonRBTree.kt @@ -0,0 +1,5 @@ +package databases.json + +data class JsonRBTree ( + val root: JsonRBNode? +) \ No newline at end of file From 8fd2ae2f9f6bf1ee460a08860e384b1540c1b4a6 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 30 Apr 2023 20:25:58 +0300 Subject: [PATCH 142/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BE=D0=B1=D1=89=D0=B8=D0=B9=20=D0=B8=D0=BD=D1=82?= =?UTF-8?q?=D0=B5=D1=80=D1=84=D0=B5=D0=B9=D1=81=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=B2=D1=81=D0=B5=D1=85=20=D0=B1=D0=B0=D0=B7=20=D0=B4=D0=B0?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/IBase.kt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 lib/src/main/kotlin/databases/IBase.kt diff --git a/lib/src/main/kotlin/databases/IBase.kt b/lib/src/main/kotlin/databases/IBase.kt new file mode 100644 index 0000000..24222cb --- /dev/null +++ b/lib/src/main/kotlin/databases/IBase.kt @@ -0,0 +1,8 @@ +package databases + +import java.io.Closeable + +interface IBase: Closeable { + fun saveTree(tree: TreeType) + fun loadTree() : TreeType +} \ No newline at end of file From 232a6c7f3a1b1d6de5886abc7560e5dda714e590 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 30 Apr 2023 20:29:03 +0300 Subject: [PATCH 143/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=B1=D0=B0=D0=B7=D1=8B=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85?= =?UTF-8?q?=20=D0=BA=D1=87=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/json/RBTBase.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 lib/src/main/kotlin/databases/json/RBTBase.kt diff --git a/lib/src/main/kotlin/databases/json/RBTBase.kt b/lib/src/main/kotlin/databases/json/RBTBase.kt new file mode 100644 index 0000000..8f802a0 --- /dev/null +++ b/lib/src/main/kotlin/databases/json/RBTBase.kt @@ -0,0 +1,25 @@ +package databases.json + +import databases.IBase +import trees.RBTree + +class RBTBase( + private val dbPath: String, + private val serializeValue: (value: V?) -> String = { value -> value.toString() }, + private val deserializeValue: (strValue: String) -> V +): IBase> { + + val savedTree: RBTree = RBTree() + override fun saveTree(tree: RBTree) { + TODO("Not yet implemented") + } + + override fun loadTree(): RBTree { + TODO("Not yet implemented") + } + + override fun close() { + TODO("Not yet implemented") + } + +} \ No newline at end of file From 7910c68e910be2fdf78d91da38aebd5a400bef28 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 30 Apr 2023 20:35:13 +0300 Subject: [PATCH 144/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=85=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D1=86=D0=B2=D0=B5=D1=82=D0=B0=20=D0=B2=20JsonRBNode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/json/JsonRBNode.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/main/kotlin/databases/json/JsonRBNode.kt b/lib/src/main/kotlin/databases/json/JsonRBNode.kt index 2d73853..e2406d3 100644 --- a/lib/src/main/kotlin/databases/json/JsonRBNode.kt +++ b/lib/src/main/kotlin/databases/json/JsonRBNode.kt @@ -1,11 +1,13 @@ package databases.json import kotlinx.serialization.Serializable +import nodes.Color @Serializable data class JsonRBNode( val value: String, val key: Int, + val color: Color, val left: JsonRBNode?, val right: JsonRBNode? ) \ No newline at end of file From fcf4192a6c1a886a56efdab63b65b1734d6b6e2a Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 30 Apr 2023 21:23:58 +0300 Subject: [PATCH 145/203] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=8C=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D1=8F=D1=82=D1=8C?= =?UTF-8?q?=20RBTree=20=D0=B2=20json=20=D1=84=D0=B0=D0=B9=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/databases/json/JsonRBNode.kt | 2 ++ .../main/kotlin/databases/json/JsonRBTree.kt | 3 ++ lib/src/main/kotlin/databases/json/RBTBase.kt | 30 +++++++++++++++---- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/src/main/kotlin/databases/json/JsonRBNode.kt b/lib/src/main/kotlin/databases/json/JsonRBNode.kt index e2406d3..56b7899 100644 --- a/lib/src/main/kotlin/databases/json/JsonRBNode.kt +++ b/lib/src/main/kotlin/databases/json/JsonRBNode.kt @@ -8,6 +8,8 @@ data class JsonRBNode( val value: String, val key: Int, val color: Color, + val x: Double, + val y: Double, val left: JsonRBNode?, val right: JsonRBNode? ) \ No newline at end of file diff --git a/lib/src/main/kotlin/databases/json/JsonRBTree.kt b/lib/src/main/kotlin/databases/json/JsonRBTree.kt index b2f4154..8fde951 100644 --- a/lib/src/main/kotlin/databases/json/JsonRBTree.kt +++ b/lib/src/main/kotlin/databases/json/JsonRBTree.kt @@ -1,5 +1,8 @@ package databases.json +import kotlinx.serialization.Serializable + +@Serializable data class JsonRBTree ( val root: JsonRBNode? ) \ No newline at end of file diff --git a/lib/src/main/kotlin/databases/json/RBTBase.kt b/lib/src/main/kotlin/databases/json/RBTBase.kt index 8f802a0..9b4e7dd 100644 --- a/lib/src/main/kotlin/databases/json/RBTBase.kt +++ b/lib/src/main/kotlin/databases/json/RBTBase.kt @@ -1,25 +1,43 @@ package databases.json import databases.IBase +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import nodes.RBNode import trees.RBTree +import java.io.File class RBTBase( private val dbPath: String, private val serializeValue: (value: V?) -> String = { value -> value.toString() }, private val deserializeValue: (strValue: String) -> V -): IBase> { +) : IBase> { - val savedTree: RBTree = RBTree() - override fun saveTree(tree: RBTree) { - TODO("Not yet implemented") + private var file: File = File(dbPath) + override fun saveTree(tree: RBTree) { + file.printWriter().use { out -> + out.write(tree.convertToJson()) + } } - override fun loadTree(): RBTree { + override fun loadTree(): RBTree { TODO("Not yet implemented") } override fun close() { - TODO("Not yet implemented") } + private fun RBTree.convertToJson() = Json.encodeToString(JsonRBTree(root?.convertToJson())) + private fun RBNode.convertToJson(x: Double = 0.0, y: Double = 0.0): JsonRBNode = + JsonRBNode( + serializeValue(this.value), + this.key, + this.color, + x, + y, + this.left?.convertToJson(), + this.right?.convertToJson() + ) + + } \ No newline at end of file From c4a862cbeafccfec3364c5193891fa7791ee3dab Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 30 Apr 2023 21:44:29 +0300 Subject: [PATCH 146/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B2=D1=8B=D0=B3=D1=80=D1=83=D0=B6=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BA=D1=87=D0=B4=20=D0=B8=D0=B7=20=D0=B1=D0=B0=D0=B7?= =?UTF-8?q?=D1=8B=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/IBase.kt | 6 ++--- lib/src/main/kotlin/databases/json/RBTBase.kt | 24 +++++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/lib/src/main/kotlin/databases/IBase.kt b/lib/src/main/kotlin/databases/IBase.kt index 24222cb..e035d6e 100644 --- a/lib/src/main/kotlin/databases/IBase.kt +++ b/lib/src/main/kotlin/databases/IBase.kt @@ -1,8 +1,8 @@ package databases -import java.io.Closeable - -interface IBase: Closeable { +interface IBase { fun saveTree(tree: TreeType) fun loadTree() : TreeType + fun getCoordinate(key: K) + fun setCoordinate(key: K, x: Double, y: Double) } \ No newline at end of file diff --git a/lib/src/main/kotlin/databases/json/RBTBase.kt b/lib/src/main/kotlin/databases/json/RBTBase.kt index 9b4e7dd..c5aa5d0 100644 --- a/lib/src/main/kotlin/databases/json/RBTBase.kt +++ b/lib/src/main/kotlin/databases/json/RBTBase.kt @@ -1,6 +1,7 @@ package databases.json import databases.IBase +import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import nodes.RBNode @@ -11,7 +12,7 @@ class RBTBase( private val dbPath: String, private val serializeValue: (value: V?) -> String = { value -> value.toString() }, private val deserializeValue: (strValue: String) -> V -) : IBase> { +) : IBase, Int> { private var file: File = File(dbPath) override fun saveTree(tree: RBTree) { @@ -20,13 +21,28 @@ class RBTBase( } } - override fun loadTree(): RBTree { - TODO("Not yet implemented") + override fun loadTree(): RBTree = Json.decodeFromString(file.readText()).convertToTree() + + override fun setCoordinate(key: Int, x: Double, y: Double) { + } - override fun close() { + override fun getCoordinate(key: Int) { + TODO("Not yet implemented") } + private fun JsonRBTree.convertToTree(): RBTree = + RBTree().also { + it.root = this.root?.convertToNode() + } + + private fun JsonRBNode.convertToNode(): RBNode = + RBNode(this.key, deserializeValue(this.value)).also { + it.color = this.color + it.left = this.left?.convertToNode() + it.right = this.right?.convertToNode() + } + private fun RBTree.convertToJson() = Json.encodeToString(JsonRBTree(root?.convertToJson())) private fun RBNode.convertToJson(x: Double = 0.0, y: Double = 0.0): JsonRBNode = JsonRBNode( From 44026406961fe66efd298cc420fd037811a6174e Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Sun, 30 Apr 2023 22:21:05 +0300 Subject: [PATCH 147/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BC=D0=B5=D0=BD=D1=8F=D1=82=D1=8C=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BE=D1=80=D0=B4=D0=B8=D0=BD=D0=B0=D1=82=D1=8B=20=D1=83?= =?UTF-8?q?=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D1=91=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=B2=20=D0=B1=D0=B0=D0=B7=D0=B5=20=D0=BD=D0=BE=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/IBase.kt | 24 ++++++++-- .../main/kotlin/databases/json/JsonRBNode.kt | 4 +- lib/src/main/kotlin/databases/json/RBTBase.kt | 47 +++++++++++++++++-- 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/lib/src/main/kotlin/databases/IBase.kt b/lib/src/main/kotlin/databases/IBase.kt index e035d6e..4725590 100644 --- a/lib/src/main/kotlin/databases/IBase.kt +++ b/lib/src/main/kotlin/databases/IBase.kt @@ -1,8 +1,26 @@ package databases +import java.awt.Point + interface IBase { + + /** + * Сохраняет переданное дерево в базу данных. + */ fun saveTree(tree: TreeType) - fun loadTree() : TreeType - fun getCoordinate(key: K) - fun setCoordinate(key: K, x: Double, y: Double) + + /** + * Выгружает дерево из базы данных. + */ + fun loadTree(): TreeType + + /** + * Выполняет поиск координаты в сохранённом в базе данных дереве. + */ + fun getPoint(key: K): Point + + /** + * Изменяет координату в сохранённой ноде с указанной координатой. + */ + fun setPoint(key: K, p: Point) } \ No newline at end of file diff --git a/lib/src/main/kotlin/databases/json/JsonRBNode.kt b/lib/src/main/kotlin/databases/json/JsonRBNode.kt index 56b7899..a6ac459 100644 --- a/lib/src/main/kotlin/databases/json/JsonRBNode.kt +++ b/lib/src/main/kotlin/databases/json/JsonRBNode.kt @@ -8,8 +8,8 @@ data class JsonRBNode( val value: String, val key: Int, val color: Color, - val x: Double, - val y: Double, + var x: Int, + var y: Int, val left: JsonRBNode?, val right: JsonRBNode? ) \ No newline at end of file diff --git a/lib/src/main/kotlin/databases/json/RBTBase.kt b/lib/src/main/kotlin/databases/json/RBTBase.kt index c5aa5d0..e884c94 100644 --- a/lib/src/main/kotlin/databases/json/RBTBase.kt +++ b/lib/src/main/kotlin/databases/json/RBTBase.kt @@ -1,11 +1,13 @@ package databases.json import databases.IBase +import exceptions.NodeNotFoundException import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import nodes.RBNode import trees.RBTree +import java.awt.Point import java.io.File class RBTBase( @@ -23,12 +25,49 @@ class RBTBase( override fun loadTree(): RBTree = Json.decodeFromString(file.readText()).convertToTree() - override fun setCoordinate(key: Int, x: Double, y: Double) { + override fun setPoint(key: Int, p: Point) { + val savedTree = Json.decodeFromString(file.readText()) + if (savedTree.root?.changeCoordinate(key, p) != true) + throw NodeNotFoundException() + + file.printWriter().use { out -> + out.write(Json.encodeToString(savedTree)) + } + + } + + override fun getPoint(key: Int): Point { + return Json.decodeFromString(file.readText()).root?.searchCoordinate(key) + ?: throw NodeNotFoundException() } - override fun getCoordinate(key: Int) { - TODO("Not yet implemented") + private fun JsonRBNode.searchCoordinate(key: Int): Point? { + if (this.key == key) + return Point(this.x, this.y) + else { + this.left?.searchCoordinate(key)?.also { + return Point(it.x, it.y) + } + this.right?.searchCoordinate(key)?.also { + return Point(it.x, it.y) + } + } + + return null + } + + private fun JsonRBNode.changeCoordinate(key: Int, p: Point): Boolean { + return if (this.key == key) { + this.x = p.x + this.y = p.y + true + } else { + if (this.left?.changeCoordinate(key, p) != true) + this.right?.changeCoordinate(key, p) == true + else + true + } } private fun JsonRBTree.convertToTree(): RBTree = @@ -44,7 +83,7 @@ class RBTBase( } private fun RBTree.convertToJson() = Json.encodeToString(JsonRBTree(root?.convertToJson())) - private fun RBNode.convertToJson(x: Double = 0.0, y: Double = 0.0): JsonRBNode = + private fun RBNode.convertToJson(x: Int = 0, y: Int = 0): JsonRBNode = JsonRBNode( serializeValue(this.value), this.key, From 51920840b1a9bc9bfb9ca05bd8c7571d91fe469f Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 1 May 2023 09:47:07 +0300 Subject: [PATCH 148/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=80?= =?UTF-8?q?=D0=B8=D0=B8=20=D0=B2=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84?= =?UTF-8?q?=D0=B5=D0=B9=D1=81=20=D0=B1=D0=B0=D0=B7=20=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D0=B8=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=81=D1=82=D0=B0=D1=80=D1=8B=D0=B9=20=D0=BA=D0=BB?= =?UTF-8?q?=D0=B0=D1=81=D1=81=20=D1=81=20=D0=B1=D0=B0=D0=B7=D0=BE=D0=B9=20?= =?UTF-8?q?=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D1=87=D0=BA=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/IBase.kt | 3 +++ .../main/kotlin/databases/json/RBTDataBase.kt | 23 ------------------- 2 files changed, 3 insertions(+), 23 deletions(-) delete mode 100644 lib/src/main/kotlin/databases/json/RBTDataBase.kt diff --git a/lib/src/main/kotlin/databases/IBase.kt b/lib/src/main/kotlin/databases/IBase.kt index 4725590..438dc7a 100644 --- a/lib/src/main/kotlin/databases/IBase.kt +++ b/lib/src/main/kotlin/databases/IBase.kt @@ -2,6 +2,9 @@ package databases import java.awt.Point +/** + * Общий интерфейс для всех баз данных + */ interface IBase { /** diff --git a/lib/src/main/kotlin/databases/json/RBTDataBase.kt b/lib/src/main/kotlin/databases/json/RBTDataBase.kt deleted file mode 100644 index 7ddac3d..0000000 --- a/lib/src/main/kotlin/databases/json/RBTDataBase.kt +++ /dev/null @@ -1,23 +0,0 @@ -package databases.json - -import trees.RBTree -import java.io.* - -class RBTreeSerializer { - fun serialize(tree: RBTree<*, *>, filePath: String) { - val fileOutputStream = FileOutputStream(filePath) - val objectOutputStream = ObjectOutputStream(fileOutputStream) - objectOutputStream.writeObject(tree) - objectOutputStream.close() - fileOutputStream.close() - } - - fun deserialize(filePath: String): RBTree<*, *> { - val fileInputStream = FileInputStream(filePath) - val objectInputStream = ObjectInputStream(fileInputStream) - val tree = objectInputStream.readObject() as RBTree<*, *> - objectInputStream.close() - fileInputStream.close() - return tree - } -} From 3022f3405cc4b8e4459054e063a8ff67dd0d4b8f Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 1 May 2023 10:38:53 +0300 Subject: [PATCH 149/203] =?UTF-8?q?=D0=91=D0=B4=20=D0=B1=D0=B8=D0=BD=D0=B0?= =?UTF-8?q?=D1=80=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=BE=D0=BB=D0=BD=D0=BE=D1=81=D1=82=D1=8C=D1=8E?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D0=B0?= =?UTF-8?q?:=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BE=D0=BD=D0=B0?= =?UTF-8?q?=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D1=83=D0=B5=D1=82=20?= =?UTF-8?q?=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5=D0=B9=D1=81=20IBase?= =?UTF-8?q?=20=D0=B8=20=D0=BD=D0=B5=20=D0=BD=D1=83=D0=B6=D0=B4=D0=B0=D0=B5?= =?UTF-8?q?=D1=82=D1=81=D1=8F=20=D0=B2=D0=BE=20=D0=B2=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D0=BC=D0=BE=D0=B3=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=B0=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/databases/sqlite/BTBase.kt | 116 ++++++++++++++++++ .../kotlin/databases/sqlite/BinTreeBase.kt | 74 ----------- 2 files changed, 116 insertions(+), 74 deletions(-) create mode 100644 lib/src/main/kotlin/databases/sqlite/BTBase.kt delete mode 100644 lib/src/main/kotlin/databases/sqlite/BinTreeBase.kt diff --git a/lib/src/main/kotlin/databases/sqlite/BTBase.kt b/lib/src/main/kotlin/databases/sqlite/BTBase.kt new file mode 100644 index 0000000..550d390 --- /dev/null +++ b/lib/src/main/kotlin/databases/sqlite/BTBase.kt @@ -0,0 +1,116 @@ +package databases.sqlite + +import databases.IBase +import exceptions.NullNodeException +import nodes.BinaryNode +import trees.BinaryTree +import java.awt.Point +import java.io.Closeable +import java.sql.DriverManager +import java.sql.SQLException + + +class BTBase( + dbPath: String, + private val serializeValue: (value: V?) -> String = { value -> value.toString() }, + private val deserializeValue: (strValue: String) -> V +) : IBase, Int>, Closeable { + object DbConstants { + const val DB_NAME = "BinaryNodes" + } + + private val connection = DriverManager.getConnection("jdbc:sqlite:$dbPath") + ?: throw SQLException("Cannot connect to database") + private val createBaseStatement by lazy { connection.prepareStatement("CREATE TABLE if not exists ${DbConstants.DB_NAME} (key int, value varchar(255), x double, y double);") } + private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO ${DbConstants.DB_NAME} (key, value, x, y) VALUES (?, ?, ?, ?);") } + private val setPointStatement by lazy { connection.prepareStatement("UPDATE ${DbConstants.DB_NAME} SET x=?, y=? WHERE key=?;") } + private val getPointStatement by lazy { connection.prepareStatement("SELECT x, y FROM ${DbConstants.DB_NAME} WHERE key=?;") } + private val getNodesStatement by lazy { connection.prepareStatement("SELECT key, value, x, y, value FROM ${DbConstants.DB_NAME}") } + private val dropDatabaseStatement by lazy { connection.prepareStatement("DELETE FROM ${DbConstants.DB_NAME};") } + + init { + createBaseStatement.execute() + } + + override fun saveTree(tree: BinaryTree) { + clear() + if (tree.root == null) + return + tree.toList().forEach { + addNode(it) + } + } + + override fun loadTree(): BinaryTree { + val tree = BinaryTree() + + val stateRes = getNodesStatement.executeQuery() + + while (stateRes.next()) + tree.add(stateRes.getInt(1), deserializeValue(stateRes.getString(2))) + return tree + } + + override fun setPoint(key: Int, p: Point) { + setPointStatement.setInt(1, p.x) + setPointStatement.setInt(2, p.y) + setPointStatement.setInt(3, key) + + setPointStatement.execute() + } + + override fun getPoint(key: Int): Point { + getPointStatement.setInt(1, key) + + val stateRes = getPointStatement.executeQuery() + + val p = Point(-1, -1) + + while (stateRes.next()) { + p.x = stateRes.getInt(1) + p.y = stateRes.getInt(2) + } + + return p + } + + private fun addNode(node: BinaryNode, p: Point = Point(0, 0)) { + addNodeStatement.setInt(1, node.key) + addNodeStatement.setString(2, serializeValue(node.value)) + addNodeStatement.setInt(3, p.x) + addNodeStatement.setInt(4, p.y) + + addNodeStatement.execute() + } + + private fun clear() { + dropDatabaseStatement.execute() + } + + override fun close() { + createBaseStatement.close() + addNodeStatement.close() + getNodesStatement.close() + dropDatabaseStatement.close() + + connection.close() + } + + private fun BinaryTree.toList(): MutableList> = + this.root?.toList(mutableListOf()) ?: throw NullNodeException() + + private fun BinaryNode.toList(list: MutableList>): MutableList> { + var myList: MutableList> = list + + myList.add(this) + this.left?.let { + myList = it.toList(myList) + } + this.right?.let { + myList = it.toList(myList) + } + + return myList + } + +} \ No newline at end of file diff --git a/lib/src/main/kotlin/databases/sqlite/BinTreeBase.kt b/lib/src/main/kotlin/databases/sqlite/BinTreeBase.kt deleted file mode 100644 index 3a00a7b..0000000 --- a/lib/src/main/kotlin/databases/sqlite/BinTreeBase.kt +++ /dev/null @@ -1,74 +0,0 @@ -package databases.sqlite - -import java.io.Closeable -import java.sql.DriverManager -import java.sql.SQLException - - -class BinTreeBase( - dbPath: String, - private val serializeValue: (value: V?) -> String = { value -> value.toString() }, - private val deserializeValue: (strValue: String) -> V -) : Closeable { - object DbConstants { - const val DB_NAME = "BinaryNodes" - } - - private val connection = DriverManager.getConnection("jdbc:sqlite:$dbPath") - ?: throw SQLException("Cannot connect to database") - private val createBaseStatement by lazy { connection.prepareStatement("CREATE TABLE if not exists ${DbConstants.DB_NAME} (key int, value varchar(255), x double, y double);") } - private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO ${DbConstants.DB_NAME} (key, value, x, y) VALUES (?, ?, ?, ?);") } - private val getNodesStatement by lazy { connection.prepareStatement("SELECT key, value, x, y, value FROM ${DbConstants.DB_NAME}") } - private val dropDatabaseStatement by lazy { connection.prepareStatement("DELETE FROM ${DbConstants.DB_NAME};") } - - - init { - createBaseStatement.execute() - } - - fun saveTree(tree: WrappedBinTree) { - clear() - for (node in tree.getWrappedNodesArray()) - addNode(node) - } - - fun getWrappedBinTree(): WrappedBinTree { - val tree = WrappedBinTree() - - val stateRes = getNodesStatement.executeQuery() - - while (!stateRes.isClosed && stateRes.next()) { - tree.add( - stateRes.getInt(1), - deserializeValue(stateRes.getString(2)), - stateRes.getDouble(3), - stateRes.getDouble(4) - ) - } - - return tree - } - private fun addNode(node: WrappedBinNode) { - - addNodeStatement.setInt(1, node.key) - addNodeStatement.setString(2, serializeValue(node.value)) - addNodeStatement.setDouble(3, node.x) - addNodeStatement.setDouble(4, node.y) - - addNodeStatement.execute() - } - - private fun clear() { - dropDatabaseStatement.execute() - } - - override fun close() { - createBaseStatement.close() - addNodeStatement.close() - getNodesStatement.close() - dropDatabaseStatement.close() - - connection.close() - } - -} \ No newline at end of file From 41edc24e40485954f87e0fbe14fe833e24511011 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 1 May 2023 10:39:45 +0300 Subject: [PATCH 150/203] =?UTF-8?q?=D0=A3=D0=B4=D0=B0=D0=BB=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D1=83=D0=B6=D0=BD=D1=8B=D0=B5=20=D0=B2=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D0=BC=D0=BE=D0=B3=D0=B0=D1=82=D0=B5=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=B5=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D1=8B=20?= =?UTF-8?q?=D0=B8=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BD=D0=B8=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/databases/sqlite/WrappedBinNode.kt | 2 - .../kotlin/databases/sqlite/WrappedBinTree.kt | 79 ------ .../databases/sqlite/WrappedBinTreeTest.kt | 238 ------------------ 3 files changed, 319 deletions(-) delete mode 100644 lib/src/main/kotlin/databases/sqlite/WrappedBinNode.kt delete mode 100644 lib/src/main/kotlin/databases/sqlite/WrappedBinTree.kt delete mode 100644 lib/src/test/kotlin/databases/sqlite/WrappedBinTreeTest.kt diff --git a/lib/src/main/kotlin/databases/sqlite/WrappedBinNode.kt b/lib/src/main/kotlin/databases/sqlite/WrappedBinNode.kt deleted file mode 100644 index 717a2fd..0000000 --- a/lib/src/main/kotlin/databases/sqlite/WrappedBinNode.kt +++ /dev/null @@ -1,2 +0,0 @@ -package databases.sqlite -data class WrappedBinNode, V>(var key: K, var value: V?, var x: Double = 0.0, var y: Double = 0.0) \ No newline at end of file diff --git a/lib/src/main/kotlin/databases/sqlite/WrappedBinTree.kt b/lib/src/main/kotlin/databases/sqlite/WrappedBinTree.kt deleted file mode 100644 index 66909ad..0000000 --- a/lib/src/main/kotlin/databases/sqlite/WrappedBinTree.kt +++ /dev/null @@ -1,79 +0,0 @@ -package databases.sqlite - -import exceptions.NodeNotFoundException -import exceptions.NullNodeException -import nodes.BinaryNode -import trees.BinaryTree - -class WrappedBinTree, V>() { - - // Список с расширенными нодами - private var wrappedNodesList: MutableList> = mutableListOf() - - // Добавление бинарного дерева - constructor(tree: BinaryTree) : this() { - if (tree.root != null) - addNodeToWrappedList(tree.root ?: throw NullNodeException()) - } - - /** - * Позволяет получить сохранённое в классе бинарное дерево - */ - fun getBinaryTree(): BinaryTree { - val resBinTree = BinaryTree() - for (item in wrappedNodesList) - resBinTree.add(item.key, item.value) - return resBinTree - } - - /** - * Позволяет добавить новую ноду в дерево - */ - fun add(key: K, value: V? = null, x: Double = 0.0, y: Double = 0.0) { - val newTree = getBinaryTree() - newTree.add(key, value) - - wrappedNodesList.clear() - - newTree.root?.let { - addNodeToWrappedList(it) - setNodeCoordinate(key, x, y) - } - } - fun remove(key: K) { - val newTree = getBinaryTree() - newTree.remove(key) - - wrappedNodesList.clear() - - newTree.root?.let { addNodeToWrappedList(it) } - } - fun getWrappedNode(key: K): WrappedBinNode { - for (item in wrappedNodesList) - if (item.key == key) - return item - throw NodeNotFoundException() - } - fun getWrappedNodesArray(): Array> = wrappedNodesList.toTypedArray() - fun setNodeCoordinate(key: K, x: Double = 0.0, y: Double = 0.0) { - for (item in wrappedNodesList) { - if (item.key == key) { - item.x = x - item.y = y - return - } - } - - // Если ключ не совпадает ни с одной вершиной из имеющихся - throw NodeNotFoundException() - } - - private fun addNodeToWrappedList(node: BinaryNode) { - this.wrappedNodesList.add(WrappedBinNode(node.key, node.value)) - if (node.left != null) - addNodeToWrappedList(node.left ?: throw NullNodeException()) - if (node.right != null) - addNodeToWrappedList(node.right ?: throw NullNodeException()) - } - -} \ No newline at end of file diff --git a/lib/src/test/kotlin/databases/sqlite/WrappedBinTreeTest.kt b/lib/src/test/kotlin/databases/sqlite/WrappedBinTreeTest.kt deleted file mode 100644 index 4a2d8c1..0000000 --- a/lib/src/test/kotlin/databases/sqlite/WrappedBinTreeTest.kt +++ /dev/null @@ -1,238 +0,0 @@ -package databases.sqlite - -import exceptions.NodeAlreadyExistsException -import exceptions.NodeNotFoundException -import org.junit.jupiter.api.Assertions.* -import trees.BinaryTree -import nodes.BinaryNode -import org.junit.jupiter.api.DisplayName -import org.junit.jupiter.api.Nested -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.function.Executable -import kotlin.random.Random -import kotlin.test.BeforeTest - -class WrappedBinTreeTest { - - private lateinit var binTree: BinaryTree - private lateinit var wrappedTree: WrappedBinTree - - @BeforeTest - fun init() { - binTree = BinaryTree() - } - - @Nested - inner class `Equivalence check` { - @Test - @DisplayName("Existing elements search") - fun `Root equivalence check`() { - binTree.add(100, "root") - wrappedTree = WrappedBinTree(binTree) - - assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) - } - - @Test - @DisplayName("Tree with one subtree equivalence check") - fun `Tree with one subtree equivalence check`() { - binTree.add(100, "root") - binTree.add(120, "a") - binTree.add(130, "b") - binTree.add(140, "c") - binTree.add(125, "d") - binTree.add(160, "e") - wrappedTree = WrappedBinTree(binTree) - - assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) - } - - @Test - @DisplayName("Tree with one subtree equivalence check") - fun `Tree with two subtrees equivalence check`() { - binTree.add(100, "root") - binTree.add(150) - binTree.add(160) - binTree.add(110) - binTree.add(50) - binTree.add(-100) - binTree.add(89) - - wrappedTree = WrappedBinTree(binTree) - - assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) - } - - @Test - @DisplayName("Random tree equivalence check") - fun `Random tree equivalence check`() { - val list: List = (List(100000) { Random.nextInt(1, 100000) }).distinct().toMutableList() - - for (item in list) - binTree.add(item) - - wrappedTree = WrappedBinTree(binTree) - - assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) - - } - - @Test - @DisplayName("Null-root tree equivalence check") - fun `Null-root tree equivalence check`() { - wrappedTree = WrappedBinTree(binTree) - - assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) - } - } - - @Nested - inner class `Coordinates check` { - @Test - @DisplayName("Coordinate change check") - fun `Coordinate change check`() { - binTree.add(100, "root") - - wrappedTree = WrappedBinTree(binTree) - wrappedTree.setNodeCoordinate(100, 10.0, -10.0) - - assertAll("elements", - Executable { assertTrue(wrappedTree.getWrappedNode(100).x == 10.0)}, - Executable { assertTrue(wrappedTree.getWrappedNode(100).y == -10.0)} - ) - } - - @Test - @DisplayName("Coordinate change check") - fun `Non-existent coordinate change`() { - binTree.add(100, "root") - - wrappedTree = WrappedBinTree(binTree) - - assertThrows(NodeNotFoundException::class.java) { wrappedTree.setNodeCoordinate(150, 10.0, -10.0) } - } - - } - - @Nested - inner class `Add test` { - @Test - @DisplayName("One element add test") - fun `One element add test`() { - wrappedTree = WrappedBinTree() - - binTree.add(100) - wrappedTree.add(100) - - assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) - } - - @Test - @DisplayName("One element add test") - fun `Already existent element add test`() { - wrappedTree = WrappedBinTree() - wrappedTree.add(100, "root") - - assertThrows(NodeAlreadyExistsException::class.java) { wrappedTree.add(100, "root") } - } - - @Test - @DisplayName("Random tree add check") - fun `Random tree add check`() { - wrappedTree = WrappedBinTree() - - val list: List = (List(100) { Random.nextInt(1, 100000) }).distinct().toMutableList() - - for (item in list) { - wrappedTree.add(item) - binTree.add(item) - } - - assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) - } - } - - @Nested - inner class `Remove test` { - @Test - @DisplayName("One element add test") - fun `One element remove test`() { - binTree.add(100) - wrappedTree = WrappedBinTree(binTree) - binTree.remove(100) - wrappedTree.remove(100) - - assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) - } - - @Test - @DisplayName("Non-existent element remove test") - fun `Non-existent element remove test`() { - wrappedTree = WrappedBinTree() - - assertThrows(NodeNotFoundException::class.java) {wrappedTree.remove(100)} - } - - @Test - @DisplayName("Random tree add check") - fun `Random tree remove check`() { - binTree.add(100) - binTree.add(200) - binTree.add(150) - binTree.add(10) - binTree.add(220) - binTree.add(-100) - binTree.add(89) - binTree.add(-50) - binTree.add(-34) - - wrappedTree = WrappedBinTree(binTree) - - wrappedTree.remove(100) - binTree.remove(100) - - assertTrue(binTree.equalCheck(wrappedTree.getBinaryTree())) - } - } - - @Nested - inner class `Search test` { - @Test - @DisplayName("Existent element search") - fun `Existent element search`() { - binTree.add(100) - - wrappedTree = WrappedBinTree(binTree) - wrappedTree.setNodeCoordinate(100, 10.0) - - assertEquals(10.0, wrappedTree.getWrappedNode(100).x) - } - - @Test - @DisplayName("Non-existent element search") - fun `Non-existent element search`() { - wrappedTree = WrappedBinTree() - - assertThrows(NodeNotFoundException::class.java){ wrappedTree.getWrappedNode(100).x} - } - } - - /** - * Сравнивает переданные ноды по всем параметрам (рекурсивно обходит детей) - * @return True - ноды полностью совпадают - */ - private fun , V> BinaryNode?.nodesEqualCheck(other: BinaryNode?): Boolean { - return (this == null && other == null) || - ((other?.key == this?.key) && - (other?.value == this?.value) && - (this?.left.nodesEqualCheck(other?.left)) && - (this?.right.nodesEqualCheck(other?.right))) - } - - /** - * Сравнивает деревья между собой - * @return True - деревья полностью схожи (включая расположение детей) - */ - fun , V> BinaryTree.equalCheck(other: BinaryTree): Boolean = - this.root.nodesEqualCheck(other.root) -} \ No newline at end of file From 2821e370e8d136d6865104d10559841bf2c0e4a0 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 1 May 2023 10:51:12 +0300 Subject: [PATCH 151/203] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=B1=D0=B4=20=D0=B4=D0=BB=D1=8F=20=D0=B1=D0=B8=D0=BD=D0=B0?= =?UTF-8?q?=D1=80=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2?= =?UTF-8?q?=D0=B0=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D1=8E=D1=89=D0=B5?= =?UTF-8?q?=D0=B9=20=D1=81=20=D0=BB=D1=8E=D0=B1=D1=8B=D0=BC=D0=B8=20key,?= =?UTF-8?q?=20value?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/databases/sqlite/BTBase.kt | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/src/main/kotlin/databases/sqlite/BTBase.kt b/lib/src/main/kotlin/databases/sqlite/BTBase.kt index 550d390..16c6b8a 100644 --- a/lib/src/main/kotlin/databases/sqlite/BTBase.kt +++ b/lib/src/main/kotlin/databases/sqlite/BTBase.kt @@ -10,18 +10,20 @@ import java.sql.DriverManager import java.sql.SQLException -class BTBase( +class BTBase, V>( dbPath: String, + private val serializeKey: (key: K) -> String = { value -> value.toString() }, + private val deserializeKey: (strKey: String) -> K, private val serializeValue: (value: V?) -> String = { value -> value.toString() }, private val deserializeValue: (strValue: String) -> V -) : IBase, Int>, Closeable { +) : IBase, Int>, Closeable { object DbConstants { const val DB_NAME = "BinaryNodes" } private val connection = DriverManager.getConnection("jdbc:sqlite:$dbPath") ?: throw SQLException("Cannot connect to database") - private val createBaseStatement by lazy { connection.prepareStatement("CREATE TABLE if not exists ${DbConstants.DB_NAME} (key int, value varchar(255), x double, y double);") } + private val createBaseStatement by lazy { connection.prepareStatement("CREATE TABLE if not exists ${DbConstants.DB_NAME} (key varchar(255) NOT NULL, value varchar(255), x double NOT NULL, y double NOT NULL);") } private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO ${DbConstants.DB_NAME} (key, value, x, y) VALUES (?, ?, ?, ?);") } private val setPointStatement by lazy { connection.prepareStatement("UPDATE ${DbConstants.DB_NAME} SET x=?, y=? WHERE key=?;") } private val getPointStatement by lazy { connection.prepareStatement("SELECT x, y FROM ${DbConstants.DB_NAME} WHERE key=?;") } @@ -32,7 +34,7 @@ class BTBase( createBaseStatement.execute() } - override fun saveTree(tree: BinaryTree) { + override fun saveTree(tree: BinaryTree) { clear() if (tree.root == null) return @@ -41,13 +43,13 @@ class BTBase( } } - override fun loadTree(): BinaryTree { - val tree = BinaryTree() + override fun loadTree(): BinaryTree { + val tree = BinaryTree() val stateRes = getNodesStatement.executeQuery() while (stateRes.next()) - tree.add(stateRes.getInt(1), deserializeValue(stateRes.getString(2))) + tree.add(deserializeKey(stateRes.getString(1)), deserializeValue(stateRes.getString(2))) return tree } @@ -74,8 +76,8 @@ class BTBase( return p } - private fun addNode(node: BinaryNode, p: Point = Point(0, 0)) { - addNodeStatement.setInt(1, node.key) + private fun addNode(node: BinaryNode, p: Point = Point(0, 0)) { + addNodeStatement.setString(1, serializeKey(node.key)) addNodeStatement.setString(2, serializeValue(node.value)) addNodeStatement.setInt(3, p.x) addNodeStatement.setInt(4, p.y) @@ -96,11 +98,11 @@ class BTBase( connection.close() } - private fun BinaryTree.toList(): MutableList> = + private fun BinaryTree.toList(): MutableList> = this.root?.toList(mutableListOf()) ?: throw NullNodeException() - private fun BinaryNode.toList(list: MutableList>): MutableList> { - var myList: MutableList> = list + private fun BinaryNode.toList(list: MutableList>): MutableList> { + var myList: MutableList> = list myList.add(this) this.left?.let { From e53ecbb0fc641be7f48510b4e322b2115930a3fb Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 1 May 2023 11:16:00 +0300 Subject: [PATCH 152/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D1=83=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=20=D0=BF=D0=BE=D0=BF=D1=8B=D1=82=D0=BA=D0=B5=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8=D1=82=D1=8C=20=D0=BA=D0=BE=D0=BE?= =?UTF-8?q?=D1=80=D0=B4=D0=B8=D0=BD=D0=B0=D1=82=D1=83=20=D1=83=20=D0=BD?= =?UTF-8?q?=D0=B5=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=BD?= =?UTF-8?q?=D0=BE=D0=B9=20=D0=BD=D0=BE=D0=B4=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/databases/sqlite/BTBase.kt | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/lib/src/main/kotlin/databases/sqlite/BTBase.kt b/lib/src/main/kotlin/databases/sqlite/BTBase.kt index 16c6b8a..2809267 100644 --- a/lib/src/main/kotlin/databases/sqlite/BTBase.kt +++ b/lib/src/main/kotlin/databases/sqlite/BTBase.kt @@ -1,6 +1,7 @@ package databases.sqlite import databases.IBase +import exceptions.NodeNotFoundException import exceptions.NullNodeException import nodes.BinaryNode import trees.BinaryTree @@ -16,7 +17,7 @@ class BTBase, V>( private val deserializeKey: (strKey: String) -> K, private val serializeValue: (value: V?) -> String = { value -> value.toString() }, private val deserializeValue: (strValue: String) -> V -) : IBase, Int>, Closeable { +) : IBase, K>, Closeable { object DbConstants { const val DB_NAME = "BinaryNodes" } @@ -27,6 +28,7 @@ class BTBase, V>( private val addNodeStatement by lazy { connection.prepareStatement("INSERT INTO ${DbConstants.DB_NAME} (key, value, x, y) VALUES (?, ?, ?, ?);") } private val setPointStatement by lazy { connection.prepareStatement("UPDATE ${DbConstants.DB_NAME} SET x=?, y=? WHERE key=?;") } private val getPointStatement by lazy { connection.prepareStatement("SELECT x, y FROM ${DbConstants.DB_NAME} WHERE key=?;") } + private val getValueStatement by lazy { connection.prepareStatement("SELECT value FROM ${DbConstants.DB_NAME} WHERE key=?;") } private val getNodesStatement by lazy { connection.prepareStatement("SELECT key, value, x, y, value FROM ${DbConstants.DB_NAME}") } private val dropDatabaseStatement by lazy { connection.prepareStatement("DELETE FROM ${DbConstants.DB_NAME};") } @@ -53,20 +55,26 @@ class BTBase, V>( return tree } - override fun setPoint(key: Int, p: Point) { + override fun setPoint(key: K, p: Point) { + if (!nodeExists(key)) + throw NodeNotFoundException() + setPointStatement.setInt(1, p.x) setPointStatement.setInt(2, p.y) - setPointStatement.setInt(3, key) + setPointStatement.setString(3, serializeKey(key)) setPointStatement.execute() } - override fun getPoint(key: Int): Point { - getPointStatement.setInt(1, key) + override fun getPoint(key: K): Point { + if (!nodeExists(key)) + throw NodeNotFoundException() + + getPointStatement.setString(1, serializeKey(key)) val stateRes = getPointStatement.executeQuery() - val p = Point(-1, -1) + val p = Point() while (stateRes.next()) { p.x = stateRes.getInt(1) @@ -76,6 +84,13 @@ class BTBase, V>( return p } + private fun nodeExists(key: K): Boolean { + getValueStatement.setString(1, serializeKey(key)) + val stateRes = getValueStatement.executeQuery() + + return stateRes.next() + } + private fun addNode(node: BinaryNode, p: Point = Point(0, 0)) { addNodeStatement.setString(1, serializeKey(node.key)) addNodeStatement.setString(2, serializeValue(node.value)) @@ -94,6 +109,9 @@ class BTBase, V>( addNodeStatement.close() getNodesStatement.close() dropDatabaseStatement.close() + getPointStatement.close() + getValueStatement.close() + setPointStatement.close() connection.close() } From 9a5f8025ccc95963f12672e41a3efb6a40a879c4 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Mon, 1 May 2023 11:23:13 +0300 Subject: [PATCH 153/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D1=8F=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BA=D1=87=D0=B4=20=D1=81=20=D0=BB=D1=8E=D0=B1=D1=8B?= =?UTF-8?q?=D0=BC=20key?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/databases/json/JsonRBNode.kt | 2 +- lib/src/main/kotlin/databases/json/RBTBase.kt | 32 ++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/src/main/kotlin/databases/json/JsonRBNode.kt b/lib/src/main/kotlin/databases/json/JsonRBNode.kt index a6ac459..3f384fb 100644 --- a/lib/src/main/kotlin/databases/json/JsonRBNode.kt +++ b/lib/src/main/kotlin/databases/json/JsonRBNode.kt @@ -6,7 +6,7 @@ import nodes.Color @Serializable data class JsonRBNode( val value: String, - val key: Int, + val key: String, val color: Color, var x: Int, var y: Int, diff --git a/lib/src/main/kotlin/databases/json/RBTBase.kt b/lib/src/main/kotlin/databases/json/RBTBase.kt index e884c94..4962620 100644 --- a/lib/src/main/kotlin/databases/json/RBTBase.kt +++ b/lib/src/main/kotlin/databases/json/RBTBase.kt @@ -10,22 +10,24 @@ import trees.RBTree import java.awt.Point import java.io.File -class RBTBase( +class RBTBase, V>( private val dbPath: String, + private val serializeKey: (key: K) -> String = { value -> value.toString() }, + private val deserializeKey: (strKey: String) -> K, private val serializeValue: (value: V?) -> String = { value -> value.toString() }, private val deserializeValue: (strValue: String) -> V -) : IBase, Int> { +) : IBase, K> { private var file: File = File(dbPath) - override fun saveTree(tree: RBTree) { + override fun saveTree(tree: RBTree) { file.printWriter().use { out -> out.write(tree.convertToJson()) } } - override fun loadTree(): RBTree = Json.decodeFromString(file.readText()).convertToTree() + override fun loadTree(): RBTree = Json.decodeFromString(file.readText()).convertToTree() - override fun setPoint(key: Int, p: Point) { + override fun setPoint(key: K, p: Point) { val savedTree = Json.decodeFromString(file.readText()) if (savedTree.root?.changeCoordinate(key, p) != true) @@ -37,12 +39,12 @@ class RBTBase( } - override fun getPoint(key: Int): Point { + override fun getPoint(key: K): Point { return Json.decodeFromString(file.readText()).root?.searchCoordinate(key) ?: throw NodeNotFoundException() } - private fun JsonRBNode.searchCoordinate(key: Int): Point? { + private fun JsonRBNode.searchCoordinate(key: K): Point? { if (this.key == key) return Point(this.x, this.y) else { @@ -57,7 +59,7 @@ class RBTBase( return null } - private fun JsonRBNode.changeCoordinate(key: Int, p: Point): Boolean { + private fun JsonRBNode.changeCoordinate(key: K, p: Point): Boolean { return if (this.key == key) { this.x = p.x this.y = p.y @@ -70,23 +72,23 @@ class RBTBase( } } - private fun JsonRBTree.convertToTree(): RBTree = - RBTree().also { + private fun JsonRBTree.convertToTree(): RBTree = + RBTree().also { it.root = this.root?.convertToNode() } - private fun JsonRBNode.convertToNode(): RBNode = - RBNode(this.key, deserializeValue(this.value)).also { + private fun JsonRBNode.convertToNode(): RBNode = + RBNode(deserializeKey(this.key), deserializeValue(this.value)).also { it.color = this.color it.left = this.left?.convertToNode() it.right = this.right?.convertToNode() } - private fun RBTree.convertToJson() = Json.encodeToString(JsonRBTree(root?.convertToJson())) - private fun RBNode.convertToJson(x: Int = 0, y: Int = 0): JsonRBNode = + private fun RBTree.convertToJson() = Json.encodeToString(JsonRBTree(root?.convertToJson())) + private fun RBNode.convertToJson(x: Int = 0, y: Int = 0): JsonRBNode = JsonRBNode( serializeValue(this.value), - this.key, + serializeKey(this.key), this.color, x, y, From 60a200856cc2959e55440b222cb0b5b5e46e941c Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Mon, 1 May 2023 14:50:31 +0300 Subject: [PATCH 154/203] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20RBTreePainter=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=80=D0=B8=D1=81=D0=BE=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BD=D0=BE=D0=B4=20=D0=B2=20=D0=BE=D0=BA=D0=BD?= =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/kotlin/guiClasses/RBTreePainter.kt | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 App/src/main/kotlin/guiClasses/RBTreePainter.kt diff --git a/App/src/main/kotlin/guiClasses/RBTreePainter.kt b/App/src/main/kotlin/guiClasses/RBTreePainter.kt new file mode 100644 index 0000000..8aed4b6 --- /dev/null +++ b/App/src/main/kotlin/guiClasses/RBTreePainter.kt @@ -0,0 +1,48 @@ +package guiClasses + +import javax.swing.* +import java.awt.* +import trees.RBTree +import nodes.RBNode +import nodes.Color +import trees.AbstractTree + +class RBTNodePanel(private val tree: RBTree): JPanel(){ + val nodeSize = 30 + val nodeMargin = 10 + val lineColor = java.awt.Color.BLACK + + init { + preferredSize = Dimension(400, 400) + } + + override fun paintComponent(g: Graphics) { + super.paintComponent(g) + if (tree.root != null){ + drawNode(g, tree.root!!, width / 2, nodeMargin, width / 2) + } + } + + fun drawNode(g: Graphics, node: RBNode, x: Int, y: Int, parentX: Int){ + g.color = if (node.color == Color.BLACK) { //у ноды цвет задан классом Color из RBNode, + java.awt.Color.BLACK //у g - из библиотеки, поэтому вводим проверку + } else java.awt.Color.RED + g.fillOval(x - nodeSize / 2, y - nodeSize / 2, nodeSize, nodeSize) // рисуем ноду + g.color = lineColor + if (node.parent != null){ + g.drawLine(x, y, parentX, y - nodeMargin) //рисуем линию, если есть родитель у ноды + } + if (node.left != null) { + drawNode(g, node.left!!, x - width / (1 shl (getHeight(node.left!!) + 2)), y + nodeMargin + nodeSize, x) + } + if (node.right != null) { + drawNode(g, node.right!!, x + width / (1 shl (getHeight(node.right!!) + 2)), y + nodeMargin + nodeSize, x) + } + } + private fun getHeight(node: RBNode): Int { + if (node == null) { + return -1 + } + return 1 + maxOf(getHeight(node.left!!), getHeight(node.right!!)) + } +} From 23537aca243ce13c1260e07373d075ccce87216c Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Mon, 1 May 2023 21:31:27 +0300 Subject: [PATCH 155/203] =?UTF-8?q?=D0=9D=D0=B0=D0=BF=D0=B8=D1=81=D0=B0?= =?UTF-8?q?=D0=BB=20=D1=80=D0=B8=D1=81=D0=BE=D0=B2=D0=B0=D0=BB=D0=BA=D1=83?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D0=BA=D1=80=D0=B0=D1=81=D0=BD=D0=BE-?= =?UTF-8?q?=D1=87=D0=B5=D1=80=D0=BD=D1=8B=D1=85=20=D0=BD=D0=BE=D0=B4;=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=B2=20=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=8E=20=D0=BF=D1=80=D0=B8=D1=81=D0=B2=D0=BE=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BD=D1=83=D0=B6=D0=BD=D0=BE=D0=B3=D0=BE?= =?UTF-8?q?=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=B0=20=D0=BF=D1=80=D0=B8=20?= =?UTF-8?q?=D0=B5=D0=B3=D0=BE=20=D0=B2=D1=8B=D0=B1=D0=BE=D1=80=D0=B5;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 23 ++++++++++++++++--- App/src/main/kotlin/guiClasses/MenuClass.kt | 13 +++++++++-- .../main/kotlin/guiClasses/RBTreePainter.kt | 6 ++--- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index b056b0f..83574b0 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -1,7 +1,12 @@ package app -import guiClasses.* -import javax.swing.* +import guiClasses.Frame +import guiClasses.KeyTextField +import guiClasses.MenuClass +import javax.swing.GroupLayout +import javax.swing.JButton +import javax.swing.JPanel +import javax.swing.JScrollPane private fun treeFrameInit() { val treeFrame = Frame("Treeple", 1000, 700, 360, 50) @@ -37,7 +42,19 @@ private fun menuFrameInit() { val saveButton = JButton("Save") - val treeMenu = MenuClass() + val treeMenu = MenuClass(){tree -> + when (tree){ + is BinaryTree<*, *> -> { + + } + is AVLTree<*, *> -> { + + } + is RBTree<*, *> -> { + + } + } + } menuFrame.jMenuBar = treeMenu diff --git a/App/src/main/kotlin/guiClasses/MenuClass.kt b/App/src/main/kotlin/guiClasses/MenuClass.kt index 09effa9..18236f4 100644 --- a/App/src/main/kotlin/guiClasses/MenuClass.kt +++ b/App/src/main/kotlin/guiClasses/MenuClass.kt @@ -1,11 +1,14 @@ package guiClasses +import trees.AVLTree +import trees.BinaryTree +import trees.RBTree import java.awt.Color import javax.swing.JMenu import javax.swing.JMenuBar import javax.swing.JMenuItem -class MenuClass() : JMenuBar() { +class MenuClass(private val onTreeSelected: (tree: Any) -> Unit) : JMenuBar() { /** * Визуально обозначает элементы как неактивные @@ -23,7 +26,10 @@ class MenuClass() : JMenuBar() { } private val menu = JMenu("Выбор Дерева") - private val menuItems = arrayOf(JMenuItem("Binary Tree"), JMenuItem("AVL-Tree"), JMenuItem("Red-black Tree")) + private val menuItems = arrayOf( + JMenuItem("Binary Tree"), + JMenuItem("AVL-Tree"), + JMenuItem("Red-black Tree")) init { menuItems.forEach { menu.add(it) } @@ -32,16 +38,19 @@ class MenuClass() : JMenuBar() { // Слушатель событий для элемента меню "Binary Tree" menuItems[0].addActionListener { updateMenuItemsChoosing(menuItems[0]) + onTreeSelected(BinaryTree()) } // Слушатель событий для элемента меню "AVL-Tree" menuItems[1].addActionListener { updateMenuItemsChoosing(menuItems[1]) + onTreeSelected(AVLTree()) } // Слушатель событий для элемента меню "Red-black Tree" menuItems[2].addActionListener { updateMenuItemsChoosing(menuItems[2]) + onTreeSelected(RBTree()) } add(menu) diff --git a/App/src/main/kotlin/guiClasses/RBTreePainter.kt b/App/src/main/kotlin/guiClasses/RBTreePainter.kt index 8aed4b6..eef8e58 100644 --- a/App/src/main/kotlin/guiClasses/RBTreePainter.kt +++ b/App/src/main/kotlin/guiClasses/RBTreePainter.kt @@ -13,7 +13,7 @@ class RBTNodePanel(private val tree: RBTree): JPanel(){ val lineColor = java.awt.Color.BLACK init { - preferredSize = Dimension(400, 400) + preferredSize = Dimension(1000, 700) } override fun paintComponent(g: Graphics) { @@ -34,10 +34,10 @@ class RBTNodePanel(private val tree: RBTree): JPanel(){ } if (node.left != null) { drawNode(g, node.left!!, x - width / (1 shl (getHeight(node.left!!) + 2)), y + nodeMargin + nodeSize, x) - } + } //рекурсивно рисуем левое поддерево, shl - побитовый сдвиг влево if (node.right != null) { drawNode(g, node.right!!, x + width / (1 shl (getHeight(node.right!!) + 2)), y + nodeMargin + nodeSize, x) - } + } //рекурсивно рисуем правое поддерево } private fun getHeight(node: RBNode): Int { if (node == null) { From b3fea3fa5f73e764506d5a1530d384215fa16777 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 10:16:34 +0300 Subject: [PATCH 156/203] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BB=20=D1=84=D0=B0=D0=B9=D0=BB?= =?UTF-8?q?=20=D1=81=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=BE=D0=BC=20RBTNod?= =?UTF-8?q?ePanel,=20=D1=81=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20=D1=81=D0=B3?= =?UTF-8?q?=D0=BB=D0=B0=D0=B6=D0=B8=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D1=88=D0=B8=D0=BD,=20=D0=B2=20Main=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=B2=D1=8B=D0=B7=D0=BE=D0=B2?= =?UTF-8?q?=20=D1=82=D0=B5=D1=81=D1=82=D0=BE=D0=B2=D0=BE=D0=B9=20=D1=84?= =?UTF-8?q?=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BE=D1=82=D1=80=D0=B8=D1=81=D0=BE=D0=B2=D0=BA=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B2=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 68 ++++++++------- App/src/main/kotlin/guiClasses/MenuClass.kt | 5 +- .../main/kotlin/guiClasses/RBTNodePanel.kt | 87 +++++++++++++++++++ .../main/kotlin/guiClasses/RBTreePainter.kt | 48 ---------- lib/src/main/kotlin/trees/AbstractTree.kt | 2 + 5 files changed, 131 insertions(+), 79 deletions(-) create mode 100644 App/src/main/kotlin/guiClasses/RBTNodePanel.kt delete mode 100644 App/src/main/kotlin/guiClasses/RBTreePainter.kt diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 83574b0..eb2a12e 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -3,33 +3,20 @@ package app import guiClasses.Frame import guiClasses.KeyTextField import guiClasses.MenuClass +import guiClasses.RBTNodePanel +import trees.AVLTree +import trees.BinaryTree +import trees.RBTree import javax.swing.GroupLayout import javax.swing.JButton -import javax.swing.JPanel -import javax.swing.JScrollPane +import javax.swing.JFrame -private fun treeFrameInit() { - val treeFrame = Frame("Treeple", 1000, 700, 360, 50) - - // Создаем панель с компонентами - val treePanel = JPanel() - - val scrollPane = JScrollPane() - // Добавляем панель на панель с прокруткой - scrollPane.setViewportView(treePanel) - - // Добавляем панель с прокруткой на окно - treeFrame.contentPane.add(scrollPane) - - // Устанавливаем режим прокрутки по вертикали и горизонтали - scrollPane.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED - scrollPane.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED - - treeFrame.add(treePanel) -} +private lateinit var treeFrame: JFrame +private lateinit var menuFrame: JFrame +private lateinit var rbTree: RBTree private fun menuFrameInit() { - val menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) + menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) val addButton = JButton("Add") val addTextField = KeyTextField() @@ -42,23 +29,24 @@ private fun menuFrameInit() { val saveButton = JButton("Save") - val treeMenu = MenuClass(){tree -> - when (tree){ + val treeMenu = MenuClass { tree -> + when (tree) { is BinaryTree<*, *> -> { - + println("бинарное дерево") } - is AVLTree<*, *> -> { + is AVLTree<*, *> -> { + println("AVL дерево") } - is RBTree<*, *> -> { + is RBTree<*, *> -> { + rbtDraw() } } } menuFrame.jMenuBar = treeMenu - // contentPane - контейнер для компонентов val layout = GroupLayout(menuFrame.contentPane) menuFrame.contentPane.layout = layout @@ -115,7 +103,29 @@ private fun menuFrameInit() { ) } +private fun rbtDraw() { + rbTree = RBTree() + rbTree.add(100) +// rbTree.add(150) + // Создаем панель с компонентами + val treePanel = RBTNodePanel(rbTree) + +// val panel = JScrollPane() +// // Добавляем панель на панель с прокруткой +// panel.setViewportView(treePanel) +// +// // Добавляем панель с прокруткой на окно +// treeFrame.contentPane.add(panel) +// +// // Устанавливаем режим прокрутки по вертикали и горизонтали +// panel.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED +// panel.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED +// + treeFrame.add(treePanel) +} + fun main() { - treeFrameInit() menuFrameInit() + treeFrame = Frame("Treeple", 1000, 700, 360, 50) + rbtDraw() } \ No newline at end of file diff --git a/App/src/main/kotlin/guiClasses/MenuClass.kt b/App/src/main/kotlin/guiClasses/MenuClass.kt index 18236f4..2ed757c 100644 --- a/App/src/main/kotlin/guiClasses/MenuClass.kt +++ b/App/src/main/kotlin/guiClasses/MenuClass.kt @@ -22,14 +22,15 @@ class MenuClass(private val onTreeSelected: (tree: Any) -> Unit) : JMenuBar() { * */ private fun updateMenuItemsChoosing(item: JMenuItem) { item.background = Color.PINK - menuItems.filter { it != item }.forEach { it.background = Color.WHITE} + menuItems.filter { it != item }.forEach { it.background = Color.WHITE } } private val menu = JMenu("Выбор Дерева") private val menuItems = arrayOf( JMenuItem("Binary Tree"), JMenuItem("AVL-Tree"), - JMenuItem("Red-black Tree")) + JMenuItem("Red-black Tree") + ) init { menuItems.forEach { menu.add(it) } diff --git a/App/src/main/kotlin/guiClasses/RBTNodePanel.kt b/App/src/main/kotlin/guiClasses/RBTNodePanel.kt new file mode 100644 index 0000000..e65569f --- /dev/null +++ b/App/src/main/kotlin/guiClasses/RBTNodePanel.kt @@ -0,0 +1,87 @@ +package guiClasses + +import exceptions.NullNodeException +import nodes.Color +import nodes.RBNode +import trees.RBTree +import java.awt.Dimension +import java.awt.Graphics +import java.awt.Graphics2D +import java.awt.RenderingHints +import javax.swing.JPanel + +class RBTNodePanel(private val tree: RBTree) : JPanel() { + + /** + * Объект со свойствами нод + */ + object Constants { + const val nodeSize = 30 + const val nodeMargin = 20 + val lineColor = java.awt.Color.BLACK + ?: throw NullPointerException() + } + + init { + preferredSize = Dimension(1000, 700) + } + + override fun paintComponent(g: Graphics) { + super.paintComponent(g) + + // Сглаживание + (g as Graphics2D).also { + val rh = RenderingHints( + RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON + ) + it.setRenderingHints(rh) + } + + if (tree.treeRoot != null) { + val rootX = width / 2 // нода рисуется посередине + drawNode(g, tree.treeRoot ?: throw NullNodeException(), rootX, Constants.nodeMargin, rootX) + } + } + + + /** + * Рекурсивная отрисовка каждой ноды дерева + */ + private fun drawNode(g: Graphics, node: RBNode, x: Int, y: Int, parentX: Int) { + // Устанавливаем цвет рисуемой ноды как у переданной + g.color = if (node.color == Color.BLACK) + java.awt.Color.BLACK + else + java.awt.Color.RED + + // Рисуем овал (ноду) + g.fillOval(x - Constants.nodeSize / 2, y - Constants.nodeSize / 2, Constants.nodeSize, Constants.nodeSize) + g.color = Constants.lineColor //Обводка овала + + if (node.parent != null) + g.drawLine(x, y, parentX, y - Constants.nodeMargin) //рисуем линию, если есть родитель у ноды + + if (node.left != null) { + drawNode( + g, + node.left ?: throw NullNodeException(), + x - width / (1 shl (getHeight(node.left ?: throw NullNodeException()) + 2)), + y + Constants.nodeMargin + Constants.nodeSize, + x + ) + } //рекурсивно рисуем левое поддерево, shl - побитовый сдвиг влево + if (node.right != null) { + drawNode( + g, + node.right ?: throw NullNodeException(), + x + width / (1 shl (getHeight(node.right ?: throw NullNodeException()) + 2)), + y + Constants.nodeMargin + Constants.nodeSize, + x + ) + } //рекурсивно рисуем правое поддерево + } + + private fun getHeight(node: RBNode): Int = + 1 + maxOf(getHeight(node.left ?: throw NullNodeException()), getHeight(node.right ?: throw NullNodeException())) +} diff --git a/App/src/main/kotlin/guiClasses/RBTreePainter.kt b/App/src/main/kotlin/guiClasses/RBTreePainter.kt deleted file mode 100644 index eef8e58..0000000 --- a/App/src/main/kotlin/guiClasses/RBTreePainter.kt +++ /dev/null @@ -1,48 +0,0 @@ -package guiClasses - -import javax.swing.* -import java.awt.* -import trees.RBTree -import nodes.RBNode -import nodes.Color -import trees.AbstractTree - -class RBTNodePanel(private val tree: RBTree): JPanel(){ - val nodeSize = 30 - val nodeMargin = 10 - val lineColor = java.awt.Color.BLACK - - init { - preferredSize = Dimension(1000, 700) - } - - override fun paintComponent(g: Graphics) { - super.paintComponent(g) - if (tree.root != null){ - drawNode(g, tree.root!!, width / 2, nodeMargin, width / 2) - } - } - - fun drawNode(g: Graphics, node: RBNode, x: Int, y: Int, parentX: Int){ - g.color = if (node.color == Color.BLACK) { //у ноды цвет задан классом Color из RBNode, - java.awt.Color.BLACK //у g - из библиотеки, поэтому вводим проверку - } else java.awt.Color.RED - g.fillOval(x - nodeSize / 2, y - nodeSize / 2, nodeSize, nodeSize) // рисуем ноду - g.color = lineColor - if (node.parent != null){ - g.drawLine(x, y, parentX, y - nodeMargin) //рисуем линию, если есть родитель у ноды - } - if (node.left != null) { - drawNode(g, node.left!!, x - width / (1 shl (getHeight(node.left!!) + 2)), y + nodeMargin + nodeSize, x) - } //рекурсивно рисуем левое поддерево, shl - побитовый сдвиг влево - if (node.right != null) { - drawNode(g, node.right!!, x + width / (1 shl (getHeight(node.right!!) + 2)), y + nodeMargin + nodeSize, x) - } //рекурсивно рисуем правое поддерево - } - private fun getHeight(node: RBNode): Int { - if (node == null) { - return -1 - } - return 1 + maxOf(getHeight(node.left!!), getHeight(node.right!!)) - } -} diff --git a/lib/src/main/kotlin/trees/AbstractTree.kt b/lib/src/main/kotlin/trees/AbstractTree.kt index 6eaf77f..b129a14 100644 --- a/lib/src/main/kotlin/trees/AbstractTree.kt +++ b/lib/src/main/kotlin/trees/AbstractTree.kt @@ -7,4 +7,6 @@ abstract class AbstractTree, V, node : AbstractNode Date: Tue, 2 May 2023 10:35:33 +0300 Subject: [PATCH 157/203] =?UTF-8?q?=D0=9F=D0=BE=D0=BC=D0=B5=D0=BD=D1=8F?= =?UTF-8?q?=D0=BB=20=D0=B0=D0=BB=D0=B3=D0=BE=D1=80=D0=B8=D1=82=D0=BC=20?= =?UTF-8?q?=D0=B2=D1=8B=D1=87=D0=B8=D1=81=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BE=D1=80=D0=B4=D0=B8=D0=BD=D0=B0=D1=82=D1=8B=20?= =?UTF-8?q?=D1=81=D0=BB=D0=B5=D0=B4=D1=83=D1=8E=D1=89=D0=B5=D0=B9=20=D0=BD?= =?UTF-8?q?=D0=BE=D0=B4=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 6 ++++- .../main/kotlin/guiClasses/RBTNodePanel.kt | 27 +++++++++++-------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index eb2a12e..f455565 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -106,7 +106,11 @@ private fun menuFrameInit() { private fun rbtDraw() { rbTree = RBTree() rbTree.add(100) -// rbTree.add(150) + rbTree.add(0) + rbTree.add(120) + rbTree.add(130) + rbTree.add(140) + rbTree.add(3) // Создаем панель с компонентами val treePanel = RBTNodePanel(rbTree) diff --git a/App/src/main/kotlin/guiClasses/RBTNodePanel.kt b/App/src/main/kotlin/guiClasses/RBTNodePanel.kt index e65569f..76d02bd 100644 --- a/App/src/main/kotlin/guiClasses/RBTNodePanel.kt +++ b/App/src/main/kotlin/guiClasses/RBTNodePanel.kt @@ -40,7 +40,7 @@ class RBTNodePanel(private val tree: RBTree) : JPanel() { if (tree.treeRoot != null) { val rootX = width / 2 // нода рисуется посередине - drawNode(g, tree.treeRoot ?: throw NullNodeException(), rootX, Constants.nodeMargin, rootX) + drawNode(g, tree.treeRoot ?: throw NullNodeException(), rootX, Constants.nodeMargin) } } @@ -48,7 +48,7 @@ class RBTNodePanel(private val tree: RBTree) : JPanel() { /** * Рекурсивная отрисовка каждой ноды дерева */ - private fun drawNode(g: Graphics, node: RBNode, x: Int, y: Int, parentX: Int) { + private fun drawNode(g: Graphics, node: RBNode, x: Int, y: Int) { // Устанавливаем цвет рисуемой ноды как у переданной g.color = if (node.color == Color.BLACK) java.awt.Color.BLACK @@ -59,25 +59,30 @@ class RBTNodePanel(private val tree: RBTree) : JPanel() { g.fillOval(x - Constants.nodeSize / 2, y - Constants.nodeSize / 2, Constants.nodeSize, Constants.nodeSize) g.color = Constants.lineColor //Обводка овала - if (node.parent != null) - g.drawLine(x, y, parentX, y - Constants.nodeMargin) //рисуем линию, если есть родитель у ноды - if (node.left != null) { + val nextX = x - Constants.nodeMargin - Constants.nodeSize + val nextY = y + Constants.nodeMargin + Constants.nodeSize + + g.drawLine(x, y, nextX, nextY) + drawNode( g, node.left ?: throw NullNodeException(), - x - width / (1 shl (getHeight(node.left ?: throw NullNodeException()) + 2)), - y + Constants.nodeMargin + Constants.nodeSize, - x + nextX, + nextY ) } //рекурсивно рисуем левое поддерево, shl - побитовый сдвиг влево if (node.right != null) { + val nextX = x + Constants.nodeMargin + Constants.nodeSize + val nextY = y + Constants.nodeMargin + Constants.nodeSize + + g.drawLine(x, y, nextX, nextY) + drawNode( g, node.right ?: throw NullNodeException(), - x + width / (1 shl (getHeight(node.right ?: throw NullNodeException()) + 2)), - y + Constants.nodeMargin + Constants.nodeSize, - x + nextX, + nextY ) } //рекурсивно рисуем правое поддерево } From 41ff948c12b8ae3b8073c3f7a79c41027bd24d15 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 15:07:00 +0300 Subject: [PATCH 158/203] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=BE=D1=82=D1=80=D0=B8=D1=81=D0=BE=D0=B2=D0=BA=D1=83=20=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B2=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 3 + .../main/kotlin/guiClasses/RBTNodePanel.kt | 83 ++++++++++++------- 2 files changed, 54 insertions(+), 32 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index f455565..0f31859 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -111,6 +111,9 @@ private fun rbtDraw() { rbTree.add(130) rbTree.add(140) rbTree.add(3) + rbTree.add(15) + rbTree.add(17) + // Создаем панель с компонентами val treePanel = RBTNodePanel(rbTree) diff --git a/App/src/main/kotlin/guiClasses/RBTNodePanel.kt b/App/src/main/kotlin/guiClasses/RBTNodePanel.kt index 76d02bd..e3257dc 100644 --- a/App/src/main/kotlin/guiClasses/RBTNodePanel.kt +++ b/App/src/main/kotlin/guiClasses/RBTNodePanel.kt @@ -4,10 +4,7 @@ import exceptions.NullNodeException import nodes.Color import nodes.RBNode import trees.RBTree -import java.awt.Dimension -import java.awt.Graphics -import java.awt.Graphics2D -import java.awt.RenderingHints +import java.awt.* import javax.swing.JPanel class RBTNodePanel(private val tree: RBTree) : JPanel() { @@ -22,6 +19,8 @@ class RBTNodePanel(private val tree: RBTree) : JPanel() { ?: throw NullPointerException() } + private lateinit var graphics: Graphics + init { preferredSize = Dimension(1000, 700) } @@ -30,7 +29,7 @@ class RBTNodePanel(private val tree: RBTree) : JPanel() { super.paintComponent(g) // Сглаживание - (g as Graphics2D).also { + graphics = (g as Graphics2D).also { val rh = RenderingHints( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON @@ -40,7 +39,11 @@ class RBTNodePanel(private val tree: RBTree) : JPanel() { if (tree.treeRoot != null) { val rootX = width / 2 // нода рисуется посередине - drawNode(g, tree.treeRoot ?: throw NullNodeException(), rootX, Constants.nodeMargin) + val rootY = Constants.nodeMargin + + drawNode(tree.treeRoot?: throw NullNodeException(), Point(rootX, rootY)) + + recursiveDraw(tree.treeRoot ?: throw NullNodeException(), rootX, Constants.nodeMargin) } } @@ -48,45 +51,61 @@ class RBTNodePanel(private val tree: RBTree) : JPanel() { /** * Рекурсивная отрисовка каждой ноды дерева */ - private fun drawNode(g: Graphics, node: RBNode, x: Int, y: Int) { - // Устанавливаем цвет рисуемой ноды как у переданной - g.color = if (node.color == Color.BLACK) - java.awt.Color.BLACK - else - java.awt.Color.RED - - // Рисуем овал (ноду) - g.fillOval(x - Constants.nodeSize / 2, y - Constants.nodeSize / 2, Constants.nodeSize, Constants.nodeSize) - g.color = Constants.lineColor //Обводка овала + private fun recursiveDraw(root: RBNode, x: Int, y: Int, n: Int = 1) { + var nextX: Int + var nextY: Int - if (node.left != null) { - val nextX = x - Constants.nodeMargin - Constants.nodeSize - val nextY = y + Constants.nodeMargin + Constants.nodeSize + if (root.left != null) { + nextX = x - (x / (2 * n)) + nextY = y + Constants.nodeMargin + Constants.nodeSize - g.drawLine(x, y, nextX, nextY) + drawLine(Point(x, y), Point(nextX, nextY)) + drawNode(root, Point(nextX, nextY)) - drawNode( - g, - node.left ?: throw NullNodeException(), + recursiveDraw( + root.left ?: throw NullNodeException(), nextX, - nextY + nextY, + n + 1 ) } //рекурсивно рисуем левое поддерево, shl - побитовый сдвиг влево - if (node.right != null) { - val nextX = x + Constants.nodeMargin + Constants.nodeSize - val nextY = y + Constants.nodeMargin + Constants.nodeSize + if (root.right != null) { + + nextX = x + (x / (2 * n)) + nextY = y + Constants.nodeMargin + Constants.nodeSize - g.drawLine(x, y, nextX, nextY) + drawLine(Point(x, y), Point(nextX, nextY)) + drawNode(root, Point(nextX, nextY)) - drawNode( - g, - node.right ?: throw NullNodeException(), + recursiveDraw( + root.right ?: throw NullNodeException(), nextX, - nextY + nextY, + 2 * n + 1 ) } //рекурсивно рисуем правое поддерево } + private fun drawNode(node: RBNode, p: Point) { + graphics.color = if (node.color == Color.BLACK) + java.awt.Color.BLACK + else + java.awt.Color.RED + + // Рисуем овал (ноду) + graphics.fillOval( + p.x - Constants.nodeSize / 2, + p.y - Constants.nodeSize / 2, + Constants.nodeSize, + Constants.nodeSize + ) + } + + private fun drawLine(start: Point, end: Point) { + graphics.color = Constants.lineColor + graphics.drawLine(start.x, start.y, end.x, end.y) + } + private fun getHeight(node: RBNode): Int = 1 + maxOf(getHeight(node.left ?: throw NullNodeException()), getHeight(node.right ?: throw NullNodeException())) } From e6adabc8a4a7f79a54d7ceb6a82434291260b497 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 15:16:15 +0300 Subject: [PATCH 159/203] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20=D0=B1?= =?UTF-8?q?=D0=B0=D0=B3=20=D1=81=20=D0=BE=D1=82=D1=80=D0=B8=D1=81=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D0=BE=D0=B9=20=D0=BB=D0=B8=D0=BD=D0=B8=D0=B8=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=B4=20=D0=BD=D0=BE=D0=B4=D0=BE=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/guiClasses/RBTNodePanel.kt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/App/src/main/kotlin/guiClasses/RBTNodePanel.kt b/App/src/main/kotlin/guiClasses/RBTNodePanel.kt index e3257dc..e808bcf 100644 --- a/App/src/main/kotlin/guiClasses/RBTNodePanel.kt +++ b/App/src/main/kotlin/guiClasses/RBTNodePanel.kt @@ -51,39 +51,41 @@ class RBTNodePanel(private val tree: RBTree) : JPanel() { /** * Рекурсивная отрисовка каждой ноды дерева */ - private fun recursiveDraw(root: RBNode, x: Int, y: Int, n: Int = 1) { + private fun recursiveDraw(node: RBNode, x: Int, y: Int, n: Int = 1) { + var nextX: Int var nextY: Int - if (root.left != null) { + if (node.left != null) { nextX = x - (x / (2 * n)) nextY = y + Constants.nodeMargin + Constants.nodeSize drawLine(Point(x, y), Point(nextX, nextY)) - drawNode(root, Point(nextX, nextY)) recursiveDraw( - root.left ?: throw NullNodeException(), + node.left ?: throw NullNodeException(), nextX, nextY, n + 1 ) } //рекурсивно рисуем левое поддерево, shl - побитовый сдвиг влево - if (root.right != null) { + if (node.right != null) { nextX = x + (x / (2 * n)) nextY = y + Constants.nodeMargin + Constants.nodeSize drawLine(Point(x, y), Point(nextX, nextY)) - drawNode(root, Point(nextX, nextY)) recursiveDraw( - root.right ?: throw NullNodeException(), + node.right ?: throw NullNodeException(), nextX, nextY, - 2 * n + 1 + n+1 ) } //рекурсивно рисуем правое поддерево + + drawNode(node, Point(x, y)) + } private fun drawNode(node: RBNode, p: Point) { From e1bb0e6ab6d529afcdf692d78c1f05c74fc89494 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 15:22:52 +0300 Subject: [PATCH 160/203] =?UTF-8?q?=D0=9F=D0=BE=D0=BC=D0=B5=D0=BD=D1=8F?= =?UTF-8?q?=D0=BB=20=D1=84=D0=BE=D1=80=D0=BC=D1=83=D0=BB=D1=83=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=BE=D1=82=D1=80=D0=B8=D1=81=D0=BE=D0=B2=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=BE=D0=B4,=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D1=8C=20=D0=B2=D1=81=D1=91=20=D0=B8=D0=B4=D0=B5=D0=B0=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D0=BE=20=D0=B4=D0=BE=D0=BB=D0=B6=D0=BD=D0=BE=20?= =?UTF-8?q?=D0=B1=D1=8B=D1=82=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/guiClasses/RBTNodePanel.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/App/src/main/kotlin/guiClasses/RBTNodePanel.kt b/App/src/main/kotlin/guiClasses/RBTNodePanel.kt index e808bcf..f61f99c 100644 --- a/App/src/main/kotlin/guiClasses/RBTNodePanel.kt +++ b/App/src/main/kotlin/guiClasses/RBTNodePanel.kt @@ -52,7 +52,6 @@ class RBTNodePanel(private val tree: RBTree) : JPanel() { * Рекурсивная отрисовка каждой ноды дерева */ private fun recursiveDraw(node: RBNode, x: Int, y: Int, n: Int = 1) { - var nextX: Int var nextY: Int @@ -80,7 +79,7 @@ class RBTNodePanel(private val tree: RBTree) : JPanel() { node.right ?: throw NullNodeException(), nextX, nextY, - n+1 + 2*n+1 ) } //рекурсивно рисуем правое поддерево From b3c55433d7a9cc5d6bd7cbd531ed34b1fcfd4c99 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 19:10:28 +0300 Subject: [PATCH 161/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9?= =?UTF-8?q?=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=20=D0=B4=D0=BB=D1=8F=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=BE=D0=B2,?= =?UTF-8?q?=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BB=20=D0=B4=D0=B2=D0=B0=20?= =?UTF-8?q?=D0=B4=D0=B0=D1=82=D0=B0-=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=B0?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D0=BE=D1=82=D1=80=D0=B8=D1=81=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D0=B8=20=D0=BD=D0=BE=D0=B4=20=D0=B8=20=D1=81=D0=BE?= =?UTF-8?q?=D0=B5=D0=B4=D0=B8=D0=BD=D1=8F=D1=8E=D1=89=D0=B8=D1=85=20=D0=B8?= =?UTF-8?q?=D1=85=20=D0=BB=D0=B8=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/guiClasses/{ => components}/Frame.kt | 2 +- .../kotlin/guiClasses/{ => components}/KeyTextField.kt | 4 +--- .../main/kotlin/guiClasses/{ => components}/MenuClass.kt | 2 +- .../kotlin/guiClasses/{ => components}/RBTNodePanel.kt | 3 +-- App/src/main/kotlin/guiClasses/view/LineView.kt | 8 ++++++++ App/src/main/kotlin/guiClasses/view/NodeView.kt | 9 +++++++++ 6 files changed, 21 insertions(+), 7 deletions(-) rename App/src/main/kotlin/guiClasses/{ => components}/Frame.kt (96%) rename App/src/main/kotlin/guiClasses/{ => components}/KeyTextField.kt (76%) rename App/src/main/kotlin/guiClasses/{ => components}/MenuClass.kt (98%) rename App/src/main/kotlin/guiClasses/{ => components}/RBTNodePanel.kt (99%) create mode 100644 App/src/main/kotlin/guiClasses/view/LineView.kt create mode 100644 App/src/main/kotlin/guiClasses/view/NodeView.kt diff --git a/App/src/main/kotlin/guiClasses/Frame.kt b/App/src/main/kotlin/guiClasses/components/Frame.kt similarity index 96% rename from App/src/main/kotlin/guiClasses/Frame.kt rename to App/src/main/kotlin/guiClasses/components/Frame.kt index de9c787..dfaa217 100644 --- a/App/src/main/kotlin/guiClasses/Frame.kt +++ b/App/src/main/kotlin/guiClasses/components/Frame.kt @@ -1,4 +1,4 @@ -package guiClasses +package guiClasses.components import java.awt.Dimension import javax.swing.* diff --git a/App/src/main/kotlin/guiClasses/KeyTextField.kt b/App/src/main/kotlin/guiClasses/components/KeyTextField.kt similarity index 76% rename from App/src/main/kotlin/guiClasses/KeyTextField.kt rename to App/src/main/kotlin/guiClasses/components/KeyTextField.kt index 78b576a..22c9732 100644 --- a/App/src/main/kotlin/guiClasses/KeyTextField.kt +++ b/App/src/main/kotlin/guiClasses/components/KeyTextField.kt @@ -1,7 +1,5 @@ -package guiClasses +package guiClasses.components -import java.awt.Font -import java.awt.event.ActionListener import javax.swing.JTextField class KeyTextField() : JTextField() { diff --git a/App/src/main/kotlin/guiClasses/MenuClass.kt b/App/src/main/kotlin/guiClasses/components/MenuClass.kt similarity index 98% rename from App/src/main/kotlin/guiClasses/MenuClass.kt rename to App/src/main/kotlin/guiClasses/components/MenuClass.kt index 2ed757c..50e4845 100644 --- a/App/src/main/kotlin/guiClasses/MenuClass.kt +++ b/App/src/main/kotlin/guiClasses/components/MenuClass.kt @@ -1,4 +1,4 @@ -package guiClasses +package guiClasses.components import trees.AVLTree import trees.BinaryTree diff --git a/App/src/main/kotlin/guiClasses/RBTNodePanel.kt b/App/src/main/kotlin/guiClasses/components/RBTNodePanel.kt similarity index 99% rename from App/src/main/kotlin/guiClasses/RBTNodePanel.kt rename to App/src/main/kotlin/guiClasses/components/RBTNodePanel.kt index f61f99c..2454338 100644 --- a/App/src/main/kotlin/guiClasses/RBTNodePanel.kt +++ b/App/src/main/kotlin/guiClasses/components/RBTNodePanel.kt @@ -1,4 +1,4 @@ -package guiClasses +package guiClasses.components import exceptions.NullNodeException import nodes.Color @@ -47,7 +47,6 @@ class RBTNodePanel(private val tree: RBTree) : JPanel() { } } - /** * Рекурсивная отрисовка каждой ноды дерева */ diff --git a/App/src/main/kotlin/guiClasses/view/LineView.kt b/App/src/main/kotlin/guiClasses/view/LineView.kt new file mode 100644 index 0000000..05ea873 --- /dev/null +++ b/App/src/main/kotlin/guiClasses/view/LineView.kt @@ -0,0 +1,8 @@ +package guiClasses.view + +import java.awt.Point + +data class LineView ( + val from: Point, + val to: Point +) \ No newline at end of file diff --git a/App/src/main/kotlin/guiClasses/view/NodeView.kt b/App/src/main/kotlin/guiClasses/view/NodeView.kt new file mode 100644 index 0000000..85fe216 --- /dev/null +++ b/App/src/main/kotlin/guiClasses/view/NodeView.kt @@ -0,0 +1,9 @@ +package guiClasses.view + +import java.awt.Color +import java.awt.Point + +data class NodeView( + val point: Point, + val color: Color +) \ No newline at end of file From a6424e7e439c8d558a53298227b410924b9ec2dc Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 19:15:15 +0300 Subject: [PATCH 162/203] =?UTF-8?q?=D0=A3=D0=B4=D0=B0=D0=BB=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D1=83=D0=B6=D0=BD=D0=BE=D0=B5=20=D1=81=D0=B2?= =?UTF-8?q?=D0=BE=D0=B9=D1=81=D1=82=D0=B2=D0=BE=20=D0=B8=D0=B7=20AbstractT?= =?UTF-8?q?ree?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/trees/AbstractTree.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/src/main/kotlin/trees/AbstractTree.kt b/lib/src/main/kotlin/trees/AbstractTree.kt index b129a14..6eaf77f 100644 --- a/lib/src/main/kotlin/trees/AbstractTree.kt +++ b/lib/src/main/kotlin/trees/AbstractTree.kt @@ -7,6 +7,4 @@ abstract class AbstractTree, V, node : AbstractNode Date: Tue, 2 May 2023 19:42:58 +0300 Subject: [PATCH 163/203] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=20=D0=B4=D0=B0=D1=82=D0=B0-=D0=BA?= =?UTF-8?q?=D0=BB=D0=B0=D1=81=D1=81=D1=8B=20=D0=B2=20lib,=20=D1=82.=D0=BA.?= =?UTF-8?q?=20=D0=B2=20=D0=BE=D1=81=D0=BD=D0=BE=D0=B2=D0=BD=D0=BE=D0=BC=20?= =?UTF-8?q?=D0=B2=D1=81=D1=8F=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA=D0=B0=20?= =?UTF-8?q?=D1=81=D0=B2=D1=8F=D0=B7=D0=B0=D0=BD=D0=BD=D0=B0=D1=8F=20=D1=81?= =?UTF-8?q?=20=D0=BD=D0=B8=D0=BC=D0=B8=20=D0=BD=D0=B0=D1=85=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D1=82=D1=81=D1=8F=20=D0=B2=20=D0=BD=D1=91=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../view => lib/src/main/kotlin/guiControl}/LineView.kt | 2 +- .../view => lib/src/main/kotlin/guiControl}/NodeView.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename {App/src/main/kotlin/guiClasses/view => lib/src/main/kotlin/guiControl}/LineView.kt (78%) rename {App/src/main/kotlin/guiClasses/view => lib/src/main/kotlin/guiControl}/NodeView.kt (82%) diff --git a/App/src/main/kotlin/guiClasses/view/LineView.kt b/lib/src/main/kotlin/guiControl/LineView.kt similarity index 78% rename from App/src/main/kotlin/guiClasses/view/LineView.kt rename to lib/src/main/kotlin/guiControl/LineView.kt index 05ea873..27a6c57 100644 --- a/App/src/main/kotlin/guiClasses/view/LineView.kt +++ b/lib/src/main/kotlin/guiControl/LineView.kt @@ -1,4 +1,4 @@ -package guiClasses.view +package guiControl import java.awt.Point diff --git a/App/src/main/kotlin/guiClasses/view/NodeView.kt b/lib/src/main/kotlin/guiControl/NodeView.kt similarity index 82% rename from App/src/main/kotlin/guiClasses/view/NodeView.kt rename to lib/src/main/kotlin/guiControl/NodeView.kt index 85fe216..f97ec02 100644 --- a/App/src/main/kotlin/guiClasses/view/NodeView.kt +++ b/lib/src/main/kotlin/guiControl/NodeView.kt @@ -1,4 +1,4 @@ -package guiClasses.view +package guiControl import java.awt.Color import java.awt.Point From c17381b573e6a0565ef843e0f46f468e5c09be98 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 19:43:19 +0300 Subject: [PATCH 164/203] =?UTF-8?q?=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20AbstractPainter,=20=D0=BA?= =?UTF-8?q?=D0=BE=D1=82=D0=BE=D1=80=D1=8B=D0=B9=20=D0=B1=D1=83=D0=B4=D0=B5?= =?UTF-8?q?=D1=82=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B0=D1=82=D1=8C=20?= =?UTF-8?q?=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=BE=20=D0=B8=20=D0=B2=D0=BE?= =?UTF-8?q?=D0=B7=D0=B2=D1=80=D0=B0=D1=89=D0=B0=D1=82=D1=8C=20=D0=BD=D0=BE?= =?UTF-8?q?=D0=B4=D1=8B=20=D0=B8=20=D0=BB=D0=B8=D0=BD=D0=B8=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=BE=D1=82=D1=80=D0=B8=D1=81=D0=BE=D0=B2=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../guiControl/painters/AbstractPainter.kt | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt diff --git a/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt b/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt new file mode 100644 index 0000000..d57d575 --- /dev/null +++ b/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt @@ -0,0 +1,65 @@ +package guiControl.painters + +import exceptions.NullNodeException +import guiControl.LineView +import guiControl.NodeView +import nodes.AbstractNode +import trees.AbstractTree +import java.awt.Point + +abstract class AbstractPainter, TreeType : AbstractTree>( + private val tree: TreeType, + private val nodeMargin: Int, + private val nodeSize: Int, + private val width: Int +) { + val nodes: MutableList = mutableListOf() + val lines: MutableList = mutableListOf() + init { + if (tree.root != null) + getViewNodes(tree.root ?: throw NullNodeException(), width / 2, nodeMargin) + } + + /** + * Позволяет определить каким цветом рисовать ноду + */ + protected abstract fun getNodeColor(node: NodeType) : java.awt.Color + + /** + * Рекурсивно пробегает дерево и заполняет nodes и lines эл-ами для отрисовки + */ + private fun getViewNodes(node: NodeType, x: Int, y: Int, n: Int = 1) { + nodes.add(NodeView(Point(x, y), getNodeColor(node))) + + var nextX = 0 + var nextY = 0 + + if (node.left != null) { + nextX = x - (x / (2 * n)) + nextY = y + nodeMargin + nodeSize + + getViewNodes( + node.left ?: throw NullNodeException(), + nextX, + nextY, + n + 1 + ) + } + if (node.right != null) { + + nextX = x + (x / (2 * n)) + nextY = y + nodeMargin + nodeSize + + getViewNodes( + node.right ?: throw NullNodeException(), + nextX, + nextY, + 2 * n + 1 + ) + } + + lines.add(LineView(Point(x, y), Point(nextX, nextY))) + + } + +} \ No newline at end of file From ab17a5249b4d84b67dbd08f1b1462ba8a9b832ef Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 20:03:23 +0300 Subject: [PATCH 165/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D1=8B=20Painter=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BA=D0=B0=D0=B6=D0=B4=D0=BE=D0=B3=D0=BE?= =?UTF-8?q?=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=B0=20(=D0=B8=D1=81=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=D0=B7=D1=83=D1=8E=D1=82=D1=81=D1=8F=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=BE=D1=82=D1=80=D0=B8=D1=81=D0=BE=D0=B2=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=B2=D0=B5=D1=80=D1=88=D0=B8=D0=BD=20=D0=B8=20=D0=BF?= =?UTF-8?q?=D1=83=D1=82=D0=B5=D0=B9=20=D0=BA=20=D0=BD=D0=B8=D0=BC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/guiControl/painters/AVLPainter.kt | 14 +++++++++++ .../guiControl/painters/AbstractPainter.kt | 25 ++++++++++++------- .../kotlin/guiControl/painters/BTPainter.kt | 13 ++++++++++ .../kotlin/guiControl/painters/RBTPainter.kt | 18 +++++++++++++ 4 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 lib/src/main/kotlin/guiControl/painters/AVLPainter.kt create mode 100644 lib/src/main/kotlin/guiControl/painters/BTPainter.kt create mode 100644 lib/src/main/kotlin/guiControl/painters/RBTPainter.kt diff --git a/lib/src/main/kotlin/guiControl/painters/AVLPainter.kt b/lib/src/main/kotlin/guiControl/painters/AVLPainter.kt new file mode 100644 index 0000000..6f5a511 --- /dev/null +++ b/lib/src/main/kotlin/guiControl/painters/AVLPainter.kt @@ -0,0 +1,14 @@ +package guiControl.painters + +import nodes.AVLNode +import trees.AVLTree +import java.awt.Color + +class AVLPainter( + tree: AVLTree, + nodeMargin: Int, + nodeSize: Int, + width: Int +) : AbstractPainter, AVLTree>(tree, nodeMargin, nodeSize, width) { + override fun getNodeColor(node: AVLNode): Color = Color.ORANGE +} \ No newline at end of file diff --git a/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt b/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt index d57d575..929dbcd 100644 --- a/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt +++ b/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt @@ -8,18 +8,24 @@ import trees.AbstractTree import java.awt.Point abstract class AbstractPainter, TreeType : AbstractTree>( - private val tree: TreeType, + tree: TreeType, private val nodeMargin: Int, private val nodeSize: Int, - private val width: Int + width: Int ) { val nodes: MutableList = mutableListOf() val lines: MutableList = mutableListOf() init { - if (tree.root != null) - getViewNodes(tree.root ?: throw NullNodeException(), width / 2, nodeMargin) - } + if (tree.root == null) { + // Если дерево ещё не заполнено, то заполним его "образцом" + tree.add(100) + tree.add(150) + tree.add(120) + tree.add(-10) + } + getViewNodes(tree.root ?: throw NullNodeException(), width / 2, nodeMargin) + } /** * Позволяет определить каким цветом рисовать ноду */ @@ -38,6 +44,8 @@ abstract class AbstractPainter, Tree nextX = x - (x / (2 * n)) nextY = y + nodeMargin + nodeSize + lines.add(LineView(Point(x, y), Point(nextX, nextY))) + getViewNodes( node.left ?: throw NullNodeException(), nextX, @@ -54,12 +62,11 @@ abstract class AbstractPainter, Tree node.right ?: throw NullNodeException(), nextX, nextY, - 2 * n + 1 + (2 * n) + 1 ) - } - - lines.add(LineView(Point(x, y), Point(nextX, nextY))) + lines.add(LineView(Point(x, y), Point(nextX, nextY))) + } } } \ No newline at end of file diff --git a/lib/src/main/kotlin/guiControl/painters/BTPainter.kt b/lib/src/main/kotlin/guiControl/painters/BTPainter.kt new file mode 100644 index 0000000..8d2b362 --- /dev/null +++ b/lib/src/main/kotlin/guiControl/painters/BTPainter.kt @@ -0,0 +1,13 @@ +package guiControl.painters + +import nodes.BinaryNode +import trees.BinaryTree +import java.awt.Color +class BTPainter( + tree: BinaryTree, + nodeMargin: Int, + nodeSize: Int, + width: Int +) : AbstractPainter, BinaryTree>(tree, nodeMargin, nodeSize, width) { + override fun getNodeColor(node: BinaryNode): Color = Color.CYAN +} \ No newline at end of file diff --git a/lib/src/main/kotlin/guiControl/painters/RBTPainter.kt b/lib/src/main/kotlin/guiControl/painters/RBTPainter.kt new file mode 100644 index 0000000..b60b3b6 --- /dev/null +++ b/lib/src/main/kotlin/guiControl/painters/RBTPainter.kt @@ -0,0 +1,18 @@ +package guiControl.painters + +import nodes.Color +import nodes.RBNode +import trees.RBTree +class RBTPainter( + tree: RBTree, + nodeMargin: Int, + nodeSize: Int, + width: Int +) : AbstractPainter, RBTree>(tree, nodeMargin, nodeSize, width) { + override fun getNodeColor(node: RBNode): java.awt.Color { + return if (node.color == Color.RED) + java.awt.Color.RED + else + java.awt.Color.BLACK + } +} \ No newline at end of file From a05e306d89f12857ca71473d96f23ea225dc5cda Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 20:48:28 +0300 Subject: [PATCH 166/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=83=D1=8E?= =?UTF-8?q?=20Panel=20=D0=B4=D0=BB=D1=8F=20=D0=BA=D0=B0=D0=B6=D0=B4=D0=BE?= =?UTF-8?q?=D0=B3=D0=BE=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/nodePanels/AVLPanel.kt | 10 +++ .../nodePanels/AbstractNodePanel.kt | 79 +++++++++++++++++++ .../components/nodePanels/BTPanel.kt | 10 +++ .../components/nodePanels/RBTPanel.kt | 10 +++ .../kotlin/guiControl/painters/AVLPainter.kt | 2 +- .../kotlin/guiControl/painters/BTPainter.kt | 2 +- 6 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 App/src/main/kotlin/guiClasses/components/nodePanels/AVLPanel.kt create mode 100644 App/src/main/kotlin/guiClasses/components/nodePanels/AbstractNodePanel.kt create mode 100644 App/src/main/kotlin/guiClasses/components/nodePanels/BTPanel.kt create mode 100644 App/src/main/kotlin/guiClasses/components/nodePanels/RBTPanel.kt diff --git a/App/src/main/kotlin/guiClasses/components/nodePanels/AVLPanel.kt b/App/src/main/kotlin/guiClasses/components/nodePanels/AVLPanel.kt new file mode 100644 index 0000000..cd7c166 --- /dev/null +++ b/App/src/main/kotlin/guiClasses/components/nodePanels/AVLPanel.kt @@ -0,0 +1,10 @@ +package guiClasses.components.nodePanels + +import guiControl.painters.AVLPainter +import nodes.AVLNode +import trees.AVLTree + +class AVLPanel(private val tree: AVLTree) : + AbstractNodePanel, AVLTree, AVLPainter>(tree) { + override fun painterInit() = AVLPainter(tree, Constants.nodeMargin, Constants.nodeSize, width) +} \ No newline at end of file diff --git a/App/src/main/kotlin/guiClasses/components/nodePanels/AbstractNodePanel.kt b/App/src/main/kotlin/guiClasses/components/nodePanels/AbstractNodePanel.kt new file mode 100644 index 0000000..6bef1c9 --- /dev/null +++ b/App/src/main/kotlin/guiClasses/components/nodePanels/AbstractNodePanel.kt @@ -0,0 +1,79 @@ +package guiClasses.components.nodePanels + +import exceptions.NullNodeException +import guiControl.LineView +import guiControl.NodeView +import guiControl.painters.AbstractPainter +import nodes.AbstractNode +import nodes.RBNode +import trees.AbstractTree +import java.awt.Dimension +import java.awt.Graphics +import java.awt.Graphics2D +import java.awt.RenderingHints +import javax.swing.JPanel + +abstract class AbstractNodePanel< + NodeType : AbstractNode, + TreeType : AbstractTree, + Painter : AbstractPainter> + (private val tree: TreeType) : JPanel() { + + /** + * Объект со свойствами нод + */ + object Constants { + const val nodeSize = 30 + const val nodeMargin = 20 + val lineColor = java.awt.Color.BLACK + ?: throw NullPointerException() + } + + private lateinit var graphics: Graphics + + init { + preferredSize = Dimension(1000, 700) + } + + override fun paintComponent(g: Graphics) { + super.paintComponent(g) + + // Сглаживание + graphics = (g as Graphics2D).also { + val rh = RenderingHints( + RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON + ) + it.setRenderingHints(rh) + } + + val painter: Painter = painterInit() + + for (line in painter.lines) + drawLine(line) + + for (node in painter.nodes) + drawNode(node) + } + + protected abstract fun painterInit() : Painter + private fun drawNode(node: NodeView) { + graphics.color = node.color + + // Рисуем овал (ноду) + graphics.fillOval( + node.point.x - Constants.nodeSize / 2, + node.point.y - Constants.nodeSize / 2, + Constants.nodeSize, + Constants.nodeSize + ) + } + + private fun drawLine(line: LineView) { + graphics.color = Constants.lineColor + graphics.drawLine(line.from.x, line.from.y, line.to.x, line.to.y) + } + + private fun getHeight(node: RBNode): Int = + 1 + maxOf(getHeight(node.left ?: throw NullNodeException()), getHeight(node.right ?: throw NullNodeException())) +} diff --git a/App/src/main/kotlin/guiClasses/components/nodePanels/BTPanel.kt b/App/src/main/kotlin/guiClasses/components/nodePanels/BTPanel.kt new file mode 100644 index 0000000..fd4f269 --- /dev/null +++ b/App/src/main/kotlin/guiClasses/components/nodePanels/BTPanel.kt @@ -0,0 +1,10 @@ +package guiClasses.components.nodePanels + +import guiControl.painters.BTPainter +import nodes.BinaryNode +import trees.BinaryTree + +class BTPanel(private val tree: BinaryTree) : + AbstractNodePanel, BinaryTree, BTPainter>(tree) { + override fun painterInit() = BTPainter(tree, Constants.nodeMargin, Constants.nodeSize, width) +} \ No newline at end of file diff --git a/App/src/main/kotlin/guiClasses/components/nodePanels/RBTPanel.kt b/App/src/main/kotlin/guiClasses/components/nodePanels/RBTPanel.kt new file mode 100644 index 0000000..944b0b1 --- /dev/null +++ b/App/src/main/kotlin/guiClasses/components/nodePanels/RBTPanel.kt @@ -0,0 +1,10 @@ +package guiClasses.components.nodePanels + +import guiControl.painters.RBTPainter +import nodes.RBNode +import trees.RBTree + +class RBTPanel(private val tree: RBTree) : + AbstractNodePanel, RBTree, RBTPainter>(tree) { + override fun painterInit() = RBTPainter(tree, Constants.nodeMargin, Constants.nodeSize, width) +} \ No newline at end of file diff --git a/lib/src/main/kotlin/guiControl/painters/AVLPainter.kt b/lib/src/main/kotlin/guiControl/painters/AVLPainter.kt index 6f5a511..d1d4cee 100644 --- a/lib/src/main/kotlin/guiControl/painters/AVLPainter.kt +++ b/lib/src/main/kotlin/guiControl/painters/AVLPainter.kt @@ -10,5 +10,5 @@ class AVLPainter( nodeSize: Int, width: Int ) : AbstractPainter, AVLTree>(tree, nodeMargin, nodeSize, width) { - override fun getNodeColor(node: AVLNode): Color = Color.ORANGE + override fun getNodeColor(node: AVLNode): Color = Color.gray } \ No newline at end of file diff --git a/lib/src/main/kotlin/guiControl/painters/BTPainter.kt b/lib/src/main/kotlin/guiControl/painters/BTPainter.kt index 8d2b362..2204463 100644 --- a/lib/src/main/kotlin/guiControl/painters/BTPainter.kt +++ b/lib/src/main/kotlin/guiControl/painters/BTPainter.kt @@ -9,5 +9,5 @@ class BTPainter( nodeSize: Int, width: Int ) : AbstractPainter, BinaryTree>(tree, nodeMargin, nodeSize, width) { - override fun getNodeColor(node: BinaryNode): Color = Color.CYAN + override fun getNodeColor(node: BinaryNode): Color = Color.DARK_GRAY } \ No newline at end of file From f870259e8c0957f30c7c1ba36c656c600ee8d969 Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Tue, 2 May 2023 20:48:38 +0300 Subject: [PATCH 167/203] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8E=20=D1=83?= =?UTF-8?q?=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B8=20=D0=B1?= =?UTF-8?q?=D0=B0=D0=BB=D0=B0=D0=BD=D1=81=D0=B8=D1=80=D0=BE=D0=B2=D0=BA?= =?UTF-8?q?=D0=B8=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/trees/RBTree.kt | 167 +++++++++++++----------- lib/src/test/kotlin/trees/RBTreeTest.kt | 4 +- 2 files changed, 96 insertions(+), 75 deletions(-) diff --git a/lib/src/main/kotlin/trees/RBTree.kt b/lib/src/main/kotlin/trees/RBTree.kt index eefa651..5a49f24 100644 --- a/lib/src/main/kotlin/trees/RBTree.kt +++ b/lib/src/main/kotlin/trees/RBTree.kt @@ -1,8 +1,10 @@ package trees +import exceptions.NodeAlreadyExistsException +import exceptions.NodeNotFoundException +import exceptions.NullNodeException import nodes.Color import nodes.RBNode -import exceptions.* class RBTree, V> : AbstractTree>() { @@ -54,40 +56,58 @@ class RBTree, V> : AbstractTree>() { } private fun removeNode(node: RBNode) { - val replacementNode = when { //объявляем ноду, которая заменит удаяемую - node.left == null -> node.right //если один ребенок - node.right == null -> node.left - else -> { //если два ребенка - var successor = node.right - while (successor?.left != null) { //ищем самого левого потомка правого ребенка удаляемой ноды - successor = successor.left + var y: RBNode + var replaceNode: RBNode + var yOriginalColor = node.color + if (node.right != null || node.left != null) { + if (node.left == null) { + replaceNode = node.right ?: throw NullNodeException() + transplant(node, node.right) + } else if (node.right == null) { + replaceNode = node.left ?: throw NullNodeException() + transplant(node, node.left) + } else { + y = node.right ?: throw NullNodeException() + while (y.left != null) { + y = y.left!! } - if (successor?.parent != node) { //если у правого ребенка удаляемой ноды есть дети - transplant(successor ?: throw IllegalArgumentException("Node cannot be null"), successor.right) - successor.right = node.right - successor.right?.parent = successor + yOriginalColor = y.color + replaceNode = if (y.right == null) { + y + } else { + y.right ?: throw NullNodeException() + } + if (replaceNode == y) { + replaceNode.parent = y.parent + } else { + if (y.parent == node) { + replaceNode.parent = y + } else { + transplant(y, y.right) + y.right = node.right + y.right?.parent = y + replaceNode.parent = y.parent + } } - transplant(node, successor) - successor.left = node.left - successor.left?.parent = successor - successor.color = node.color - successor + transplant(node, y) + y.left = node.left + y.left?.parent = y + y.color = node.color + } + if (yOriginalColor == Color.BLACK) { + fixDelete(replaceNode) } - } - - if (node.color == Color.BLACK) { - fixDelete(replacementNode) - } - - if (node.parent == null) { - root = replacementNode - } else if (node == (node.parent as RBNode).left) { - (node.parent as RBNode).left = replacementNode } else { - (node.parent as RBNode).right = replacementNode + if (node.parent == null) { + root = null + } else { + if (node.parent?.left == node) { + node.parent?.left = null + } else { + node.parent?.right = null + } + } } - - replacementNode?.parent = node.parent } private fun fixInsert(node: RBNode) { @@ -131,59 +151,60 @@ class RBTree, V> : AbstractTree>() { } private fun fixDelete(node: RBNode?) { - var currentNode = node - while (currentNode != root && currentNode?.color == Color.BLACK) { //пока нода не корень и она черная - if (currentNode == currentNode.parent?.left) { //если нода - левый сын - var sibling = currentNode.parent?.right - if (sibling?.color == Color.RED) { //если брат - красный - sibling.color = Color.BLACK - currentNode.parent?.color = Color.RED - currentNode.parent?.let { leftRotate(it) } - sibling = currentNode.parent?.right + var x = node + while (x != root && x?.color == Color.BLACK) { + if (x == x.parent!!.left) { + var w = x.parent!!.right ?: throw NullNodeException() + if (w.color == Color.RED) { + w.color = Color.BLACK + x.parent!!.color = Color.RED + leftRotate(x.parent!!) + w = x.parent!!.right ?: throw NullNodeException() } - if (sibling?.left?.color == Color.BLACK && sibling.right?.color == Color.BLACK) { //если дети брата черные - sibling.color = Color.RED - currentNode = currentNode.parent + if ((w.left?.color ?: Color.BLACK) == Color.BLACK && (w.right?.color ?: Color.BLACK) == Color.BLACK) { + w.color = Color.RED + x = x.parent!! } else { - if (sibling?.right?.color == Color.BLACK) { //левый сын брата красный, правый - черный - sibling.left?.color = Color.BLACK - sibling.color = Color.RED - sibling.let { rightRotate(it) } - sibling = currentNode.parent?.right + if ((w.right?.color ?: Color.BLACK) == Color.BLACK) { + w.left?.color = Color.BLACK + w.color = Color.RED + rightRotate(w) + w = x.parent!!.right ?: throw NullNodeException() } - sibling?.color = currentNode.parent?.color ?: throw TreeException("Parent color is null") - currentNode.parent?.color = Color.BLACK - sibling?.right?.color = Color.BLACK - currentNode.parent?.let { leftRotate(it) } - currentNode = root + w.color = x.parent!!.color + x.parent!!.color = Color.BLACK + w.right?.color = Color.BLACK + leftRotate(x.parent!!) + x = root ?: throw NullNodeException() } - } else { //нода - правый сын - var sibling = currentNode.parent?.left - if (sibling?.color == Color.RED) { //если брат - красный - sibling.color = Color.BLACK - currentNode.parent?.color = Color.RED - currentNode.parent?.let { rightRotate(it) } - sibling = currentNode.parent?.left + } else { + var w = x.parent!!.left ?: throw NullNodeException() + if (w.color == Color.RED) { + w.color = Color.BLACK + x.parent!!.color = Color.RED + rightRotate(x.parent!!) + w = x.parent!!.left ?: throw NullNodeException() } - if (sibling?.right?.color == Color.BLACK && sibling.left?.color == Color.BLACK) { //дети брата черные - sibling.color = Color.RED - currentNode = currentNode.parent + if ((w.right?.color ?: Color.BLACK) == Color.BLACK && (w.left?.color ?: Color.BLACK) == Color.BLACK) { + w.color = Color.RED + x = x.parent!! } else { - if (sibling?.left?.color == Color.BLACK) { //левый сын брата черный, правый - красный - sibling.right?.color = Color.BLACK - sibling.color = Color.RED - sibling.let { leftRotate(it) } - sibling = currentNode.parent?.left + if ((w.left?.color ?: Color.BLACK) == Color.BLACK) { + w.right?.color = Color.BLACK + w.color = Color.RED + leftRotate(w) + w = x.parent!!.left ?: throw NullNodeException() } - sibling?.color = currentNode.parent?.color ?: throw TreeException("Parent color is null") - currentNode.parent?.color = Color.BLACK - sibling?.left?.color = Color.BLACK - currentNode.parent?.let { rightRotate(it) } - currentNode = root + w.color = x.parent!!.color + x.parent!!.color = Color.BLACK + w.left?.color = Color.BLACK + rightRotate(x.parent!!) + x = root ?: throw NullNodeException() } } } - currentNode?.color = Color.BLACK + x?.color = Color.BLACK + root?.color = Color.BLACK } diff --git a/lib/src/test/kotlin/trees/RBTreeTest.kt b/lib/src/test/kotlin/trees/RBTreeTest.kt index 6afad17..e480ce6 100644 --- a/lib/src/test/kotlin/trees/RBTreeTest.kt +++ b/lib/src/test/kotlin/trees/RBTreeTest.kt @@ -286,8 +286,8 @@ class RBTreeTest { throw TreeException("Неверное расположение узлов, key слева должен быть меньше, а key справа - больше") if (this.root?.color != Color.BLACK) throw TreeException("root у RBTree не можешь быть красным") - if (this.root?.checkEndNodesColor() == false) - throw TreeException("Конечные узлы RBTree не могут быть красными") + //if (this.root?.checkEndNodesColor() == false) + //throw TreeException("Конечные узлы RBTree не могут быть красными") if (this.root?.checkEndNodesColor() == false) throw TreeException("У красного узла родительский узел может быть только чёрным") From 4f52cfb289ae5181cbcc963d5ee1ef9d0f0622fe Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 21:01:10 +0300 Subject: [PATCH 168/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D1=8E=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8E=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 106 ++++++++++-------- .../kotlin/guiClasses/components/MenuClass.kt | 15 +-- 2 files changed, 65 insertions(+), 56 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 0f31859..9281424 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -1,9 +1,11 @@ package app -import guiClasses.Frame -import guiClasses.KeyTextField -import guiClasses.MenuClass -import guiClasses.RBTNodePanel +import guiClasses.components.Frame +import guiClasses.components.KeyTextField +import guiClasses.components.MenuClass +import guiClasses.components.nodePanels.AVLPanel +import guiClasses.components.nodePanels.BTPanel +import guiClasses.components.nodePanels.RBTPanel import trees.AVLTree import trees.BinaryTree import trees.RBTree @@ -11,10 +13,53 @@ import javax.swing.GroupLayout import javax.swing.JButton import javax.swing.JFrame +/** + * Объект, хранящий отдельно каждое из деревьев + * (позволяет параллельно работать сразу со всеми) + */ +private object Trees { + val binTree: BinaryTree = BinaryTree() + val AVLTree: AVLTree = AVLTree() + val RBTree: RBTree = RBTree() +} + +/** + * Возможные виды деревьев, которые доступны пользователю + */ +private enum class TreeTypes { + BINARY, + AVL, + RB, + None +} + +/** + * Дерево, выбранное пользователем на данный момент + */ +private var currentTree: TreeTypes = TreeTypes.None + private lateinit var treeFrame: JFrame private lateinit var menuFrame: JFrame -private lateinit var rbTree: RBTree +private fun rbtInit() { + currentTree = TreeTypes.RB + + //here + Trees.RBTree.add(100) + Trees.RBTree.add(120) + Trees.RBTree.add(130) + treeFrame.add(RBTPanel(Trees.RBTree)) +} +private fun binTreeInit() { + currentTree = TreeTypes.BINARY + + treeFrame.add(BTPanel(Trees.binTree)) +} +private fun avlInit() { + currentTree = TreeTypes.AVL + + treeFrame.add(AVLPanel(Trees.AVLTree)) +} private fun menuFrameInit() { menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) @@ -29,21 +74,11 @@ private fun menuFrameInit() { val saveButton = JButton("Save") - val treeMenu = MenuClass { tree -> - when (tree) { - is BinaryTree<*, *> -> { - println("бинарное дерево") - } - - is AVLTree<*, *> -> { - println("AVL дерево") - } - - is RBTree<*, *> -> { - rbtDraw() - } - } - } + val treeMenu = MenuClass( + onBTSelected = ::binTreeInit, + onAVLSelected = ::avlInit, + onRBTSelected = ::rbtInit + ) menuFrame.jMenuBar = treeMenu @@ -103,36 +138,9 @@ private fun menuFrameInit() { ) } -private fun rbtDraw() { - rbTree = RBTree() - rbTree.add(100) - rbTree.add(0) - rbTree.add(120) - rbTree.add(130) - rbTree.add(140) - rbTree.add(3) - rbTree.add(15) - rbTree.add(17) - - // Создаем панель с компонентами - val treePanel = RBTNodePanel(rbTree) - -// val panel = JScrollPane() -// // Добавляем панель на панель с прокруткой -// panel.setViewportView(treePanel) -// -// // Добавляем панель с прокруткой на окно -// treeFrame.contentPane.add(panel) -// -// // Устанавливаем режим прокрутки по вертикали и горизонтали -// panel.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED -// panel.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED -// - treeFrame.add(treePanel) -} - fun main() { menuFrameInit() treeFrame = Frame("Treeple", 1000, 700, 360, 50) - rbtDraw() + + rbtInit() } \ No newline at end of file diff --git a/App/src/main/kotlin/guiClasses/components/MenuClass.kt b/App/src/main/kotlin/guiClasses/components/MenuClass.kt index 50e4845..d6db910 100644 --- a/App/src/main/kotlin/guiClasses/components/MenuClass.kt +++ b/App/src/main/kotlin/guiClasses/components/MenuClass.kt @@ -1,14 +1,15 @@ package guiClasses.components -import trees.AVLTree -import trees.BinaryTree -import trees.RBTree import java.awt.Color import javax.swing.JMenu import javax.swing.JMenuBar import javax.swing.JMenuItem -class MenuClass(private val onTreeSelected: (tree: Any) -> Unit) : JMenuBar() { +class MenuClass( + private val onBTSelected: () -> Unit, + private val onAVLSelected: () -> Unit, + private val onRBTSelected: () -> Unit +) : JMenuBar() { /** * Визуально обозначает элементы как неактивные @@ -39,19 +40,19 @@ class MenuClass(private val onTreeSelected: (tree: Any) -> Unit) : JMenuBar() { // Слушатель событий для элемента меню "Binary Tree" menuItems[0].addActionListener { updateMenuItemsChoosing(menuItems[0]) - onTreeSelected(BinaryTree()) + onBTSelected() } // Слушатель событий для элемента меню "AVL-Tree" menuItems[1].addActionListener { updateMenuItemsChoosing(menuItems[1]) - onTreeSelected(AVLTree()) + onAVLSelected() } // Слушатель событий для элемента меню "Red-black Tree" menuItems[2].addActionListener { updateMenuItemsChoosing(menuItems[2]) - onTreeSelected(RBTree()) + onRBTSelected() } add(menu) From 27e0d7cf5fb2ea4bd2af4b2cb298a8b4be6b6b70 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 21:10:56 +0300 Subject: [PATCH 169/203] =?UTF-8?q?=D0=9A=D0=BE=D0=BC=D0=BC=D0=B8=D1=82=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=98=D0=BB=D1=8C=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 28 +++-- .../guiClasses/components/RBTNodePanel.kt | 111 ------------------ .../guiControl/painters/AbstractPainter.kt | 3 +- 3 files changed, 20 insertions(+), 122 deletions(-) delete mode 100644 App/src/main/kotlin/guiClasses/components/RBTNodePanel.kt diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 9281424..f7247df 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -41,24 +41,36 @@ private var currentTree: TreeTypes = TreeTypes.None private lateinit var treeFrame: JFrame private lateinit var menuFrame: JFrame +private val rbtPanel = RBTPanel(Trees.RBTree) +private val avlPanel = AVLPanel(Trees.AVLTree) +private val binPanel = BTPanel(Trees.binTree) + +private fun curPanelRemove() { + when(currentTree) { + TreeTypes.BINARY -> treeFrame.remove(binPanel) + TreeTypes.AVL -> treeFrame.remove(avlPanel) + TreeTypes.RB -> treeFrame.remove(rbtPanel) + else -> return + } + +} private fun rbtInit() { + curPanelRemove() currentTree = TreeTypes.RB - //here - Trees.RBTree.add(100) - Trees.RBTree.add(120) - Trees.RBTree.add(130) - treeFrame.add(RBTPanel(Trees.RBTree)) + treeFrame.add(rbtPanel) } private fun binTreeInit() { + curPanelRemove() currentTree = TreeTypes.BINARY - treeFrame.add(BTPanel(Trees.binTree)) + treeFrame.add(binPanel) } private fun avlInit() { + curPanelRemove() currentTree = TreeTypes.AVL - treeFrame.add(AVLPanel(Trees.AVLTree)) + treeFrame.add(avlPanel) } private fun menuFrameInit() { menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) @@ -141,6 +153,4 @@ private fun menuFrameInit() { fun main() { menuFrameInit() treeFrame = Frame("Treeple", 1000, 700, 360, 50) - - rbtInit() } \ No newline at end of file diff --git a/App/src/main/kotlin/guiClasses/components/RBTNodePanel.kt b/App/src/main/kotlin/guiClasses/components/RBTNodePanel.kt deleted file mode 100644 index 2454338..0000000 --- a/App/src/main/kotlin/guiClasses/components/RBTNodePanel.kt +++ /dev/null @@ -1,111 +0,0 @@ -package guiClasses.components - -import exceptions.NullNodeException -import nodes.Color -import nodes.RBNode -import trees.RBTree -import java.awt.* -import javax.swing.JPanel - -class RBTNodePanel(private val tree: RBTree) : JPanel() { - - /** - * Объект со свойствами нод - */ - object Constants { - const val nodeSize = 30 - const val nodeMargin = 20 - val lineColor = java.awt.Color.BLACK - ?: throw NullPointerException() - } - - private lateinit var graphics: Graphics - - init { - preferredSize = Dimension(1000, 700) - } - - override fun paintComponent(g: Graphics) { - super.paintComponent(g) - - // Сглаживание - graphics = (g as Graphics2D).also { - val rh = RenderingHints( - RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON - ) - it.setRenderingHints(rh) - } - - if (tree.treeRoot != null) { - val rootX = width / 2 // нода рисуется посередине - val rootY = Constants.nodeMargin - - drawNode(tree.treeRoot?: throw NullNodeException(), Point(rootX, rootY)) - - recursiveDraw(tree.treeRoot ?: throw NullNodeException(), rootX, Constants.nodeMargin) - } - } - - /** - * Рекурсивная отрисовка каждой ноды дерева - */ - private fun recursiveDraw(node: RBNode, x: Int, y: Int, n: Int = 1) { - var nextX: Int - var nextY: Int - - if (node.left != null) { - nextX = x - (x / (2 * n)) - nextY = y + Constants.nodeMargin + Constants.nodeSize - - drawLine(Point(x, y), Point(nextX, nextY)) - - recursiveDraw( - node.left ?: throw NullNodeException(), - nextX, - nextY, - n + 1 - ) - } //рекурсивно рисуем левое поддерево, shl - побитовый сдвиг влево - if (node.right != null) { - - nextX = x + (x / (2 * n)) - nextY = y + Constants.nodeMargin + Constants.nodeSize - - drawLine(Point(x, y), Point(nextX, nextY)) - - recursiveDraw( - node.right ?: throw NullNodeException(), - nextX, - nextY, - 2*n+1 - ) - } //рекурсивно рисуем правое поддерево - - drawNode(node, Point(x, y)) - - } - - private fun drawNode(node: RBNode, p: Point) { - graphics.color = if (node.color == Color.BLACK) - java.awt.Color.BLACK - else - java.awt.Color.RED - - // Рисуем овал (ноду) - graphics.fillOval( - p.x - Constants.nodeSize / 2, - p.y - Constants.nodeSize / 2, - Constants.nodeSize, - Constants.nodeSize - ) - } - - private fun drawLine(start: Point, end: Point) { - graphics.color = Constants.lineColor - graphics.drawLine(start.x, start.y, end.x, end.y) - } - - private fun getHeight(node: RBNode): Int = - 1 + maxOf(getHeight(node.left ?: throw NullNodeException()), getHeight(node.right ?: throw NullNodeException())) -} diff --git a/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt b/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt index 929dbcd..6efb265 100644 --- a/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt +++ b/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt @@ -19,9 +19,8 @@ abstract class AbstractPainter, Tree if (tree.root == null) { // Если дерево ещё не заполнено, то заполним его "образцом" tree.add(100) - tree.add(150) - tree.add(120) tree.add(-10) + tree.add(120) } getViewNodes(tree.root ?: throw NullNodeException(), width / 2, nodeMargin) From 27a78ab4170aca726fba489d9586eb0ffc75b084 Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Tue, 2 May 2023 21:25:40 +0300 Subject: [PATCH 170/203] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=BC=D0=B5=D0=B6?= =?UTF-8?q?=D1=83=D1=82=D0=BE=D1=87=D0=BD=D1=8B=D0=B9=20=D0=BA=D0=BE=D0=BC?= =?UTF-8?q?=D0=BC=D0=B8=D1=82=20=D0=B4=D0=BB=D1=8F=20=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D0=B4=D0=B6=D0=B0=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B9=20=D0=B8=D0=B7=20=D0=B4=D1=80=D1=83=D0=B3=D0=BE?= =?UTF-8?q?=D0=B9=20=D0=B2=D0=B5=D1=82=D0=BA=D0=B8,=20=D0=BD=D0=B8=D1=87?= =?UTF-8?q?=D0=B5=D0=B3=D0=BE=20=D0=BD=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/trees/RBTree.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/main/kotlin/trees/RBTree.kt b/lib/src/main/kotlin/trees/RBTree.kt index eefa651..0b4f0bd 100644 --- a/lib/src/main/kotlin/trees/RBTree.kt +++ b/lib/src/main/kotlin/trees/RBTree.kt @@ -1,8 +1,8 @@ package trees +import exceptions.* import nodes.Color import nodes.RBNode -import exceptions.* class RBTree, V> : AbstractTree>() { From f6652efb0b0df17384190c1925dc8bde005cb025 Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Tue, 2 May 2023 22:58:06 +0300 Subject: [PATCH 171/203] =?UTF-8?q?=D0=92=D1=81=D0=BF=D0=BE=D0=BC=D0=BE?= =?UTF-8?q?=D0=B3=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=BC=D0=B8=D1=82,=20=D0=BD=D0=B8=D1=87=D0=B5?= =?UTF-8?q?=D0=B3=D0=BE=20=D0=BD=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=BB=D0=BE=D1=81=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/trees/RBTree.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/main/kotlin/trees/RBTree.kt b/lib/src/main/kotlin/trees/RBTree.kt index 27f3c3e..5a49f24 100644 --- a/lib/src/main/kotlin/trees/RBTree.kt +++ b/lib/src/main/kotlin/trees/RBTree.kt @@ -1,6 +1,8 @@ package trees -import exceptions.* +import exceptions.NodeAlreadyExistsException +import exceptions.NodeNotFoundException +import exceptions.NullNodeException import nodes.Color import nodes.RBNode From 982e4972bce85fb3761f5fa792b257b1bad8e4d9 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 23:06:42 +0300 Subject: [PATCH 172/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BE=D1=82=D1=80=D0=B8=D1=81=D0=BE=D0=B2?= =?UTF-8?q?=D0=BA=D0=B0=20value=20=D0=BF=D0=BE=D0=B4=20=D0=BD=D0=BE=D0=B4?= =?UTF-8?q?=D0=BE=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../guiClasses/components/nodePanels/AbstractNodePanel.kt | 8 ++++---- lib/src/main/kotlin/guiControl/NodeView.kt | 3 ++- .../main/kotlin/guiControl/painters/AbstractPainter.kt | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/App/src/main/kotlin/guiClasses/components/nodePanels/AbstractNodePanel.kt b/App/src/main/kotlin/guiClasses/components/nodePanels/AbstractNodePanel.kt index 6bef1c9..b49fdc6 100644 --- a/App/src/main/kotlin/guiClasses/components/nodePanels/AbstractNodePanel.kt +++ b/App/src/main/kotlin/guiClasses/components/nodePanels/AbstractNodePanel.kt @@ -7,10 +7,7 @@ import guiControl.painters.AbstractPainter import nodes.AbstractNode import nodes.RBNode import trees.AbstractTree -import java.awt.Dimension -import java.awt.Graphics -import java.awt.Graphics2D -import java.awt.RenderingHints +import java.awt.* import javax.swing.JPanel abstract class AbstractNodePanel< @@ -67,6 +64,9 @@ abstract class AbstractNodePanel< Constants.nodeSize, Constants.nodeSize ) + + graphics.color = Color.BLACK + graphics.drawString(node.value, node.point.x - node.value.length * 4, node.point.y + Constants.nodeSize) } private fun drawLine(line: LineView) { diff --git a/lib/src/main/kotlin/guiControl/NodeView.kt b/lib/src/main/kotlin/guiControl/NodeView.kt index f97ec02..e2432cd 100644 --- a/lib/src/main/kotlin/guiControl/NodeView.kt +++ b/lib/src/main/kotlin/guiControl/NodeView.kt @@ -5,5 +5,6 @@ import java.awt.Point data class NodeView( val point: Point, - val color: Color + val color: Color, + val value: String ) \ No newline at end of file diff --git a/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt b/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt index 6efb265..463cd9d 100644 --- a/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt +++ b/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt @@ -34,7 +34,7 @@ abstract class AbstractPainter, Tree * Рекурсивно пробегает дерево и заполняет nodes и lines эл-ами для отрисовки */ private fun getViewNodes(node: NodeType, x: Int, y: Int, n: Int = 1) { - nodes.add(NodeView(Point(x, y), getNodeColor(node))) + nodes.add(NodeView(Point(x, y), getNodeColor(node), node.key.toString())) var nextX = 0 var nextY = 0 From 7ec3506940acadf541f04126b324bd8715925f8a Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 23:40:37 +0300 Subject: [PATCH 173/203] =?UTF-8?q?=D0=A1=D0=BE=D0=B1=D1=80=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=83=D0=B6=D0=B8=D0=B2=D0=BE=D0=B9=20=D0=B2?= =?UTF-8?q?=D0=B0=D1=80=D0=B8=D0=B0=D0=BD=D1=82=20=D0=BE=D1=82=D1=80=D0=B8?= =?UTF-8?q?=D1=81=D0=BE=D0=B2=D0=BA=D0=B8=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 67 ++++++------------- .../kotlin/guiClasses/components/Frame.kt | 3 +- .../kotlin/guiClasses/components/MenuClass.kt | 11 ++- 3 files changed, 28 insertions(+), 53 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index f7247df..020f6a7 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -12,6 +12,7 @@ import trees.RBTree import javax.swing.GroupLayout import javax.swing.JButton import javax.swing.JFrame +import javax.swing.JTextField /** * Объект, хранящий отдельно каждое из деревьев @@ -24,9 +25,9 @@ private object Trees { } /** - * Возможные виды деревьев, которые доступны пользователю + * Возможные виды деревьев, которые доступны пользователю RBTree */ -private enum class TreeTypes { +enum class TreeTypes { BINARY, AVL, RB, @@ -40,40 +41,12 @@ private var currentTree: TreeTypes = TreeTypes.None private lateinit var treeFrame: JFrame private lateinit var menuFrame: JFrame - -private val rbtPanel = RBTPanel(Trees.RBTree) -private val avlPanel = AVLPanel(Trees.AVLTree) -private val binPanel = BTPanel(Trees.binTree) - -private fun curPanelRemove() { - when(currentTree) { - TreeTypes.BINARY -> treeFrame.remove(binPanel) - TreeTypes.AVL -> treeFrame.remove(avlPanel) - TreeTypes.RB -> treeFrame.remove(rbtPanel) - else -> return - } - -} -private fun rbtInit() { - curPanelRemove() - currentTree = TreeTypes.RB - - treeFrame.add(rbtPanel) -} -private fun binTreeInit() { - curPanelRemove() - currentTree = TreeTypes.BINARY - - treeFrame.add(binPanel) -} -private fun avlInit() { - curPanelRemove() - currentTree = TreeTypes.AVL - - treeFrame.add(avlPanel) +fun main() { + menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) + menuFrameInit() + treeFrame = Frame("Treeple", 1000, 700, 360, 50) } private fun menuFrameInit() { - menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) val addButton = JButton("Add") val addTextField = KeyTextField() @@ -82,17 +55,11 @@ private fun menuFrameInit() { val removeTextField = KeyTextField() val searchButton = JButton("Find") - val searchTextField = KeyTextField() + val searchTextField = JTextField("Test") val saveButton = JButton("Save") - val treeMenu = MenuClass( - onBTSelected = ::binTreeInit, - onAVLSelected = ::avlInit, - onRBTSelected = ::rbtInit - ) - - menuFrame.jMenuBar = treeMenu + menuFrame.jMenuBar = MenuClass (::treeInit) // contentPane - контейнер для компонентов val layout = GroupLayout(menuFrame.contentPane) @@ -149,8 +116,16 @@ private fun menuFrameInit() { ) } - -fun main() { - menuFrameInit() +private fun treeInit(newTree: TreeTypes) { + treeFrame.dispose() treeFrame = Frame("Treeple", 1000, 700, 360, 50) -} \ No newline at end of file + when (newTree) { + TreeTypes.RB -> treeFrame.add(RBTPanel(Trees.RBTree)) + TreeTypes.AVL -> treeFrame.add(AVLPanel(Trees.AVLTree)) + TreeTypes.BINARY -> treeFrame.add(BTPanel(Trees.binTree)) + else -> return + } + println(newTree) + currentTree = newTree + +} diff --git a/App/src/main/kotlin/guiClasses/components/Frame.kt b/App/src/main/kotlin/guiClasses/components/Frame.kt index dfaa217..b168337 100644 --- a/App/src/main/kotlin/guiClasses/components/Frame.kt +++ b/App/src/main/kotlin/guiClasses/components/Frame.kt @@ -1,7 +1,8 @@ package guiClasses.components import java.awt.Dimension -import javax.swing.* +import javax.swing.ImageIcon +import javax.swing.JFrame class Frame(name: String, width: Int, height: Int, locX: Int, locY: Int) : JFrame() { init { diff --git a/App/src/main/kotlin/guiClasses/components/MenuClass.kt b/App/src/main/kotlin/guiClasses/components/MenuClass.kt index d6db910..0f52459 100644 --- a/App/src/main/kotlin/guiClasses/components/MenuClass.kt +++ b/App/src/main/kotlin/guiClasses/components/MenuClass.kt @@ -1,14 +1,13 @@ package guiClasses.components +import app.TreeTypes import java.awt.Color import javax.swing.JMenu import javax.swing.JMenuBar import javax.swing.JMenuItem class MenuClass( - private val onBTSelected: () -> Unit, - private val onAVLSelected: () -> Unit, - private val onRBTSelected: () -> Unit + private val onTreeSelected: (type: TreeTypes) -> Unit ) : JMenuBar() { /** @@ -40,19 +39,19 @@ class MenuClass( // Слушатель событий для элемента меню "Binary Tree" menuItems[0].addActionListener { updateMenuItemsChoosing(menuItems[0]) - onBTSelected() + onTreeSelected(TreeTypes.BINARY) } // Слушатель событий для элемента меню "AVL-Tree" menuItems[1].addActionListener { updateMenuItemsChoosing(menuItems[1]) - onAVLSelected() + onTreeSelected(TreeTypes.AVL) } // Слушатель событий для элемента меню "Red-black Tree" menuItems[2].addActionListener { updateMenuItemsChoosing(menuItems[2]) - onRBTSelected() + onTreeSelected(TreeTypes.RB) } add(menu) From e7031808cad0ac2b28725b56570ea51feeca9668 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 23:52:41 +0300 Subject: [PATCH 174/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=BE=D0=BD=D0=B0?= =?UTF-8?q?=D0=BB=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B5=20Add?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 020f6a7..714cce1 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -1,5 +1,6 @@ package app +import exceptions.NodeAlreadyExistsException import guiClasses.components.Frame import guiClasses.components.KeyTextField import guiClasses.components.MenuClass @@ -9,10 +10,7 @@ import guiClasses.components.nodePanels.RBTPanel import trees.AVLTree import trees.BinaryTree import trees.RBTree -import javax.swing.GroupLayout -import javax.swing.JButton -import javax.swing.JFrame -import javax.swing.JTextField +import javax.swing.* /** * Объект, хранящий отдельно каждое из деревьев @@ -46,11 +44,36 @@ fun main() { menuFrameInit() treeFrame = Frame("Treeple", 1000, 700, 360, 50) } + +private fun showError(text: String, frame: JFrame) { + JOptionPane.showMessageDialog(frame, text, "Произошла ошибка" , JOptionPane.ERROR_MESSAGE) +} private fun menuFrameInit() { val addButton = JButton("Add") val addTextField = KeyTextField() + addButton.addActionListener { + if (addTextField.text.toIntOrNull() != null) { + val key = addTextField.text.toInt() + try { + when (currentTree) { + TreeTypes.RB -> Trees.RBTree.add(key) + TreeTypes.BINARY -> Trees.binTree.add(key) + TreeTypes.AVL -> Trees.AVLTree.add(key) + + else -> showError("Сначала выберите дерево", menuFrame) + } + + treeInit(currentTree) + + } catch (ex: NodeAlreadyExistsException) { + showError("Узел с таким значением уже существует", menuFrame) + } + } else + showError("Добавлять можно только узлы с числовыми значениями", menuFrame) + } + val removeButton = JButton("Remove") val removeTextField = KeyTextField() @@ -115,6 +138,7 @@ private fun menuFrameInit() { ) ) + } private fun treeInit(newTree: TreeTypes) { treeFrame.dispose() From 9fa3435b3e3a908c1e0f53702b97d924cfcc1424 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Tue, 2 May 2023 23:56:07 +0300 Subject: [PATCH 175/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=BE=D0=BD=D0=B0?= =?UTF-8?q?=D0=BB=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B5=20remove?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 714cce1..aff8e84 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -1,6 +1,7 @@ package app import exceptions.NodeAlreadyExistsException +import exceptions.NodeNotFoundException import guiClasses.components.Frame import guiClasses.components.KeyTextField import guiClasses.components.MenuClass @@ -77,6 +78,27 @@ private fun menuFrameInit() { val removeButton = JButton("Remove") val removeTextField = KeyTextField() + removeButton.addActionListener { + if (removeTextField.text.toIntOrNull() != null) { + val key = removeTextField.text.toInt() + try { + when (currentTree) { + TreeTypes.RB -> Trees.RBTree.remove(key) + TreeTypes.BINARY -> Trees.binTree.remove(key) + TreeTypes.AVL -> Trees.AVLTree.remove(key) + + else -> showError("Сначала выберите дерево", menuFrame) + } + + treeInit(currentTree) + + } catch (ex: NodeNotFoundException) { + showError("Узела с таким значением не существует", menuFrame) + } + } else + showError("Добавлять можно только узлы с числовыми значениями", menuFrame) + } + val searchButton = JButton("Find") val searchTextField = JTextField("Test") From 63fb66b189fa37a4244b5860c249032985bf3471 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 3 May 2023 00:20:19 +0300 Subject: [PATCH 176/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D0=BE=D0=BD=D0=B0=D0=BB=D0=B0=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA?= =?UTF-8?q?=D0=B5=20Save?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 78 ++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index aff8e84..3d32348 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -1,5 +1,7 @@ package app +import databases.json.RBTBase +import databases.sqlite.BTBase import exceptions.NodeAlreadyExistsException import exceptions.NodeNotFoundException import guiClasses.components.Frame @@ -11,7 +13,10 @@ import guiClasses.components.nodePanels.RBTPanel import trees.AVLTree import trees.BinaryTree import trees.RBTree -import javax.swing.* +import javax.swing.GroupLayout +import javax.swing.JButton +import javax.swing.JFrame +import javax.swing.JOptionPane /** * Объект, хранящий отдельно каждое из деревьев @@ -41,15 +46,28 @@ private var currentTree: TreeTypes = TreeTypes.None private lateinit var treeFrame: JFrame private lateinit var menuFrame: JFrame fun main() { - menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) menuFrameInit() - treeFrame = Frame("Treeple", 1000, 700, 360, 50) } +private fun treeInit(newTree: TreeTypes) { + if (::treeFrame.isInitialized) + treeFrame.dispose() + treeFrame = Frame("Treeple", 1000, 700, 360, 50) + when (newTree) { + TreeTypes.RB -> treeFrame.add(RBTPanel(Trees.RBTree)) + TreeTypes.AVL -> treeFrame.add(AVLPanel(Trees.AVLTree)) + TreeTypes.BINARY -> treeFrame.add(BTPanel(Trees.binTree)) + else -> return + } + println(newTree) + currentTree = newTree + +} private fun showError(text: String, frame: JFrame) { JOptionPane.showMessageDialog(frame, text, "Произошла ошибка" , JOptionPane.ERROR_MESSAGE) } private fun menuFrameInit() { + menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) val addButton = JButton("Add") val addTextField = KeyTextField() @@ -66,8 +84,6 @@ private fun menuFrameInit() { else -> showError("Сначала выберите дерево", menuFrame) } - treeInit(currentTree) - } catch (ex: NodeAlreadyExistsException) { showError("Узел с таким значением уже существует", menuFrame) } @@ -90,19 +106,37 @@ private fun menuFrameInit() { else -> showError("Сначала выберите дерево", menuFrame) } - treeInit(currentTree) - } catch (ex: NodeNotFoundException) { - showError("Узела с таким значением не существует", menuFrame) + showError("Узла с таким значением не существует", menuFrame) } } else showError("Добавлять можно только узлы с числовыми значениями", menuFrame) } - val searchButton = JButton("Find") - val searchTextField = JTextField("Test") - val saveButton = JButton("Save") + val refreshButton = JButton("Refresh") + + refreshButton.addActionListener { + treeInit(currentTree) + } + + saveButton.addActionListener { + when (currentTree) { + TreeTypes.BINARY -> { + val base = BTBase("BinaryTree.db", deserializeValue = {value -> value.toInt()}, deserializeKey = { value -> value.toInt() }) + base.saveTree(Trees.binTree) + } + TreeTypes.RB -> { + val base = RBTBase("Red-Black Tree.db", deserializeValue = {value -> value.toInt()}, deserializeKey = { value -> value.toInt() }) + base.saveTree(Trees.RBTree) + } + TreeTypes.AVL -> { + + } + + else -> showError("Сначала выберите дерево", menuFrame) + } + } menuFrame.jMenuBar = MenuClass (::treeInit) @@ -122,16 +156,15 @@ private fun menuFrameInit() { layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(addButton) .addComponent(removeButton) - .addComponent(searchButton) ) .addGroup( // Группа с TextFields layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(addTextField) .addComponent(removeTextField) - .addComponent(searchTextField) ) ) .addComponent(saveButton) + .addComponent(refreshButton) ) layout.setVerticalGroup( @@ -148,30 +181,13 @@ private fun menuFrameInit() { .addComponent(removeTextField) ) - .addGroup( - layout.createParallelGroup(GroupLayout.Alignment.BASELINE) - .addComponent(searchButton) - .addComponent(searchTextField) - ) .addGroup( layout.createSequentialGroup() .addComponent(saveButton) + .addComponent(refreshButton) ) ) } -private fun treeInit(newTree: TreeTypes) { - treeFrame.dispose() - treeFrame = Frame("Treeple", 1000, 700, 360, 50) - when (newTree) { - TreeTypes.RB -> treeFrame.add(RBTPanel(Trees.RBTree)) - TreeTypes.AVL -> treeFrame.add(AVLPanel(Trees.AVLTree)) - TreeTypes.BINARY -> treeFrame.add(BTPanel(Trees.binTree)) - else -> return - } - println(newTree) - currentTree = newTree - -} From 19f145ce5d5c1f86df782ec3b6b03744c3d2878b Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 3 May 2023 00:45:57 +0300 Subject: [PATCH 177/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=B8=20=D0=B2=D1=8B=D0=B3=D1=80=D1=83=D0=B7=D0=BA?= =?UTF-8?q?=D1=83=20=D0=B8=D0=B7=20=D0=B1=D0=B0=D0=B7=20=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=BD=D1=8B=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 79 ++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 3d32348..a4b96bb 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -13,6 +13,7 @@ import guiClasses.components.nodePanels.RBTPanel import trees.AVLTree import trees.BinaryTree import trees.RBTree +import java.io.File import javax.swing.GroupLayout import javax.swing.JButton import javax.swing.JFrame @@ -23,9 +24,9 @@ import javax.swing.JOptionPane * (позволяет параллельно работать сразу со всеми) */ private object Trees { - val binTree: BinaryTree = BinaryTree() - val AVLTree: AVLTree = AVLTree() - val RBTree: RBTree = RBTree() + var binTree: BinaryTree = BinaryTree() + var AVLTree: AVLTree = AVLTree() + var RBTree: RBTree = RBTree() } /** @@ -38,6 +39,11 @@ enum class TreeTypes { None } +object Constants { + const val BinaryBaseName = "Binary Tree Data.db" + const val RBTBaseName = "Red-Black Tree Data.yml" +} + /** * Дерево, выбранное пользователем на данный момент */ @@ -47,6 +53,42 @@ private lateinit var treeFrame: JFrame private lateinit var menuFrame: JFrame fun main() { menuFrameInit() + + if (File(Constants.RBTBaseName).exists()) { + try { + val base = RBTBase(Constants.RBTBaseName, + serializeValue = { value -> value?.toString() ?: "null" }, + deserializeValue = { value -> + if (value == "null") + 0 + else + value.toInt() + }, + deserializeKey = { value -> value.toInt() }) + + Trees.RBTree = base.loadTree() + } catch (ex: Exception) { + showError("Не удалось прочитать данных из файла ${Constants.RBTBaseName}", menuFrame) + showError(ex.message.toString(), menuFrame) + } + } + if (File(Constants.BinaryBaseName).exists()) { + try { + val base = BTBase(Constants.BinaryBaseName, + serializeValue = { value -> value?.toString() ?: "null" }, + deserializeValue = { value -> + if (value == "null") + 0 + else + value.toInt() + }, + deserializeKey = { value -> value.toInt() }) + + Trees.binTree = base.loadTree() + } catch (ex: Exception) { + showError("Не удалось прочитать данных из файла ${Constants.BinaryBaseName}", menuFrame) + } + } } private fun treeInit(newTree: TreeTypes) { @@ -63,9 +105,11 @@ private fun treeInit(newTree: TreeTypes) { currentTree = newTree } + private fun showError(text: String, frame: JFrame) { - JOptionPane.showMessageDialog(frame, text, "Произошла ошибка" , JOptionPane.ERROR_MESSAGE) + JOptionPane.showMessageDialog(frame, text, "Произошла ошибка", JOptionPane.ERROR_MESSAGE) } + private fun menuFrameInit() { menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) @@ -123,22 +167,41 @@ private fun menuFrameInit() { saveButton.addActionListener { when (currentTree) { TreeTypes.BINARY -> { - val base = BTBase("BinaryTree.db", deserializeValue = {value -> value.toInt()}, deserializeKey = { value -> value.toInt() }) + val base = BTBase(Constants.BinaryBaseName, + serializeValue = { value -> value?.toString() ?: "null" }, + deserializeValue = { value -> + if (value == "null") + 0 + else + value.toInt() + }, + deserializeKey = { value -> value.toInt() }) base.saveTree(Trees.binTree) } + TreeTypes.RB -> { - val base = RBTBase("Red-Black Tree.db", deserializeValue = {value -> value.toInt()}, deserializeKey = { value -> value.toInt() }) + val base = RBTBase( + Constants.RBTBaseName, + serializeValue = { value -> value?.toString() ?: "null" }, + deserializeValue = { value -> + if (value == "null") + 0 + else + value.toInt() + }, + deserializeKey = { value -> value.toInt() }) base.saveTree(Trees.RBTree) } - TreeTypes.AVL -> { + TreeTypes.AVL -> { + showError("Сохранение AVL дерева не реализовано", menuFrame) } else -> showError("Сначала выберите дерево", menuFrame) } } - menuFrame.jMenuBar = MenuClass (::treeInit) + menuFrame.jMenuBar = MenuClass(::treeInit) // contentPane - контейнер для компонентов val layout = GroupLayout(menuFrame.contentPane) From f0b1a1262171fe5c37817a766109301bdd49089d Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Wed, 3 May 2023 00:46:30 +0300 Subject: [PATCH 178/203] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE?= =?UTF-8?q?=D0=B1=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B5=20=D0=B2=20=D1=81?= =?UTF-8?q?=D0=BB=D1=83=D1=87=D0=B0=D0=B5=20=D0=BD=D0=B5=D1=83=D0=B4=D0=B0?= =?UTF-8?q?=D1=87=D0=BD=D0=BE=D0=B3=D0=BE=20=D1=87=D1=82=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=B8=D0=B7=20=D0=B1=D0=B0=D0=B7=D1=8B=20=D0=B4=D0=B0?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index a4b96bb..826ad40 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -69,7 +69,6 @@ fun main() { Trees.RBTree = base.loadTree() } catch (ex: Exception) { showError("Не удалось прочитать данных из файла ${Constants.RBTBaseName}", menuFrame) - showError(ex.message.toString(), menuFrame) } } if (File(Constants.BinaryBaseName).exists()) { From dd982de3281c688757025de2d2f2603a47490ef5 Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Wed, 3 May 2023 02:57:32 +0300 Subject: [PATCH 179/203] =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D1=8C=D0=B5=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 15 ------- lib/src/main/kotlin/trees/RBTree.kt | 62 ++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 8119bd1..4498d8e 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -59,20 +59,6 @@ private fun rbtInit() { currentTree = TreeTypes.RB - Trees.RBTree.add(100, 100) - Trees.RBTree.add(120, 120) - Trees.RBTree.add(50, 50) - Trees.RBTree.add(125, 125) - Trees.RBTree.add(115, 115) - Trees.RBTree.add(10, 100) - Trees.RBTree.add(60, 120) - Trees.RBTree.add(9, 120) - Trees.RBTree.add(11, 120) - Trees.RBTree.add(55, 120) - Trees.RBTree.add(53, 120) - Trees.RBTree.add(52, 120) - - treeFrame.add(rbtPanel) } private fun binTreeInit() { @@ -168,5 +154,4 @@ private fun menuFrameInit() { fun main() { menuFrameInit() treeFrame = Frame("Treeple", 1000, 700, 360, 50) - rbtInit() } \ No newline at end of file diff --git a/lib/src/main/kotlin/trees/RBTree.kt b/lib/src/main/kotlin/trees/RBTree.kt index 5a49f24..ade800f 100644 --- a/lib/src/main/kotlin/trees/RBTree.kt +++ b/lib/src/main/kotlin/trees/RBTree.kt @@ -56,28 +56,28 @@ class RBTree, V> : AbstractTree>() { } private fun removeNode(node: RBNode) { - var y: RBNode - var replaceNode: RBNode + var replaceNode2: RBNode + var replaceNode1: RBNode var yOriginalColor = node.color if (node.right != null || node.left != null) { if (node.left == null) { - replaceNode = node.right ?: throw NullNodeException() + replaceNode1 = node.right ?: throw NullNodeException() transplant(node, node.right) } else if (node.right == null) { - replaceNode = node.left ?: throw NullNodeException() + replaceNode1 = node.left ?: throw NullNodeException() transplant(node, node.left) } else { - y = node.right ?: throw NullNodeException() - while (y.left != null) { - y = y.left!! + replaceNode2 = node.right ?: throw NullNodeException() + while (replaceNode2.left != null) { + replaceNode2 = replaceNode2.left!! } - yOriginalColor = y.color - replaceNode = if (y.right == null) { - y + yOriginalColor = replaceNode2.color + replaceNode1 = if (replaceNode2.right != null) { + replaceNode2.right ?: throw NullNodeException() } else { - y.right ?: throw NullNodeException() + replaceNode2 } - if (replaceNode == y) { + /*if (replaceNode == y) { replaceNode.parent = y.parent } else { if (y.parent == node) { @@ -90,12 +90,46 @@ class RBTree, V> : AbstractTree>() { } } transplant(node, y) + y.right = node.right y.left = node.left y.left?.parent = y - y.color = node.color + y.color = node.color*/ + if (replaceNode2.right != null && replaceNode2.parent != node){ + replaceNode1.parent = replaceNode2 + transplant(replaceNode2, replaceNode2.right) + transplant(node, replaceNode2) + replaceNode2.left = node.left + replaceNode2.right = node.right + replaceNode2.left?.parent = replaceNode2 + replaceNode2.right?.parent = replaceNode2 + replaceNode2.color = node.color + } else if (replaceNode2.right == null && replaceNode2.parent != node) { + replaceNode1.parent = replaceNode2.parent + transplant(node, replaceNode2) + replaceNode2.left = node.left + replaceNode2.right = node.right + replaceNode2.left?.parent = replaceNode2 + replaceNode2.right?.parent = replaceNode2 + replaceNode2.color = node.color + } else if (replaceNode2.right != null){ + replaceNode1.parent = replaceNode2 + transplant(replaceNode2, replaceNode2.right) + transplant(node, replaceNode2) + replaceNode2.left = node.left + replaceNode2.right = node.right + replaceNode2.left?.parent = replaceNode2 + replaceNode2.right?.parent = replaceNode2 + replaceNode2.color = node.color + } else { + replaceNode1.parent = replaceNode2.parent + transplant(node, replaceNode2) + replaceNode2.left = node.left + replaceNode2.left?.parent = replaceNode2 + replaceNode2.color = node.color + } } if (yOriginalColor == Color.BLACK) { - fixDelete(replaceNode) + fixDelete(replaceNode1) } } else { if (node.parent == null) { From b5dd73ebccc35adc32f704b39b064784f88405a0 Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov <113210919+twotwozeronine@users.noreply.github.com> Date: Wed, 3 May 2023 03:12:26 +0300 Subject: [PATCH 180/203] Update README.md --- README.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4c0ab6f..d419046 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Описание проекта TREES-10 +# Описание проекта TREEPLE Этот проект содержит реализации трех типов деревьев: бинарное дерево поиска, AVL-дерево и красно-черное дерево. Все три типа деревьев наследуются из абстрактного класса AbstractTree, а их узлы наследуются из абстрактного класса AbstractNode. Система сборки - Gradle @@ -22,13 +22,17 @@ AVL-дерево - это сбалансированное бинарное де Тестирование каждого дерева проходит с помощью фреймворка JUnit. -# Методы - -Чтобы пользоваться деревьями, необходимо использовать следующие команды: +# Запуск программы +Для того, чтобы запустить программу, необходимо скачать код и в командной строке ввести ``` -val tree = \необходимое дерево\ -add.tree(key, value) //добавление элемента по ключу -remove.tree(key) //удаление элемента с заданным ключом -search.tree(key) //поиск элемента по заданному ключу +gradle App: run ``` + +# Использование приложения + +В верхнем меню выбираете необходимое вам дерево. Чтобы добавить элемент в дерево, введите ключ вашего элемента перед кнопкой 'Add'. Нажимаете на эту кнопку. Чтобы изменения отобразились в дереве, нажмите кнопку 'Refresh'. + +Чтобы удалить элемент из дерева, введите ключ вашего элемента перед кнопкой 'Remove'. Нажимаете на эту кнопку. Чтобы изменения отобразились в дереве, нажмите кнопку 'Refresh'. + +Чтобы сохранить дерево, нажмите кнопку 'Save'. При повторном запуске приложения ваше сохраненное дерево отобразится автоматически. From d9b5d11e1395c2a5c953d48a60eee74d41e1410d Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 4 May 2023 19:25:07 +0300 Subject: [PATCH 181/203] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=20Gui=20Control=20=D0=B2=20App,=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BC=D0=B5=D0=BD=D1=8F=D0=BB=20=D0=BC=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=82=D0=BE=D1=80=D1=8B=20=D0=B4?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=83=D0=BF=D0=B0=20=D0=B2=20AbstractTree=20?= =?UTF-8?q?=D0=B8=20AbstractNode=20(=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C?= =?UTF-8?q?=20=D0=BA=20root=20=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=20=D0=BE?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D1=89=D0=B0=D1=82=D1=8C=D1=81=D1=8F=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=B2=D0=BD=D0=B5,=20=D0=BD=D0=BE=20=D0=BF=D0=BE=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=8F=D1=82=D1=8C=20=D1=81=D1=82=D1=80=D1=83=D0=BA?= =?UTF-8?q?=D1=82=D1=83=D1=80=D1=83=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=B0?= =?UTF-8?q?=20=D0=BD=D0=B5=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B8=D1=82?= =?UTF-8?q?=D1=81=D1=8F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- {lib => App}/src/main/kotlin/guiControl/LineView.kt | 0 {lib => App}/src/main/kotlin/guiControl/NodeView.kt | 0 .../src/main/kotlin/guiControl/painters/AVLPainter.kt | 0 .../main/kotlin/guiControl/painters/AbstractPainter.kt | 8 +++++--- .../src/main/kotlin/guiControl/painters/BTPainter.kt | 0 .../src/main/kotlin/guiControl/painters/RBTPainter.kt | 0 lib/src/main/kotlin/nodes/AbstractNode.kt | 5 ++--- lib/src/main/kotlin/trees/AbstractTree.kt | 3 ++- 8 files changed, 9 insertions(+), 7 deletions(-) rename {lib => App}/src/main/kotlin/guiControl/LineView.kt (100%) rename {lib => App}/src/main/kotlin/guiControl/NodeView.kt (100%) rename {lib => App}/src/main/kotlin/guiControl/painters/AVLPainter.kt (100%) rename {lib => App}/src/main/kotlin/guiControl/painters/AbstractPainter.kt (94%) rename {lib => App}/src/main/kotlin/guiControl/painters/BTPainter.kt (100%) rename {lib => App}/src/main/kotlin/guiControl/painters/RBTPainter.kt (100%) diff --git a/lib/src/main/kotlin/guiControl/LineView.kt b/App/src/main/kotlin/guiControl/LineView.kt similarity index 100% rename from lib/src/main/kotlin/guiControl/LineView.kt rename to App/src/main/kotlin/guiControl/LineView.kt diff --git a/lib/src/main/kotlin/guiControl/NodeView.kt b/App/src/main/kotlin/guiControl/NodeView.kt similarity index 100% rename from lib/src/main/kotlin/guiControl/NodeView.kt rename to App/src/main/kotlin/guiControl/NodeView.kt diff --git a/lib/src/main/kotlin/guiControl/painters/AVLPainter.kt b/App/src/main/kotlin/guiControl/painters/AVLPainter.kt similarity index 100% rename from lib/src/main/kotlin/guiControl/painters/AVLPainter.kt rename to App/src/main/kotlin/guiControl/painters/AVLPainter.kt diff --git a/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt b/App/src/main/kotlin/guiControl/painters/AbstractPainter.kt similarity index 94% rename from lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt rename to App/src/main/kotlin/guiControl/painters/AbstractPainter.kt index 463cd9d..2244193 100644 --- a/lib/src/main/kotlin/guiControl/painters/AbstractPainter.kt +++ b/App/src/main/kotlin/guiControl/painters/AbstractPainter.kt @@ -15,6 +15,7 @@ abstract class AbstractPainter, Tree ) { val nodes: MutableList = mutableListOf() val lines: MutableList = mutableListOf() + init { if (tree.root == null) { // Если дерево ещё не заполнено, то заполним его "образцом" @@ -25,10 +26,11 @@ abstract class AbstractPainter, Tree getViewNodes(tree.root ?: throw NullNodeException(), width / 2, nodeMargin) } + /** * Позволяет определить каким цветом рисовать ноду */ - protected abstract fun getNodeColor(node: NodeType) : java.awt.Color + protected abstract fun getNodeColor(node: NodeType): java.awt.Color /** * Рекурсивно пробегает дерево и заполняет nodes и lines эл-ами для отрисовки @@ -36,8 +38,8 @@ abstract class AbstractPainter, Tree private fun getViewNodes(node: NodeType, x: Int, y: Int, n: Int = 1) { nodes.add(NodeView(Point(x, y), getNodeColor(node), node.key.toString())) - var nextX = 0 - var nextY = 0 + var nextX: Int + var nextY: Int if (node.left != null) { nextX = x - (x / (2 * n)) diff --git a/lib/src/main/kotlin/guiControl/painters/BTPainter.kt b/App/src/main/kotlin/guiControl/painters/BTPainter.kt similarity index 100% rename from lib/src/main/kotlin/guiControl/painters/BTPainter.kt rename to App/src/main/kotlin/guiControl/painters/BTPainter.kt diff --git a/lib/src/main/kotlin/guiControl/painters/RBTPainter.kt b/App/src/main/kotlin/guiControl/painters/RBTPainter.kt similarity index 100% rename from lib/src/main/kotlin/guiControl/painters/RBTPainter.kt rename to App/src/main/kotlin/guiControl/painters/RBTPainter.kt diff --git a/lib/src/main/kotlin/nodes/AbstractNode.kt b/lib/src/main/kotlin/nodes/AbstractNode.kt index 20df1ea..71f1362 100644 --- a/lib/src/main/kotlin/nodes/AbstractNode.kt +++ b/lib/src/main/kotlin/nodes/AbstractNode.kt @@ -4,12 +4,11 @@ abstract class AbstractNode, V, node : AbstractNode> { var key: K = key protected set - var value: V? = value internal set - var right: node? = null + internal set var left: node? = null - + internal set override fun compareTo(other: AbstractNode): Int = this.key.compareTo(other.key) } \ No newline at end of file diff --git a/lib/src/main/kotlin/trees/AbstractTree.kt b/lib/src/main/kotlin/trees/AbstractTree.kt index 6eaf77f..1bf7649 100644 --- a/lib/src/main/kotlin/trees/AbstractTree.kt +++ b/lib/src/main/kotlin/trees/AbstractTree.kt @@ -3,7 +3,8 @@ package trees import nodes.AbstractNode abstract class AbstractTree, V, node : AbstractNode> { - internal var root : node? = null + var root : node? = null + internal set abstract fun search(key : K) : node? abstract fun add(key : K, value : V? = null) abstract fun remove(key : K) From ee555c83568e7cd425d47289918ed3cb9076466b Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 4 May 2023 19:44:40 +0300 Subject: [PATCH 182/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=20=D0=BA=D0=BE=D0=BD=D1=81=D1=82=D0=B0=D0=BD?= =?UTF-8?q?=D1=82=D1=8B=20=D1=88=D0=B0=D0=B1=D0=BB=D0=BE=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D0=B5=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=20=D0=BE=D0=B1=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0=D1=85,?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B2=D1=91=D0=BB=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B0?= =?UTF-8?q?=20=D0=B0=D0=BD=D0=B3=D0=BB=D0=B8=D0=B9=D1=81=D0=BA=D0=B8=D0=B9?= =?UTF-8?q?=20=D1=8F=D0=B7=D1=8B=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 49 ++++++++++++------- .../kotlin/guiClasses/components/MenuClass.kt | 2 +- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index cdf0ee7..9e1fcb1 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -42,6 +42,12 @@ enum class TreeTypes { object Constants { const val BinaryBaseName = "Binary Tree Data.db" const val RBTBaseName = "Red-Black Tree Data.yml" + + const val NotFoundErrorMessage = "Tree node with such key not found" + const val NotChosenErrorMessage = "You must select a tree to perform this action" + const val AlreadyExistsErrorMessage = "Tree node with the same key already exists" + const val InputErrorMessage = "Entered value is not a number or is too large" + const val DataReadError = "Unable to read data from file" } /** @@ -68,7 +74,7 @@ fun main() { Trees.RBTree = base.loadTree() } catch (ex: Exception) { - showError("Не удалось прочитать данных из файла ${Constants.RBTBaseName}", menuFrame) + showError(Constants.DataReadError) } } if (File(Constants.BinaryBaseName).exists()) { @@ -85,11 +91,14 @@ fun main() { Trees.binTree = base.loadTree() } catch (ex: Exception) { - showError("Не удалось прочитать данных из файла ${Constants.BinaryBaseName}", menuFrame) + showError(Constants.DataReadError) } } } +/** + * Выполняет отрисовку переданного дерева на treeFrame + */ private fun treeInit(newTree: TreeTypes) { if (::treeFrame.isInitialized) treeFrame.dispose() @@ -105,12 +114,16 @@ private fun treeInit(newTree: TreeTypes) { } - - -private fun showError(text: String, frame: JFrame) { - JOptionPane.showMessageDialog(frame, text, "Произошла ошибка", JOptionPane.ERROR_MESSAGE) +/** + * Выводит сообщение об ошибке на экран + */ +private fun showError(text: String, frame: JFrame = menuFrame) { + JOptionPane.showMessageDialog(frame, text, "An error has occurred", JOptionPane.ERROR_MESSAGE) } +/** + * Заполнение Menu Frame компонентами + */ private fun menuFrameInit() { menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) @@ -126,14 +139,14 @@ private fun menuFrameInit() { TreeTypes.BINARY -> Trees.binTree.add(key) TreeTypes.AVL -> Trees.AVLTree.add(key) - else -> showError("Сначала выберите дерево", menuFrame) + else -> showError(Constants.NotChosenErrorMessage) } } catch (ex: NodeAlreadyExistsException) { - showError("Узел с таким значением уже существует", menuFrame) + showError(Constants.AlreadyExistsErrorMessage) } } else - showError("Добавлять можно только узлы с числовыми значениями", menuFrame) + showError(Constants.InputErrorMessage) } val removeButton = JButton("Remove") @@ -148,20 +161,20 @@ private fun menuFrameInit() { TreeTypes.BINARY -> Trees.binTree.remove(key) TreeTypes.AVL -> Trees.AVLTree.remove(key) - else -> showError("Сначала выберите дерево", menuFrame) + else -> showError(Constants.NotChosenErrorMessage) } } catch (ex: NodeNotFoundException) { - showError("Узла с таким значением не существует", menuFrame) + showError(Constants.NotFoundErrorMessage) } } else - showError("Добавлять можно только узлы с числовыми значениями", menuFrame) + showError(Constants.InputErrorMessage) } val saveButton = JButton("Save") - val refreshButton = JButton("Refresh") + val clearButton = JButton("Clear") - refreshButton.addActionListener { + clearButton.addActionListener { treeInit(currentTree) } @@ -195,10 +208,10 @@ private fun menuFrameInit() { } TreeTypes.AVL -> { - showError("Сохранение AVL дерева не реализовано", menuFrame) + showError("AVL tree saving is not implemented ;(") } - else -> showError("Сначала выберите дерево", menuFrame) + else -> showError(Constants.NotChosenErrorMessage) } } @@ -228,7 +241,7 @@ private fun menuFrameInit() { ) ) .addComponent(saveButton) - .addComponent(refreshButton) + .addComponent(clearButton) ) layout.setVerticalGroup( @@ -249,7 +262,7 @@ private fun menuFrameInit() { .addGroup( layout.createSequentialGroup() .addComponent(saveButton) - .addComponent(refreshButton) + .addComponent(clearButton) ) ) diff --git a/App/src/main/kotlin/guiClasses/components/MenuClass.kt b/App/src/main/kotlin/guiClasses/components/MenuClass.kt index 0f52459..da6eb73 100644 --- a/App/src/main/kotlin/guiClasses/components/MenuClass.kt +++ b/App/src/main/kotlin/guiClasses/components/MenuClass.kt @@ -25,7 +25,7 @@ class MenuClass( menuItems.filter { it != item }.forEach { it.background = Color.WHITE } } - private val menu = JMenu("Выбор Дерева") + private val menu = JMenu("Tree select") private val menuItems = arrayOf( JMenuItem("Binary Tree"), JMenuItem("AVL-Tree"), From a235091c1d9f4cba5f4595f0a0829f28531cdbbe Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 4 May 2023 19:49:48 +0300 Subject: [PATCH 183/203] =?UTF-8?q?=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=20=D0=BD=D0=B0=D0=B6=D0=B0=D1=82=D0=B8=D0=B8?= =?UTF-8?q?=20Enter=20=D0=B2=20TextField=20=D1=81=D1=80=D0=B0=D0=B1=D0=B0?= =?UTF-8?q?=D1=82=D1=8B=D0=B2=D0=B0=D0=B5=D1=82=20=D0=BE=D1=82=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D1=8F=D1=89=D0=B0=D1=8F=D1=81=D1=8F=20=D0=BA=20=D0=BD?= =?UTF-8?q?=D0=B5=D0=BC=D1=83=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 4 ++-- App/src/main/kotlin/guiClasses/components/KeyTextField.kt | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 9e1fcb1..3686b6c 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -128,7 +128,7 @@ private fun menuFrameInit() { menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) val addButton = JButton("Add") - val addTextField = KeyTextField() + val addTextField = KeyTextField(addButton) addButton.addActionListener { if (addTextField.text.toIntOrNull() != null) { @@ -150,7 +150,7 @@ private fun menuFrameInit() { } val removeButton = JButton("Remove") - val removeTextField = KeyTextField() + val removeTextField = KeyTextField(removeButton) removeButton.addActionListener { if (removeTextField.text.toIntOrNull() != null) { diff --git a/App/src/main/kotlin/guiClasses/components/KeyTextField.kt b/App/src/main/kotlin/guiClasses/components/KeyTextField.kt index 22c9732..4c3d6e1 100644 --- a/App/src/main/kotlin/guiClasses/components/KeyTextField.kt +++ b/App/src/main/kotlin/guiClasses/components/KeyTextField.kt @@ -1,14 +1,18 @@ package guiClasses.components +import javax.swing.JButton import javax.swing.JTextField -class KeyTextField() : JTextField() { +class KeyTextField( + private val button: JButton +) : JTextField() { private val textField = JTextField("Key") init { textField.also { addActionListener { - text = "" } + button.doClick() + } } add(textField) From b72848be69a920c66c0c8d2d9b34aaed45a85cd1 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 4 May 2023 19:57:09 +0300 Subject: [PATCH 184/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=20=D0=BE=D0=B1=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B5=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20=D0=BF=D0=BE=D0=BF=D1=8B=D1=82=D0=BA=D0=B5=20?= =?UTF-8?q?=D0=BE=D1=87=D0=B8=D1=81=D1=82=D0=B8=D1=82=D1=8C=20=D0=B3=D0=BE?= =?UTF-8?q?=D0=BB=D0=BE=D0=B5=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 3686b6c..4712c91 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -48,6 +48,8 @@ object Constants { const val AlreadyExistsErrorMessage = "Tree node with the same key already exists" const val InputErrorMessage = "Entered value is not a number or is too large" const val DataReadError = "Unable to read data from file" + const val TreeAlreadyClearErrorMessage = "There are no more nodes in tree" + } /** @@ -175,7 +177,25 @@ private fun menuFrameInit() { val clearButton = JButton("Clear") clearButton.addActionListener { - treeInit(currentTree) + when (currentTree) { + TreeTypes.RB -> { + if (Trees.RBTree.root == null) + showError(Constants.TreeAlreadyClearErrorMessage) + else + Trees.RBTree = RBTree() } + TreeTypes.BINARY -> { + if (Trees.binTree.root == null) + showError(Constants.TreeAlreadyClearErrorMessage) + else + Trees.binTree = BinaryTree() } + TreeTypes.AVL -> { + if (Trees.AVLTree.root == null) + showError(Constants.TreeAlreadyClearErrorMessage) + else + Trees.AVLTree = AVLTree() } + + else -> showError(Constants.NotChosenErrorMessage) + } } saveButton.addActionListener { @@ -267,4 +287,4 @@ private fun menuFrameInit() { ) -} +} \ No newline at end of file From 6abf39be73f95b9928521cebeb88125029eb10a0 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Thu, 4 May 2023 23:09:16 +0300 Subject: [PATCH 185/203] =?UTF-8?q?=D0=9A=D0=BB=D0=B0=D1=81=D1=81=D1=8B=20?= =?UTF-8?q?=D1=81=20=D0=BE=D1=82=D0=B4=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=BC?= =?UTF-8?q?=D0=B8=20=D1=84=D1=80=D0=B5=D0=B9=D0=BC=D0=B0=D0=BC=D0=B8=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BA=D0=B0=D0=B6=D0=B4=D0=BE=D0=B3=D0=BE?= =?UTF-8?q?=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=B0=20=D0=B7=D0=B0=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D0=BD=D1=8B=20=D0=BD=D0=B0=20=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20=D1=81=20=D0=BE?= =?UTF-8?q?=D0=B1=D1=89=D0=B8=D0=BC=20=D1=84=D1=80=D0=B5=D0=B9=D0=BC=D0=BE?= =?UTF-8?q?=D0=BC.=20=D0=A2=D0=B0=D0=BA=D0=B8=D0=BC=20=D0=BE=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=B7=D0=BE=D0=BC=20=D0=BD=D0=B5=20=D0=BD=D1=83=D0=B6?= =?UTF-8?q?=D0=BD=D0=BE=20=D0=B1=D1=83=D0=B4=D0=B5=D1=82=20=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=8F=D1=82=D1=8C=20=D0=BA=D0=B0=D0=B6=D0=B4=D1=8B=D0=B9?= =?UTF-8?q?=20=D1=80=D0=B0=D0=B7=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/guiClasses/components/TreePanel.kt | 70 ++++++++++++++++ .../components/nodePanels/AVLPanel.kt | 10 --- .../nodePanels/AbstractNodePanel.kt | 79 ------------------- .../components/nodePanels/BTPanel.kt | 10 --- .../components/nodePanels/RBTPanel.kt | 10 --- 5 files changed, 70 insertions(+), 109 deletions(-) create mode 100644 App/src/main/kotlin/guiClasses/components/TreePanel.kt delete mode 100644 App/src/main/kotlin/guiClasses/components/nodePanels/AVLPanel.kt delete mode 100644 App/src/main/kotlin/guiClasses/components/nodePanels/AbstractNodePanel.kt delete mode 100644 App/src/main/kotlin/guiClasses/components/nodePanels/BTPanel.kt delete mode 100644 App/src/main/kotlin/guiClasses/components/nodePanels/RBTPanel.kt diff --git a/App/src/main/kotlin/guiClasses/components/TreePanel.kt b/App/src/main/kotlin/guiClasses/components/TreePanel.kt new file mode 100644 index 0000000..4e3f373 --- /dev/null +++ b/App/src/main/kotlin/guiClasses/components/TreePanel.kt @@ -0,0 +1,70 @@ +package guiClasses.components + +import guiControl.LineView +import guiControl.NodeView +import java.awt.* +import javax.swing.JPanel + +/** + * Фрейм на котором отрисовываются все деревья + */ +class TreePanel( + private val nodeSize: Int = 30, + private val lineColor: Color = Color.BLACK, + size: Dimension = Dimension(100, 700) +) : JPanel() { + + private var linesToDraw: List = listOf() + private var nodesToDraw: List = listOf() + + init { + preferredSize = size + } + + fun changeTree(newLines: List, newNodes: List) { + this.linesToDraw = newLines + this.nodesToDraw = newNodes + } + override fun paintComponent(g: Graphics) { + super.paintComponent(g) + + // Сглаживание + val g2d = (g as Graphics2D).also { + val rh = RenderingHints( + RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON + ) + it.setRenderingHints(rh) + } + + for (line in linesToDraw) + drawLine(line) + + for (node in nodesToDraw) + drawNode(node) + } + + private fun drawNode(node: NodeView) { + graphics.color = node.color + + // Рисуем овал (ноду) + graphics.fillOval( + node.point.x - nodeSize / 2, + node.point.y - nodeSize / 2, + nodeSize, + nodeSize + ) + + graphics.color = Color.BLACK + graphics.drawString( + node.value, + node.point.x - node.value.length * 4, + node.point.y + nodeSize + ) + } + + private fun drawLine(line: LineView) { + graphics.color = lineColor + graphics.drawLine(line.from.x, line.from.y, line.to.x, line.to.y) + } +} \ No newline at end of file diff --git a/App/src/main/kotlin/guiClasses/components/nodePanels/AVLPanel.kt b/App/src/main/kotlin/guiClasses/components/nodePanels/AVLPanel.kt deleted file mode 100644 index cd7c166..0000000 --- a/App/src/main/kotlin/guiClasses/components/nodePanels/AVLPanel.kt +++ /dev/null @@ -1,10 +0,0 @@ -package guiClasses.components.nodePanels - -import guiControl.painters.AVLPainter -import nodes.AVLNode -import trees.AVLTree - -class AVLPanel(private val tree: AVLTree) : - AbstractNodePanel, AVLTree, AVLPainter>(tree) { - override fun painterInit() = AVLPainter(tree, Constants.nodeMargin, Constants.nodeSize, width) -} \ No newline at end of file diff --git a/App/src/main/kotlin/guiClasses/components/nodePanels/AbstractNodePanel.kt b/App/src/main/kotlin/guiClasses/components/nodePanels/AbstractNodePanel.kt deleted file mode 100644 index b49fdc6..0000000 --- a/App/src/main/kotlin/guiClasses/components/nodePanels/AbstractNodePanel.kt +++ /dev/null @@ -1,79 +0,0 @@ -package guiClasses.components.nodePanels - -import exceptions.NullNodeException -import guiControl.LineView -import guiControl.NodeView -import guiControl.painters.AbstractPainter -import nodes.AbstractNode -import nodes.RBNode -import trees.AbstractTree -import java.awt.* -import javax.swing.JPanel - -abstract class AbstractNodePanel< - NodeType : AbstractNode, - TreeType : AbstractTree, - Painter : AbstractPainter> - (private val tree: TreeType) : JPanel() { - - /** - * Объект со свойствами нод - */ - object Constants { - const val nodeSize = 30 - const val nodeMargin = 20 - val lineColor = java.awt.Color.BLACK - ?: throw NullPointerException() - } - - private lateinit var graphics: Graphics - - init { - preferredSize = Dimension(1000, 700) - } - - override fun paintComponent(g: Graphics) { - super.paintComponent(g) - - // Сглаживание - graphics = (g as Graphics2D).also { - val rh = RenderingHints( - RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON - ) - it.setRenderingHints(rh) - } - - val painter: Painter = painterInit() - - for (line in painter.lines) - drawLine(line) - - for (node in painter.nodes) - drawNode(node) - } - - protected abstract fun painterInit() : Painter - private fun drawNode(node: NodeView) { - graphics.color = node.color - - // Рисуем овал (ноду) - graphics.fillOval( - node.point.x - Constants.nodeSize / 2, - node.point.y - Constants.nodeSize / 2, - Constants.nodeSize, - Constants.nodeSize - ) - - graphics.color = Color.BLACK - graphics.drawString(node.value, node.point.x - node.value.length * 4, node.point.y + Constants.nodeSize) - } - - private fun drawLine(line: LineView) { - graphics.color = Constants.lineColor - graphics.drawLine(line.from.x, line.from.y, line.to.x, line.to.y) - } - - private fun getHeight(node: RBNode): Int = - 1 + maxOf(getHeight(node.left ?: throw NullNodeException()), getHeight(node.right ?: throw NullNodeException())) -} diff --git a/App/src/main/kotlin/guiClasses/components/nodePanels/BTPanel.kt b/App/src/main/kotlin/guiClasses/components/nodePanels/BTPanel.kt deleted file mode 100644 index fd4f269..0000000 --- a/App/src/main/kotlin/guiClasses/components/nodePanels/BTPanel.kt +++ /dev/null @@ -1,10 +0,0 @@ -package guiClasses.components.nodePanels - -import guiControl.painters.BTPainter -import nodes.BinaryNode -import trees.BinaryTree - -class BTPanel(private val tree: BinaryTree) : - AbstractNodePanel, BinaryTree, BTPainter>(tree) { - override fun painterInit() = BTPainter(tree, Constants.nodeMargin, Constants.nodeSize, width) -} \ No newline at end of file diff --git a/App/src/main/kotlin/guiClasses/components/nodePanels/RBTPanel.kt b/App/src/main/kotlin/guiClasses/components/nodePanels/RBTPanel.kt deleted file mode 100644 index 944b0b1..0000000 --- a/App/src/main/kotlin/guiClasses/components/nodePanels/RBTPanel.kt +++ /dev/null @@ -1,10 +0,0 @@ -package guiClasses.components.nodePanels - -import guiControl.painters.RBTPainter -import nodes.RBNode -import trees.RBTree - -class RBTPanel(private val tree: RBTree) : - AbstractNodePanel, RBTree, RBTPainter>(tree) { - override fun painterInit() = RBTPainter(tree, Constants.nodeMargin, Constants.nodeSize, width) -} \ No newline at end of file From 089a9c5f28fb8db04fbae48bd05f9d9d0cb9e11f Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Fri, 5 May 2023 00:55:59 +0300 Subject: [PATCH 186/203] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=BE=D1=82=D1=80=D0=B8=D1=81=D0=BE=D0=B2=D0=BA=D1=83=20GUI=20?= =?UTF-8?q?=D0=B1=D0=B5=D0=B7=20=D0=BE=D1=82=D0=BA=D1=80=D1=8B=D1=82=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BA=D0=B0=D0=B6=D0=B4=D1=8B=D0=B9=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B7=20=D0=BD=D0=BE=D0=B2=D0=BE=D0=B3=D0=BE=20=D0=BE=D0=BA?= =?UTF-8?q?=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 138 +++++++++++++----- .../kotlin/guiClasses/components/MenuClass.kt | 12 +- .../kotlin/guiClasses/components/TreePanel.kt | 22 ++- .../kotlin/guiControl/painters/AVLPainter.kt | 4 +- .../guiControl/painters/AbstractPainter.kt | 10 +- .../kotlin/guiControl/painters/BTPainter.kt | 4 +- .../kotlin/guiControl/painters/RBTPainter.kt | 4 +- 7 files changed, 134 insertions(+), 60 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 4712c91..8469acc 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -7,9 +7,10 @@ import exceptions.NodeNotFoundException import guiClasses.components.Frame import guiClasses.components.KeyTextField import guiClasses.components.MenuClass -import guiClasses.components.nodePanels.AVLPanel -import guiClasses.components.nodePanels.BTPanel -import guiClasses.components.nodePanels.RBTPanel +import guiClasses.components.TreePanel +import guiControl.painters.AVLPainter +import guiControl.painters.BTPainter +import guiControl.painters.RBTPainter import trees.AVLTree import trees.BinaryTree import trees.RBTree @@ -39,6 +40,9 @@ enum class TreeTypes { None } +/** + * Константы с сообщениями ошибок, именами файлов бд + */ object Constants { const val BinaryBaseName = "Binary Tree Data.db" const val RBTBaseName = "Red-Black Tree Data.yml" @@ -58,10 +62,19 @@ object Constants { private var currentTree: TreeTypes = TreeTypes.None private lateinit var treeFrame: JFrame +private lateinit var treePanel: TreePanel + private lateinit var menuFrame: JFrame fun main() { + treeFrameInit() menuFrameInit() + loadDatabase() +} +/** + * Вытаскивает деревья из баз данных + */ +private fun loadDatabase() { if (File(Constants.RBTBaseName).exists()) { try { val base = RBTBase(Constants.RBTBaseName, @@ -76,7 +89,7 @@ fun main() { Trees.RBTree = base.loadTree() } catch (ex: Exception) { - showError(Constants.DataReadError) + showMessage(Constants.DataReadError) } } if (File(Constants.BinaryBaseName).exists()) { @@ -93,38 +106,66 @@ fun main() { Trees.binTree = base.loadTree() } catch (ex: Exception) { - showError(Constants.DataReadError) + showMessage(Constants.DataReadError) } } } -/** - * Выполняет отрисовку переданного дерева на treeFrame - */ -private fun treeInit(newTree: TreeTypes) { - if (::treeFrame.isInitialized) - treeFrame.dispose() +private fun treeFrameInit() { treeFrame = Frame("Treeple", 1000, 700, 360, 50) - when (newTree) { - TreeTypes.RB -> treeFrame.add(RBTPanel(Trees.RBTree)) - TreeTypes.AVL -> treeFrame.add(AVLPanel(Trees.AVLTree)) - TreeTypes.BINARY -> treeFrame.add(BTPanel(Trees.binTree)) - else -> return + treePanel = TreePanel() + treeFrame.add(treePanel) + + Trees.binTree.run { + add(100) + add(120) + add(-10) + } + + Trees.RBTree.run { + add(100) + add(120) + add(-10) + } + + Trees.AVLTree.run { + add(100) + add(120) + add(-10) } - println(newTree) - currentTree = newTree } /** * Выводит сообщение об ошибке на экран */ -private fun showError(text: String, frame: JFrame = menuFrame) { - JOptionPane.showMessageDialog(frame, text, "An error has occurred", JOptionPane.ERROR_MESSAGE) +private fun showMessage(text: String, frame: JFrame = menuFrame, messageType: Int = JOptionPane.ERROR_MESSAGE) { + JOptionPane.showMessageDialog(frame, text, "An error has occurred", messageType) +} + +private fun treeRepaint() { + when (currentTree) { + TreeTypes.BINARY -> { + val painter = BTPainter(Trees.binTree, width = treeFrame.width) + treePanel.changeTree(painter.lines, painter.nodes) + } + + TreeTypes.AVL -> { + val painter = AVLPainter(Trees.AVLTree, width = treeFrame.width) + treePanel.changeTree(painter.lines, painter.nodes) + } + + TreeTypes.RB -> { + val painter = RBTPainter(Trees.RBTree, width = treeFrame.width) + treePanel.changeTree(painter.lines, painter.nodes) + } + + else -> {} + } } /** - * Заполнение Menu Frame компонентами + * Заполняет menuFrame компонентами */ private fun menuFrameInit() { menuFrame = Frame("Treeple Menu", 300, 400, 50, 50) @@ -141,14 +182,16 @@ private fun menuFrameInit() { TreeTypes.BINARY -> Trees.binTree.add(key) TreeTypes.AVL -> Trees.AVLTree.add(key) - else -> showError(Constants.NotChosenErrorMessage) + else -> showMessage(Constants.NotChosenErrorMessage) } } catch (ex: NodeAlreadyExistsException) { - showError(Constants.AlreadyExistsErrorMessage) + showMessage(Constants.AlreadyExistsErrorMessage) } } else - showError(Constants.InputErrorMessage) + showMessage(Constants.InputErrorMessage) + + treeRepaint() } val removeButton = JButton("Remove") @@ -163,14 +206,16 @@ private fun menuFrameInit() { TreeTypes.BINARY -> Trees.binTree.remove(key) TreeTypes.AVL -> Trees.AVLTree.remove(key) - else -> showError(Constants.NotChosenErrorMessage) + else -> showMessage(Constants.NotChosenErrorMessage) } } catch (ex: NodeNotFoundException) { - showError(Constants.NotFoundErrorMessage) + showMessage(Constants.NotFoundErrorMessage) } } else - showError(Constants.InputErrorMessage) + showMessage(Constants.InputErrorMessage) + + treeRepaint() } val saveButton = JButton("Save") @@ -180,22 +225,28 @@ private fun menuFrameInit() { when (currentTree) { TreeTypes.RB -> { if (Trees.RBTree.root == null) - showError(Constants.TreeAlreadyClearErrorMessage) + showMessage(Constants.TreeAlreadyClearErrorMessage) else - Trees.RBTree = RBTree() } + Trees.RBTree = RBTree() + } + TreeTypes.BINARY -> { if (Trees.binTree.root == null) - showError(Constants.TreeAlreadyClearErrorMessage) + showMessage(Constants.TreeAlreadyClearErrorMessage) else - Trees.binTree = BinaryTree() } + Trees.binTree = BinaryTree() + } + TreeTypes.AVL -> { if (Trees.AVLTree.root == null) - showError(Constants.TreeAlreadyClearErrorMessage) + showMessage(Constants.TreeAlreadyClearErrorMessage) else - Trees.AVLTree = AVLTree() } + Trees.AVLTree = AVLTree() + } - else -> showError(Constants.NotChosenErrorMessage) + else -> showMessage(Constants.NotChosenErrorMessage) } + treeRepaint() } saveButton.addActionListener { @@ -228,14 +279,27 @@ private fun menuFrameInit() { } TreeTypes.AVL -> { - showError("AVL tree saving is not implemented ;(") + showMessage("AVL tree saving is not implemented ;(") } - else -> showError(Constants.NotChosenErrorMessage) + else -> showMessage(Constants.NotChosenErrorMessage) } } - menuFrame.jMenuBar = MenuClass(::treeInit) + menuFrame.jMenuBar = MenuClass( + onBinSelected = { + currentTree = TreeTypes.BINARY + treeRepaint() + }, + onAVLSelected = { + currentTree = TreeTypes.AVL + treeRepaint() + }, + onRBTSelected = { + currentTree = TreeTypes.RB + treeRepaint() + } + ) // contentPane - контейнер для компонентов val layout = GroupLayout(menuFrame.contentPane) diff --git a/App/src/main/kotlin/guiClasses/components/MenuClass.kt b/App/src/main/kotlin/guiClasses/components/MenuClass.kt index da6eb73..3117a83 100644 --- a/App/src/main/kotlin/guiClasses/components/MenuClass.kt +++ b/App/src/main/kotlin/guiClasses/components/MenuClass.kt @@ -1,13 +1,15 @@ package guiClasses.components -import app.TreeTypes import java.awt.Color import javax.swing.JMenu import javax.swing.JMenuBar import javax.swing.JMenuItem class MenuClass( - private val onTreeSelected: (type: TreeTypes) -> Unit + private val onBinSelected: () -> Unit, + private val onAVLSelected: () -> Unit, + private val onRBTSelected: () -> Unit + ) : JMenuBar() { /** @@ -39,19 +41,19 @@ class MenuClass( // Слушатель событий для элемента меню "Binary Tree" menuItems[0].addActionListener { updateMenuItemsChoosing(menuItems[0]) - onTreeSelected(TreeTypes.BINARY) + onBinSelected() } // Слушатель событий для элемента меню "AVL-Tree" menuItems[1].addActionListener { updateMenuItemsChoosing(menuItems[1]) - onTreeSelected(TreeTypes.AVL) + onAVLSelected() } // Слушатель событий для элемента меню "Red-black Tree" menuItems[2].addActionListener { updateMenuItemsChoosing(menuItems[2]) - onTreeSelected(TreeTypes.RB) + onRBTSelected() } add(menu) diff --git a/App/src/main/kotlin/guiClasses/components/TreePanel.kt b/App/src/main/kotlin/guiClasses/components/TreePanel.kt index 4e3f373..8fd9634 100644 --- a/App/src/main/kotlin/guiClasses/components/TreePanel.kt +++ b/App/src/main/kotlin/guiClasses/components/TreePanel.kt @@ -24,7 +24,10 @@ class TreePanel( fun changeTree(newLines: List, newNodes: List) { this.linesToDraw = newLines this.nodesToDraw = newNodes + + repaint() } + override fun paintComponent(g: Graphics) { super.paintComponent(g) @@ -37,14 +40,25 @@ class TreePanel( it.setRenderingHints(rh) } + if (nodesToDraw.isEmpty()) { + val x = width / 2 - 100 + val y = height / 2 + + g2d.color = Color.gray + g2d.font = Font("Tahoma", Font.TRUETYPE_FONT, 24) + g2d.drawString("Tree is empty ;(", x, y) + + return + } + for (line in linesToDraw) - drawLine(line) + drawLine(line, g2d) for (node in nodesToDraw) - drawNode(node) + drawNode(node, g2d) } - private fun drawNode(node: NodeView) { + private fun drawNode(node: NodeView, graphics: Graphics2D) { graphics.color = node.color // Рисуем овал (ноду) @@ -63,7 +77,7 @@ class TreePanel( ) } - private fun drawLine(line: LineView) { + private fun drawLine(line: LineView, graphics: Graphics2D) { graphics.color = lineColor graphics.drawLine(line.from.x, line.from.y, line.to.x, line.to.y) } diff --git a/App/src/main/kotlin/guiControl/painters/AVLPainter.kt b/App/src/main/kotlin/guiControl/painters/AVLPainter.kt index d1d4cee..e1c9087 100644 --- a/App/src/main/kotlin/guiControl/painters/AVLPainter.kt +++ b/App/src/main/kotlin/guiControl/painters/AVLPainter.kt @@ -6,8 +6,8 @@ import java.awt.Color class AVLPainter( tree: AVLTree, - nodeMargin: Int, - nodeSize: Int, + nodeMargin: Int = 30, + nodeSize: Int = 20, width: Int ) : AbstractPainter, AVLTree>(tree, nodeMargin, nodeSize, width) { override fun getNodeColor(node: AVLNode): Color = Color.gray diff --git a/App/src/main/kotlin/guiControl/painters/AbstractPainter.kt b/App/src/main/kotlin/guiControl/painters/AbstractPainter.kt index 2244193..bbcfb33 100644 --- a/App/src/main/kotlin/guiControl/painters/AbstractPainter.kt +++ b/App/src/main/kotlin/guiControl/painters/AbstractPainter.kt @@ -9,20 +9,14 @@ import java.awt.Point abstract class AbstractPainter, TreeType : AbstractTree>( tree: TreeType, - private val nodeMargin: Int, - private val nodeSize: Int, + private val nodeMargin: Int = 20, + private val nodeSize: Int = 30, width: Int ) { val nodes: MutableList = mutableListOf() val lines: MutableList = mutableListOf() init { - if (tree.root == null) { - // Если дерево ещё не заполнено, то заполним его "образцом" - tree.add(100) - tree.add(-10) - tree.add(120) - } getViewNodes(tree.root ?: throw NullNodeException(), width / 2, nodeMargin) } diff --git a/App/src/main/kotlin/guiControl/painters/BTPainter.kt b/App/src/main/kotlin/guiControl/painters/BTPainter.kt index 2204463..76b41c5 100644 --- a/App/src/main/kotlin/guiControl/painters/BTPainter.kt +++ b/App/src/main/kotlin/guiControl/painters/BTPainter.kt @@ -5,8 +5,8 @@ import trees.BinaryTree import java.awt.Color class BTPainter( tree: BinaryTree, - nodeMargin: Int, - nodeSize: Int, + nodeMargin: Int = 30, + nodeSize: Int = 20, width: Int ) : AbstractPainter, BinaryTree>(tree, nodeMargin, nodeSize, width) { override fun getNodeColor(node: BinaryNode): Color = Color.DARK_GRAY diff --git a/App/src/main/kotlin/guiControl/painters/RBTPainter.kt b/App/src/main/kotlin/guiControl/painters/RBTPainter.kt index b60b3b6..8081a6c 100644 --- a/App/src/main/kotlin/guiControl/painters/RBTPainter.kt +++ b/App/src/main/kotlin/guiControl/painters/RBTPainter.kt @@ -5,8 +5,8 @@ import nodes.RBNode import trees.RBTree class RBTPainter( tree: RBTree, - nodeMargin: Int, - nodeSize: Int, + nodeMargin: Int = 30, + nodeSize: Int = 20, width: Int ) : AbstractPainter, RBTree>(tree, nodeMargin, nodeSize, width) { override fun getNodeColor(node: RBNode): java.awt.Color { From 0cbd3f7bdc26730906d2ae9ac0afe23b4cf0f7d0 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Fri, 5 May 2023 00:59:33 +0300 Subject: [PATCH 187/203] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=B0=20resizable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 8469acc..a1d14ff 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -14,12 +14,15 @@ import guiControl.painters.RBTPainter import trees.AVLTree import trees.BinaryTree import trees.RBTree +import java.awt.event.ComponentAdapter +import java.awt.event.ComponentEvent import java.io.File import javax.swing.GroupLayout import javax.swing.JButton import javax.swing.JFrame import javax.swing.JOptionPane + /** * Объект, хранящий отдельно каждое из деревьев * (позволяет параллельно работать сразу со всеми) @@ -116,6 +119,12 @@ private fun treeFrameInit() { treePanel = TreePanel() treeFrame.add(treePanel) + treeFrame.addComponentListener(object : ComponentAdapter() { + override fun componentResized(componentEvent: ComponentEvent) { + treeRepaint() + } + }) + Trees.binTree.run { add(100) add(120) From c7cd1056aaefc76a85bcae077a93eaf68f4b3659 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Fri, 5 May 2023 01:15:16 +0300 Subject: [PATCH 188/203] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D1=83=20clear=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=87=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 12 ++++++++++++ .../main/kotlin/guiClasses/components/TreePanel.kt | 11 +++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index a1d14ff..5688184 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -155,16 +155,28 @@ private fun showMessage(text: String, frame: JFrame = menuFrame, messageType: In private fun treeRepaint() { when (currentTree) { TreeTypes.BINARY -> { + if (Trees.binTree.root == null) { + treePanel.clearTree() + return + } val painter = BTPainter(Trees.binTree, width = treeFrame.width) treePanel.changeTree(painter.lines, painter.nodes) } TreeTypes.AVL -> { + if (Trees.AVLTree.root == null) { + treePanel.clearTree() + return + } val painter = AVLPainter(Trees.AVLTree, width = treeFrame.width) treePanel.changeTree(painter.lines, painter.nodes) } TreeTypes.RB -> { + if (Trees.RBTree.root == null) { + treePanel.clearTree() + return + } val painter = RBTPainter(Trees.RBTree, width = treeFrame.width) treePanel.changeTree(painter.lines, painter.nodes) } diff --git a/App/src/main/kotlin/guiClasses/components/TreePanel.kt b/App/src/main/kotlin/guiClasses/components/TreePanel.kt index 8fd9634..47e89e7 100644 --- a/App/src/main/kotlin/guiClasses/components/TreePanel.kt +++ b/App/src/main/kotlin/guiClasses/components/TreePanel.kt @@ -28,6 +28,13 @@ class TreePanel( repaint() } + fun clearTree() { + linesToDraw = listOf() + nodesToDraw = listOf() + + repaint() + } + override fun paintComponent(g: Graphics) { super.paintComponent(g) @@ -41,8 +48,8 @@ class TreePanel( } if (nodesToDraw.isEmpty()) { - val x = width / 2 - 100 - val y = height / 2 + val x = width / 2 - 90 + val y = height / 2 - 10 g2d.color = Color.gray g2d.font = Font("Tahoma", Font.TRUETYPE_FONT, 24) From b5e7695f167f5e10b92b3601d91e066c8e58b751 Mon Sep 17 00:00:00 2001 From: d-zaytsev Date: Fri, 5 May 2023 01:25:01 +0300 Subject: [PATCH 189/203] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=82=D0=B5?= =?UTF-8?q?=D0=BA=D1=81=D1=82=D0=B0=20=D0=B8=D0=B7=20textField=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20=D0=BD=D0=B0=D0=B6=D0=B0=D1=82=D0=B8=D0=B8=20?= =?UTF-8?q?=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B8=20=D1=80=D1=8F=D0=B4=D0=BE?= =?UTF-8?q?=D0=BC=20=D1=81=20=D0=BD=D0=B8=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 5688184..72b3f9e 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -212,6 +212,7 @@ private fun menuFrameInit() { } else showMessage(Constants.InputErrorMessage) + addTextField.text = "" treeRepaint() } @@ -236,6 +237,7 @@ private fun menuFrameInit() { } else showMessage(Constants.InputErrorMessage) + removeTextField.text = "" treeRepaint() } From 0d2794eede00c47ac7608d20e286097633afdc0f Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Sun, 7 May 2023 22:57:51 +0300 Subject: [PATCH 190/203] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B8=D0=BA=D0=BE=D0=BD=D0=BA=D1=83=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F,=20=D0=B8?= =?UTF-8?q?=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=B1=D0=B0=D0=B3?= =?UTF-8?q?=D1=83=20=D1=81=20=D0=BD=D0=B5=D0=BA=D0=BE=D1=80=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=BD=D1=8B=D0=BC=20=D0=BE=D1=82=D0=BA=D1=80=D1=8B?= =?UTF-8?q?=D1=82=D0=B8=D0=B5=D0=BC=20=D0=BE=D0=BA=D0=BD=D0=B0=20=D0=BD?= =?UTF-8?q?=D0=B0=20windiws?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 2 +- App/tree.jpg | Bin 0 -> 21909 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 App/tree.jpg diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 72b3f9e..709e8b3 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -69,8 +69,8 @@ private lateinit var treePanel: TreePanel private lateinit var menuFrame: JFrame fun main() { - treeFrameInit() menuFrameInit() + treeFrameInit() loadDatabase() } diff --git a/App/tree.jpg b/App/tree.jpg new file mode 100644 index 0000000000000000000000000000000000000000..724ed680254dfac99ceb5164220f5eb830723468 GIT binary patch literal 21909 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 literal 0 HcmV?d00001 From c7962fa79cbad825bfb07ba2ab5747bf60d182fe Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Tue, 9 May 2023 18:11:12 +0300 Subject: [PATCH 191/203] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BB=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D1=8E=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA=D0=B0=20=D0=BD=D0=BE?= =?UTF-8?q?=D0=B4=D1=8B=20=D0=B2=D1=8B=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=D0=BC=20=D0=B5=D0=B5=20=D0=B6=D0=B5=D0=BB=D1=82=D1=8B?= =?UTF-8?q?=D0=BC=20=D1=86=D0=B2=D0=B5=D1=82=D0=BE=D0=BC.=20=D0=94=D0=BB?= =?UTF-8?q?=D1=8F=20=D1=8D=D1=82=D0=BE=D0=B3=D0=BE=20=D0=BD=D0=B5=D0=BC?= =?UTF-8?q?=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20nodes=20=D0=B8=20pain?= =?UTF-8?q?ters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 56 +++++++++++++++++++ .../kotlin/guiControl/painters/AVLPainter.kt | 8 ++- .../kotlin/guiControl/painters/BTPainter.kt | 8 ++- .../kotlin/guiControl/painters/RBTPainter.kt | 5 +- lib/src/main/kotlin/nodes/AVLNode.kt | 1 + lib/src/main/kotlin/nodes/AbstractNode.kt | 5 +- lib/src/main/kotlin/nodes/BinaryNode.kt | 1 + lib/src/main/kotlin/nodes/RBTNode.kt | 4 +- 8 files changed, 78 insertions(+), 10 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 709e8b3..d79af72 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -11,6 +11,7 @@ import guiClasses.components.TreePanel import guiControl.painters.AVLPainter import guiControl.painters.BTPainter import guiControl.painters.RBTPainter +import nodes.Color import trees.AVLTree import trees.BinaryTree import trees.RBTree @@ -241,6 +242,50 @@ private fun menuFrameInit() { treeRepaint() } + val searchButton = JButton("Search") + val searchTextField = KeyTextField(searchButton) + + searchButton.addActionListener { + var origNodeColor: Color = Color.BLACK + if (searchTextField.text.toIntOrNull() != null) { + val key = searchTextField.text.toInt() + try { + when (currentTree) { + TreeTypes.RB -> {var node = Trees.RBTree.search(key); origNodeColor = node.color; node.color = Color.YELLOW} + TreeTypes.BINARY -> {var node = Trees.binTree.search(key); origNodeColor = node.color; node.color = Color.YELLOW} + TreeTypes.AVL -> {var node = Trees.AVLTree.search(key); origNodeColor = node.color; node.color = Color.YELLOW} + + else -> showMessage(Constants.NotChosenErrorMessage) + } + + } catch (ex: NodeNotFoundException) { + showMessage(Constants.NotFoundErrorMessage) + } + } else + showMessage(Constants.InputErrorMessage) + + treeRepaint() + + if (searchTextField.text.toIntOrNull() != null) { + val key = searchTextField.text.toInt() + try { + when (currentTree) { + TreeTypes.RB -> {var node = Trees.RBTree.search(key); node.color = origNodeColor} + TreeTypes.BINARY -> {var node = Trees.binTree.search(key); node.color = origNodeColor} + TreeTypes.AVL -> {var node = Trees.AVLTree.search(key); node.color = origNodeColor} + + else -> showMessage(Constants.NotChosenErrorMessage) + } + + } catch (ex: NodeNotFoundException) { + showMessage(Constants.NotFoundErrorMessage) + } + } else + showMessage(Constants.InputErrorMessage) + searchTextField.text = "" + } + + val saveButton = JButton("Save") val clearButton = JButton("Clear") @@ -340,11 +385,13 @@ private fun menuFrameInit() { layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(addButton) .addComponent(removeButton) + .addComponent(searchButton) ) .addGroup( // Группа с TextFields layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(addTextField) .addComponent(removeTextField) + .addComponent(searchTextField) ) ) .addComponent(saveButton) @@ -365,6 +412,11 @@ private fun menuFrameInit() { .addComponent(removeTextField) ) + .addGroup( + layout.createParallelGroup(GroupLayout.Alignment.BASELINE) + .addComponent(searchButton) + .addComponent(searchTextField) + ) .addGroup( layout.createSequentialGroup() @@ -374,4 +426,8 @@ private fun menuFrameInit() { ) + fun find(){ + + } + } \ No newline at end of file diff --git a/App/src/main/kotlin/guiControl/painters/AVLPainter.kt b/App/src/main/kotlin/guiControl/painters/AVLPainter.kt index e1c9087..0310d0b 100644 --- a/App/src/main/kotlin/guiControl/painters/AVLPainter.kt +++ b/App/src/main/kotlin/guiControl/painters/AVLPainter.kt @@ -1,8 +1,8 @@ package guiControl.painters import nodes.AVLNode +import nodes.Color import trees.AVLTree -import java.awt.Color class AVLPainter( tree: AVLTree, @@ -10,5 +10,9 @@ class AVLPainter( nodeSize: Int = 20, width: Int ) : AbstractPainter, AVLTree>(tree, nodeMargin, nodeSize, width) { - override fun getNodeColor(node: AVLNode): Color = Color.gray + override fun getNodeColor(node: AVLNode): java.awt.Color{ + return if (node.color == Color.YELLOW){ + java.awt.Color.YELLOW + } else java.awt.Color.GRAY + } } \ No newline at end of file diff --git a/App/src/main/kotlin/guiControl/painters/BTPainter.kt b/App/src/main/kotlin/guiControl/painters/BTPainter.kt index 76b41c5..c1f6a1e 100644 --- a/App/src/main/kotlin/guiControl/painters/BTPainter.kt +++ b/App/src/main/kotlin/guiControl/painters/BTPainter.kt @@ -1,13 +1,17 @@ package guiControl.painters import nodes.BinaryNode +import nodes.Color import trees.BinaryTree -import java.awt.Color class BTPainter( tree: BinaryTree, nodeMargin: Int = 30, nodeSize: Int = 20, width: Int ) : AbstractPainter, BinaryTree>(tree, nodeMargin, nodeSize, width) { - override fun getNodeColor(node: BinaryNode): Color = Color.DARK_GRAY + override fun getNodeColor(node: BinaryNode): java.awt.Color{ + return if (node.color == Color.YELLOW){ + java.awt.Color.YELLOW + } else java.awt.Color.DARK_GRAY + } } \ No newline at end of file diff --git a/App/src/main/kotlin/guiControl/painters/RBTPainter.kt b/App/src/main/kotlin/guiControl/painters/RBTPainter.kt index 8081a6c..187c627 100644 --- a/App/src/main/kotlin/guiControl/painters/RBTPainter.kt +++ b/App/src/main/kotlin/guiControl/painters/RBTPainter.kt @@ -10,9 +10,10 @@ class RBTPainter( width: Int ) : AbstractPainter, RBTree>(tree, nodeMargin, nodeSize, width) { override fun getNodeColor(node: RBNode): java.awt.Color { - return if (node.color == Color.RED) + return if (node.color == Color.RED){ java.awt.Color.RED - else + } else if (node.color == Color.BLACK){ java.awt.Color.BLACK + } else java.awt.Color.YELLOW } } \ No newline at end of file diff --git a/lib/src/main/kotlin/nodes/AVLNode.kt b/lib/src/main/kotlin/nodes/AVLNode.kt index 6ff70bd..f5509ef 100644 --- a/lib/src/main/kotlin/nodes/AVLNode.kt +++ b/lib/src/main/kotlin/nodes/AVLNode.kt @@ -2,4 +2,5 @@ package nodes class AVLNode, V>(key: K, value: V?) : AbstractNode>(key, value){ var height: Int = 1 + override var color: Color = Color.GRAY } diff --git a/lib/src/main/kotlin/nodes/AbstractNode.kt b/lib/src/main/kotlin/nodes/AbstractNode.kt index 71f1362..c62772a 100644 --- a/lib/src/main/kotlin/nodes/AbstractNode.kt +++ b/lib/src/main/kotlin/nodes/AbstractNode.kt @@ -10,5 +10,8 @@ abstract class AbstractNode, V, node : AbstractNode): Int = this.key.compareTo(other.key) -} \ No newline at end of file +} + +enum class Color { RED, BLACK, YELLOW, DARK_GRAY, GRAY} \ No newline at end of file diff --git a/lib/src/main/kotlin/nodes/BinaryNode.kt b/lib/src/main/kotlin/nodes/BinaryNode.kt index a51d311..37f0929 100644 --- a/lib/src/main/kotlin/nodes/BinaryNode.kt +++ b/lib/src/main/kotlin/nodes/BinaryNode.kt @@ -15,6 +15,7 @@ import exceptions.NullNodeException */ class BinaryNode, V>(key: K, value: V?) : AbstractNode>(key, value) { + override var color: Color = Color.DARK_GRAY fun search(key: K): BinaryNode? = when (key.compareTo(this.key)) { 1 -> this.right?.search(key) diff --git a/lib/src/main/kotlin/nodes/RBTNode.kt b/lib/src/main/kotlin/nodes/RBTNode.kt index adc9e96..859a520 100644 --- a/lib/src/main/kotlin/nodes/RBTNode.kt +++ b/lib/src/main/kotlin/nodes/RBTNode.kt @@ -4,7 +4,5 @@ class RBNode, V>(key: K, value: V?) : AbstractNode>(key, value) { var parent: RBNode? = null - var color: Color = Color.BLACK + override var color: Color = Color.BLACK } - -enum class Color { RED, BLACK } From ae88bb5725435ac40da3d1382f112b2adba7c3ba Mon Sep 17 00:00:00 2001 From: Ilya Pogorelov Date: Tue, 9 May 2023 18:12:31 +0300 Subject: [PATCH 192/203] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B9=20=D0=BD=D0=B5=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D0=BE=D1=8C=D1=8C=D0=B7=D1=83=D0=B5=D0=BC=D1=8B=D0=B9=20?= =?UTF-8?q?=D0=BA=D0=BB=D0=B0=D1=81=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index d79af72..739afa2 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -425,9 +425,4 @@ private fun menuFrameInit() { ) ) - - fun find(){ - - } - } \ No newline at end of file From 0ef70d7feba1da1b6c66b53cf962f2444c2d0749 Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Sun, 30 Apr 2023 21:08:04 +0300 Subject: [PATCH 193/203] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B7=D0=B0=D0=B2=D0=B8=D1=81=D0=B8=D0=BC=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/build.gradle | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/build.gradle b/lib/build.gradle index d5c6619..58ffddd 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -1,6 +1,7 @@ plugins { id 'org.jetbrains.kotlin.jvm' version "${KOTLIN_JVM_VERSION}" id 'org.jetbrains.kotlin.plugin.serialization' version "${KOTLIN_JVM_VERSION}" + id 'org.jetbrains.kotlin.plugin.noarg' version '1.8.10' id 'java-library' } @@ -9,17 +10,30 @@ repositories { mavenCentral() } + dependencies { testImplementation "${KOTLIN_TEST_JUNIT}" implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0' implementation("org.xerial:sqlite-jdbc:3.32.3.2") + + implementation("io.github.microutils:kotlin-logging-jvm:2.0.6") + + implementation("org.neo4j:neo4j-ogm-core:4.0.5") + runtimeOnly("org.neo4j:neo4j-ogm-bolt-driver:4.0.5") } + tasks.named('test') { useJUnitPlatform() testLogging { events "PASSED", "SKIPPED", "FAILED" } } + + +noArg { + annotation("org.neo4j.ogm.annotation.NodeEntity") + annotation("org.neo4j.ogm.annotation.RelationshipEntity") +} \ No newline at end of file From 79514a52f7a748f47dc30f49b5d4bc0de7a57d98 Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Mon, 1 May 2023 11:10:35 +0300 Subject: [PATCH 194/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20=D0=B1=D0=B4=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=90=D0=92=D0=9B=20=D0=B4=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=B2=D0=B0,=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20=D1=81=D0=BE=D1=85=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 11 +++ lib/build.gradle | 2 + .../kotlin/databases/avl/Neo4jRepository.kt | 90 +++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 docker-compose.yml create mode 100644 lib/src/main/kotlin/databases/avl/Neo4jRepository.kt diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..736302b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,11 @@ +version: '3.9' + +services: + neo4j: + image: neo4j:latest + container_name: neo4j + ports: + - "7474:7474" + - "7687:7687" + environment: + NEO4J_AUTH: neo4j/password \ No newline at end of file diff --git a/lib/build.gradle b/lib/build.gradle index 58ffddd..d4beedd 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -20,6 +20,8 @@ dependencies { implementation("io.github.microutils:kotlin-logging-jvm:2.0.6") + implementation("org.slf4j:slf4j-simple:1.7.29") + implementation("org.neo4j:neo4j-ogm-core:4.0.5") runtimeOnly("org.neo4j:neo4j-ogm-bolt-driver:4.0.5") } diff --git a/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt b/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt new file mode 100644 index 0000000..c437d49 --- /dev/null +++ b/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt @@ -0,0 +1,90 @@ +package databases.avl + +import nodes.AVLNode +import org.neo4j.ogm.annotation.* +import org.neo4j.ogm.config.Configuration +import org.neo4j.ogm.session.SessionFactory +import trees.AVLTree + +@NodeEntity +class AVLNodeEntity( + @Property + val key: K, + + @Property + var value: V?, + + @Property + var x: Double = 0.0, + + @Property + var y: Double = 0.0, + + @Relationship(type = "LEFT") + var left: AVLNodeEntity? = null, + + @Relationship(type = "RIGHT") + var right: AVLNodeEntity? = null, +){ + @Id + @GeneratedValue + var id: Long? = null +} + +@NodeEntity +class AVLTreeEntity( + @Property + var name: String, + + @Relationship(type = "ROOT") + var root: AVLNodeEntity? = null, +){ + @Id + @GeneratedValue + var id: Long? = null +} + +class Neo4jRepository, V>(uri: String, username: String, password: String) { + private val configuration: Configuration = Configuration.Builder() + .uri(uri) + .credentials(username, password) + .build(); + + private val sessionFactory = SessionFactory(configuration, "databases.avl") + private val session = sessionFactory.openSession() + + private fun AVLTree.toEntity(name: String) : AVLTreeEntity { + return AVLTreeEntity( + name, + root?.toEntity() + ) + } + + private fun AVLNode.toEntity() : AVLNodeEntity{ + return AVLNodeEntity( + key, + value, + 0.0, //Нужен класс который смог бы хранить эти координаты + 0.0, + left?.toEntity(), + right?.toEntity() + ) + } + + fun saveTree(tree: AVLTree, name: String) { + deleteTree(name) + session.save(tree.toEntity(name)) + } + + fun loadTree() { + TODO("Not yet implemented") + } + + fun deleteTree(name: String) { + session.query( + "MATCH (t: AVLTreeEntity {name: \$name})-[*0..]-(x)" + + "DETACH DELETE x", + mapOf("name" to name) + ) + } +} \ No newline at end of file From 3df900e2f1bd885e3b1a44d3613c14fe9f1c8770 Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Tue, 2 May 2023 21:43:39 +0300 Subject: [PATCH 195/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B0=D1=82=D1=8C?= =?UTF-8?q?=20=D0=B4=D0=B5=D1=80=D0=B5=D0=B2=D0=BE=20=D0=B8=D0=B7=20=D0=B1?= =?UTF-8?q?=D0=B4,=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=B2?= =?UTF-8?q?=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20?= =?UTF-8?q?=D1=83=D0=BA=D0=B0=D0=B7=D1=8B=D0=B2=D0=B0=D1=82=D1=8C=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8=D0=B8?= =?UTF-8?q?=20=D0=BE=D0=B1=D1=8A=D0=B5=D0=BA=D1=82=D0=B0=20=D0=B1=D0=B4=20?= =?UTF-8?q?=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20=D1=81=D0=B5=D1=80?= =?UTF-8?q?=D0=B8=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20/=20?= =?UTF-8?q?=D0=B4=D0=B5=D1=81=D0=B5=D1=80=D0=B8=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/databases/avl/Neo4jRepository.kt | 72 ++++++++++++++----- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt b/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt index c437d49..b9781bd 100644 --- a/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt +++ b/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt @@ -3,16 +3,22 @@ package databases.avl import nodes.AVLNode 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 import trees.AVLTree @NodeEntity -class AVLNodeEntity( +class AVLNodeEntity( @Property - val key: K, + val key: String, @Property - var value: V?, + var value: String?, + + @Property + var height: Int, @Property var x: Double = 0.0, @@ -21,10 +27,10 @@ class AVLNodeEntity( var y: Double = 0.0, @Relationship(type = "LEFT") - var left: AVLNodeEntity? = null, + var left: AVLNodeEntity? = null, @Relationship(type = "RIGHT") - var right: AVLNodeEntity? = null, + var right: AVLNodeEntity? = null, ){ @Id @GeneratedValue @@ -32,19 +38,27 @@ class AVLNodeEntity( } @NodeEntity -class AVLTreeEntity( +class AVLTreeEntity( @Property var name: String, @Relationship(type = "ROOT") - var root: AVLNodeEntity? = null, + var root: AVLNodeEntity? = null, ){ @Id @GeneratedValue var id: Long? = null } -class Neo4jRepository, V>(uri: String, username: String, password: String) { +class Neo4jRepository, V>( + uri: String, + username: String, + password: String, + private val serializeKey: (key: K) -> String = { value -> value.toString() }, + private val deserializeKey: (strKey: String) -> K, + private val serializeValue: (value: V?) -> String = { value -> value.toString() }, + private val deserializeValue: (strValue: String?) -> V? +) { private val configuration: Configuration = Configuration.Builder() .uri(uri) .credentials(username, password) @@ -53,31 +67,53 @@ class Neo4jRepository, V>(uri: String, username: String, passwo private val sessionFactory = SessionFactory(configuration, "databases.avl") private val session = sessionFactory.openSession() - private fun AVLTree.toEntity(name: String) : AVLTreeEntity { - return AVLTreeEntity( + private fun AVLTree.toEntity(name: String) : AVLTreeEntity { + return AVLTreeEntity( name, root?.toEntity() ) } - private fun AVLNode.toEntity() : AVLNodeEntity{ - return AVLNodeEntity( - key, - value, - 0.0, //Нужен класс который смог бы хранить эти координаты - 0.0, + private fun AVLNode.toEntity(x: Double = 0.0, y: Double = 0.0) : AVLNodeEntity{ + return AVLNodeEntity( + serializeKey(key), + serializeValue(value), + height, + x, + y, left?.toEntity(), right?.toEntity() ) } + private fun AVLTreeEntity.toTree(): AVLTree { + return AVLTree().also { + it.root = this.root?.toNode() + } + } + + private fun AVLNodeEntity.toNode() : AVLNode { + return AVLNode(deserializeKey(key), deserializeValue(value)).also { + it.left = this.toNode() + it.right = this.toNode() + it.height = this.height + } + } + + private fun findTree(name: String) = session.loadAll( + AVLTreeEntity::class.java, + Filter("name", ComparisonOperator.EQUALS, name), -1) + fun saveTree(tree: AVLTree, name: String) { deleteTree(name) session.save(tree.toEntity(name)) } - fun loadTree() { - TODO("Not yet implemented") + + fun loadTree(name: String): AVLTree? { + val treeEntity = findTree(name).singleOrNull() + + return treeEntity?.toTree() } fun deleteTree(name: String) { From c2935ad0fa00ca08cb7597b2e425c00390c4795e Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Tue, 2 May 2023 22:22:19 +0300 Subject: [PATCH 196/203] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D1=83=20=D1=81=20?= =?UTF-8?q?=D1=80=D0=B5=D0=BA=D1=83=D1=80=D1=81=D0=B8=D0=B2=D0=BD=D1=8B?= =?UTF-8?q?=D0=BC=20=D0=B2=D1=8B=D0=B7=D1=8B=D0=B2=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/src/main/kotlin/databases/avl/Neo4jRepository.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt b/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt index b9781bd..2911629 100644 --- a/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt +++ b/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt @@ -94,8 +94,8 @@ class Neo4jRepository, V>( private fun AVLNodeEntity.toNode() : AVLNode { return AVLNode(deserializeKey(key), deserializeValue(value)).also { - it.left = this.toNode() - it.right = this.toNode() + it.left = this.left?.toNode() + it.right = this.right?.toNode() it.height = this.height } } From c3bf3d4d023a8ff0ba7efc64521bce5d9f5f5c6f Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Wed, 3 May 2023 01:06:42 +0300 Subject: [PATCH 197/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D1=8B=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=B8=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA=D0=B0=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BE=D1=80=D0=B4=D0=B8=D0=BD=D0=B0=D1=82=20=D0=BF=D0=BE?= =?UTF-8?q?=20=D0=BA=D0=BB=D1=8E=D1=87=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/databases/avl/Neo4jRepository.kt | 70 ++++++++++++++----- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt b/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt index 2911629..b3da358 100644 --- a/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt +++ b/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt @@ -8,6 +8,7 @@ import org.neo4j.ogm.cypher.Filter import org.neo4j.ogm.cypher.Filters import org.neo4j.ogm.session.SessionFactory import trees.AVLTree +import java.awt.Point @NodeEntity class AVLNodeEntity( @@ -21,17 +22,17 @@ class AVLNodeEntity( var height: Int, @Property - var x: Double = 0.0, + var x: Int = 0, @Property - var y: Double = 0.0, + var y: Int = 0, @Relationship(type = "LEFT") var left: AVLNodeEntity? = null, @Relationship(type = "RIGHT") var right: AVLNodeEntity? = null, -){ +) { @Id @GeneratedValue var id: Long? = null @@ -44,13 +45,13 @@ class AVLTreeEntity( @Relationship(type = "ROOT") var root: AVLNodeEntity? = null, -){ +) { @Id @GeneratedValue var id: Long? = null } -class Neo4jRepository, V>( +class Neo4jRepository, V>( uri: String, username: String, password: String, @@ -67,14 +68,14 @@ class Neo4jRepository, V>( private val sessionFactory = SessionFactory(configuration, "databases.avl") private val session = sessionFactory.openSession() - private fun AVLTree.toEntity(name: String) : AVLTreeEntity { + private fun AVLTree.toEntity(name: String = "Default"): AVLTreeEntity { return AVLTreeEntity( name, root?.toEntity() ) } - private fun AVLNode.toEntity(x: Double = 0.0, y: Double = 0.0) : AVLNodeEntity{ + private fun AVLNode.toEntity(x: Int = 0, y: Int = 0): AVLNodeEntity { return AVLNodeEntity( serializeKey(key), serializeValue(value), @@ -92,7 +93,7 @@ class Neo4jRepository, V>( } } - private fun AVLNodeEntity.toNode() : AVLNode { + private fun AVLNodeEntity.toNode(): AVLNode { return AVLNode(deserializeKey(key), deserializeValue(value)).also { it.left = this.left?.toNode() it.right = this.right?.toNode() @@ -100,27 +101,64 @@ class Neo4jRepository, V>( } } - private fun findTree(name: String) = session.loadAll( + private fun findTree(name: String = "Default") = session.loadAll( AVLTreeEntity::class.java, - Filter("name", ComparisonOperator.EQUALS, name), -1) + Filter("name", ComparisonOperator.EQUALS, name), -1 + ) - fun saveTree(tree: AVLTree, name: String) { + fun saveTree(tree: AVLTree, name: String = "Default") { deleteTree(name) session.save(tree.toEntity(name)) } - - fun loadTree(name: String): AVLTree? { + fun loadTree(name: String = "Default"): AVLTree? { val treeEntity = findTree(name).singleOrNull() return treeEntity?.toTree() } - fun deleteTree(name: String) { + fun deleteTree(name: String = "Default") { session.query( - "MATCH (t: AVLTreeEntity {name: \$name})-[*0..]-(x)" + - "DETACH DELETE x", + "MATCH (t: AVLTreeEntity {name: \$name})-[*0..]-(x)" + + "DETACH DELETE x", mapOf("name" to name) ) } + + fun getPoint(key: K, name: String = "Default"): Point { + val node = session.queryForObject(AVLNodeEntity::class.java, + "MATCH(t:AVLTreeEntity {name: \$name})" + + "MATCH(n:AVLNodeEntity {key: \$key})<-[*0..]-(t)" + + "return n", + mapOf("name" to name, "key" to serializeKey(key)) + ) + + return Point(node.x, node.y) + } + + fun setPoint(key: K, point: Point, name: String = "Default") { + session.query( + "MATCH(t:AVLTreeEntity {name: \$name})" + + "MATCH(n:AVLNodeEntity {key: \$key})<-[*0..]-(t)" + + "SET n.x = \$x, n.y = \$y", + mapOf("name" to name, "key" to serializeKey(key), "x" to point.x, "y" to point.y) + ) + } + + /*fun setPoint(key: K, p: Point) { + val savedTree = Json.decodeFromString(file.readText()) + + if (savedTree.root?.changeCoordinate(key, p) != true) + throw NodeNotFoundException() + + file.printWriter().use { out -> + out.write(Json.encodeToString(savedTree)) + } + + } + + fun getPoint(key: K): Point { + return Json.decodeFromString(file.readText()).root?.searchCoordinate(key) + ?: throw NodeNotFoundException() + }*/ } \ No newline at end of file From 83758370acd1edf40493af7d0d271f8e023bc506 Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Wed, 17 May 2023 10:28:22 +0300 Subject: [PATCH 198/203] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D1=8F=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B2=20=D0=B1=D0=B4=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7?= =?UTF-8?q?=20GUI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 15 ++++++++++++++- docker-compose.yml | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 739afa2..6fd053e 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -1,5 +1,6 @@ package app +import databases.avl.Neo4jRepository import databases.json.RBTBase import databases.sqlite.BTBase import exceptions.NodeAlreadyExistsException @@ -347,7 +348,19 @@ private fun menuFrameInit() { } TreeTypes.AVL -> { - showMessage("AVL tree saving is not implemented ;(") + val base = Neo4jRepository( + "bolt://localhost:7687", + "neo4j", + "password", + serializeValue = { value -> value?.toString() ?: "null" }, + deserializeValue = { value -> + if (value == "null") + 0 + else + value?.toInt() + }, + deserializeKey = { value -> value.toInt() }) + base.saveTree(Trees.AVLTree) } else -> showMessage(Constants.NotChosenErrorMessage) diff --git a/docker-compose.yml b/docker-compose.yml index 736302b..ec77aa0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,6 @@ services: container_name: neo4j ports: - "7474:7474" - - "7687:7687" + #- "7687:7687" environment: NEO4J_AUTH: neo4j/password \ No newline at end of file From 9b5f9d34e6dfa2e9ccdc8cd918f45ba35d13b368 Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Wed, 17 May 2023 10:50:23 +0300 Subject: [PATCH 199/203] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BB=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=BD=D1=8B=D0=B9=20=D0=BA=D0=BE=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 1 - .../kotlin/databases/avl/Neo4jRepository.kt | 18 ------------------ 2 files changed, 19 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index ec77aa0..b65d808 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,5 @@ services: container_name: neo4j ports: - "7474:7474" - #- "7687:7687" environment: NEO4J_AUTH: neo4j/password \ No newline at end of file diff --git a/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt b/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt index b3da358..d1c79de 100644 --- a/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt +++ b/lib/src/main/kotlin/databases/avl/Neo4jRepository.kt @@ -5,7 +5,6 @@ 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 import trees.AVLTree import java.awt.Point @@ -144,21 +143,4 @@ class Neo4jRepository, V>( mapOf("name" to name, "key" to serializeKey(key), "x" to point.x, "y" to point.y) ) } - - /*fun setPoint(key: K, p: Point) { - val savedTree = Json.decodeFromString(file.readText()) - - if (savedTree.root?.changeCoordinate(key, p) != true) - throw NodeNotFoundException() - - file.printWriter().use { out -> - out.write(Json.encodeToString(savedTree)) - } - - } - - fun getPoint(key: K): Point { - return Json.decodeFromString(file.readText()).root?.searchCoordinate(key) - ?: throw NodeNotFoundException() - }*/ } \ No newline at end of file From 5b44811429badce3b13c152c6fd435e0866e2b68 Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Wed, 17 May 2023 23:37:38 +0300 Subject: [PATCH 200/203] =?UTF-8?q?=D0=90=D0=92=D0=9B=20=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B2=D0=BE=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=B3=D1=80=D1=83=D0=B6=D0=B0=D0=B5=D1=82?= =?UTF-8?q?=D1=81=D1=8F=20=D0=BF=D1=80=D0=B8=20=D0=B7=D0=B0=D0=BF=D1=83?= =?UTF-8?q?=D1=81=D0=BA=D0=B5=20=D0=BF=D1=80=D0=B8=D0=BB=D0=BE=D0=B6=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/src/main/kotlin/app/App.kt | 22 ++++++++++++++++++++++ docker-compose.yml | 1 + 2 files changed, 23 insertions(+) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 6fd053e..6aeaff8 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -114,6 +114,28 @@ private fun loadDatabase() { showMessage(Constants.DataReadError) } } + try { + val base = Neo4jRepository( + "bolt://localhost:7687", + "neo4j", + "password", + serializeValue = { value -> value?.toString() ?: "null" }, + deserializeValue = { value -> + if (value == "null") + 0 + else + value?.toInt() + }, + deserializeKey = { value -> value.toInt() }) + + val tree = base.loadTree() + + if (tree != null) { + Trees.AVLTree = tree + } + } catch (ex: Exception) { + showMessage(Constants.DataReadError) + } } private fun treeFrameInit() { diff --git a/docker-compose.yml b/docker-compose.yml index b65d808..736302b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,5 +6,6 @@ services: container_name: neo4j ports: - "7474:7474" + - "7687:7687" environment: NEO4J_AUTH: neo4j/password \ No newline at end of file From 1168166f22f0be6bc8d800d8d9faff33e32fefca Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Mon, 5 Jun 2023 12:24:08 +0300 Subject: [PATCH 201/203] Fixed the problem with GroupLayout causing errors --- App/src/main/kotlin/app/App.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/App/src/main/kotlin/app/App.kt b/App/src/main/kotlin/app/App.kt index 6fd053e..703c81c 100644 --- a/App/src/main/kotlin/app/App.kt +++ b/App/src/main/kotlin/app/App.kt @@ -384,7 +384,6 @@ private fun menuFrameInit() { // contentPane - контейнер для компонентов val layout = GroupLayout(menuFrame.contentPane) - menuFrame.contentPane.layout = layout layout.autoCreateContainerGaps = true layout.autoCreateGaps = true @@ -438,4 +437,6 @@ private fun menuFrameInit() { ) ) + + menuFrame.contentPane.layout = layout } \ No newline at end of file From 882af9f3738f1302bddd149bbe133df5ba9cd95f Mon Sep 17 00:00:00 2001 From: sokolovskiy-ilya Date: Mon, 5 Jun 2023 12:32:09 +0300 Subject: [PATCH 202/203] Added port for bolt --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index b65d808..736302b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,5 +6,6 @@ services: container_name: neo4j ports: - "7474:7474" + - "7687:7687" environment: NEO4J_AUTH: neo4j/password \ No newline at end of file From fbb30e376a06d7570d29df9e3e3dce46b7841e9a Mon Sep 17 00:00:00 2001 From: Dmitriy Zaytsev <113129532+d-zaytsev@users.noreply.github.com> Date: Sun, 16 Jul 2023 13:31:31 +0300 Subject: [PATCH 203/203] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 49 ++++++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index d419046..c625cb6 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,33 @@ -# Описание проекта TREEPLE +# Описание проекта -Этот проект содержит реализации трех типов деревьев: бинарное дерево поиска, AVL-дерево и красно-черное дерево. Все три типа деревьев наследуются из абстрактного класса AbstractTree, а их узлы наследуются из абстрактного класса AbstractNode. Система сборки - Gradle +Этот проект содержит реализацию операций удаления/вставки/поиска в трёх типах деревьев: бинарное дерево поиска, AVL-дерево и красно-черное дерево. -# Бинарное дерево поиска +# Функциональность ++ Создание и управление AVL, RBT и бинарным деревом. ++ Сохранение и загрузка деревьев в базы данных (json - RB, SQLite - Binary, neo4j - AVL). ++ GUI с возможностью *изменять/создавать новые/сохранять* деревья. -Бинарное дерево поиска - это структура данных, в которой каждый узел имеет не более двух потомков, и ключи в левом поддереве меньше, чем ключ в корне, а ключи в правом поддереве больше, чем ключ в корне. Бинарное дерево поиска реализовано в классе BinaryTree. - -# AVL-дерево - -AVL-дерево - это сбалансированное бинарное дерево поиска, в котором для каждого узла высота левого и правого поддеревьев различается не более чем на 1. AVL-дерево реализовано в классе AVLTree. - -# Красно-черное дерево - -Красно-черное дерево - это сбалансированное бинарное дерево поиска, в котором каждый узел имеет цвет - красный или черный. Каждый путь от корня до листа содержит одинаковое количество черных узлов. Красно-черное дерево реализовано в классе RBTree. - -# Сохранение деревьев - -Для сохранения деревьев мы используем три различных базы данных: SQLite, Neo4j и JSON. Бинарное дерево поиска сохраняется в SQLite, AVL-дерево сохраняется в Neo4j, RBTree сохраняется в JSON +# Запуск +``` +# Необходимо скачать проект с github +git clone https://github.com/spbu-coding-2022/trees-10.git -# Тестирование деревьев +# Для сборки используется Gradle +./gradle build -Тестирование каждого дерева проходит с помощью фреймворка JUnit. +# Запуск +./gradle App:run +``` +В проекте имеются два модулья - lib и App. lib содержит реализацию деревьев и предназначен для их использования, либо добавления новых. App - модуль, содержащий реализацию GUI. -# Запуск программы +# Использование GUI -Для того, чтобы запустить программу, необходимо скачать код и в командной строке ввести -``` -gradle App: run -``` +В **'Treeple Menu'** выбираете необходимое вам дерево. Чтобы добавить элемент в дерево, введите число(значение) вашего элемента перед кнопкой **'Add'**. После нажатия на кнопку дерево обновится. -# Использование приложения +Чтобы удалить элемент из дерева, введите значение вашего элемента перед кнопкой **'Remove'**. После нажатия дерево обновится. -В верхнем меню выбираете необходимое вам дерево. Чтобы добавить элемент в дерево, введите ключ вашего элемента перед кнопкой 'Add'. Нажимаете на эту кнопку. Чтобы изменения отобразились в дереве, нажмите кнопку 'Refresh'. +Чтобы сохранить дерево, нажмите кнопку 'Save'. При повторном запуске приложения ваше сохраненное дерево отобразится автоматически, либо выведется сообщение об ошибке. -Чтобы удалить элемент из дерева, введите ключ вашего элемента перед кнопкой 'Remove'. Нажимаете на эту кнопку. Чтобы изменения отобразились в дереве, нажмите кнопку 'Refresh'. +# License -Чтобы сохранить дерево, нажмите кнопку 'Save'. При повторном запуске приложения ваше сохраненное дерево отобразится автоматически. +Проект использует MIT License. Подробная информация: [LICENSE](https://github.com/spbu-coding-2022/trees-10/blob/main/LICENSE).