I found that using a recursive function is not suitable for long lengths and integers, because it digests too much RAM, and using a generator / renewable function (which gives values) was too slow and required a large library to make it cross-platform.
So, here is a non-recursive solution in C ++ that creates partitions in sorted order (which is also ideal for permutations). I found this to be more than 10 times faster than the seemingly smart and concise recursive solutions that I tried for section lengths of 4 or more, but for lengths 1-3 the performance is not always better (and I don't care about the short length, because they are fast with any approach).
// Inputs unsigned short myInt = 10; unsigned short len = 3; // Partition variables. vector<unsigned short> partition(len); unsigned short last = len - 1; unsigned short penult = last - 1; short cur = penult; // Can dip into negative value when len is 1 or 2. Can be changed to unsigned if len is always >=3. unsigned short sum = 0; // Prefill partition with 0. fill(partition.begin(), partition.end(), 0); do { // Calculate remainder. partition[last] = max(0, myInt - sum); // Would only need "myInt - sum" if partition vector contains signed ints. /* * * DO SOMETHING WITH "partition" HERE. * */ if (partition[cur + 1] <= partition[cur] + 1) { do { cur--; } while ( cur > 0 && accumulate(partition.cbegin(), partition.cbegin() + cur, 0) + (len - cur) * (partition[cur] + 1) > myInt ); // Escape if seeked behind too far. // I think this if-statement is only useful when len is 1 or 2, can probably be removed if len is always >=3. if (cur < 0) { break; } // Increment the new cur position. sum++; partition[cur]++; // The value in each position must be at least as large as the // value in the previous position. for (unsigned short i = cur + 1; i < last; ++i) { sum = sum - partition[i] + partition[i - 1]; partition[i] = partition[i - 1]; } // Reset cur for next time. cur = penult; } else { sum++; partition[penult]++; } } while (myInt - sum >= partition[penult]);
Where I wrote DO SOMETHING WITH "partition" HERE. where you actually consume value. (At the last iteration, the code will continue the rest of the loop, but I found it to be better than constantly checking the exit conditions - it is optimized for large operations)
0,0,10 0,1,9 0,2,8 0,3,7 0,4,6 0,5,5 1,1,8 1,2,7 1,3,6 1,4,5 2,2,6 2,3,5 2,4,4 3,3,4
Oh, I used "unsigned short" because I know that my length and integer will not exceed certain limits, change this if it does not suit you :) Check the comments; one variable there (cur) had to be signed to handle lengths 1 or 2, and there is a corresponding if-statement that comes with it, and I also noted in the comment that if your section vector has signed ints, there is another line which can be simplified.
To get all the compositions, in C ++ I would use this simple permutation strategy, which, fortunately, does not give duplicates:
do { // Your code goes here. } while (next_permutation(partition.begin(), partition.end()));
The socket that is in DO SOMETHING WITH "partition" is HERE and you will go well.
An alternative to finding songs (based on Java code here https://www.nayuki.io/page/next-lexicographical-permutation-algorithm ) is the following. I found this to work better than next_permutation ().
// Process lexicographic permutations of partition (compositions). composition = partition; do { // Your code goes here. // Find longest non-increasing suffix i = last; while (i > 0 && composition[i - 1] >= composition[i]) { --i; } // Now i is the head index of the suffix // Are we at the last permutation already? if (i <= 0) { break; } // Let array[i - 1] be the pivot // Find rightmost element that exceeds the pivot j = last; while (composition[j] <= composition[i - 1]) --j; // Now the value array[j] will become the new pivot // Assertion: j >= i // Swap the pivot with j temp = composition[i - 1]; composition[i - 1] = composition[j]; composition[j] = temp; // Reverse the suffix j = last; while (i < j) { temp = composition[i]; composition[i] = composition[j]; composition[j] = temp; ++i; --j; } } while (true);
You will notice some undeclared variables, just declare them earlier in the code before all your do-loops: i , j , pos and temp (unsigned shorts) and composition (the same type and length as the partition ). You can reuse declaration i to use it in a for loop in a section code snippet. Also pay attention to variables of the last type, which assume that this code is nested in the section code specified earlier.
Again, โYour code goes hereโ is where you consume the composition for your purposes.
For reference, here are my headers.
#include <vector> // for std::vector #include <numeric> // for std::accumulate #include <algorithm> // for std::next_permutation and std::max using namespace std;
Despite a significant increase in speed using these approaches, for any significant integers and partition lengths this will still make you crazy on your CPU :)