From 33213c2faed8b78053c18aeb577e7a47d1a7582b Mon Sep 17 00:00:00 2001 From: Kostya Date: Sat, 6 Apr 2024 23:49:15 +0300 Subject: [PATCH 1/4] feat: add class enum for color --- lib/src/main/kotlin/trees/RBSearchTree.kt | 104 +++++++++++----------- lib/src/main/kotlin/vertexes/RBVertex.kt | 10 ++- 2 files changed, 61 insertions(+), 53 deletions(-) diff --git a/lib/src/main/kotlin/trees/RBSearchTree.kt b/lib/src/main/kotlin/trees/RBSearchTree.kt index dfaaa7e..37dda32 100644 --- a/lib/src/main/kotlin/trees/RBSearchTree.kt +++ b/lib/src/main/kotlin/trees/RBSearchTree.kt @@ -32,6 +32,9 @@ import main.vertexes.RBVertex * @property root The root vertex of the tree. */ class RBSearchTree : AbstractBinarySearchTree> { + private val red = RBVertex.Color.RED + private val black = RBVertex.Color.BLACK + /** * This method removes the vertex with the given key from the tree and returns its associated value, * maintaining the properties of the red-black tree. @@ -75,7 +78,7 @@ class RBSearchTree : AbstractBinarySearchTree> { private fun needToBalance(vertex: RBVertex): Boolean { when (countChildren(vertex)) { 0 -> { - if (vertex.isRed) { + if (vertex.color == red) { replaceVertexBy(vertex, null) return false } @@ -127,37 +130,37 @@ class RBSearchTree : AbstractBinarySearchTree> { */ private fun balanceAfterRemove(vertex: RBVertex?) { var currentVertex = vertex - while (currentVertex != root && (currentVertex?.isRed == false || currentVertex == null)) { + while (currentVertex != root && (currentVertex?.color == black || currentVertex == null)) { var brother: RBVertex? if (currentVertex == currentVertex?.parent?.leftSon) { brother = currentVertex?.parent?.rightSon - if (brother?.isRed == true) { - brother.isRed = false - currentVertex?.parent?.isRed = true + if (brother?.color == red) { + brother.color = black + currentVertex?.parent?.color = red val vertexForRotate = currentVertex?.parent vertexForRotate?.let { rotateLeft(vertexForRotate) } brother = currentVertex?.parent?.rightSon } - if ((brother?.leftSon?.isRed == false || brother?.leftSon == null) && - (brother?.rightSon?.isRed == false || brother?.rightSon == null) + if ((brother?.leftSon?.color == black || brother?.leftSon == null) && + (brother?.rightSon?.color == black || brother?.rightSon == null) ) { - brother?.isRed = true + brother?.color = red currentVertex = currentVertex?.parent if (vertex == currentVertex?.leftSon) currentVertex?.leftSon = null } else { - if (brother.rightSon?.isRed == false || brother.rightSon == null) { - brother.leftSon?.isRed = false - brother.isRed = true + if (brother.rightSon?.color == black || brother.rightSon == null) { + brother.leftSon?.color = black + brother.color = red rotateRight(brother) brother = currentVertex?.parent?.rightSon } - val parentColor = currentVertex?.parent?.isRed - parentColor?.let { brother?.isRed = parentColor } - currentVertex?.parent?.isRed = false - brother?.rightSon?.isRed = false + val parentColor = currentVertex?.parent?.color + parentColor?.let { brother?.color = parentColor } + currentVertex?.parent?.color = black + brother?.rightSon?.color = black val vertexForRotate = currentVertex?.parent vertexForRotate?.let { rotateLeft(vertexForRotate) } if (currentVertex == vertex) currentVertex?.parent?.leftSon = null @@ -166,32 +169,32 @@ class RBSearchTree : AbstractBinarySearchTree> { } else { brother = currentVertex?.parent?.leftSon - if (brother?.isRed == true) { - brother.isRed = false - currentVertex?.parent?.isRed = true + if (brother?.color == red) { + brother.color = black + currentVertex?.parent?.color = red val vertexForRotate = currentVertex?.parent vertexForRotate?.let { rotateRight(vertexForRotate) } brother = currentVertex?.parent?.leftSon } - if ((brother?.leftSon?.isRed == false || brother?.leftSon == null) && - (brother?.rightSon?.isRed == false || brother?.rightSon == null) + if ((brother?.leftSon?.color == black || brother?.leftSon == null) && + (brother?.rightSon?.color == black || brother?.rightSon == null) ) { - brother?.isRed = true + brother?.color = red currentVertex = currentVertex?.parent if (vertex == currentVertex?.rightSon) currentVertex?.rightSon = null } else { - if (brother.leftSon?.isRed == false || brother.leftSon == null) { - brother.rightSon?.isRed = false - brother.isRed = true + if (brother.leftSon?.color == black || brother.leftSon == null) { + brother.rightSon?.color = black + brother.color = red rotateLeft(brother) brother = currentVertex?.parent?.leftSon } - val parentColor = currentVertex?.parent?.isRed - parentColor?.let { brother?.isRed = parentColor } - currentVertex?.parent?.isRed = false - brother?.leftSon?.isRed = false + val parentColor = currentVertex?.parent?.color + parentColor?.let { brother?.color = parentColor } + currentVertex?.parent?.color = black + brother?.leftSon?.color = black val vertexForRotate = currentVertex?.parent vertexForRotate?.let { rotateRight(vertexForRotate) } if (currentVertex == vertex) currentVertex?.parent?.rightSon = null @@ -199,7 +202,7 @@ class RBSearchTree : AbstractBinarySearchTree> { } } } - currentVertex?.isRed = false + currentVertex?.color = black } /** @@ -265,7 +268,7 @@ class RBSearchTree : AbstractBinarySearchTree> { } if (currentVertex == null) { - currentVertex = RBVertex(key, value, null, null, true, parent) + currentVertex = RBVertex(key, value, null, null, red, parent) if (root == null) { root = currentVertex } else if (isLeft) { @@ -295,16 +298,16 @@ class RBSearchTree : AbstractBinarySearchTree> { private fun balanceAfterPut(vertex: RBVertex) { var currentVertex = vertex - while (currentVertex.parent?.isRed == true) { + while (currentVertex.parent?.color == red) { val grandparent = currentVertex.parent?.parent if (currentVertex.parent == grandparent?.leftSon) { val uncle = grandparent?.rightSon - if (uncle?.isRed == true) { - currentVertex.parent?.isRed = false - uncle.isRed = false - grandparent.isRed = true + if (uncle?.color == red) { + currentVertex.parent?.color = black + uncle.color = black + grandparent.color = red currentVertex = grandparent } else { if (currentVertex == currentVertex.parent?.rightSon) { @@ -312,18 +315,18 @@ class RBSearchTree : AbstractBinarySearchTree> { rotateLeft(currentVertex) } - currentVertex.parent?.isRed = false - currentVertex.parent?.parent?.isRed = true + currentVertex.parent?.color = black + currentVertex.parent?.parent?.color = red val vertexForRightRotate = currentVertex.parent?.parent vertexForRightRotate?.let { rotateRight(vertexForRightRotate) } } } else { val uncle = grandparent?.leftSon - if (uncle?.isRed == true) { - currentVertex.parent?.isRed = false - uncle.isRed = false - grandparent.isRed = true + if (uncle?.color == red) { + currentVertex.parent?.color = black + uncle.color = black + grandparent.color = red currentVertex = grandparent } else { if (currentVertex == currentVertex.parent?.leftSon) { @@ -331,14 +334,14 @@ class RBSearchTree : AbstractBinarySearchTree> { rotateRight(currentVertex) } - currentVertex.parent?.isRed = false - currentVertex.parent?.parent?.isRed = true + currentVertex.parent?.color = black + currentVertex.parent?.parent?.color = red val vertexForLeftRotate = currentVertex.parent?.parent vertexForLeftRotate?.let { rotateLeft(vertexForLeftRotate) } } } } - root?.isRed = false + root?.color = black } /** @@ -421,7 +424,9 @@ class RBSearchTree : AbstractBinarySearchTree> { * Constructs a new binary search tree with the specified comparator. * @param comparator the comparator to use for comparing keys, or null to use natural ordering */ - constructor(comparator: Comparator? = null) : super(comparator) + constructor(comparator: Comparator? = null) { + this.comparator = comparator + } /** * Constructs a new binary search tree and initializes it with the mappings from the specified map. @@ -429,9 +434,8 @@ class RBSearchTree : AbstractBinarySearchTree> { * @param replaceIfExists if true, replaces the value if the key already exists, otherwise ignores it * @param comparator the comparator to use for comparing keys, or null to use natural ordering */ - constructor(map: Map, replaceIfExists: Boolean = true, comparator: Comparator? = null) : super( - map, - replaceIfExists, - comparator, - ) + constructor(map: Map, replaceIfExists: Boolean = true, comparator: Comparator? = null) { + this.comparator = comparator + putAll(map, replaceIfExists) + } } diff --git a/lib/src/main/kotlin/vertexes/RBVertex.kt b/lib/src/main/kotlin/vertexes/RBVertex.kt index 4a4e06c..fe69a14 100644 --- a/lib/src/main/kotlin/vertexes/RBVertex.kt +++ b/lib/src/main/kotlin/vertexes/RBVertex.kt @@ -15,7 +15,11 @@ class RBVertex( override var key: K, override var value: V, ) : InterfaceBSTVertex> { - var isRed = true + enum class Color { + RED, + BLACK + } + var color: Color = Color.RED var parent: RBVertex? = null override var leftSon: RBVertex? = null override var rightSon: RBVertex? = null @@ -34,12 +38,12 @@ class RBVertex( value: V, leftSon: RBVertex?, rightSon: RBVertex?, - isRed: Boolean, + color: Color, parent: RBVertex?, ) : this(key, value) { this.leftSon = leftSon this.rightSon = rightSon this.parent = parent - this.isRed = isRed + this.color = color } } From 392fd21af1ce0d2de087079efba4c023097c11f3 Mon Sep 17 00:00:00 2001 From: Kostya Date: Sun, 7 Apr 2024 14:50:45 +0300 Subject: [PATCH 2/4] fix: reuse code in balanceAfterPut, delete extra code --- lib/src/main/kotlin/trees/RBSearchTree.kt | 56 ++++++++--------------- 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/lib/src/main/kotlin/trees/RBSearchTree.kt b/lib/src/main/kotlin/trees/RBSearchTree.kt index 37dda32..21c0b31 100644 --- a/lib/src/main/kotlin/trees/RBSearchTree.kt +++ b/lib/src/main/kotlin/trees/RBSearchTree.kt @@ -300,45 +300,29 @@ class RBSearchTree : AbstractBinarySearchTree> { while (currentVertex.parent?.color == red) { val grandparent = currentVertex.parent?.parent - - if (currentVertex.parent == grandparent?.leftSon) { - val uncle = grandparent?.rightSon - - if (uncle?.color == red) { - currentVertex.parent?.color = black - uncle.color = black - grandparent.color = red - currentVertex = grandparent - } else { - if (currentVertex == currentVertex.parent?.rightSon) { - currentVertex = currentVertex.parent ?: currentVertex - rotateLeft(currentVertex) - } - - currentVertex.parent?.color = black - currentVertex.parent?.parent?.color = red - val vertexForRightRotate = currentVertex.parent?.parent - vertexForRightRotate?.let { rotateRight(vertexForRightRotate) } - } + val isUncleRightSon = (currentVertex.parent == grandparent?.leftSon) + val uncle = if (isUncleRightSon) grandparent?.rightSon else grandparent?.leftSon + + if (uncle?.color == red) { + currentVertex.parent?.color = black + uncle.color = black + grandparent?.color = red + currentVertex = grandparent ?: currentVertex } else { - val uncle = grandparent?.leftSon - - if (uncle?.color == red) { - currentVertex.parent?.color = black - uncle.color = black - grandparent.color = red - currentVertex = grandparent - } else { - if (currentVertex == currentVertex.parent?.leftSon) { - currentVertex = currentVertex.parent ?: currentVertex - rotateRight(currentVertex) - } + if ((isUncleRightSon) && (currentVertex == currentVertex.parent?.rightSon)) { + currentVertex = currentVertex.parent ?: currentVertex + rotateLeft(currentVertex) + } - currentVertex.parent?.color = black - currentVertex.parent?.parent?.color = red - val vertexForLeftRotate = currentVertex.parent?.parent - vertexForLeftRotate?.let { rotateLeft(vertexForLeftRotate) } + else if ((!isUncleRightSon) && (currentVertex == currentVertex.parent?.leftSon)) { + currentVertex = currentVertex.parent ?: currentVertex + rotateRight(currentVertex) } + + currentVertex.parent?.color = black + currentVertex.parent?.parent?.color = red + val vertexForRotate = currentVertex.parent?.parent + vertexForRotate?.let { if (isUncleRightSon) rotateRight(vertexForRotate) else rotateLeft(vertexForRotate) } } } root?.color = black From 46400e436837a75f683bfdc27596e2718c32b4d9 Mon Sep 17 00:00:00 2001 From: Kostya Date: Sun, 7 Apr 2024 16:45:54 +0300 Subject: [PATCH 3/4] fix: reuse code in BalanceAfterRemove, delete extra code --- lib/src/main/kotlin/trees/RBSearchTree.kt | 110 ++++++++++------------ 1 file changed, 51 insertions(+), 59 deletions(-) diff --git a/lib/src/main/kotlin/trees/RBSearchTree.kt b/lib/src/main/kotlin/trees/RBSearchTree.kt index 21c0b31..63518a8 100644 --- a/lib/src/main/kotlin/trees/RBSearchTree.kt +++ b/lib/src/main/kotlin/trees/RBSearchTree.kt @@ -41,14 +41,14 @@ class RBSearchTree : AbstractBinarySearchTree> { * * 4 cases we need to look at: * - * 1) remove red vertex with 0 children -> just remove vetrex + * 1) remove red vertex with 0 children -> just remove vertex * * 2) remove red or black vertex with 2 children -> * find min vertex on the right subtree and swap it's key and value with * key and value of vertex that we need to remove. * Now we can work with vertex which has 1 or 0 children * - * 3) remove black vetrex with 1 child -> child can be only red + * 3) remove black vertex with 1 child -> child can be only red * so we just swap child's key and value with key and value that we need to remove * and look at case 1) * @@ -131,75 +131,67 @@ class RBSearchTree : AbstractBinarySearchTree> { private fun balanceAfterRemove(vertex: RBVertex?) { var currentVertex = vertex while (currentVertex != root && (currentVertex?.color == black || currentVertex == null)) { - var brother: RBVertex? - if (currentVertex == currentVertex?.parent?.leftSon) { - brother = currentVertex?.parent?.rightSon - - if (brother?.color == red) { - brother.color = black - currentVertex?.parent?.color = red - val vertexForRotate = currentVertex?.parent - vertexForRotate?.let { rotateLeft(vertexForRotate) } - brother = currentVertex?.parent?.rightSon - } + val isBrotherRightSon = (currentVertex == currentVertex?.parent?.leftSon) + var brother: RBVertex? = if (isBrotherRightSon) currentVertex?.parent?.rightSon else currentVertex?.parent?.leftSon + + if (brother?.color == red) { + brother.color = black + currentVertex?.parent?.color = red + val vertexForRotate = currentVertex?.parent - if ((brother?.leftSon?.color == black || brother?.leftSon == null) && - (brother?.rightSon?.color == black || brother?.rightSon == null) - ) { - brother?.color = red - currentVertex = currentVertex?.parent - if (vertex == currentVertex?.leftSon) currentVertex?.leftSon = null - } else { - if (brother.rightSon?.color == black || brother.rightSon == null) { - brother.leftSon?.color = black - brother.color = red - rotateRight(brother) + when (isBrotherRightSon) { + true -> { + vertexForRotate?.let { rotateLeft(vertexForRotate) } brother = currentVertex?.parent?.rightSon + } else -> { + vertexForRotate?.let { rotateRight(vertexForRotate) } + brother = currentVertex?.parent?.leftSon } + } + } - val parentColor = currentVertex?.parent?.color - parentColor?.let { brother?.color = parentColor } - currentVertex?.parent?.color = black - brother?.rightSon?.color = black - val vertexForRotate = currentVertex?.parent - vertexForRotate?.let { rotateLeft(vertexForRotate) } - if (currentVertex == vertex) currentVertex?.parent?.leftSon = null - currentVertex = root + if ((brother?.leftSon?.color == black || brother?.leftSon == null) && + (brother?.rightSon?.color == black || brother?.rightSon == null) + ) { + brother?.color = red + currentVertex = currentVertex?.parent + + when (vertex) { + currentVertex?.leftSon -> currentVertex?.leftSon = null + currentVertex?.rightSon -> currentVertex?.rightSon = null } } else { - brother = currentVertex?.parent?.leftSon + if ((isBrotherRightSon) && (brother.rightSon?.color == black || brother.rightSon == null)) { + brother.leftSon?.color = black + brother.color = red + rotateRight(brother) + brother = currentVertex?.parent?.rightSon + } - if (brother?.color == red) { - brother.color = black - currentVertex?.parent?.color = red - val vertexForRotate = currentVertex?.parent - vertexForRotate?.let { rotateRight(vertexForRotate) } + else if ((!isBrotherRightSon) && (brother.leftSon?.color == black || brother.leftSon == null)) { + brother.rightSon?.color = black + brother.color = red + rotateLeft(brother) brother = currentVertex?.parent?.leftSon } - if ((brother?.leftSon?.color == black || brother?.leftSon == null) && - (brother?.rightSon?.color == black || brother?.rightSon == null) - ) { - brother?.color = red - currentVertex = currentVertex?.parent - if (vertex == currentVertex?.rightSon) currentVertex?.rightSon = null - } else { - if (brother.leftSon?.color == black || brother.leftSon == null) { - brother.rightSon?.color = black - brother.color = red - rotateLeft(brother) - brother = currentVertex?.parent?.leftSon + val parentColor = currentVertex?.parent?.color + parentColor?.let { brother?.color = parentColor } + currentVertex?.parent?.color = black + val vertexForRotate = currentVertex?.parent + + when (isBrotherRightSon) { + true -> { + brother?.rightSon?.color = black + vertexForRotate?.let { rotateLeft(vertexForRotate) } + if (currentVertex == vertex) currentVertex?.parent?.leftSon = null + } else -> { + brother?.leftSon?.color = black + vertexForRotate?.let { rotateRight(vertexForRotate) } + if (currentVertex == vertex) currentVertex?.parent?.rightSon = null } - - val parentColor = currentVertex?.parent?.color - parentColor?.let { brother?.color = parentColor } - currentVertex?.parent?.color = black - brother?.leftSon?.color = black - val vertexForRotate = currentVertex?.parent - vertexForRotate?.let { rotateRight(vertexForRotate) } - if (currentVertex == vertex) currentVertex?.parent?.rightSon = null - currentVertex = root } + currentVertex = root } } currentVertex?.color = black From 2ac169d4f06498e8e569052a6bb86daf8c9482d7 Mon Sep 17 00:00:00 2001 From: Kostya Date: Sun, 7 Apr 2024 21:55:08 +0300 Subject: [PATCH 4/4] docs: replace property isRed with a color --- lib/src/main/kotlin/vertexes/RBVertex.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/main/kotlin/vertexes/RBVertex.kt b/lib/src/main/kotlin/vertexes/RBVertex.kt index fe69a14..9576ddb 100644 --- a/lib/src/main/kotlin/vertexes/RBVertex.kt +++ b/lib/src/main/kotlin/vertexes/RBVertex.kt @@ -6,7 +6,7 @@ package main.vertexes * @param V Type of values. * @property key The key associated with this vertex. * @property value The value associated with this vertex. - * @property isRed A boolean indicating whether this vertex is red. + * @property color The color of this vertex (red or black). * @property parent The parent vertex of this vertex. * @property leftSon The left child vertex of this vertex. * @property rightSon The right child vertex of this vertex. @@ -30,7 +30,7 @@ class RBVertex( * @param value The value associated with this vertex. * @param leftSon The left child vertex of this vertex. * @param rightSon The right child vertex of this vertex. - * @param isRed A boolean indicating whether this vertex is red. + * @param color The color of this vertex (red or black). * @param parent The parent vertex of this vertex. */ constructor(