可变嵌套循环

8

我正在尝试使用递归来完成n层嵌套的for循环。例如,如果n = 3,则会有3个“级别”。

for(z=0;z<6;z++){
   for(y=0;y<6;y++){
      for(x=0;x<6;x++){
         if (z+y+x==f){
            //do something
         } 
      }
   }
}

等等。

我似乎无法想出如何将if循环放置在最后的for循环中,以及如何从if语句中访问前面for循环的变量。我知道关于变量嵌套循环的问题已经被问了很多次,我已经查看了所有的答案。但是没有一个能帮助我。

有人能够提供一种使用递归轻松实现此目的的方法吗?请记住,我仍然是C++的初学者,请指点我正确的方向。

用例如下:

编写一个程序来输入骰子数m。该程序将输出可能情况的总数,每个可能n的可能情况以及具有最高概率的n。注意:只读取一个输入m。 n由程序计算

例如,如果用户输入m = 2,则程序应输出

可能情况的总数为36。
可能性有:
2 1
3 2
4 3
.
.
.
12 1


3
第二个循环中有错别字吗? - wildplasser
1
你想要实现什么?为什么要使用递归? - BЈовић
VJovic所说的话。你试图做什么并不清楚。将其拆分为递归函数调用似乎有些毫无目标。我们需要看到更多关于您想要它看起来的信息。“使用递归”太模糊了。此外,“if循环”这种东西是不存在的。 - Lightness Races in Orbit
我知道这可以通过迭代实现。但我想知道如何通过递归实现。 - cortex
1
我不需要递归来解决这个问题。我想尝试一种不同的解决方法,因此向社区寻求帮助。 - cortex
显示剩余4条评论
8个回答

17

为了提高效率,我避免使用递归。此外,它不使用任何特定的C++语法 - 它也可以在C上良好运行。

我们正在尝试创建N个嵌套的"for"循环。 而不是使用

for(int i = 0; i<max; i++)
  for (int j = 0; j<max; j++)
    ...

我将使用一个数组来替换i、j等变量:i[0]、i[1],...,i[n-1]。

以下是我的解决方案:

const int n = /*Insert N here: how many loops do you need?*/;
int i[n+1]; // if "n" is not known before hand, then this array will need to be created dynamically.
//Note: there is an extra element at the end of the array, in order to keep track of whether to exit the array.

for (int a=0; a<n+1; a++) {
  i[a]=0;
}

int MAX = 79; //That's just an example, if all of the loops are identical: e.g. "for(int i=0; i<79; i++)". If the value of MAX changes for each loop, then make MAX an array instead: (new) int MAX [n]; MAX[0]=10; MAX[1]=20;...;MAX[n-1]=whatever.

int p = 0; //Used to increment all of the indicies correctly, at the end of each loop.
while (i[n]==0) {//Remember, you're only using indicies i[0], ..., i[n-1]. The (n+1)th index, i[n], is just to check whether to the nested loop stuff has finished.

  //DO STUFF HERE. Pretend you're inside your nested for loops. The more usual i,j,k,... have been replaced here with i[0], i[1], ..., i[n-1].


  //Now, after you've done your stuff, we need to increment all of the indicies correctly.
  i[0]++;
  // p = 0;//Commented out, because it's replaced by a more efficient alternative below.
  while(i[p]==MAX) {//(or "MAX[p]" if each "for" loop is different. Note that from an English point of view, this is more like "if(i[p]==MAX". (Initially i[0]) If this is true, then i[p] is reset to 0, and i[p+1] is incremented.
    i[p]=0;
    i[++p]++; //increase p by 1, and increase the next (p+1)th index
    if(i[p]!=MAX)
      p=0;//Alternatively, "p=0" can be inserted above (currently commented-out). This one's more efficient though, since it only resets p when it actually needs to be reset!
  }
}

就是这样,希望注释可以清楚地说明它的意图。我认为它应该相当高效——几乎和真正的嵌套for循环一样高效。大部分开销只在开始时发生一次,因此使用递归函数等比其更加高效。


10

具有多个循环的递归算法的基本结构如下:

void recursiveLoops(vector<int>& indexes, const vector<int>& endPerIndex, int currentIndex) {
    if (currentIndex == indexes.size()) {
        // This is where the real logic goes.
        // indexes[i] contain the value of the i-th index.
    } else {
        for (indexes[pos] = 0 ; indexes[pos] != endPerIndex[pos] ; indexes[pos]++) {
            // Recurse for the next level
            recursiveLoops(indexes, endPerIndex, pos+1);
        }
    }
}

从顶层调用recursiveLoops的设置需要两个向量 - 一个用于索引,另一个用于每个级别的迭代次数。下面的示例设置了三个嵌套循环,在每个级别上迭代5、6和9次:

vector<int> indexes(3, 0);
vector<int> endPerIndex;
endPerIndex.push_back(5);
endPerIndex.push_back(6);
endPerIndex.push_back(9);
recursiveLoops(indexes, endPerIndex, 0);

递归函数的一个典型问题是堆栈溢出。对于变量级别嵌套的for循环,这种情况非常容易发生。我知道我们的供应商将它们的循环硬编码为最大嵌套级别为5,并表示他们将将限制提高到9。三年过去了,他们仍然没有这样做,哈哈。 - fchen

5

这里是一个简单的C++示例。首先,我创建了一个包含每个维度范围的向量,称为maxes。如果所有索引的总和为2,则打印“did something”。在这个示例中,我循环z从0到1,y从0到2,x从0到3。

你当然可以让它更整洁。

以下是:

#include <iostream>
#include <vector>
using namespace std;

int f(){ 
    return 2 ;
}

void inner(int depth,vector<int> & numbers,vector<int> & maxes){
  if (depth>0){
     for(int i=0;i<maxes[depth-1];i++){
        numbers[depth-1]=i;
        inner(depth-1, numbers,maxes) ;
     }
  }else{
     // calculate sum of x,y,z:
     cout << "values are ";
     for(int i=0;i<numbers.size();i++){
        cout <<numbers[i]<<" ";
     }
     int thesum(0);
     for(int i=0;i<numbers.size();i++){
        thesum+=numbers[i];
     }
     if (thesum==f()){
        cout << "did something! ";
     }
     cout<<endl;
   }
}

void donest(){
   vector<int>  numbers;
   numbers.resize(3);
   vector<int>  maxes;
   maxes.push_back(4);
   maxes.push_back(3);
   maxes.push_back(2);
   inner(numbers.size(),numbers,maxes);
}

int main(){
   donest();
}

结果:

values are 0 0 0 
values are 1 0 0 
values are 2 0 0  did something! 
values are 3 0 0 
values are 0 1 0 
values are 1 1 0  did something! 
values are 2 1 0 
values are 3 1 0 
values are 0 2 0  did something! 
values are 1 2 0 
values are 2 2 0 
values are 3 2 0 
values are 0 0 1 
values are 1 0 1  did something! 
values are 2 0 1 
values are 3 0 1 
values are 0 1 1  did something! 
values are 1 1 1 
values are 2 1 1 
values are 3 1 1 
values are 0 2 1 
values are 1 2 1 
values are 2 2 1 
values are 3 2 1 

0

只需为每个递归函数计算深度,并计数到f即可。

void myRecursiveFunc(int depth){
   if(depth == f)
      //do something
      return;
   else{
      myRecursiveFunc(depth + 1);
   }
}

如果你真的想要,你可以使用三个不同的函数来处理 x、y 和 z。


嗯,@Lightness。我的问题如下。 - cortex

0

你可以这样写,但是...我不建议。这段代码令人困惑,而且没有任何好处。如果你之所以想这么写是因为你的实际使用情况有很多嵌套循环,那么请考虑不要那样做,因为这是一个设计上的严重问题。

void nested_loop(const int levels, const int comparator, const int level = 0, const int accumulator = 0)
{
   if (level < levels) {
      for (int i = 0; i < 6; i++) {
         nested_loop(levels, comparator, level + 1, accumulator + i);
      }
   }
   else {
      if (accumulator == comparator) {   // your if (z+y+x==f)
         //do something
      }
   }
}

int main() {
   const int levels = 3;
   const int f = 42;

   nested_loop(levels, f);
}

在线演示


0

你对为什么需要这样做非常模糊。作为一个入门解决方案,可能的解决方法是将每个for循环替换为递归函数。

void recursiveX(int zVal, int yVal, int xVal)
{
    if(zVal+yVal+xVal == f)...
    if(xVal != 0)
        recursiveX(zVal, yVal, xVal -1);
}

void recursiveY(int zVal, int yVal)
{
    recursiveX(zVal, yVal, 6);
    if(yVal != 0)
        recursiveY(zVal, yVal-1);
}

void recursiveZ(int val)
{
    recursiveY(val, 6);
    if(val != 0)
        recursiveZ(val-1);
}
...
recursiveZ(6);

最后,您可以将所有内容合并为一个函数。然而,仅仅因为可以使用递归而使用它并不是一个好主意。

0
这是一个晚回答,但也许会对某些人有所帮助。
以下是我的C++解决方案,没有使用递归函数:
int n_loops{3}; //number of nested for loops

int loops_idx[n_loops]; //like i,j,k but in an array
for (int i = 0; i < n_loops; i++)
    loops_idx[i]=0;

int max_idx[n_loops]{3,2,4}; // like in for(; i < counter ;), but the counters in an array

bool is_finished = false;
int debug_n_of_execution{0};

while (!is_finished)
{
    for (; loops_idx[0]<max_idx[0]; loops_idx[0]++)
    {
        /*
        some code with loops_idx array as i,j,k...
        */
        ++debug_n_of_execution;
        for (int i = 0; i < n_loops; i++)
            std::cout<<loops_idx[i]<<" ";
        std::cout << "\n";
    }

    --loops_idx[0]; //to cancel last increment
    //Here it will increment the last loop_idx which isn't equal to max_idx[i]-1
    //eg. after first above for loop loops_idx will be (max-1, 0, 0)
    //So it will be after this loop (0, 1, 0) and start from the beginning...
    for (int i = 0; i < n_loops+1; i++) //+1 to know if all loops are finished
    {
        if (i == n_loops)
        {is_finished= true; break;}

        if(loops_idx[i]==max_idx[i]-1)
            continue;
        
        ++loops_idx[i];
        for (int j = 0; j < i; j++) //make any previous loop = 0  
            loops_idx[j]=0;
        
        break;
    }
}

//just to check
int debug_perfect_n_of_execution{max_idx[0]};
for (int i = 1; i < n_loops; i++)
    debug_perfect_n_of_execution*= max_idx[i];
std::cout<<"Number of execution: "<<debug_n_of_execution<<" = "<<debug_perfect_n_of_execution;
assert(debug_n_of_execution==debug_perfect_n_of_execution);
std::cout << "\nTests Finished";

这里是结果:

0 0 0 
1 0 0
2 0 0
0 1 0
1 1 0
2 1 0
0 0 1
1 0 1
2 0 1
0 1 1
1 1 1
2 1 1
0 0 2
1 0 2
2 0 2
0 1 2
1 1 2
2 1 2
0 0 3
1 0 3
2 0 3
0 1 3
1 1 3
2 1 3
Number of execution: 24 = 24
Tests Finished

0

使用while循环在"C"中创建变量循环。

概念

  1. 创建一个二维数组(arr[level][2]),其中第一个元素是起始点,第二个元素是结束点。
    x[3][2] = {{0, 10}, {5, 20}, {2, 60}};
  2. 创建另一个数组,其中包含起始元素。
    y[3] = {0, 5, 2};
  3. 我们创建了第二个数组,因为在循环过程中,我们将更改"x"数组的第一个元素。

代码

#include <stdio.h>
int main(){
// bruteforce
int level = 10;
int start[10] = {0, 0, 0, 0};
int x[10][2] = {{0, 5}, {0, 5}, {0, 5}, {0, 5}};


for (int i = 1;i < level; ++i){
    x[i][1] = x[i][1] + 1;
}
while(3>2){
    // Your code here



   // 

    printf("%d %d %d %d\n", x[0][0], x[1][0], x[2][0], x[3][0]);


    // variable loop code
    // ==== Not To Modify ====
    int a = 0;
    int b = 0;
    for(int i = 0;i < level; ++i){
        if (x[i][0] >= x[i][1])
        {
                if(i != level-1){
                    x[i][0] = start[i];
                    x[i+1][0] = x[i+1][0] + 1;
                }else{
                    a = 1;
                }
                b = 1;
            
        }else{
            if(b == 0){
                x[0][0] = x[0][0] + 1;
                b = 1;
            }
        }
    }
    if(a == 1){
        break;
    }
}
return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接