如何在递归期间将所有先前帧(较高帧)的值传递到较低帧

Posted

技术标签:

【中文标题】如何在递归期间将所有先前帧(较高帧)的值传递到较低帧【英文标题】:How to pass a value from all previous frames (higher frames) to a lower frame during recursion 【发布时间】:2016-11-12 18:28:23 【问题描述】:

为了简化我的问题,让我们考虑打印数组的所有排列,而不重复。因此,如果 1,2,3 是数组,则输出如下

1 2 3 
1 3 2 
2 1 3 
2 3 1 
3 1 2 
3 2 1 
count == 6

如何将已经是数组一部分的所有元素的计数传递给较低的帧。我的意思是说,在递归的前两帧中,我的堆栈中有元素 1 和 2。我需要告诉下面的框架,它可以使用除 1 和 2 之外的所有元素,因为它已经被使用了。

请参阅下面的代码,其中我将所有遇到的元素的数组作为函数调用的一部分传递给下面的框架。但是我还必须为同一帧中的其他递归调用保存和恢复数组的元素,因为 Java 不会在每一帧中保存数组的副本,并且传递引用会导致数组被覆盖。

import java.util.Arrays;

public class SendfromHigherFrameToLowerFrame 
    static int count = 0;

    public static void main(String[] args) 
        int[] a = 1,2,3;

        int[] stack = new int[3];
        fun(a, stack, 0);

        System.out.println("count == "+count);
    

    static void fun(int[] a, int[] stack, int frame)
    
        if(a.length == frame)
        
            count++;
            print(stack);
            return;
        

        for(int i = 0;i<a.length;i++)
        
            //save stack
            int[] temp = new int[stack.length];
            save(stack, temp);
            if(isValid(stack, a[i]) == true)
            
                stack[frame] = a[i];
                fun(a, stack, frame+1);
                //restore stack
                restore(temp, stack);
            
        
    

    static void save(int[] source, int[] destination)
    
        for(int i = 0;i<source.length;i++)
            destination[i] = source[i];
    

    static void restore(int[] source, int[] destination)
    
        for(int i = 0;i<source.length;i++)
            destination[i] = source[i];
    

    static boolean isValid(int[] a, int key)
    
        for(int i = 0;i<a.length;i++)
        
            if(a[i] == key)
                return false;
        
        return true;
    

    static void print(int[] a)
    
        for(int x : a)
            System.out.print(x + " ");
        System.out.println();
    

请提出改进​​代码的建议,或者更简单的方法将元素传递到调用中。

PS:请注意,生成排列不是我最初的问题,我知道有更简单的方法可以做到这一点,这只是为了传达我的问题。

【问题讨论】:

为什么不将您的方法转换为非静态然后使用实例字段?.. 【参考方案1】:

由于在 Java 中无法继续通过引用传递原语,因此您不能简单地创建一个 int,然后将其向下传递到调用堆栈。这个问题有三种解决方法:

使用可变类,例如单个intAtomicInteger 的数组。但是,这种方法会误用数组和可变类。 按照您的方式创建实例变量或静态变量。这远非理想,因为您的递归函数变得不可重入,因此更难测试。 从方法返回修改后的值,并将其添加/分配给递归方法内的局部变量,以作为其自己的返回值向下传递。这种方法很好,但它只容纳一个返回值,并且需要您在编写代码时非常小心。

您可以通过以下方式修改函数以实现上述最后一种方法:

static int fun(int[] a, int[] stack, int frame) 
    if(a.length == frame) 
        print(stack);
        return 1;
    
    int res = 0;
    for(int i = 0;i<a.length;i++) 
        //save stack
        int[] temp = new int[stack.length];
        save(stack, temp);
        if(isValid(stack, a[i]) == true) 
            stack[frame] = a[i];
            res += fun(a, stack, frame+1);
            //restore stack
            restore(temp, stack);
        
    
    return res;

Demo.

注意:不用说你的练习不需要做任何这些,因为count总是等于stack.length

【讨论】:

对于您提到的第三个项目符号,您能否使用伪代码编辑您的答案。我还没有完全明白。 谢谢。但是这里的小语言检查。考虑一个调用堆栈,例如 fun(5);fun(4);fun(3);fun(2);fun(1);fun(0);。在这里,当我的意思是“较高的帧”时,我的意思是 5 和 fun(4) 是较低的帧。我在问如何将值从 fun(5) 传递到 fun(4)、fun(3)、fun(2) 一直到 fun(0)。也就是说,如果一个元素在 fun(5) 中被取走,我还需要 fun(0) 来知道它被取走并且不能被使用。我觉得您的第三个要点更多的是关于从较低的框架“返回”到较高的框架,这与我对“较低”和“较高”的使用保持一致。 ? @saltandwater 这可以通过传递对可变集合的引用来解决 - 例如,Set&lt;Integer&gt;。***方法将创建它,并将其传递给较低级别​​。当较低级别在返回之前修改此集合时,较高级别会看到修改。但是,具有可变状态会使您更难理解递归函数。

以上是关于如何在递归期间将所有先前帧(较高帧)的值传递到较低帧的主要内容,如果未能解决你的问题,请参考以下文章

我们如何在没有条件的情况下递增然后递减计数器?

学习笔记:帧率转换之三维递归搜索块匹配算法

学习笔记:帧率转换之三维递归搜索块匹配算法

如何为kafka主题分配优先级

libav 生成具有极高帧速率的 MP4 文件

为啥堆栈会增长到较低的地址? [复制]