I have the following code, that generates a combination of numbers/indices for variable nested for loops
#include <iostream>
#include <array>
template<size_t ... Rest>
inline void index_generator() {
constexpr int size = sizeof...(Rest);
std::array<int,size> maxes = {Rest...};
std::array<int,size> a;
int i,j;
std::fill(a.begin(),a.end(),0);
while(1)
{
for(i = 0; i<size; i++) {
std::cout << a[i] << " ";
}
std::cout << "\n";
for(j = size-1 ; j>=0 ; j--)
{
if(++a[j]<maxes[j])
break;
else
a[j]=0;
}
if(j<0)
break;
}
}
int main()
{
index_generator<2,3,3>();
return 0;
}
which outputs the following
0 0 0
0 0 1
0 0 2
0 1 0
0 1 1
0 1 2
0 2 0
0 2 1
0 2 2
1 0 0
1 0 1
1 0 2
1 1 0
1 1 1
1 1 2
1 2 0
1 2 1
1 2 2
this is indeed equivalent to having
for (int i=0; i<2; ++i)
for (int j=0; j<3; ++j)
for (int k=0; i<3; ++k)
I can generate the equivalent of any number of nested for loops using the above method, however I have noticed that as the number of loops increase this code performs slower and slower, compared to its equivalent counterpart (i.e. nested for loops). I have checked both with gcc 5.3 and clang 3.8. Maybe this is due the processor having a hard time predicting the branch in while(true) or maybe its something else.
What I do in the innermost loops is typically access the data from two arrays and do multiplications on them something like c_ptr[idx] +=a_ptr[idx]*b_ptr[idx]. Since the indices generated using both nested for loops and using the above technique is the same, the memory access pattern remains the same. So I am quite sure this is not a cache miss/hit problem as far as data access is concerned.
So my question is:
Is there a way to generate these combination/indices as fast as the nested for loop style code or potentially even faster?
Since we know the number of for loops to set up and the indices of the for loop are known at compile time, can better optimisation opportunities not be exploited? SIMD for instance?
You can generate it with a single loop of the multiplication of all the dimensions and use modulo for the final indices.
#include <iostream>
#include <array>
template<size_t ... Rest>
inline void index_generator( ) {
constexpr int size = sizeof...( Rest );
std::array<int, size> maxes = { Rest... };
int total = 1;
for (int i = 0; i<size; ++i) {
total *= maxes[i];
}
for (int i = 0; i < total; ++i) {
int remaining = total;
for (int n = 0; n < size; ++n) {
remaining /= maxes[n];
std::cout << ( i / remaining ) % maxes[n] << " ";
}
std::cout << std::endl;
}
}
Or just generate recursive templates to actually produce nested loops and let the compiler optimize it for you. It depends on the actual usage of the indices. Right now your function is not too useful.
EDIT:
Benchmarked the three solution, first is the one in the question, the second is mine without the arrays, and thirs is recursive templates. The last one has a fault that its a bit harder to access the actual parameters to use, but not impossible. Also had to add a sum calculation to not suffer from being optimized out, and had to remove the console output to reduce the effect of that in the benchmark. The results are from my i7 machine release mode (VS 2015 community) and with the given setup below. The LOG and PROFILE_SCOPE are my macros.
#include <array>
// Original from the question
template<size_t ... Rest>
inline void index_generator1( ) {
constexpr int size = sizeof...( Rest );
std::array<int, size> maxes = { Rest... };
std::array<int, size> a;
int i, j;
std::fill( a.begin( ), a.end( ), 0 );
int x = 0;
while (1) {
for (i = 0; i < size; i++) {
x += a[i];
}
for (j = size - 1; j >= 0; j--) {
if (++a[j] < maxes[j])
break;
else
a[j] = 0;
}
if (j < 0)
break;
}
LOG( x )
}
// Initial try
template<size_t ... Rest>
inline void index_generator2( ) {
constexpr int size = sizeof...( Rest );
int x = 0;
std::array<int, size> maxes = { Rest... };
int total = 1;
for (int i = 0; i < size; ++i) {
total *= maxes[i];
}
for (int i = 0; i < total; ++i) {
int remaining = total;
for (int n = 0; n < size; ++n) {
remaining /= maxes[n];
x += ( i / remaining ) % maxes[n];
}
}
LOG(x)
}
// Recursive templates
template <int... Args>
struct Impl;
template <int First, int... Args>
struct Impl<First, Args...>
{
static int Do( int sum )
{
int x = 0;
for (int i = 0; i < First; ++i) {
x += Impl<Args...>::Do( sum + i );
}
return x;
}
};
template <>
struct Impl<>
{
static int Do( int sum )
{
return sum;
}
};
template <int... Args>
void index_generator3( )
{
LOG( Impl<Args...>::Do( 0 ) );
}
Executed code
{
PROFILE_SCOPE( Index1 )
index_generator1<200, 3, 400, 20>( );
}
{
PROFILE_SCOPE( Index2 )
index_generator2<200, 3, 400, 20>( );
}
{
PROFILE_SCOPE( Index3 )
index_generator3<200, 3, 400, 20>( );
}
Result in console:
[19:35:50]: 1485600000
[19:35:50]: 1485600000
[19:35:50]: 1485600000
[19:35:56]: PerCall(ms)
[19:35:56]: Index1 10.4016
[19:35:56]: Index2 75.3770
[19:35:56]: Index3 4.2299
Related
I decide 2D Dinamic Coding on C++, i'm decide task about count of ways to bottom-right field in table, and my program return %. Why?
Program:
#include <iostream>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
int arr[n][m];
for (int i = 0; i < n; i++)
arr[i][0] = 1;
for (int i = 0; i < m; i++)
arr[0][i] = 1;
for (int i = 1; i < n; i++) {
for (int j = 1; j < m; j++)
arr[i][j] = arr[i-1][j] + arr[i][j-1];
}
cout << arr[n-1][m-1];
}
I would like answer
Request:
1 10
Response:
1
Your program has undefined behavior for any other sizes than n = 1 and m = 1 because you leave the non-standard VLA (variable length array) arr's positions outside arr[0][0] uninitialized and later read from those positions. If you want to continue using these non-standard VLA:s, you need to initialize them after constructing them. Example:
#include <cstring> // std::memset
// ...
int arr[n][m];
std::memset(arr, 0, sizeof arr); // zero out the memory
// ...
Another approach that would both make it initialized and be compliant with standard C++ would be to use std::vectors instead:
#include <vector>
// ...
std::vector<std::vector<int>> arr(n, std::vector<int>(m));
// ...
A slightly more cumbersome approach is to store the data in a 1D vector inside a class and provide methods of accessing the data as if it was stored in a 2D matrix. A class letting you store arbitrary number of dimensions could look something like below:
#include <utility>
#include <vector>
template <class T, size_t Dim> // number of dimensions as a template parameter
class matrix {
public:
template <class... Args>
matrix(size_t s, Args&&... sizes) // sizes of all dimensions
: m_data(s * (... * sizes)), // allocate the total amount of data
m_sizes{s, static_cast<size_t>(sizes)...}, // store sizes
m_muls{static_cast<size_t>(sizes)..., 1} // and multipliers
{
static_assert(sizeof...(Args) + 1 == Dim);
for (size_t i = Dim - 1; i--;)
m_muls[i] *= m_muls[i + 1]; // calculate dimensional multipliers
}
template <size_t D> size_t size() const { return m_sizes[D]; }
size_t size(size_t D) const { return m_sizes[D]; }
// access the data using (y,z) instead of [y][x]
template <class... Args>
T& operator()(Args&&... indices) {
static_assert(sizeof...(Args) == Dim);
return op_impl(std::make_index_sequence<Dim>{}, indices...);
}
private:
template <std::size_t... I, class... Args>
T& op_impl(std::index_sequence<I...>, Args&&... indices) {
return m_data[(... + (indices * m_muls[I]))];
}
std::vector<T> m_data;
size_t m_sizes[Dim];
size_t m_muls[Dim];
};
With such a wrapper, you'd only need to change the implementation slightly:
#include <iostream>
int main() {
int n, m;
if(!(std::cin >> n >> m && n > 0 && m > 0)) return 1;
matrix<int, 2> arr(n, m);
for (int i = 0; i < arr.size<0>(); i++)
arr(i, 0) = 1;
for (int i = 0; i < arr.size<1>(); i++)
arr(0, i) = 1;
for (int i = 1; i < n; i++) {
for (int j = 1; j < m; j++)
arr(i, j) = arr(i - 1, j) + arr(i, j - 1);
}
std::cout << arr(n - 1, m - 1) << '\n';
}
I have a piece of code as follows, and the number of for loops is determined by n which is known at compile time. Each for loop iterates over the values 0 and 1. Currently, my code looks something like this
for(int in=0;in<2;in++){
for(int in_1=0;in_1<2;in_1++){
for(int in_2=0;in_2<2;in_2++){
// ... n times
for(int i2=0;i2<2;i2++){
for(int i1=0;i1<2;i1++){
d[in][in_1][in_2]...[i2][i1] =updown(in)+updown(in_1)+...+updown(i1);
}
}
// ...
}
}
}
Now my question is whether one can write it in a more compact form.
The n bits in_k can be interpreted as the representation of one integer less than 2^n.
This allows easily to work with a 1-D array (vector) d[.].
In practice, an interger j corresponds to
j = in[0] + 2*in[1] + ... + 2^n-1*in[n-1]
Moreover, a direct implementation is O(NlogN). (N = 2^n)
A recursive solution is possible, for example using
f(val, n) = updown(val%2) + f(val/2, n-1) and f(val, 0) = 0.
This would correspond to a O(N) complexity, at the condition to introduce memoization, not implemented here.
Result:
0 : 0
1 : 1
2 : 1
3 : 2
4 : 1
5 : 2
6 : 2
7 : 3
8 : 1
9 : 2
10 : 2
11 : 3
12 : 2
13 : 3
14 : 3
15 : 4
#include <iostream>
#include <vector>
int up_down (int b) {
if (b) return 1;
return 0;
}
int f(int val, int n) {
if (n < 0) return 0;
return up_down (val%2) + f(val/2, n-1);
}
int main() {
const int n = 4;
int size = 1;
for (int i = 0; i < n; ++i) size *= 2;
std::vector<int> d(size, 0);
for (int i = 0; i < size; ++i) {
d[i] = f(i, n);
}
for (int i = 0; i < size; ++i) {
std::cout << i << " : " << d[i] << '\n';
}
return 0;
}
As mentioned above, the recursive approach allows a O(N) complexity, at the condition to implement memoization.
Another possibility is to use a simple iterative approach, in order to get this O(N) complexity.
(here N represents to total number of data)
#include <iostream>
#include <vector>
int up_down (int b) {
if (b) return 1;
return 0;
}
int main() {
const int n = 4;
int size = 1;
for (int i = 0; i < n; ++i) size *= 2;
std::vector<int> d(size, 0);
int size_block = 1;
for (int i = 0; i < n; ++i) {
for (int j = size_block-1; j >= 0; --j) {
d[2*j+1] = d[j] + up_down(1);
d[2*j] = d[j] + up_down(0);
}
size_block *= 2;
}
for (int i = 0; i < size; ++i) {
std::cout << i << " : " << d[i] << '\n';
}
return 0;
}
You can refactor your code slightly like this:
for(int in=0;in<2;in++) {
auto& dn = d[in];
auto updown_n = updown(in);
for(int in_1=0;in_1<2;in_1++) {
// dn_1 == d[in][in_1]
auto& dn_1 = dn[in_1];
// updown_n_1 == updown(in)+updown(in_1)
auto updown_n_1 = updown_n + updown(in_1);
for(int in_2=0;in_2<2;in_2++) {
// dn_2 == d[in][in_1][in_2]
auto& dn_2 = dn_1[in_2];
// updown_n_2 == updown(in)+updown(in_1)+updown(in_2)
auto updown_n_2 = updown_n_1 + updown(in_2);
.
.
.
for(int i2=0;i2<2;i1++) {
// d2 == d[in][in_1][in_2]...[i2]
auto& d2 = d3[i2];
// updown_2 = updown(in)+updown(in_1)+updown(in_2)+...+updown(i2)
auto updown_2 = updown_3 + updown(i2);
for(int i1=0;i1<2;i1++) {
// d1 == d[in][in_1][in_2]...[i2][i1]
auto& d1 = d2[i1];
// updown_1 = updown(in)+updown(in_1)+updown(in_2)+...+updown(i2)+updown(i1)
auto updown_1 = updown_2 + updown(i1);
// d[in][in_1][in_2]...[i2][i1] = updown(in)+updown(in_1)+...+updown(i1);
d1 = updown_1;
}
}
}
}
}
And make this into a recursive function now:
template<std::size_t N, typename T>
void loop(T& d) {
for (int i = 0; i < 2; ++i) {
loop<N-1>(d[i], updown(i));
}
}
template<std::size_t N, typename T, typename U>
typename std::enable_if<N != 0>::type loop(T& d, U updown_result) {
for (int i = 0; i < 2; ++i) {
loop<N-1>(d[i], updown_result + updown(i));
}
}
template<std::size_t N, typename T, typename U>
typename std::enable_if<N == 0>::type loop(T& d, U updown_result) {
d = updown_result;
}
If your type is int d[2][2][2]...[2][2]; or int*****... d;, you can also stop when the type isn't an array or pointer instead of manually specifying N (or change for whatever the type of d[0][0][0]...[0][0] is)
Here's a version that does that with a recursive lambda:
auto loop = [](auto& self, auto& d, auto updown_result) -> void {
using d_t = typename std::remove_cv<typename std::remove_reference<decltype(d)>::type>::type;
if constexpr (!std::is_array<d_t>::value && !std::is_pointer<d_t>::value) {
// Last level of nesting
d = updown_result;
} else {
for (int i = 0; i < 2; ++i) {
self(self, d[i], updown_result + updown(i));
}
}
};
for (int i = 0; i < 2; ++i) {
loop(loop, d[i], updown(i));
}
I am assuming that it is a multi-dimensional matrix. You may have to solve it mathematically first and then write the respective equations in the program.
Minutes ago, I was pracitise trival algorithm problem. The codes below(concrete logic of the algorithm problem is not importnant, so all we need to know is codes above main function are just TMP):
#include <array>
#include <algorithm>
#include <iterator>
#include <iostream>
constexpr int digit_in_ones[10] = { 6, 2, 5, 5, 4, 5, 6, 3, 7, 6 };
constexpr int createOneD(int index);
template<int ...>
struct seq
{
};
template<int A, int ...B>
struct gens : gens<A - 1, A - 1, B...>
{
};
template<int ...S>
struct gens<0, S ...>
{
typedef seq<S...> type;
};
template<int N>
class oneDArrayMaker
{
private:
typedef typename gens<N>::type sequence;
template<int ...S>
static constexpr std::array<int, N> make(seq<S ...>)
{
return std::array<int, N>{ {createOneD(S)...}};
}
public:
static constexpr std::array<int, N> oneDArr = make(sequence());
};
template<int N>
constexpr std::array<int, N> oneDArrayMaker<N>::oneDArr;
constexpr int createOneD(int index)
{
return index < 10 ?
digit_in_ones[index] :
digit_in_ones[(index % 100) / 10] + digit_in_ones[index % 10] +
(index >= 100 ? digit_in_ones[index / 100] : 0);
}
int main()
{
int n{}, ans{};
scanf("%d", &n);
for (int i = 0; i < 800; i++)
{
for (int j = 0; j < 800; j++)
{
auto temp = oneDArrayMaker<800>::oneDArr[i] + oneDArrayMaker<800>::oneDArr[j] + (i+j < 800 ? oneDArrayMaker<800>::oneDArr[i+j] : 100) + 4;
if (temp == n)
{
ans++;
}
}
}
printf("%d", ans);
}
I knew loop and if(exclude constexpr function and if constexpr) are run-time, not compile time. So tricks like template specialization are substations for if and loop. I learned a lesson about silly usage of if in template programming from this article-
Compile Time Loops with C++11 - Creating a Generalized static_for Implementation, here the codes:
#include <iostream>
template<int index> void do_stuff()
{
std::cout << index << std::endl;
}
template<int max_index, int index = 0> void stuff_helper()
{
if (index <= max_index)
{
do_stuff<index>();
stuff_helper<max_index, index + 1>();
}
}
int main()
{
stuff_helper<100>();
return 0;
}
author's explanation:
On the surface, it could look like the if statement would be responsible for terminating the recursion, like how this would work with a "normal" run-time based recursion algorithm. But that's the problem. What works at runtime doesn't work at compile time.
This is an infinite loop, and only stops because compilers limit themselves to a certain recursion depth. In clang, I get an error fatal error: recursive template instantiation exceeded maximum depth of 256. You can expect a similar error with your compiler of choice.
Oops..., I just state what I have known...
Finally, it comes to my question:
Now that templates's instantiation(specifically, two-parses) is at compile time. So all templates instantiation in the toppest codes should be at compile time:
for (int i = 0; i < 800; i++)
{
for (int j = 0; j < 800; j++)
{
auto temp = oneDArrayMaker<800>::oneDArr[i] + ... // 800 * 800 instantiations should be deternimated at compile time
...
}
...
}
As we known
1. the two for loop here is runtime ahthough it is out of template function/class's definition and just in main function.
2. every auto temp = oneDArrayMaker<800>::oneDArr[i] + ... should be initializated at compile time, so 800 * 800 instantiations should be deternimated at compile time.
Q1: Is runtime loop in main function confliced with 799*799 compile-time template initializations?
My assumption: At compile time, compiler know the depth of the loop, so just unroll the loops, which there is no loop at runtime.
But I maintain that the two loops(i and j) can also not be deternimated at runtime, I change main function to:
int main()
{
int n{}, ans{}, i{}, j{};
scanf("%d", &n);
scanf("%d %d", &i, &j);
std::cout << n << " " << i << " " << j << std::endl;
for (; i < 800; i++)
{
for (; j < 800; j++)
{
auto temp = oneDArrayMaker<800>::oneDArr[i] + oneDArrayMaker<800>::oneDArr[j] + (i+j < 800 ? oneDArrayMaker<800>::oneDArr[i+j] : 100) + 4;
if (temp == n)
{
ans++;
}
}
}
printf("%d", ans);
}
Now i and j have to be deternimated at runtime because of scanf. I just pass extra two 0 to stdin.
Here is live example after alter main function, and output is 12(the right answer is 128)
It compile successfully and no warning is generated. What confuses me is the output is different from the original codes(live code, whose output is 128(equal to the rigth answer).
After dubug, I find the key is after altering codes, for (; i < 800; i++) is only excuate once i = 0, whereas it should have excauted 1~799, that's the reason for 12, not 128.
Q2: If depth of for loop cannot be deternimated at runtime and TMP codes live in loops, what will happen?
Q3: How to explain the output 12
Update:
Q3 has been resolved by #Scott Brown, I'm so careless.
Q1 and Q2 still confuses me
You forget to reset j before 'for (; j < 800; j++)'.
int main()
{
int n{}, ans{}, i{}, j{};
scanf("%d", &n);
scanf("%d %d", &i, &j);
std::cout << n << " " << i << " " << j << std::endl;
int j_orig = j;// here
for (; i < 800; i++)
{
j = j_orig;// and here
for (; j < 800; j++)
{
auto temp = oneDArrayMaker<800>::oneDArr[i] + oneDArrayMaker<800>::oneDArr[j] + (i+j < 800 ? oneDArrayMaker<800>::oneDArr[i+j] : 100) + 4;
if (temp == n)
{
ans++;
}
}
}
printf("%d", ans);
}
So, I was searching for a good solution for my problem.
I need to generate(print) all the combination of a list of integers, for example:
if the array contain integers from 0 to n-1, where n = 5:
int array[] = {0,1,2,3,4};
the order of integers in the combination are NOT important, meaning {1,1,3}, {1,3,1} and {3,1,1} are actually the same combination because they all contain one 3 and two ones.
so for the above array, all combination of length 3:
0,0,0 -> the 1st combination
0,0,1
0,0,2
0,0,3
0,0,4
0,1,1 -> this combination is 0,1,1, not 0,1,0 because we already have 0,0,1.
0,1,2
0,1,3
0,1,4
0,2,2 -> this combination is 0,2,2, not 0,2,0 because we already have 0,0,2.
0,2,3
.
.
0,4,4
1,1,1 -> this combination is 1,1,1, not 1,0,0 because we already have 0,0,1.
1,1,2
1,1,3
1,1,4
1,2,2 -> this combination is 1,2,2, not 1,2,0 because we already have 0,1,2.
.
.
4,4,4 -> Last combination
For Now I Wrote Code for doing this, but my problem is:
if the numbers in the array are not integer from 0 to n-1, lets say if the array was like this
int array[] = {1,3,6,7};
my code doesn't work on this case, any algorithm or code for solving this problem,,
Here is my code :
unsigned int next_combination(unsigned int *ar, int n, unsigned int k){
unsigned int finished = 0;
unsigned int changed = 0;
unsigned int i;
for (i = k - 1; !finished && !changed; i--) {
if (ar[i] < n - 1) {
/* Increment this element */
ar[i]++;
if (i < k - 1) {
/* Make the elements after it the same */
unsigned int j;
for (j = i + 1; j < k; j++) {
ar[j] = ar[j - 1];
}
}
changed = 1;
}
finished = i == 0;
}
if (!changed) {
/* Reset to first combination */
for (i = 0; i < k; i++){
ar[i] = 0;
}
}
return changed;
}
And this is the main:
int main(){
unsigned int numbers[] = {0, 0, 0, 0, 0};
const unsigned int k = 3;
unsigned int n = 5;
do{
for(int i=0 ; i<k ; ++i)
cout << numbers[i] << " ";
cout << endl;
}while (next_combination(numbers, n, k));
return 0;
}
If you have working code to generate all combinations of numbers from 0 to n-1, then this is very simple. You have your array of numbers:
int array[] = {1,3,6,7};
Now, take n = 4, because there are 4 items in the array. Generate all combinations from 0 to 3, and use those as indices into your array. You now have all combinations of your array values by using all combinations of indices into that array.
This code requires that the "element pool" array be sorted from minimum to maximum, with no duplicate entries.
The function first_combination initializes the result array ("dist") to the first combination. After this, next_combination is called in a loop until it returns false (just like in your example). The "n" and "k" arguments have been replaced with template parameters that pick up the arrays' sizes -- so the enumeration functions need the pool array in addition to the result.
#include <iostream>
template<typename T, int N, int K>
void first_combination(const T (&pool)[N], T (&dist)[K]) {
for(int ki=0; ki<K; ++ki) {
dist[ki] = pool[0];
}
}
template<typename T, int N, int K>
bool next_combination(const T (&pool)[N], T (&dist)[K]) {
int ni = 0;;
int ki = 0;
for(;;) {
const int prev_ni = ni;
// search the pool for the value in this slot
for(ni=0; pool[ni] != dist[ki]; ++ni) {
if(ni == N) return false; // slot contains a value not found in the pool
}
if(++ni < N) break;
ni = 0;
dist[ki] = pool[0];
if(++ki == K) return false;
}
int v = pool[ni];
dist[ki] = v;
// code below assumes pool[] is sorted
for(--ki; ki>=0; --ki) {
if(dist[ki] < v) {
dist[ki] = v;
}
else {
v = dist[ki];
}
}
return true;
}
template<typename T, int COUNT>
void dumparray( T (&dist)[COUNT]) {
std::cout << '{';
for(int i=0; i<COUNT; ++i) {
if(i) std::cout << ',';
std::cout << dist[i];
}
std::cout << '}' << std::endl;
}
int main(int argc, char* argv[]) {
const int pool[] = {1,3,6,7};
int dist[3] = {0};
first_combination(pool, dist);
do {
dumparray(dist);
} while(next_combination(pool, dist));
return 0;
}
So you need program for generating combination (wiki link).
Here you have complete description and even ready to use algorithm: http://compprog.wordpress.com/2007/10/17/generating-combinations-1/
How can I loop through all combinations of n playing cards in a standard deck of 52 cards?
You need all combinations of n items from a set of N items (in your case, N == 52, but I'll keep the answer generic).
Each combination can be represented as an array of item indexes, size_t item[n], such that:
0 <= item[i] < N
item[i] < item[i+1], so that each combination is a unique subset.
Start with item[i] = i. Then to iterate to the next combination:
If the final index can be incremented (i.e. item[n-1] < N-1), then do that.
Otherwise, work backwards until you find an index that can be incremented, and still leave room for all the following indexes (i.e. item[n-i] < N-i). Increment that, then reset all the following indexes to the smallest possible values.
If you can't find any index that you can increment (i.e. item[0] == N-n), then you're done.
In code, it might look something vaguely like this (untested):
void first_combination(size_t item[], size_t n)
{
for (size_t i = 0; i < n; ++i) {
item[i] = i;
}
}
bool next_combination(size_t item[], size_t n, size_t N)
{
for (size_t i = 1; i <= n; ++i) {
if (item[n-i] < N-i) {
++item[n-i];
for (size_t j = n-i+1; j < n; ++j) {
item[j] = item[j-1] + 1;
}
return true;
}
}
return false;
}
It might be nice to make it more generic, and to look more like std::next_permutation, but that's the general idea.
This combinations iterator class is derived from the previous answers posted here.
I did some benchmarks and it is a least 3x faster than any next_combination() function you would have used before.
I wrote the code in MetaTrader mql4 to do testing of triangular arbitrage trading in forex. I think you can port it easily to Java or C++.
class CombinationsIterator
{
private:
int input_array[];
int index_array[];
int m_indices; // K
int m_elements; // N
public:
CombinationsIterator(int &src_data[], int k)
{
m_indices = k;
m_elements = ArraySize(src_data);
ArrayCopy(input_array, src_data);
ArrayResize(index_array, m_indices);
// create initial combination (0..k-1)
for (int i = 0; i < m_indices; i++)
{
index_array[i] = i;
}
}
// https://stackoverflow.com/questions/5076695
// bool next_combination(int &item[], int k, int N)
bool advance()
{
int N = m_elements;
for (int i = m_indices - 1; i >= 0; --i)
{
if (index_array[i] < --N)
{
++index_array[i];
for (int j = i + 1; j < m_indices; ++j)
{
index_array[j] = index_array[j - 1] + 1;
}
return true;
}
}
return false;
}
void get(int &items[])
{
// fill items[] from input array
for (int i = 0; i < m_indices; i++)
{
items[i] = input_array[index_array[i]];
}
}
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
// driver program to test above class
#define N 5
#define K 3
void OnStart()
{
int x[N] = {1, 2, 3, 4, 5};
CombinationsIterator comboIt(x, K);
int items[K];
do
{
comboIt.get(items);
printf("%s", ArrayToString(items));
} while (comboIt.advance());
}
Output:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
#include <iostream>
#include <vector>
using namespace std;
class CombinationsIndexArray {
vector<int> index_array;
int last_index;
public:
CombinationsIndexArray(int number_of_things_to_choose_from, int number_of_things_to_choose_in_one_combination) {
last_index = number_of_things_to_choose_from - 1;
for (int i = 0; i < number_of_things_to_choose_in_one_combination; i++) {
index_array.push_back(i);
}
}
int operator[](int i) {
return index_array[i];
}
int size() {
return index_array.size();
}
bool advance() {
int i = index_array.size() - 1;
if (index_array[i] < last_index) {
index_array[i]++;
return true;
} else {
while (i > 0 && index_array[i-1] == index_array[i]-1) {
i--;
}
if (i == 0) {
return false;
} else {
index_array[i-1]++;
while (i < index_array.size()) {
index_array[i] = index_array[i-1]+1;
i++;
}
return true;
}
}
}
};
int main() {
vector<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);
a.push_back(4);
a.push_back(5);
int k = 3;
CombinationsIndexArray combos(a.size(), k);
do {
for (int i = 0; i < combos.size(); i++) {
cout << a[combos[i]] << " ";
}
cout << "\n";
} while (combos.advance());
return 0;
}
Output:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
I see this problem is essentially the same as the power set problem. Please see Problems with writing powerset code to get an elegant solution.