我如何像这样打印递归跟踪?

wfauudbj  于 2021-06-30  发布在  Java
关注(0)|答案(4)|浏览(394)

所以我试着打印出斐波那契数列递归函数的轨迹。
我的输出应该是这样的:

但是,我不确定如何格式化这个。我真的不知道从哪里开始。我试过这个:

private static int fibCount;

public static long fibonacci(int n) {
    fibCount++;
    long result;
    if (n == 0 || n == 1) {
        result = n;
        System.out.printf("fib(%s)-->%s%n", n, result);
    } else {
        result = fibonacci(n - 1) + fibonacci(n - 2);
        System.out.printf("fib(%s)%n", n);
    }
    return result;
}

public static void main(String args[]) {
    fibonacci(5);
}

打印出来的

fib(1)-->1
fib(0)-->0
fib(2)
fib(1)-->1
fib(3)
fib(1)-->1
fib(0)-->0
fib(2)
fib(4)
fib(1)-->1
fib(0)-->0
fib(2)
fib(1)-->1
fib(3)
fib(5)

我觉得我需要使用fibcount变量(我这样做只是因为我认为缩进将依赖于它),但我不知道我是否应该,或者如何。

n6lpvg4x

n6lpvg4x1#

你应该保持一种缩进计数器,每次你输入斐波那契函数时它都会递增,每次你离开它时它都会递减。
然后,在打印时,在实际打印之前放入与此计数器当前值相同的空格。为了更好地观看,你可以放两倍的空间,但这只是个人的选择。

tjvv9vkg

tjvv9vkg2#

我假设在现实世界中,您只需要输入这样的跟踪(尤其是使用静态变量的跟踪)作为临时调试度量,并在将代码投入生产之前删除代码。如果你想把它留在生产代码中,我会寻找一个不同的解决方案。
首先,如果要为此使用静态变量,则需要确保每次递归调用之后都恢复其值。最好是在一个 finally 块,以确保即使有 return 隐藏在代码内部的某个地方(或在出现异常时):

public static long fibonacci(int n) {
    int saveFibCount = fibCount;
    fibCount++;
    try {
        fibCount++;
        long result;
        if (n == 0 || n == 1) {
            result = n;
            System.out.printf("fib(%s)-->%s%n", n, result);
        } else {
            result = fibonacci(n - 1) + fibonacci(n - 2);
            System.out.printf("fib(%s)%n", n);
        }
        return result;
    } finally {
        fibCount = saveFibCount;
    }
}

第二,在缩进中使用:不幸的是,java没有一个内置的方法来返回字符串 n 空间。您可以很容易地编写一个(或者使用apache commons中提供的方法,我认为),并以这种方式使用它们:

if (n == 0 || n == 1) {
            result = n;
            System.out.printf("%sfib(%s)-->%s%n", blanks(4*fibCount), n, result);
        } else {
            result = fibonacci(n - 1) + fibonacci(n - 2);
            System.out.printf("%sfib(%s)%n", blanks(4*fibCount), n);
        }

哪里 blanks(b) 返回字符串 b 空白。你可以用 StringBuilder 创建空白字符串,或类似的内容:

String blanks = String.format("%" + numOfBlanks + "s", "");

[**注:**根据对另一个答案的评论,如果 numOfBlanks 是0。]
或者你可以替换 fibCount 用一个 String fibIndent ,而不是 fibCount++ 使用

fibIndent += "    ";

保存以前版本后。
另一件需要考虑的事情:如果这是生产代码,我建议向递归例程传递另一个参数,而不是使用静态变量。即使在单线程程序中,尝试用递归例程处理静态变量也是混乱和容易出错的。递归参数应该是一个值参数,或者是一个不可变的对象,每次调用在将其传递给下一个调用之前都会复制它。在这种情况下,“递归深度”(您的 fibCount )可能是参数。我不建议将引用传递给所有递归调用都将共享的对象,因为这几乎和使用静态变量一样容易出错(尽管线程更安全)。
[注意:我职业生涯的大部分时间都在研究递归下降编译器,因此这些问题我非常熟悉。]
[最后:我知道这只是为了练习,但不要使用递归来计算斐波那契数。这样做可以得到指数算法,而不是像直接循环那样的线性算法。这是因为递归算法执行了大量的冗余工作,对同一个参数的结果进行多次计算。]

ngynwnxp

ngynwnxp3#

请尝试以下操作:
分割递归调用(以便可以打印中间的当前调用)
通过 depth 用于跟踪缩进量的参数
 

public static long fibonacci(int depth, int n) {
    String indent = new String(new char[depth]).replace('\0', ' ');
    long result;
    if (n == 0 || n == 1) {
        result = n;
        System.out.printf(indent + "fib(%s)-->%s%n", n, result);
    } else {
        long first = fibonacci(depth+1, n - 1);
        System.out.printf(indent + "fib(%s)%n", n);
        long second = fibonacci(depth+1, n - 2);
        result = first + second;
    }
    return result;
}

public static void main(String args[]) {
    fibonacci(0, 5);
}

输出:

fib(1)-->1
   fib(2)
    fib(0)-->0
  fib(3)
   fib(1)-->1
 fib(4)
   fib(1)-->1
  fib(2)
   fib(0)-->0
fib(5)
   fib(1)-->1
  fib(2)
   fib(0)-->0
 fib(3)
  fib(1)-->1
yftpprvb

yftpprvb4#

每次调用都需要传入缩进级别。每次你都可以增加压痕。

public static long fibonacci(int n) {
    return fibonacci(n, 1);
}

public static long fibonacci(int n, int indent) {
    System.out.printf("%"+indent+"s", "");
    long result;
    if (n == 0 || n == 1) {
        result = n;
        System.out.printf("fib(%s)-->%s%n", n, result);
    } else {
        result = fibonacci(n - 1, indent + 2) + fibonacci(n - 2, indent + 2);
        System.out.printf("fib(%s)%n", n);
    }
    return result;
}

相关问题