Intellij idea 这个尾部是递归的还是Kotlin编译器的问题?

Intellij idea 这个尾部是递归的还是Kotlin编译器的问题?,intellij-idea,kotlin,tail-recursion,Intellij Idea,Kotlin,Tail Recursion,我对以下函数是尾部递归还是Kotlin编译器或IntelliJ Idea有问题感到有点困惑 根据我的理解,这不符合tailrec优化的条件,因为递归调用不是最后一次调用。这是代码 tailrec fun hasRouteBetween(first: GraphNode, second: GraphNode): Boolean { if (first.id == second.id) return true if (second.children.isEm

我对以下函数是尾部递归还是Kotlin编译器或IntelliJ Idea有问题感到有点困惑

根据我的理解,这不符合
tailrec
优化的条件,因为递归调用不是最后一次调用。这是代码

    tailrec fun hasRouteBetween(first: GraphNode, second: GraphNode): Boolean {
        if (first.id == second.id) return true

        if (second.children.isEmpty()) return false

        second.visited = true

        for (child in second.children) {
            if (!child.visited) {
                return hasRouteBetween(first, child)
            }
        }
        return false
    }

data class GraphNode(val id: Int, var visited: Boolean = false, val children: LinkedList<GraphNode>)

tailrec fun hasRouteBetween(第一个:GraphNode,第二个:GraphNode):布尔值{
if(first.id==second.id)返回true
if(second.children.isEmpty())返回false
second.visted=true
for(第二个孩子中的孩子){
如果(!child.visted){
返回HasRouteBeween(第一个,孩子)
}
}
返回错误
}
数据类GraphNode(val id:Int,var访问:Boolean=false,val子项:LinkedList)
根据Kotlin文档、论坛帖子和我找到的一些答案,这种用法应该被标记为警告

我也在IntelliJ Kotlin编译器上启用了编译器警告。但我在IntelliJ(IntelliJ IDEA 2018.3.3(最终版-Build#IU-183.5153.38,于2019年1月9日构建)或Gradle(5.2)上没有看到任何警告。我使用Kotlin 1.3和Java 1.8_141

我在这里遗漏了什么?(我想确保我正确使用了
tailrec
,因为此代码将与其他人共享)。如有任何帮助,将不胜感激。

此函数是尾部递归。要使尾部递归起作用,您需要的是递归调用直接生成函数的结果,而不需要在调用的位置进行任何附加处理。这可以确保在递归之前清除当前函数调用的堆栈ive呼叫开始,因为那里的数据不再需要了

例如,这个实现不起作用,因为它需要在递归的每个级别保持堆栈的状态:

var result = false
for (child in second.children) {
    if (!child.visited) {
        if (hasRouteBetween(first, child)) {
            result = true
        }
    }
}
return result
你的函数不需要做这类事情。在你的
if
语句中,你进行递归调用,在那一点上,不管当前调用发生了什么,都会被抛出,因为递归调用的结果就是你所需要的


我不确定您的算法本身是否正确,因为第一个未访问的子级将是唯一进行递归调用的子级。

此函数是尾部递归的。尾部递归工作所需的是递归调用直接生成函数的结果,而不需要任何额外的处理这可以确保在递归调用开始之前清除当前函数调用的堆栈,因为不再需要那里的数据

例如,这个实现不起作用,因为它需要在递归的每个级别保持堆栈的状态:

var result = false
for (child in second.children) {
    if (!child.visited) {
        if (hasRouteBetween(first, child)) {
            result = true
        }
    }
}
return result
你的函数不需要做这类事情。在你的
if
语句中,你进行递归调用,在那一点上,不管当前调用发生了什么,都会被抛出,因为递归调用的结果就是你所需要的



我不确定您的算法本身是否正确,因为第一个未访问的子级将是唯一一个进行递归调用的子级。

谢谢@zsmb13,这似乎超出了我对尾部递归的理解。让我消化一下您所说的。对于tailrec来说,重要的是递归调用必须是最后一次调用一个函数的给定执行路径。如果你总是返回递归调用的结果,你就可以满足TraceRC条件,即使它恰好出现在函数的中间。谢谢进一步的信息并显示ALGO中的缺陷。我试图用简单的DFS来找到是否存在路径。谢谢@ ZSMB13,这超出了我的联合国。对尾随递归的理解。让我消化一下您所说的。TaleRC最重要的一点是递归调用必须是函数的给定执行路径上的最后一个调用。如果总是返回递归调用的结果,即使在函数的中间,也会满足TraceRC条件。n视觉上。感谢您提供更多信息并显示算法中的缺陷。我尝试使用简单的DFS来查找路径是否存在。