std::next_permutation (and std::prev_permutation) permute all values in the range [first, last) given for a total of n! permutations (assuming that all elements are unique).
is it possible to write a function like this:
template<class Iter> bool next_permutation(Iter first, Iter last, Iter choice_last);
That permutes the elements in the range [first, last) but only chooses elements in the range [first, choice_last). ie we have maybe 20 elements and want to iterate through all permutations of 10 choices of them, 20 P 10 options vs 20 P 20.
- Iter is a random access iterator for my purposes, but if it can be implemented as a bidirectional iterator, then great!
- The less amount of external memory needed the better, but for my purposes it doesn’t matter.
- The chosen elements on each iteration are input to the first elements of the sequence.
Is such a function possible to implement? Does anyone know of any existing implementations?
Here is essentially what I am doing to hack around this. Suggestions on how to improve this are also welcome.
- Start with a vector
VofNelements of which I want to visit each permutation ofRelements chosen from it (R <= N). - Build a vector
Iof lengthRwith values{ 0, 1, 2, ... R - 1 }to serve as an index to the elements ofV - On each iteration, build a vector
Cof lengthRwith values{ V[I[0]], V[I[1]], ... V[I[R - 1]] } - Do something with the values in
C. - Apply a function to permute the elements of
Iand iterate again if it was able to.
That function looks like this:
bool NextPermutationIndices(std::vector<int> &I, int N) { const int R = I.size(); for (int i = R - 1; ; --i) { if (I[i] < N - R + i) { ++I[i]; return true; } if (i == 0) return false; if (I[i] > I[i-1] + 1) { ++I[i-1]; for (int j = i; j < R; ++j) I[j] = I[j-1] + 1; return true; } } }
That function is very complicated due to all the possible off-by-one errors, as well everything using it are more complicated than is probably necessary.
EDIT:
It turns out that it was significantly easier than I had even imagined. From here, I was able to find exact implementations of many of the exact algorithms I needed (combinations, permutations, etc.).
template<class BidirectionalIterator> bool next_partial_permutation(BidirectionalIterator first, BidirectionalIterator middle, BidirectionalIterator last) { std::reverse(middle, last); return std::next_permutation(first, last); }
Plus there is a combination algorithm there that works in a similar way. The implementation of that is much more complication though.
To iterate over nPk permutations, I’ve used the
for_each_permutation()algorithm presented in this old CUJ article before. It uses a nice algorithm from Knuth which rotates the elements in situ, leaving them in the original order at the end. Therefore, it meets your no external memory requirement. It also works for BidirectionalIterators. It doesn’t meet your requirement of looking likenext_permutation(). However, I think this is a win – I don’t like stateful APIs.