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