【问题标题】:Generating all the values of N nested for loops生成N个嵌套for循环的所有值
【发布时间】:2016-09-15 16:39:47
【问题描述】:

我想编写一个函数来执行以下操作,给定函数int Kint nest_level 的两个参数,生成由创建nest_level 嵌套循环产生的所有可能点,其中每个循环的范围从-KK。例如,如果 k = 5nest_level = 3 函数打印由以下结果产生的数字序列:

for(int i = -k; i <= k; ++i)
    for(int j = -k; j <= k; ++j)
        for(int m = -k; m <= k; ++m)
            print(i, j, k)

这应该适用于任何Knest_level

根据我的研究,我知道这应该是一个递归解决方案,但我很难在 C++ 中专门实现它。

【问题讨论】:

标签: c++ recursion nested-loops cartesian-product


【解决方案1】:

使用std::vector。通过引用传递它。在 i 从 -k 到 k 的循环中:

  • i推入其中。

  • 如果向量的长度等于嵌套级别,则打印。

  • 否则,递归,通过引用传入向量。

  • 现在,弹出向量末尾的最后一个元素,然后继续循环。

【讨论】:

    【解决方案2】:

    考虑这个问题的另一种方法是,您正在使用一个数字,其中每个数字的范围从 -K 到 K。您可以递增 (-K)(-K)(-K)...(-K) (-K)(-K) 直到 KKK...KKK 并打印中间结果。

    #include <iostream>
    #include <vector>
    
    bool increment(int K, std::vector<int> & vals) {
        int position = vals.size()-1; 
        while (vals[position] == K) {
            vals[position] = -K;
            --position;
            if (position == -1) {
                return false;
            }
        }
        ++vals[position];
        return true;
    }
    
    void count(int K, int nest_level) {
        std::vector<int> vals;
        for (int n=0; n<nest_level; ++n) {
            vals.push_back(-K);
        }
    
        do {
            for (auto v : vals) {
                std::cout << v << " ";
            }
            std::cout << "\n";
        } while (increment(K, vals));
    }
    
    int main()
    {
        count(1, 2);
        return 0;
    }
    

    我不确定哪种方式更好,但我认为这是一个很好的平行。

    【讨论】:

      【解决方案3】:

      这样的,你需要一个容器来存储号码

      #include "iostream"
      #include "vector"
      
      void print(const std::vector<int>& v) {
          for (auto i : v) {
              std::cout << i << ' ';
          }
          std::cout << std::endl;
      }
      
      void genImpl(int K, int level, std::vector<int>& cache) {
          if (level == 1) {
              for (int i = -K; i <= K; ++i) {
                  cache.push_back(i);
                  print(cache);
                  cache.pop_back();
              }
          } else {
              for (int i = -K; i <= K; ++i) {
                  cache.push_back(i);
                  genImpl(K, level - 1, cache);
                  cache.pop_back();
              }
          }
      }
      
      void gen(int K, int level) {
          std::vector<int> cache;
          genImpl(K, level, cache);
      }
      
      int main() {
          gen(2, 3);
          return 0;
      }
      

      【讨论】:

        【解决方案4】:
        because both parameters are int type, so ,first you should get their abs value.
        
        //pseud0-code
        
        {
           k = abs(k);
           nest_level = abs(nest_level);
           while(nest_level--){
             for(int i = -k; i < k; i++){
                printf("%d,%d", nest_level, i);
             }
             printf("\r\n");
           }
        }
        

        【讨论】:

          【解决方案5】:

          根据我的研究,我知道这应该是一个递归解决方案

          一点也不。
          请注意,如果您没有不必要地使用递归,则可以避免某些潜在问题(递归级别和每级堆栈增长),并且通常更容易理解代码。

          让我们看看你在做什么。如果我们暂时忽略负数,您基本上会生成以下序列(对于 k=2,n=4):

          0 0 0 0     0 1 0 0     0 2 0 0
          0 0 0 1     0 1 0 1     0 2 0 1
          0 0 0 2     0 1 0 2     0 2 0 2
          0 0 1 0     0 1 1 0     0 2 1 0
          0 0 1 1     0 1 1 1     0 2 1 1
          0 0 1 2     0 1 1 2     0 2 1 2
          0 0 2 0     0 1 2 0     0 2 2 0
          0 0 2 1     0 1 2 1     0 2 2 1
          0 0 2 2     0 1 2 2     0 2 2 2
          

          如果 k 是 9,那么您只需按十进制计数。在我见过的所有学习数数的孩子中,我从来不知道有人会使用递归来数数。 ;) 如果你退后一步想想你是如何学会计算大数的,你应该会找到一个更简单的解决方案......但我会留到以后。

          如果你用二进制计算,它会如下所示:

          0 = 000
          1 = 001
          2 = 010
          3 = 011
          4 = 100
          5 = 101
          6 = 110
          7 = 111
          

          或用k=1n=3 计数(使用-k 到k):

           0 = -1 -1 -1       9 =  0 -1 -1      18 =  1 -1 -1
           1 = -1 -1  0      10 =  0 -1  0      19 =  1 -1  0
           2 = -1 -1  1      11 =  0 -1  1      20 =  1 -1  1
           3 = -1  0 -1      12 =  0  0 -1      21 =  1  0 -1
           4 = -1  0  0      13 =  0  0  0      22 =  1  0  0
           5 = -1  0  1      14 =  0  0  1      23 =  1  0  1
           6 = -1  1 -1      15 =  0  1 -1      24 =  1  1 -1
           7 = -1  1  0      16 =  0  1  0      25 =  1  1  0
           8 = -1  1  1      17 =  0  1  1      26 =  1  1  1
          

          因此,如果您喜欢冒险,您可以:

          • 轻松计算要输出的排列数
          • 使用简单的循环在范围内循环
          • 将每个数字转换为基数 k*2+1
          • 通过减去 k 来偏移每个数字

          当然还有前面提到的更简单的方法。在下面的代码中调用Counter(k, nest_level);。 (后解释)

          void WriteVector(const std::vector<int>& v)
          {
              for (const auto i : v)
                  std::cout << i << " ";
              std::cout << std::endl;
          }
          
          bool VectorInc(const int k, std::vector<int>& v)
          {
              for (auto it = v.rbegin(); it != v.rend(); it++)
              {
                  if ((*it) < k) {
                      (*it)++;
                      return true;
                  }
                  (*it) = -k;
              }
              return false;
          }
          
          void Counter(const int k, const int n)
          {
              std::vector<int> v(n, -k);
              WriteVector(v);
              while (VectorInc(k, v))
                  WriteVector(v);
          }
          
          • Countersize == nest_level 初始化一个向量,每个元素都包含-k
          • 在循环中调用VectorInc 来模拟加1(或计数)。
          • VectorInc 是一个非常简单的函数,只要它需要执行“结转”,它就会从右到左循环遍历向量元素。
          • 它通过添加 1 来更新当前元素。
          • 但如果当前元素最大为k,它应该回滚到-k,并且“结转”+1 到左边的数字。
          • 当向量最终到达 {k, k, k, ..., k} 时,将每个数字加 1 回滚到 -kVectorInc 返回 false,表示存在溢出。

          优点:简单,无递归,几乎可以使用任何 k & n 值。
          缺点:几乎可以使用任何值k&n。 尝试像Counter(10, 80) 这样看似无害的调用,您将花费很长时间等待您的程序计算宇宙中的原子。

          【讨论】:

            猜你喜欢
            • 2020-05-25
            • 1970-01-01
            • 2015-07-29
            • 1970-01-01
            • 2017-10-05
            • 1970-01-01
            • 2017-04-08
            • 1970-01-01
            • 2014-11-15
            相关资源
            最近更新 更多