我想写一个函数,它接受函数将执行的嵌套循环数作为输入。例如,如果输入参数为3,则函数将执行3个嵌套循环,如下所示:
for i=0:[any]
for j=0:[any]
for k=0:[any]
如果输入参数为2,则如下所示:
for i=0:[any]
for j=0:[any]
如何实现此算法?
如上所述,这个问题通常可以通过递归来解决。
不知怎么的:
function res = nestedloop_function(numLoops,remainingParams)
res = rec_function(numLoops,[],remainingParams);
end
function res = rec_function(numLoops, loopVars, remainingParams)
if numLoops == 0
res = whatever(loopVars, remainingParams);
return res;
end
for k = 1:[any]
loopVars = [loopVars,k];
res = rec_function(numLoops-1, loopVars, remainingParams);
end
end
如果你不想有传递remainingParams
和loopVars
的开销,你可以考虑将它们声明为global
,但通常最好避免这种情况。。。
您可以将所有循环"打包"到一个循环中。以下代码假设
- 所有循环的上限是相同的
- 你只想做最内层的事情
Matlab代码:
N = 3; %// number of loops
M = 10; %// range for each variable is from 0 to M-1
for generalCounter = 0:M^N-1
counters = dec2base(generalCounter,M,N)-'0';
%// Now you are at the innermost "loop". counters(1) is your "i",
%// counters(2) is your "j" etc
end
关键是使用一个通用计数器,并由此计算计数器i
、j
等。这是用dec2base(...)-'0'
在Matlab中完成的。-'0'
部分是必要的,因为dec2base
返回一个char数组,所以-'0'
将每个char转换为它所代表的数字。在其他语言中,可能会有不同的做法,但你会明白的。
这可能对您有用。
不过也有一些假设。1.你只能在最里面的循环中执行一些东西。2.所有嵌套循环具有相同的上限
void loop(int n)
{
if(n < 1)
{
return;
}
int i;
loop(--n);
for( i=0; i<2; i++)
{
printf("%d", i); //consider this portion to be executing inside the inner most loop
}
}
int main()
{
int x;
int n = 5; //number of for loops you wanted nested
loop(n);
}
您可以使用一个平面循环,并在一个被视为里程表的数组中跟踪循环变量:通过增加最内部的变量来推进循环,根据需要重置并转移到下一个外部变量。当进位超过嵌套的pasudo循环数时,停止循环。
这里有一个C语言的解决方案,它有一个无限平坦的循环,使用辅助函数来推进循环变量并测试里程表溢出:
#include <stdlib.h>
#include <stdio.h>
void odo_init(int ix[], int n)
{
while (n--) ix[n] = 0;
}
int odo(int ix[], int m, int n)
{
int i = 0;
do {
ix[i]++;
if(ix[i] < m) return 1;
ix[i++] = 0;
} while (i < n);
return 0;
}
int main()
{
int m = 2;
int n = 4;
int ix[n];
odo_init(ix, n);
do {
int i;
/* Do something, e.g. print loop vars */
for (i = 0; i < n; i++) {
if (i) printf(", ");
printf("%d", ix[i]);
}
printf("n");
/* Advance and test loop variables */
} while(odo(ix, m, n));
return 0;
}
(函数odo_init
是不必要的,因为可变长度数组不能用ix[n] = {0}
初始化。)
如果你不介意C预处理器宏的晦涩,你可以使用这个框架来编写一个multi_for
:
#define multi_for(ix, m, n)
for (int ix[n], ix##_cnt_ = 0;
!(ix##_cnt_ || odo_init(ix, n));
ix##_cnt_++)
for (int ix##_aux_ = 1;
ix##_aux_;
ix##_aux_ = odo(ix, m, n))
无可否认,这个宏观政策很笨拙。它通过标记粘贴创建了局部循环变量数组ix
和两个隐藏变量。外部for
循环正好用于正确初始化循环变量数组。do
。。。while
已被重写为for
,因此您可以像调用循环的正则函数一样调用宏:
int main()
{
int N = 4;
multi_for(ix, 2, N) {
int i;
/* Do something, e.g. print loop vars */
for (i = 0; i < N; i++) {
if (i) printf(", ");
printf("%d", ix[i]);
}
printf("n");
}
return 0;
}
要使其工作,必须更改odo_init
以返回0:
int odo_init(int ix[], int n)
{
while (n--) ix[n] = 0;
return 0;
}
该宏依赖于在for
内部定义变量和可变长度数组,因此需要C99。
用递归实现并不太困难,尽管它看起来仍然是一个奇怪的用例
无论如何,这使代码尽可能地易于理解,同时具有"无限"可扩展性*
每个循环也有自己的功能(尽管是相同的),正如您在对其他答案的注释中所指定的那样。
void do_loop(std::vector<int> *loop_vars, int loop_level, int max_loop_level, int loop_iter_limit, void* data)
{
while(loop_vars[loop_level] < loop_iter_limit)
{
//do work on *data
*loop_vars[loop_level]++;
do_loop(loop_vars, loop_level+1, max_loop_level, loop_iter_limit, data);
}
else
{
return;
}
}
void nestedloops(int loop_count, loop_limit, void* data)
{
std::vector<int> vars;
for (int i = 0; i<loop_count; i++)
vars.pushback(0);
do_loop(&vars, 0, loop_count, loop_limit, data);
return;
}
例如用nestedloops(5,10,data);
调用以执行5个嵌套循环,每个循环10次迭代。
您将想要将void* data
更改为更合适的内容(我不知道您将要做什么工作)。当操作数据时,循环变量(i,j,k...
)由矢量提供,因此不是:
for (int i = 0; i<max; i++)
{
for (int j = 0; j<max; j++)
{
x += i+j;
}
}
您将用替换工作(在本例中为x=i+j
)
*data += loop_vars[0]+loop_vars[1];
void* data
将改为int* data
而不是循环,你可以调用
nestedloops(2,max,&x);
如果您需要澄清,请发表评论。
*不确定编译器是否能够对此执行tail call elimination
,如果不能,则受堆栈深度的限制。然而,我认为500(GCC默认值)已经足够开始嵌套循环了,而且它可以配置得更高,但我也不知道你的用例,在这之前运行时间会变得非常可怕。
您可以使用meshgrid
生成所有组合。
例如,考虑一个长度未知的向量limits
,其中每个循环都应该执行for idx_k = 1:limit(k)
。然后
function unknownNested( limts )
n = numel(limits); %// how many neted loops there are
range = cell(1,n); %// range for each loop
for ii=1:n
range(ii) = 1:limits(ii);
end
[idx{1:n}] = meshgrid( range{:} );
idx = cellfun( @(x) x(:), idx, 'uni', false ); %// "flatten" all ranges
allRanges = [idx{:}];
%// now you can loop once over all combinations
for ii = 1:size(allRanes,1)
counters = allRanges(ii,:); %// now you have an n-vector with the counter of each nested loop
%// do you work here...
end
您已经用Mathlab和C++标记了您的问题。你需要哪一个?这是用C++编写的。
如果我正确理解你的问题(n个循环,上限为m),那么你需要这样的东西:
void func(int countLoops, int loopUpperLimit) {
// simpler code with 2 loops
while (countLoops-- > 0) {
for (int i = 0; i < loopUpperLimit; i++) {
// do something
}
}
// shorter code with one loop
for (int i = 0, limit = loopUpperLimit * countLoops; i < limit; i++) {
// do something
}
}
上面的代码假设您不需要单独的控制变量(i、j、k等等)。