问题
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 withsize == 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
andVectorInc
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