如何让kotlin实现这个BST比较功能是尾递归?

时间:2017-10-22 17:42:22

标签: kotlin

这是一个简单的二进制搜索树类,我放在一起。

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眼中使这些调用变为尾递归?

1 个答案:

答案 0 :(得分:1)

Tail recursive functions中所述:

  

要获得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