24

Can somebody provide me a link or pseudocode of a function for finding all combinations of k elements out of n? possibly in STL. I don't need to compute n choose k, I need to list all vectors of numbers of size k.

Thanks

Tamas
  • 3,254
  • 4
  • 29
  • 51
Bob
  • 10,741
  • 27
  • 89
  • 143
  • 3
    What does "I don't need to compute n choose k, I need to list all vectors of numbers of size k." mean? In any case, writing a `next_combination` function is [straightforward](http://stackoverflow.com/questions/2211915/combination-and-permutation-in-c/2616837#2616837). – James McNellis Feb 23 '11 at 18:36
  • 7
    Have you tried to do this yourself yet? Sounds like your asking us to do your homework. – prolink007 Feb 23 '11 at 18:37
  • I suggest moving this to http://programmers.stackexchange.com/ – Andrei Duma Feb 23 '11 at 18:39
  • 1
    @Andrei I would posit that this is algorithm oriented, thus making it more suitable for here. Programmers.stackexchange would be like "No one on my team understands combinatorics, how can we educate ourselves on it?" – corsiKa Feb 23 '11 at 18:41
  • @glowcoder ..oow.. I thought this is where implementing is questioned. Sorry ^^ – Andrei Duma Feb 23 '11 at 18:44
  • Well, it kind of is. Implementing an algorithm in code is for SO, no questions asked. From the Programmers FAQ: "Specific programming problem, software algorithms, coding, ask on Stack Overflow." But it's good that you're on the lookout for where to put questions to get them answered the best! :-D – corsiKa Feb 23 '11 at 18:47
  • 1
    possible duplicate of [How can I iterate throught every possible combination of n playing cards](http://stackoverflow.com/questions/5076695/how-can-i-iterate-throught-every-possible-combination-of-n-playing-cards) – Mike Seymour Feb 23 '11 at 20:20
  • Possible duplicate of [Algorithm to return all combinations of k elements from n](http://stackoverflow.com/questions/127704/algorithm-to-return-all-combinations-of-k-elements-from-n) – Daniel Wolf Dec 29 '16 at 11:25

5 Answers5

26

In C++ given the following routine:

template <typename Iterator>
inline bool next_combination(const Iterator first, Iterator k, const Iterator last)
{
   /* Credits: Thomas Draper */
   if ((first == last) || (first == k) || (last == k))
      return false;
   Iterator itr1 = first;
   Iterator itr2 = last;
   ++itr1;
   if (last == itr1)
      return false;
   itr1 = last;
   --itr1;
   itr1 = k;
   --itr2;
   while (first != itr1)
   {
      if (*--itr1 < *itr2)
      {
         Iterator j = k;
         while (!(*itr1 < *j)) ++j;
         std::iter_swap(itr1,j);
         ++itr1;
         ++j;
         itr2 = k;
         std::rotate(itr1,j,last);
         while (last != j)
         {
            ++j;
            ++itr2;
         }
         std::rotate(k,itr2,last);
         return true;
      }
   }
   std::rotate(first,k,last);
   return false;
}

You can then proceed to do the following:

// 9-choose-3 
std::string s = "123456789";
std::size_t k = 3;
do
{
   std::cout << std::string(s.begin(),s.begin() + k) << std::endl;
}
while(next_combination(s.begin(),s.begin() + k,s.end()));

Or for a std::vector of int's:

// 5-choose-3 
std::size_t n = 5;
std::size_t k = 3;

std::vector<int> ints;
for (int i = 0; i < n; ints.push_back(i++));

do
{
   for (int i = 0; i < k; ++i)
   {
      std::cout << ints[i];
   }
   std::cout << "\n";
}
while(next_combination(ints.begin(),ints.begin() + k,ints.end()));
  • Can you provide some intuition as to how your code works? I'm trying to follow the logic but I honestly don't have any reason to believe that it works. – templatetypedef Feb 23 '11 at 21:20
  • 5
    @templatetypedef: If you print out the whole string in the first example, you might see how the algorithm operates. The string contains of two sorted halves at any time. – UncleBens Feb 24 '11 at 11:03
  • Might be worthy of note that the do...while is incorrect when k equals zero, as no combinations should be generated then. – Alexander Kjäll May 14 '13 at 19:27
  • 2
    That code above has some kind of mistake due to unused assignment and modification of itr1: itr1 = last; --itr1; itr1 = k; – ThreeBit Feb 16 '14 at 07:18
11

http://howardhinnant.github.io/combinations.html

Search for "for_each_combination". If you find something faster, please let me know. Unlike other algorithms I often see, this one doesn't require the element type to be LessThanComparable.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • As usual, your library is amazing. Ty. One wouldn't mind the addition of std::execution::par to the loops [wink wink] – scx Apr 03 '19 at 03:55
3

Create an auxiliary vector with n - k zeros followed by k ones. A zero means the element in the original container is not included, whereas one means the element is included.

Now use std::next_permutation on the auxiliary vector to get the next combination.

user515430
  • 3,341
  • 2
  • 17
  • 13
1

Here is a lazy example of pseudocode that can get the job done...

void nChooseK(array[n],k){
    recurse("",array[n],k);      
}

void recurse(initialString,array[n],k){
    if(k == 0){
        print initialString;
        return;
     }
    for(i=0;i<n;i++){
        tmpArray = array[0...i-1]+array[i+1...];//the array without the object to remove
        recurse(initialString + array[i], tmpArray,k-1)
    }        
}
nosirrahcd
  • 1,467
  • 3
  • 18
  • 36
0

You could use std::next_permutation but it is n! and not n choose k. You could filter them after you created them. But this solution is O(n!), not really perfect. Here is the trial and error solution:

int factorial(int value)
{
    int result = 1;

    for(int i = 1; i <= value; i++)
    {
        result *= i;
    }

    return result;
}

std::set<std::set<int>> binomial_coefficient(std::vector<int> input, int k)
{
    std::set<std::set<int>> solutions;

    for(unsigned int i = 0; i < factorial(input.size()); i++)
    {
        std::next_permutation(input.begin(), input.end());

        solutions.insert(std::set<int>(input.begin(), input.begin() + k));
    }

    return solutions;
}
Fox32
  • 13,126
  • 9
  • 50
  • 71
  • 3
    Slowing an algorithm down by a factor of `n!` is worse than "not really perfect". For any reasonable value of `n`, it means it won't finish before the death of the universe. Although, in this case, the `factorial` function will simply overflow the range of `int` and produce garbage. – Mike Seymour Feb 23 '11 at 23:39