Java 如何将查找列表最大数量的递归实现可视化?
我有一个递归函数来查找列表中的最大数。我根据自己曾经遇到的一个技巧编写了这个函数。提示建议,当尝试在整数列表中查找最大整数时,应:Java 如何将查找列表最大数量的递归实现可视化?,java,scala,recursion,Java,Scala,Recursion,我有一个递归函数来查找列表中的最大数。我根据自己曾经遇到的一个技巧编写了这个函数。提示建议,当尝试在整数列表中查找最大整数时,应: 覆盖基本情况 想象一下,如果有另一个函数给出列表尾部的最大值 用你的函数替换虚函数 所以伪代码看起来像 def max(somelist: List[Int]): Int = { // base case 1: empty then error out if (somelist.isEmpty) { Error out } // base ca
def max(somelist: List[Int]): Int = {
// base case 1: empty then error out
if (somelist.isEmpty) {
Error out
}
// base case 2: if the list has one elements
if (somelist.tail.isEmpty) {
somelist.head
}
// Otherwise imagine I have a function that return the max of the tail of the list
// call it imaginary_max(tailOfList).
// get the max of the tail and then compare to the head of your list
// and return the appropriate result.
// replace imaginary_max with max and it works
else {
val m = max(somelist.tail);
if (somelist.head > m) {
somelist.head
}
else {
m
}
}
}
这是可行的,但我很难想象背景中发生了什么,尤其是当我试图向其他人解释时。感谢您的帮助和指导 如果考虑堆栈,递归的可视化通常是最容易的 假设我正在尝试使用您的算法查找
[1,2,5,0]
的最大值。您可以这样设想:
max( [0] ) => 0
max( [5, 0] ) => 5
max( [2, 5, 0] )
max( [1, 2, 5, 0] )
堆栈的底部是您开始的地方,您可以将输入传递到
max()
。第一次调用的结果是调用列表尾部的max
,即[2,5,0]
。同上,下一级除外,下一级为基本情况。因此,在堆栈的顶部,返回数字5。数字5“从堆栈中掉出来”作为答案。在试图理解递归的工作原理时,使用堆栈框架的概念是很有帮助的。简言之,堆栈框架只是一块内存,用于存储传递到函数中的参数值以及该函数中定义的局部变量。任何时候调用函数时,该函数的新堆栈帧都会位于当前函数的堆栈帧之上,以此类推,继续调用函数。当当前函数结束时,它的堆栈帧从当前“调用堆栈”中“弹出”,这意味着与调用函数相关联的变量现在处于“堆栈顶部”或可供使用
以下图片可能有助于展示:
在本例中,看起来调用堆栈实际上在向下增长,但概念是相同的。这是我正在实现的工具的一个很好的用例,所以我很快调整了您的源代码。 最终的可视化不需要一些痕迹,但我添加了它们以防万一:
package com.example
import org.stellabs.scart.tracing._
object KillerApp extends App{
def max(somelist: List[Int]): Int = s"max([${somelist mkString ", "}])".e_++:
{
// base case 1: empty then error out
if (somelist.isEmpty) {
???
}
// base case 2: if the list has one elements
if (somelist.tail.isEmpty) {
somelist.head
}
// Otherwise imagine I have a function that return the max of the tail of the list
// call it imaginary_max(tailOfList).
// get the max of the tail and then compare to the head of your list
// and return the appropriate result.
// replace imaginary_max with max and it works
else { ;|++: $$ s"recursion >> max(${somelist.tail})"
val m = max(somelist.tail) ;|++: $$ s"recursion << m = $m"
if (somelist.head > m) {
somelist.head
}
else {
m
}
}
}
// MAIN
max( {args map {_.toInt}}.toList ) e_++: 'main
}
干杯。我看不到的是数字之间什么时候进行比较。它是在值开始从堆栈中弹出时发生的吗?不,它发生在max()中function@awm,它在值开始从堆栈中弹出时发生。需要注意的重要一点是,是的,你是对的,所有的调用都发生在任何比较之前。。。当函数调用return时,返回值被分配给
m
,此时将进行比较。。。我希望我解释得很好…是的。我很久以前在cs学校就处理过这个问题。我觉得我对递归的理解是公平的,但不是100%。可视化递归的最好方法是交互式的。您可以使用调试器逐步完成代码并查看各种变量的值。这还允许您查看每个递归调用如何包含自己的参数和局部变量,这些参数和局部变量因调用而异,因此每个函数调用独立于其他函数调用。我没有使用scala,但我假设您可以使用Eclipse或IntelliJ逐步完成这段代码。这就是我的建议。@Jake我确信这会逐渐变得更好,但不久前IDEs中的交互式调试器(我使用Eclipse)还不成熟。这就是为什么我从跟踪值开始,这并不理想,但对于您提到的是一个实际的解决方法。+1用于添加缩进、函数调用、函数返回值和结果的比较操作。为了演示如何运行该示例,请使用git克隆完成。。。
mkdir -p ~/tmp
cd ~/tmp
git clone https://github.com/stellabs/scart.git
cd scart
git checkout v0.02.001
cd sbt
cd scart
sbt publishLocal
cd ..
cd template/inline
mv build.sbt build.sbt.ori
sed -e 's/all-last/as-is/' build.sbt.ori > build.sbt
# EDIT ./killerapp/src/KillerApp.scala,
# REPLACE CONTENTS WITH THE SOURCE SHOWN ABOVE
# SAVE
sbt run
# ...
> max([])<scala.NotImplementedError: an implementation is missing>
[error] (run-main) scala.NotImplementedError: an implementation is missing
# ...
sbt "run 1 2 5 0"
# ...
> > recursion >> max(List(2, 5, 0))
> > > recursion >> max(List(5, 0))
> > > > recursion >> max(List(0))
> > > > max([0])=0
> > > > recursion << m = 0
> > > max([5, 0])=5
> > > recursion << m = 5
> > max([2, 5, 0])=5
> > recursion << m = 5
> max([1, 2, 5, 0])=5
> main=5
# ...
// MAIN
'main.e_++:
{
max( {args map {_.toInt}}.toList )
}