C语言 递归获取特定范围内的所有矩阵

mum43rcc  于 2023-05-16  发布在  其他
关注(0)|答案(1)|浏览(63)

我试图计算并保存到C中的每个N x N矩阵组合,其中每个元素都在特定范围内,例如:

N = 3
Range: 0,1

1st iteration
0 0 0
0 0 0
0 0 0

2nd iteration
0 0 0
0 0 0
0 0 1

3rd iteration
0 0 0
0 0 0
0 1 0

4th iteration
0 0 0
0 0 0
0 1 1

5th iteration
0 0 0
0 0 0
1 0 0

etc.

我已经发现最合理的解决方案是递归地进行,以避免为更大的Ns嵌套很多for循环,所以下面是我的函数:

void get_all_matricies(int** matrix, int size, int min, int max, FILE* file, int i, int j) {
    if(i == size) return;

    for(int k = min; k <= max; k++) {
        matrix[i][j] = k;
        if(j < size-1) {
            get_all_matricies(matrix, size, min, max, file, i, j+1);
        } else {
            get_all_matricies(matrix, size, min, max, file, i+1, 0);
            save_matrix(matrix, size, file);
        }
    }
}

它看起来工作得很好,但有一个问题,有时(当底部行被“填充”时)我会得到相同的矩阵两次,例如:

N = 3
Range: 0,1

nth iteration
0 0 0 
0 0 0 
1 1 0 

nth+1 iteration
0 0 0 
0 0 0 
1 1 1 

nth+2 iteration
0 0 0 
0 0 0 
1 1 1 

nth+3 iteration
0 0 0 
0 0 1 
0 0 0

为什么会发生这种情况,有什么问题吗?

flvlnr44

flvlnr441#

这是一个非常简单的迭代集合的例子:枚举,即计数。计数**不需要递归。
所以,如果你的问题恰好是关于以逻辑上简单的方式迭代所有可能的矩阵,让我通过枚举(计数)来解释简单的迭代。如果你的问题是关于通过递归实现迭代的,这不是对你问题的回答。
对于N×N矩阵,您可以使用范围中的任何B值填充矩阵中的N*N位置。这相当于一个以B为基数的N*N数字,每个数字都是该范围中的一个值(或者1:1Map到该范围中的一个值,如果您的范围碰巧不是0, 1, 2, ..., B-1的形式)。要枚举所有以N*N为基数的B数字,只需从0计数到B^(N*N)-1
在您的示例中,每个数字都是01,因此您只需从0计数到2^(N*N)-1,然后以2为基数显示计数器,同时以N×N矩阵的形式排列N*N基数2数字。这将需要N*N位移位和&1掩码每个计数器值,没有除法指令。
如果您的范围是0, 1, 2-1, 0, +1,则该范围中有3值,您需要从0计数到3^[N*N)-1,然后以3为基数显示计数器,同时将第二个示例中的3基数数字0, 1, 2Map到-1, 0, +1。这将需要每个计数器值N*N除以3(准确地说是divmod运算,因为您需要商和余数)。
等等。
如果您担心性能:在循环中从0计数到一个正整数是一个非常便宜的操作,你可以在内部循环中通过乘法或移位来替换将计数器值转换为以B为基数的数字序列所需的除法,而且你的编译器可能已经这样做了。虽然位移位确实很便宜,但避免除法可能是回到递归的一个原因。假设您计划对矩阵执行的操作所需的CPU周期数量级为N*N基数B的枚举循环和转换循环所需的CPU周期数量级或更多,也是合理的。
关于内存性能,如果你不介意矩阵发出的顺序,枚举函数甚至不需要存储一个完整的矩阵,它可以一个接一个地吐出矩阵系数。如果你想要枚举矩阵的特殊顺序,反转数字可能会有帮助,这需要存储单个N×N矩阵的系数。
注意:如果你的范围集的基数B不是2的幂,你将需要在每次迭代中除以N*Ndivmod运算,以显示基数B的计数器。在递归方法中,每一级递归都将迭代一个数字,这些数字需要与调用堆栈分开存储,因为在C中无法迭代调用堆栈。因此,由于这些数字已经单独存储(可能在一个简单的数组中),因此打印这些数字将不需要除法。

**如果你有一个for循环或一个可用于计数的迭代器,那么这里不需要递归。你只需要在一个通过递归实现计数和迭代的语言中使用递归,例如。Erlang或XSLT(存在其他此类语言)。

相关问题