简化 C++ For 循环

Simplifying C++ For Loop

目前我有以下代码:

for(int i = 0; i < 4; i++){
    cout << rowNo[i] << endl;
}

for(int i = 0; i < 4; i++){
    for(int j = 0; j < 4; j++){
        cout << rowNo[i] << '.';
        cout << rowNo[j] << endl;
    }
}

for(int i = 0; i < 4; i++){
    for(int j = 0; j < 4; j++){
        for(int k = 0; k < 4; k++){
            cout << rowNo[i] << '.';
            cout << rowNo[j] << '.';
            cout << rowNo[k] << endl;
        }
    }
}

for(int i = 0; i < 4; i++){
    for(int j = 0; j < 4; j++){
        for(int k = 0; k < 4; k++){
            for(int l = 0; l < 4; l++){
                cout << rowNo[i] << '.';
                cout << rowNo[j] << '.';
                cout << rowNo[k] << '.';
                cout << rowNo[l] << endl;
            }
        }
    }
}

其中rowNo[]是数组{1,2,3,4}

我想知道两件事:

  1. 这可以简化吗,所以可以放入某种递归循环?
  2. 那么,这是否可以针对大小为N的数组进行?

我想到的第一个解决方案是在每个循环中放入一个缓冲区,最后打印所有缓冲区。 我觉得还有一些巧妙的方法

for(int i = 0; i < 4; i++){
        put in buffer1 rowNo[i]
        for(int j = 0; j < 4; j++){
            put in buffer2 rowNo[i],rowNo[j]
            for(int k = 0; k < 4; k++){
                 put in buffer3 rowNo[i],rowNo[j],rowNo[k]
                for(int l = 0; l < 4; l++){
                    put in buffer4 rowNo[i],rowNo[j],rowNo[k],rowNo[l],endl.
                }
            }
        }
    }
     print(buffer1);
     print(buffer2);
     print(buffer3);
     print(buffer4);

以下是我想出的最简单的代码。必须有更直接的方法来做到这一点...

它基本上引入了一个"ghost"索引-1,对应一个数字中的一个空位。循环条件中的三元运算符是为了避免重复。

int main()
{
    int N = 4;
    int rowNo[4] = {1, 2, 3, 4};

    for (int i = -1; i < N; i++)
        for (int j = (i > -1 ? 0 : -1); j < N; j++)
            for (int k = (j > -1 ? 0 : -1); k < N; k++)
                for (int l = (k > -1 ? 0 : -1); l < N; l++)
                {
                    if (i > -1) std::cout << rowNo[i] << '.';
                    if (j > -1) std::cout << rowNo[j] << '.';
                    if (k > -1) std::cout << rowNo[k] << '.';
                    if (l > -1) std::cout << rowNo[l];
                    std::cout << std::endl;
                }
}

它当然可以泛化为任意大小的数组,可能需要一些代码生成脚本。

您正在寻找Cartesian_product

bool increment(std::vector<std::size_t>& v, std::size_t maxSize)
{
    for (auto it = v.rbegin(); it != v.rend(); ++it) {
        ++*it;
        if (*it != maxSize) {
            return true;
        }
        *it = 0;
    }
    return false;
}

那么你可以这样做:

void print_cartesian_product(const std::vector<int>&v, int n)
{
    std::vector<std::size_t> indexes(n);

    do {
        print(v, indexes);
    } while (increment(indexes, v.size()));

}

Demo

您实际上是在尝试打印一个以 base4 编码的数字,其中包含数字 {1, 2, 3, 4}。要实现它,你只需要定义一个函数来增加一个。我在打印数量和基础数量方面提出了一个通用解决方案。 和其他人一样,我用数字来表示"empty digit",我用零来表示很方便。

完整的源代码:

#include <iostream>
#include <vector>

bool increment_basep(std::vector<int>& number, int p)
{ 
    int i = 0; 
    while(i < number.size() && number[i] == p)
    { 
       number[i] = 1;
       ++i;
    }
    if(i >= number.size())
        return false;

    ++number[i];
    return true;
}

void print_vect(std::vector<int>& number)
{
   for(int i = number.size() -1 ; i >= 0; --i)
   {
       if(number[i] != 0)
          std::cout << number[i];
   }
   std::cout << std::endl;
}

int main() {
    int n = 4;
    int p = 4;
    std::vector<int> num4(n);
    std::fill(num4.begin(), num4.end(), 0);

    while(increment_basep(num4, p))
    {
        print_vect(num4);
    }
    return 0;
}

计算是否溢出的增量return。当我们溢出时,我们知道我们需要停止。