Generating all the values of N nested for loops

…衆ロ難τιáo~ 提交于 2019-12-11 13:58:02

问题


I would like to write a function to do the following, given two arguments to the function int K and int nest_level generate all possible points that result from creating nest_level nested loops where each loop ranges from -K to K. For example if k = 5 and nest_level = 3 the function prints the sequences of numbers that result from the following:

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)

This should work for any K and nest_level

From my research, I understand this should be a recursive solution but i'm having difficulty implementing it specifically in C++.


回答1:


Use a std::vector. Pass it by reference. In a loop of i from -k to k:

  • push i into it.

  • If length of vector equals nest level, print.

  • Otherwise, recurse, passing in the vector by reference.

  • Now, pop the last element off the end of the vector, and continue the loop.




回答2:


Another way to think about this problem is that you are working with a number where each digit ranges from -K to K. You can increment (-K)(-K)(-K)...(-K)(-K)(-K) up to KKK...KKK and print the intermediate results.

#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;
}

I'm not sure which way is better but I figured it was a neat parallel.




回答3:


Something like this, you need a container to store number

#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:


From my research, I understand this should be a recursive solution

Not at all.
Note that if you don't use recursion unnecessarily, you can avoid certain potential problems (recursion levels and stack growth per level) and it is often easier to understand the code.

Let's take a look at what you're doing. If we ignore the negative numbers for the moment, you're basically generating the following sequence (for 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

If k were 9 you'd simply be counting in decimal. Of all the children I've seen learn to count, I've never known any to do so using recursion. ;) If you step back and think about how you learnt to count big numbers, you should find a much simpler solution.... But I'll save that for later.

If you count in binary it would look as follows:

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

Or count with k=1 and n=3 (using -k to 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

So if you're feeling adventurous, you can:

  • easily calculate the number of permutations to output
  • use a simple loop to cycle through the range
  • convert each number into base k*2+1
  • offset each digit by subtracting k

Of course there's also the simpler approach hinted at earlier. Call Counter(k, nest_level); in the code below. (Explanation after)

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);
}
  • Counter initialises a vector with size == nest_level and each element containing -k.
  • In a loop it calls VectorInc to simulate adding 1 (or counting).
  • VectorInc is a very simple function that loops through the vector elements from right to left for as long as it needs to perform a "carry-over".
  • It updates the current element by adding 1.
  • But if the current element it at the maximum k, it should rollover back to -k, and "carry-over" +1 to the digit on the left.
  • When the vector eventually reaches {k, k, k, ..., k}, adding 1 rolls every digit back to -k and VectorInc returns false indicating there was an overflow.

Pros: Simple, no recursion, and will work with pretty much any values of k & n.
Cons: Will work with pretty much any values of k & n. Try a seemingly innocuous call like Counter(10, 80) and you'll spend a long time waiting for your program to count the atoms in the universe.



来源:https://stackoverflow.com/questions/37312388/generating-all-the-values-of-n-nested-for-loops

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!