Skip to content

Commit

Permalink
Merge pull request #5 from spbu-coding-2023/test
Browse files Browse the repository at this point in the history
Merge branches test and main
  • Loading branch information
RodionovMaxim05 authored Apr 3, 2024
2 parents 5e78d5c + 316a638 commit bc671e0
Show file tree
Hide file tree
Showing 18 changed files with 675 additions and 283 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 Ilia Suponev, Rodionov Maxim, Vladimir Zaikin
Copyright (c) 2024 Ilia Suponev, Maxim Rodionov, Vladimir Zaikin

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
80 changes: 42 additions & 38 deletions ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,19 @@ fun main() {
tree.insert(key = 1, value = 1)
tree.insert(key = 2, value = 2)
tree.insert(key = 3, value = 3)
tree.insert(key = 4, value = 4)
tree.insert(key = 5, value = 5)


/* The words `key` and `value` are optional */
tree.insert(4, 4)

/* Alternative insert method */
tree[5] = 5

println(tree)
}
```
Output:
```text
BSTree(1: 1, 2: 2, 3: 3, 4: 4, 5: 5, )
BSTree(1: 1, 2: 2, 3: 3, 4: 4, 5: 5)
```

##### Example 3 (searching)
Expand All @@ -76,7 +80,7 @@ Code:
import tree_tripper.binary_trees.BSTree

fun main() {
val tree = BSTree<Int, Int>()
val tree = BSTree<Int, Any>()
/*
...
inserting from `example 2`
Expand All @@ -90,7 +94,7 @@ fun main() {

/* Unexciting element in tree */
println(tree.search(key = -2))
println(tree.search(key = 7))
println(tree.searchOrDefault(7, "Element not found"))

/* Alternative search method */
println(tree[2])
Expand All @@ -103,7 +107,7 @@ Output:
3
5
null
null
Element not found
2
null
```
Expand Down Expand Up @@ -140,7 +144,7 @@ Output:
5
null
Element not found
BSTree(2: 2, 4: 4, )
BSTree(2: 2, 4: 4)
```

##### Example 5 (tree-like printing)
Expand Down Expand Up @@ -168,27 +172,27 @@ fun main() {
Output:
```text
BSTree(
(5, 5)
(4, 4)
(3, 3)
(2, 2)
(1, 1)
(5: 5)
(4: 4)
(3: 3)
(2: 2)
(1: 1)
)
AVLTree(
(5, 5)
(4, 4)
(3, 3)
(2, 2)
(1, 1)
(5: 5)
(4: 4)
(3: 3)
(2: 2)
(1: 1)
)
RBTree(
(5, 5) - BLACK
(4, 4) - BLACK
(3, 3) - BLACK
(2, 2) - RED
(1, 1) - BLACK
(5: 5) - BLACK
(4: 4) - BLACK
(3: 3) - BLACK
(2: 2) - RED
(1: 1) - BLACK
)
```

Expand Down Expand Up @@ -224,25 +228,25 @@ fun main() {
Output:
```text
WIDTH ORDER:
(2, 2)
(1, 1)
(4, 4)
(3, 3)
(5, 5)
(2: 2)
(1: 1)
(4: 4)
(3: 3)
(5: 5)
INCREASING ORDER:
(1, 1)
(2, 2)
(3, 3)
(4, 4)
(5, 5)
(1: 1)
(2: 2)
(3: 3)
(4: 4)
(5: 5)
DECREASING ORDER:
(5, 5)
(4, 4)
(3, 3)
(2, 2)
(1, 1)
(5: 5)
(4: 4)
(3: 3)
(2: 2)
(1: 1)
```

## Documentation
Expand Down
40 changes: 25 additions & 15 deletions lib/src/main/kotlin/tree_tripper/binary_trees/AbstractBSTree.kt
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public abstract class AbstractBSTree<K: Comparable<K>, V, N: AbstractBSTreeNode<
}

override fun getMax(): Pair<K, V>? {
return notNullNodeAction(root, null) {node -> getMaxInSubtree(node.key)}
return notNullNodeAction(root, null) { node -> getMaxInSubtree(node.key) }
}

override fun getMinInSubtree(key: K): Pair<K, V>? {
Expand All @@ -73,7 +73,7 @@ public abstract class AbstractBSTree<K: Comparable<K>, V, N: AbstractBSTreeNode<
}

override fun getMin(): Pair<K, V>? {
return notNullNodeAction(root, null) {node -> getMinInSubtree(node.key)}
return notNullNodeAction(root, null) { node -> getMinInSubtree(node.key) }
}

override fun getSize(): Int {
Expand Down Expand Up @@ -101,12 +101,14 @@ public abstract class AbstractBSTree<K: Comparable<K>, V, N: AbstractBSTreeNode<
override fun toString(order: IterationOrders): String {
val builder = StringBuilder()
this.forEach(order) { pair: Pair<K, V> -> builder.append("${pair.first}: ${pair.second}, ") }
if (builder.isNotEmpty())
repeat(2) { builder.deleteCharAt(builder.length - 1) } // remove ", " in the last pair
return "${this.javaClass.simpleName}($builder)"
}

override fun toStringWithTreeView(): String {
val builder = StringBuilder()
notNullNodeAction(root, Unit) {node -> node.toStringWithSubtreeView(0, builder)}
notNullNodeAction(root, Unit) { node -> node.toStringWithSubtreeView(0, builder) }
return "${this.javaClass.simpleName}(\n$builder)"
}

Expand Down Expand Up @@ -172,7 +174,7 @@ public abstract class AbstractBSTree<K: Comparable<K>, V, N: AbstractBSTreeNode<
* @return a pair of a balanced [N] node or null, and [V] value corresponding the given [key]
* if a node was removed, null if not.
*/
protected open fun removeNode(node: N?, key: K): Pair<N?, V?> {
protected fun removeNode(node: N?, key: K): Pair<N?, V?> {
if (node == null) return Pair(null, null)

val resultRemove: Pair<N?, V?>
Expand All @@ -184,22 +186,30 @@ public abstract class AbstractBSTree<K: Comparable<K>, V, N: AbstractBSTreeNode<
resultRemove = removeNode(node.rightChild, key)
node.rightChild = resultRemove.first
} else {
val nodeSubstitutive: N?
if (node.leftChild == null || node.rightChild == null) {
nodeSubstitutive = node.leftChild ?: node.rightChild
return Pair(nodeSubstitutive, node.value)
} else {
nodeSubstitutive = getMaxNodeInSubtree(node.leftChild) as N
node.leftChild = removeNode(node.leftChild, nodeSubstitutive.key).first
nodeSubstitutive.rightChild = node.rightChild
nodeSubstitutive.leftChild = node.leftChild
return Pair(balanceTree(nodeSubstitutive), node.value)
}
return substituteNode(node)
}

return Pair(balanceTree(node), resultRemove.second)
}

/**
* Substitutes the node on the node with the max key.
* @return a pair of a balanced [N] node or null, and [V] value removed node
* if a node was removed, null if not.
*/
protected open fun substituteNode(node: N): Pair<N?, V?> {
val nodeSubstitutive: N?
if (node.leftChild == null || node.rightChild == null) {
nodeSubstitutive = node.leftChild ?: node.rightChild
return Pair(nodeSubstitutive, node.value)
}
nodeSubstitutive = getMaxNodeInSubtree(node.leftChild) as N
node.leftChild = removeNode(node.leftChild, nodeSubstitutive.key).first
nodeSubstitutive.rightChild = node.rightChild
nodeSubstitutive.leftChild = node.leftChild
return Pair(balanceTree(nodeSubstitutive), node.value)
}

/**
* Searches the node with a given key.
* @return the found node or null if the node is not contained in a tree.
Expand Down
118 changes: 51 additions & 67 deletions lib/src/main/kotlin/tree_tripper/binary_trees/RBTree.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package tree_tripper.binary_trees

import tree_tripper.nodes.binary_nodes.RBTreeNode
import tree_tripper.nodes.notNullNodeAction
import tree_tripper.nodes.notNullNodeUpdate


Expand Down Expand Up @@ -36,79 +35,64 @@ public open class RBTree<K: Comparable<K>, V>: AbstractBSTree<K, V, RBTreeNode<K
return nodeCurrent
}

override fun removeNode(node: RBTreeNode<K, V>?, key: K): Pair<RBTreeNode<K, V>?, V?> {
if (node == null) return Pair(null, null)

val removeResult: Pair<RBTreeNode<K, V>?, V?>
val resultCompare: Int = key.compareTo(node.key)
val nodeCurrent: RBTreeNode<K, V> = node
if (resultCompare < 0) {
removeResult = removeNode(nodeCurrent.leftChild, key)
nodeCurrent.leftChild = removeResult.first
} else if (resultCompare > 0) {
removeResult = removeNode(nodeCurrent.rightChild, key)
nodeCurrent.rightChild = removeResult.first
} else {
val leftChild = nodeCurrent.leftChild
val rightChild = nodeCurrent.rightChild
if (leftChild == null && rightChild == null) {
if (isRedColor(nodeCurrent)) return Pair(null, nodeCurrent.value)
if (isRedColor(nodeCurrent.parent)) {
flipColors(nodeCurrent.parent)
} else {
val uncle = nodeCurrent.getUncle()
if (isRedColor(uncle)) {
flipColors(uncle)
nodeCurrent.parent?.flipColor()
}
uncle?.flipColor()
override fun substituteNode(node: RBTreeNode<K, V>): Pair<RBTreeNode<K, V>?, V?> {
val leftChild = node.leftChild
val rightChild = node.rightChild
if (leftChild == null && rightChild == null) {
if (isRedColor(node)) return Pair(null, node.value)
if (isRedColor(node.parent)) {
flipColors(node.parent)
} else {
val uncle = node.getUncle()
if (isRedColor(uncle)) {
flipColors(uncle)
node.parent?.flipColor()
}
return Pair(null, nodeCurrent.value)
} else if (leftChild == null) {
throw IllegalArgumentException(
"Invalid RedBlackTree state, node with one child as right is not valid rb-tree"
)
} else if (rightChild == null) {
uncle?.flipColor()
}
return Pair(null, node.value)
} else if (leftChild == null) {
throw IllegalArgumentException(
"Invalid RedBlackTree state, node with one child as right is not valid rb-tree"
)
} else if (rightChild == null) {
if (isRedColor(leftChild)) {
flipColors(node)
return Pair(leftChild, node.value)
}
throw IllegalArgumentException(
"Invalid RedBlackTree state, node with one child as left with black color is not valid rb-tree"
)
} else {
val nodeNew: RBTreeNode<K, V>
val nodeCached: RBTreeNode<K, V>
if (isRedColor(node)) {
nodeCached = getMinNodeInSubtree(rightChild) as RBTreeNode<K, V>
nodeNew = RBTreeNode(nodeCached.key, nodeCached.value, nodeCached.isRed)
nodeNew.leftChild = leftChild
nodeNew.rightChild = removeNode(rightChild, nodeCached.key).first
if (!isRedColor(nodeCached)) leftChild.flipColor()
} else {
if (isRedColor(leftChild)) {
flipColors(nodeCurrent)
return Pair(leftChild, nodeCurrent.value)
nodeCached = getMaxNodeInSubtree(leftChild) as RBTreeNode<K, V>
nodeNew = RBTreeNode(nodeCached.key, nodeCached.value, node.isRed)
nodeNew.rightChild = rightChild
nodeNew.leftChild = removeNode(leftChild, nodeCached.key).first
return Pair(balanceTree(nodeNew), node.value)
}
throw IllegalArgumentException(
"Invalid RedBlackTree state, node with one child as left with black color is not valid rb-tree"
)
} else {
val newNode: RBTreeNode<K, V>
val nodeCached: RBTreeNode<K, V>
if (isRedColor(nodeCurrent)) {
nodeCached = getMinNodeInSubtree(rightChild) as RBTreeNode<K, V>
newNode = RBTreeNode(nodeCached.key, nodeCached.value, nodeCached.isRed)
newNode.leftChild = leftChild
newNode.rightChild = removeNode(rightChild, nodeCached.key).first
if (!isRedColor(nodeCached)) leftChild.flipColor()
} else {
if (isRedColor(leftChild)) {
nodeCached = getMaxNodeInSubtree(leftChild) as RBTreeNode<K, V>
newNode = RBTreeNode(nodeCached.key, nodeCached.value, nodeCurrent.isRed)
newNode.rightChild = rightChild
newNode.leftChild = removeNode(leftChild, nodeCached.key).first
return Pair(balanceTree(newNode), nodeCurrent.value)
}
nodeCached = getMinNodeInSubtree(rightChild) as RBTreeNode<K, V>
newNode = RBTreeNode(nodeCached.key, nodeCached.value, nodeCurrent.isRed)
newNode.leftChild = leftChild
newNode.rightChild = removeNode(rightChild, nodeCached.key).first
if (!isRedColor(nodeCached)) {
leftChild.isRed = true
newNode.isRed = true
}
nodeCached = getMinNodeInSubtree(rightChild) as RBTreeNode<K, V>
nodeNew = RBTreeNode(nodeCached.key, nodeCached.value, node.isRed)
nodeNew.leftChild = leftChild
nodeNew.rightChild = removeNode(rightChild, nodeCached.key).first
if (!isRedColor(nodeCached)) {
leftChild.isRed = true
nodeNew.isRed = true
}
return Pair(balanceTree(newNode), nodeCurrent.value)
}
return Pair(balanceTree(nodeNew), node.value)
}

return Pair(balanceTree(nodeCurrent), removeResult.second)
}

/**
* Returns whether the specified node is red or not.
*
Expand Down
Loading

0 comments on commit bc671e0

Please sign in to comment.