不可预测的嵌套循环数

时间:2018-12-02 07:33:06

标签: c++ recursion

我正在尝试制作一个需要嵌套循环才能正常工作的程序。 但是嵌套循环的数量取决于用户输入的字符数以及要输出的字符。

到目前为止,这是我的代码。

#include<iostream>
using namespace std;


int main(){
    string str;
    cout<<"Enter some string: ";
    cin>>str;

    // for two characters
    for(int i = 0; i < 2; i++){
        for(int j = 0; j < 2 ; j++){
            cout<<str[i]<<str[j]<<endl;
        }
    };

    // for four characters
    for(int i = 0; i<4; i++){
        for(int j=0;j<4;j++){
            for(int k =0;k<4;k++){
                for(int z=0;z<4;z++)
                    cout<<str[i]<<str[j]<<str[k]<<str[z]<<endl;
                }
        }
    }
    return 0;
}

所以,有什么办法可以解决这个问题。

3 个答案:

答案 0 :(得分:6)

您需要动态地进行操作:

std::vector<unsigned int> offsets(s.size());

bool isContinue;
do
{
    for(auto offset : offsets)
    {
        std::cout << s[offset];
    }
    std::cout << std::endl;

    isContinue = false;
    for(auto offset = offsets.rbegin(); offset != offsets.rend(); ++offset)
    {
        if(++*offset < s.size())
        {
            isContinue = true;
            break;
        }

        *offset = 0;
    }
}
while(isContinue);

背后的想法就像递增计数(十进制):达到9后,就递增下一位。同样,向量中的每个偏移量代表一个循环变量,在“溢出”时,增加下一个偏移量,一旦最重要的偏移量“溢出”,我们就完成了。

高性能变体(使用goto,保留一个比较和条件变量):

std::vector<unsigned int> offsets(s.size());

NEXT:
for(auto offset : offsets)
{
    std::cout << s[offset];
}
std::cout << std::endl;

for(auto offset = offsets.rbegin(); offset != offsets.rend(); ++offset)
{
    if(++*offset < s.size())
        goto NEXT;

    *offset = 0;
}

答案 1 :(得分:3)

有两种基本的方法可以进行循环。

第一个是显式的:您需要使用索引数组,而不是循环索引的单个变量。然后,在每个步骤中,您都增加最后一个索引,当该索引超过限制时,将其重置并增加上一个索引:

int n = str.size(); // Get rid of unsigned
std::vector<int> index(n);
for(;;) {
    // Generate output
    for (int i=0; i<n; i++) {
        std::cout << str[index[i]];
    }
    std::cout << std::endl;

    // Increment
    int i = n-1; // start from last index
    while (i>=0 && index[i] == n-1) {
        // I-th index has reached the end of the string, flip over to 0
        index[i] = 0;
        --i;
    }
    if (i == -1) break; // all of them returned to 0... that's all, folks
    index[i] += 1;
}

第二种方法是使用递归,例如,使用接受部分字符串作为参数构建的函数,并且如果此前缀不完整,则会遍历字符串并通过扩展前缀调用自身:

std::function<void(const std::string&)> proc = [&](const std::string& prefix) {
    if (prefix.size() == str.size()) {
        // Prefix is complete, just output result
        std::cout << prefix << std::endl;
    } else {
        // Extend the prefix and call yourself for the nested loops
        for (int j=0; j<n; j++) {
            proc(prefix + str[j]);
        }
    }
};
proc("");

递归方法更紧凑,但要花一些时间才能适应,在某些情况下可能会出现问题。

避免嵌套循环的另一种方式是使用简单的计数和数学运算...编写一个返回您要查找的第n个字符串而无需循环前一个字符串的函数很容易...

for (int i=0,loops=pow(n, n); i<loops; i++){
    std::string s = "";
    int k = i;
    for (int j=0; j<n; j++) {
        s = str[k % n] + s;
        k /= n;
    }
    std::cout << s << std::endl;
}

答案 2 :(得分:0)

让我们将所有N个嵌套循环折叠成一个嵌套循环。首先,我们需要N个索引,这些索引会适当增加:

class Multiindex
{
public:
    Multiindex(int size, int last_) : idx(size,0), last(last_) {}

    void inc()
    {
        for (int i = idx.size() - 1; i >= 0; --i) {
            if (idx[i] == last - 1) {
                idx[i] = 0;
                if (i == 0) complete = true;
            }
            else {
                ++idx[i];
                break;
            }
        }
    }

    const auto& getIdx() const { return idx; }
    const auto isComplete() const { return complete; }

private:
    std::vector<int> idx;
    int last;
    bool complete = false;
};

这是multiindex类的最小示例。如果嵌套循环中需要不同的索引,也可以编写decrement方法或使用最后一个索引的向量。

现在一切准备就绪,可以替换嵌套循环了:

std::string s;// From user
Multiindex midx(s.length(), s.length());
while (!midx.isComplete()) { // Your nested loop
    const auto& idx = midx.getIdx();
    for (int i = 0; i < idx.size(); ++i) { // Replacement for cout << s[i] << s[j] << ... << s[z] << endl;
        std::cout << s[idx[i]];
    }
    std::cout << std::endl;
    midx.inc();
}