【问题标题】:Creating N nested for-loops创建 N 个嵌套的 for 循环
【发布时间】:2015-07-29 05:02:16
【问题描述】:

有没有办法创建表单的for循环

for(int i = 0; i < 9; ++i) {
    for(int j = 0; j < 9; ++i) {
    //...
        for(int k = 0; k < 9; ++k) { //N-th loop

在编译时不知道 N。理想情况下,如果一定数量的数字被不同的数字替换,我试图找出一种方法来循环遍历数字向量的单独元素以创建每个可能的数字。

【问题讨论】:

  • 您可以对包含 for 循环的函数使用 N 次递归调用。

标签: c++ algorithm for-loop recursion nested-loops


【解决方案1】:

您可以使用递归代替基本条件 -

void doRecursion(int baseCondition){

   if(baseCondition==0) return;

   //place your code here

   doRecursion(baseCondition-1);
}  

现在您无需在编译时提供baseCondition 值。您可以在调用doRecursion() 方法时提供它。

【讨论】:

  • 为什么if和else之间有差距?我不确定它会如何解决
  • @Andrew,谢谢。我已经修好了。实际上,起初那里没有注释(//将您的代码放在这里)部分。添加评论后,我忘记删除else
【解决方案2】:

这是一个不错的多索引小类,可以通过基于范围的 for 循环进行迭代:

#include<array>

template<int dim>
struct multi_index_t
{
    std::array<int, dim> size_array;
    template<typename ... Args>
    multi_index_t(Args&& ... args) : size_array(std::forward<Args>(args) ...) {}

    struct iterator
    {
        struct sentinel_t {};

        std::array<int, dim> index_array = {};
        std::array<int, dim> const& size_array;
        bool _end = false;

        iterator(std::array<int, dim> const& size_array) : size_array(size_array) {}

        auto& operator++()
        {
            for (int i = 0;i < dim;++i)
            {
                if (index_array[i] < size_array[i] - 1)
                {
                    ++index_array[i];
                    for (int j = 0;j < i;++j)
                    {
                        index_array[j] = 0;
                    }
                    return *this;
                }
            }
            _end = true;
            return *this;
        }
        auto& operator*()
        {
            return index_array;
        }
        bool operator!=(sentinel_t) const
        {
            return !_end;
        }
    };

    auto begin() const
    {
        return iterator{ size_array };
    }
    auto end() const
    {
        return typename iterator::sentinel_t{};
    }
};

template<typename ... index_t>
auto multi_index(index_t&& ... index)
{
    static constexpr int size = sizeof ... (index_t); 
    auto ar = std::array<int, size>{std::forward<index_t>(index) ...};
    return multi_index_t<size>(ar);
}

基本思想是使用一个包含多个dim 索引的数组,然后实现operator++ 以适当增加这些索引。

把它当做

for(auto m : multi_index(3,3,4))
{
    // now m[i] holds index of i-th loop
    // m[0] goes from 0 to 2
    // m[1] goes from 0 to 2
    // m[2] goes from 0 to 3
    std::cout<<m[0]<<" "<<m[1]<<" "<<m[2]<<std::endl;
}

Live On Coliru

【讨论】:

  • 向量中保存min_ind和max_ind的原因是什么?使用 int min_ind 和 int max_ind 不是更容易吗?
  • 如果这对你来说足够了,就这样做吧。然而,第一个循环可能从 3 到 6,第二个循环从 1 到 8,依此类推。
【解决方案3】:

你可以使用递归函数:

void loop_function(/*params*/,int N){
for(int i=0;i<9;++i){
    if(N>0) loop_function(/*new params*/,N-1);
}

这将递归调用loop_function N次,而每个函数将迭代调用loop_function

以这种方式编程可能有点困难,但它应该做你想做的事

【讨论】:

  • 当我尝试运行 int counter = 0; void loop_function(vector& digits,int n) { int index = n-1; for(digits[index] = 0;digits[index] 1) loop_function(digits, n-1);显示(数字); ++计数器; } } int main() { 向量 vec(3, 0);循环函数(vec,vec.size()); cout
  • 据我了解您的代码,您的矢量数字一直在变化,直到矢量为 {9,9,9},为此,您对最后一个元素执行 9*9*9 迭代(您去在 2 个循环内从 0 到 9),第二次执行 9*9 迭代,最后再进行 9 次迭代。所以,最后,你有到 {9,9,9} 的数字向量,为了得到它,你总共执行了 9*9*9+9*9+9=819 次迭代,这就是你说的计数器
  • 我正在尝试创建从 1 到 999 的每个元素。我需要在代码中进行哪些更改?
  • 每次调用函数时,您都在重新启动该位置元素,我不明白您想要什么,如果您想在最小迭代 (2997) 中获得 {999,999,999} 嵌套循环不会似乎是一个不错的选择,因为您将问题复杂化了,如果您想像您正在做的那样做(导致 998001999 次迭代)只需将 9 更改为 999,但显然这不是一个好主意。当您嵌套循环时,最终循环的迭代次数将比上一次多 n 次,因此如果您不重新开始计数并保持原样,您将得到 {9,81,719} 作为 819 次迭代的结果
【解决方案4】:

你可以使用递归调用:

void runNextNestedFor(std::vector<int> counters, int index)
{
     for(counters[index] = 0; counters[index] < 9; ++counters[index]) {
       // DO
       if(index!=N)
          runNextNestedFor(counters, index+1);
     }
}

第一次调用为:

std::vectors<int> counters(N);
runNextNestedFor(counters, 0);

【讨论】:

    【解决方案5】:

    我将按照给出的示例代码的面值来考虑 OP,并假设所要求的解决方案是通过任意以 10 为底的数字进行计数的解决方案。 (我的评论基于“理想情况下,我试图找出一种方法来循环遍历数字向量的单独元素以创建每个可能的数字”。

    这个解决方案有一个循环,它通过一个以 10 为底的数字向量进行计数,并将每个连续值传递给一个辅助函数 (doThingWithNumber)。出于测试目的,我让这个助手简单地打印出数字。

    #include <iostream>
    
    using namespace std;
    
    void doThingWithNumber(const int* digits, int numDigits)
    {
        int i;
        for (i = numDigits-1; i>=0; i--)
            cout << digits[i];
        cout << endl;
    }
    
    void loopOverAllNumbers(int numDigits)
    {
        int* digits = new int [numDigits];
        int i;
        for (i = 0; i< numDigits; i++) 
            digits[i] = 0;
    
        int maxDigit = 0;
        while (maxDigit < numDigits) {
            doThingWithNumber(digits, numDigits);
            for (i = 0; i < numDigits; i++) {
                digits[i]++;
                if (digits[i] < 10)
                    break;
                digits[i] = 0;
            }
            if (i > maxDigit)
                maxDigit = i;
        }
    }
    
    int main()
    {
        loopOverAllNumbers(3);
        return 0;
    }
    

    【讨论】:

      【解决方案6】:

      我为自己编写了一些实现 N 嵌套 for 循环的 C++ 11 代码。以下是可用作单个 .hpp 导入的主要代码部分(我将其命名为 nestedLoop.hpp):

      #ifndef NESTEDLOOP_HPP
      #define NESTEDLOOP_HPP
      #include <vector>
      
      namespace nestedLoop{
      
          class nestedLoop {
              public:
                  //Variables
                  std::vector<int> maxes;
                  std::vector<int> idxes; //The last element is used for boundary control
                  int N=0;
                  int nestLevel=0;
      
                  nestedLoop();
                  nestedLoop(int,int);
                  nestedLoop(int,std::vector<int>);
      
                  void reset(int numberOfNests, int Max);
                  void reset(int numberOfNests, std::vector<int> theMaxes);
      
                  bool next();
                  void jumpNest(int theNest);
      
              private:
                  void clear();
          };
      
          //Initialisations
          nestedLoop::nestedLoop(){}
      
          nestedLoop::nestedLoop(int numberOfNests, int Max) {
              reset(numberOfNests, Max);
          }
      
          nestedLoop::nestedLoop(int numberOfNests, std::vector<int> theMaxes) {
              reset(numberOfNests,  theMaxes);
          }
      
          void nestedLoop::clear(){
              maxes.clear();
              idxes.clear();
              N = 0;
              nestLevel = 0;
          }
      
          //Reset the scene
          void nestedLoop::reset(int numberOfNests, int Max){
              std::vector<int> theMaxes;
              for(int i =0; i < numberOfNests; i++) theMaxes.push_back(Max);
              reset(numberOfNests, theMaxes);
          }
      
          void nestedLoop::reset(int numberOfNests, std::vector<int> theMaxes){
              clear();
              N = numberOfNests;
      
              maxes=theMaxes;
      
              idxes.push_back(-1);
              for(int i=1; i<N; i++) idxes.push_back(theMaxes[i]-1);
          }
      
          bool nestedLoop::next(){
              idxes[N-1]+=1;
      
              for(int i=N-1; i>=0; i--){
                  if(idxes[i]>=maxes[i]) {
                      idxes[i] = 0;
      
                      if(i){ //actually, if i > 0 is needed
                          idxes[i-1] += 1;
                      }else{
                          return false;
                      }
                  }else{
                      nestLevel = i;
                      break;
                  }
              }
              return true;
          }
      
          void nestedLoop::jumpNest(int theNest){
              for(int i = N-1; i>theNest; i--) {
                  idxes[i] = maxes[i]-1;
              }
          }
      }
      #endif // NESTEDLOOP_HPP
      

      这是一个预期输出的示例:

      #include <iostream>
      #include "stlvecs.hpp"
      #include "nestedLoop.hpp"
      
      int main(){
          nestedLoop::nestedLoop looper;
          std::vector<int> maxes = {2, 3, 2, 2};
          looper.reset(4,maxes);
          int i = 0;
          while(looper.next()){
              std::cout << "Indices: " << looper.idxes << ", Last nest incremented: " << looper.nestLevel << std::endl;
              if(i == 5){
                  std::cout << "...Jump Second Nest (index 1)..." << std::endl;
                  looper.jumpNest(1);
              }
              i++;
          }
      }
      
      /* Expected output
      Indices: 4  0 0 0 0 , Last nest incremented: 0
      Indices: 4  0 0 0 1 , Last nest incremented: 3
      Indices: 4  0 0 1 0 , Last nest incremented: 2
      Indices: 4  0 0 1 1 , Last nest incremented: 3
      Indices: 4  0 1 0 0 , Last nest incremented: 1
      Indices: 4  0 1 0 1 , Last nest incremented: 3
      ...Jump Second Nest (index 1)...
      Indices: 4  0 2 0 0 , Last nest incremented: 1
      Indices: 4  0 2 0 1 , Last nest incremented: 3
      Indices: 4  0 2 1 0 , Last nest incremented: 2
      Indices: 4  0 2 1 1 , Last nest incremented: 3
      Indices: 4  1 0 0 0 , Last nest incremented: 0
      Indices: 4  1 0 0 1 , Last nest incremented: 3
      Indices: 4  1 0 1 0 , Last nest incremented: 2
      Indices: 4  1 0 1 1 , Last nest incremented: 3
      Indices: 4  1 1 0 0 , Last nest incremented: 1
      Indices: 4  1 1 0 1 , Last nest incremented: 3
      Indices: 4  1 1 1 0 , Last nest incremented: 2
      Indices: 4  1 1 1 1 , Last nest incremented: 3
      Indices: 4  1 2 0 0 , Last nest incremented: 1
      Indices: 4  1 2 0 1 , Last nest incremented: 3
      Indices: 4  1 2 1 0 , Last nest incremented: 2
      Indices: 4  1 2 1 1 , Last nest incremented: 3
      */
      

      【讨论】:

      • 好答案!对我来说即插即用。
      【解决方案7】:

      我使用这个解决方案:

      unsigned int dim = 3;
      unsigned int top = 5;
      std::vector<unsigned int> m(dim, 0);
      for (unsigned int i = 0; i < pow(top,dim); i++)
      {
          // What you want to do comes here 
          //      |
          //      |
          //      v
          // -----------------------------------
          for (unsigned int j = 0; j < dim; j++)
          {
              std::cout << m[j] << ",";
          }
          std::cout << std::endl;
          // -----------------------------------
      
          // Increment m
          if (i == pow(top, dim) - 1) break;
          unsigned int index_to_increment = dim - 1;
          while(m[index_to_increment] == (top-1)) {
              m[index_to_increment] = 0;
              index_to_increment -= 1;
          }
          m[index_to_increment] += 1;
      }
      

      它当然可以优化和调整,但它工作得很好,你不需要将参数传递给递归函数。使用单独的函数来增加多索引:

      typedef std::vector<unsigned int> ivec;
      void increment_multi_index(ivec &m, ivec const & upper_bounds)
      {
          unsigned int dim = m.size();
          unsigned int i = dim - 1;
          while(m[i] == upper_bounds[i] - 1 && i>0) {
              m[i] = 0;
              i -= 1;
          }
          m[i] += 1;
      }
      
      int main() {
      
          unsigned int dim = 3;
          unsigned int top = 5;
          ivec m(dim, 0);
          ivec t(dim, top);
          for (unsigned int i = 0; i < pow(top,dim); i++)
          {
              // What you want to do comes here 
              //      |
              //      |
              //      v
              // -----------------------------------
              for (unsigned int j = 0; j < dim; j++)
              {
                  std::cout << m[j] << ",";
              }
              std::cout << std::endl;
              // -----------------------------------
      
              // Increment m
              increment_multi_index(m, t);
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-15
        • 2020-05-25
        相关资源
        最近更新 更多