195 lines
4.8 KiB
Plaintext
195 lines
4.8 KiB
Plaintext
class BinaryTree<T> : IMutableSet<T> {
|
|
private class TreeNode(
|
|
var value : T, var parent : TreeNode
|
|
) {
|
|
var left : TreeNode
|
|
var right : TreeNode
|
|
|
|
}
|
|
|
|
private val compare : MatchableComparison<T>
|
|
private var root : TreeNode
|
|
private var version = 0
|
|
|
|
// override var size : Int { get; private set; }
|
|
|
|
this(compare : Comparison<T>) {
|
|
this.compare = asMatchableComparison(comparison)
|
|
}
|
|
|
|
this() : this(naturalOrder<T>()) {
|
|
}
|
|
|
|
private [operator] fun T.compareTo(other : T) : Int = compare(this, other)
|
|
|
|
override fun contains(item : T) : Boolean {
|
|
return contains(root, item)
|
|
|
|
fun contains(node : TreeNode, item : T) : Boolean {
|
|
if (node == null) return false
|
|
when (compare(item, node.value)) {
|
|
EQ => true
|
|
LS => contains(node.left, item)
|
|
GT => contains(node.right, item)
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun add(item : T) : Boolean {
|
|
if (add(ref root, null)) {
|
|
size++
|
|
version++
|
|
return true
|
|
}
|
|
return false
|
|
|
|
// In principle, this has access to item anyway, but then it's unreachable code
|
|
// BAD: the naive implementation of ref will create H(T) ref objects, but can be optimized to create only one
|
|
fun add(ref node : TreeNode, parent : TreeNode) : Boolean {
|
|
if (node == null) {
|
|
node = TreeNode(item, parent)
|
|
return true
|
|
}
|
|
when (compare(item, node.value)) {
|
|
EQ => false
|
|
LS => add(ref node.left, node)
|
|
GT => add(ref node.right, node)
|
|
}
|
|
}
|
|
|
|
// In principle, this has access to item anyway
|
|
fun addNoRef(node : TreeNode) : Boolean {
|
|
if (node == null) {
|
|
root = TreeNode(item, null)
|
|
return true
|
|
}
|
|
when (compare(item, node.value)) {
|
|
EQ => return false
|
|
LS =>
|
|
if (node.left == null) {
|
|
node.left = TreeNode(item, node)
|
|
return true
|
|
} else return add(node.left)
|
|
GT =>
|
|
if (node.right == null) {
|
|
node.right = TreeNode(item, node)
|
|
return true
|
|
} else return add(node.right)
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun remove(item : T) : Boolean {
|
|
val toRemove = find(root, item)
|
|
if (toRemove == null) return false
|
|
remove(toRemove)
|
|
size--
|
|
version++
|
|
return true
|
|
|
|
fun find(node : TreeNode) : TreeNode {
|
|
if (node == null) return null
|
|
when (compare(item, node.value)) {
|
|
EQ => node
|
|
LS => find(node.left)
|
|
GT => find(node.right)
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun remove(node : TreeNode) {
|
|
when (node) {
|
|
is TreeNode(null, null) => replace(node, null)
|
|
is TreeNode(null, ?right) => replace(node, right)
|
|
is TreeNode(?left, null) => replace(node, left)
|
|
is TreeNode(?left, ?right) => {
|
|
val min = min(node.right)
|
|
node.value = min.value
|
|
remove(min)
|
|
}
|
|
}
|
|
|
|
fun replace(node : TreeNode, replace : TreeNode) {
|
|
if (node == root) {
|
|
root = replace
|
|
return
|
|
}
|
|
if (node.parent.left == node) {
|
|
node.parent.left = replace
|
|
} else if (node.parent.right == node) {
|
|
node.parent.right = replace
|
|
} else Assert(false)
|
|
}
|
|
}
|
|
|
|
// Relies on tail-recursion optimization
|
|
private fun min(node : TreeNode) {
|
|
if (node.left == null) node else min(node.left)
|
|
}
|
|
|
|
override fun iterator() : IIterator<T> = mutableIterator()
|
|
|
|
override fun mutableIterator() : IMutableIterator<T> = object IMutableIterator {
|
|
val version = BinaryTree.this.version
|
|
val down = Stack<TreeNode>()
|
|
val up = Stack<TreeNode>()
|
|
var lastNode : TreeNode
|
|
|
|
this() {
|
|
if (root != null)
|
|
down.push(root)
|
|
}
|
|
|
|
override fun next() : T {
|
|
if (!hasNext)
|
|
throw NoMoreElementsException()
|
|
checkVersion()
|
|
|
|
lastNode = nextNode()
|
|
return lastNode.value
|
|
}
|
|
|
|
private fun nextNode() : TreeNode {
|
|
while (true) {
|
|
if (!down.isEmpty) {
|
|
val curNode = down.pop()
|
|
if (curNode.left != null) {
|
|
up.push(curNode)
|
|
down.push(curNode.left)
|
|
} else {
|
|
if (curNode.right != null) {
|
|
down.push(curNode.right)
|
|
}
|
|
return curNode;
|
|
}
|
|
} else {
|
|
val curNode = up.pop()
|
|
if (curNode.right != null) {
|
|
down.push(curNode.right)
|
|
}
|
|
return curNode
|
|
}
|
|
}
|
|
}
|
|
|
|
override val hasNext : Boolean
|
|
get() = !down.isEmpty || !up.isEmpty
|
|
|
|
|
|
override fun remove() {
|
|
checkVersion()
|
|
if (lastNode == null)
|
|
throw IterationException("Nothing to remove")
|
|
remove(lastNode)
|
|
version++
|
|
BinaryTree.this.version = version
|
|
}
|
|
|
|
private fun checkVersion() {
|
|
if (version != BinaryTree.this.version) {
|
|
throw ConcurrentModificationException()
|
|
}
|
|
}
|
|
}
|
|
|
|
} |