这是一个简单的二进制搜索树类,我放在一起。
data class Bst<T: Comparable<T>>(var left: Bst<T>?, var value: T, var right: Bst<T>?) {
tailrec fun contains(key: T): Boolean {
return if (key < value) {
left?.contains(key) ?: false
} else if (key > value) {
right?.contains(key) ?: false
} else {
true
}
}
}
不幸的是,当我将其粘贴到try.kotlinlang.org时,它表示递归调用不是尾递归的。如果我将left?.contains
代码重构为测试left == null
的if语句,则会出现另一个错误,指出left
如何可变并且自if
语句以来可能已更改。如何在kotlin眼中使这些调用变为尾递归?
答案 0 :(得分:1)
要获得
tailrec
修饰符的资格,函数必须将自身称为它执行的最后一个操作。当递归调用后有更多代码时,你不能使用尾递归,你不能在try / catch / finally块中使用它。
您的实现已失败,第一个约束是再次调用函数本身。即使你调用这个函数,它也在另一个实例上,也不是这个块的最后一个操作。
我能想到的最好的方法是在 Kotlin 上下文中实现“静态”。
data class Bst<T: Comparable<T>>(var left: Bst<T>?, var value: T, var right: Bst<T>?) {
fun contains(key: T) = contains(key, this)
companion object {
tailrec fun <T: Comparable<T>> contains(key: T, bst: Bst<T>): Boolean {
if (key == bst.value) return true
val bst2 = bst.run { if (key < value) left else right }
if (bst2 == null) return false
return contains(key, bst2)
}
}
}
但另外你应该考虑实现一个空值模式,而不是使用左和右的可空值。您可以使用Sealed Classes。