A: 

Here's a relatively simple/efficient nCr program I wrote a while ago in C:

main(n,k){float t=0,r=1;for(scanf("%d, %d",&n,&k);t++<k;r*=(1+n-t)/t);printf("%.0f\n",r);}

Okay ... readable version. =] (Not sure if this is 1:1 corresponding with the above.)

void nCr(int n, int k) {
    float curK = 0, r = 1;
    while(curK < k) {
        ++curK;
        printf("%.0f\n", r);
        r *= (1 + n - curK) / curK;
    }
}

Instead of printing, you could yield or whatever (I don't know C#) into your list.

strager
As I understand it, this code prints the amount of possible combinations (aka nCr) for each r up to k. I fail to see how to change it to print *every* combination, without ending up to something similar to my algorithm (k nested for loops). Can you please elaborate on this?
Asaf R
A: 

Asaf,

You are asking us to evaluate your algorithm, but you don't explain your algorithm -- not even in code comments. So you want everyone to spend an hour or more reverse engineering the algorithm from the code, just so we can understand your question before we answer it?

Please edit your question to explain your algorithm.

One thing is obvious -- the memory footprint of your code is horrendous. For even modest values of n, the number of combinatations will easily be in the billions, which will require more memory than most computers have. Plus you are using dynamically grown arrays, which keep reallocating and copying themselves as they grow. Plus your program generates subsets in different arrays and merges them. All in all, your program will require many times the amount of memory that would be ideally needed to store the list, and it will spend most of it's time just copying data back and forth.

If you must have all the values in an array at once, at least start off by computing the size of the array you need -- n! / (n-k)! / k! -- and then just filling it in.

Even better would be code that "lazily" just computed each member of the sequence as it was needed. See this question from the related questions sidebar

Die in Sente
You're right on both - the footprint and explaining the algorithm. I don't mind the first as I wrote this for pure fun. I edited to add an explanation.
Asaf R
The question you referred me to relates to a slightly different problem, but I do agree that "lazy" computation will save space.Thanks!
Asaf R
A: 

Donald Knuth has a section on "Generating all Combinations" in The Art of Computer Programming. You can download it here: TAOCP v4 f3 [ps]

Imran
+5  A: 

In C++ given the following routine:

template <typename Iterator>
bool next_combination(const Iterator first, Iterator k, const Iterator last)
{
   /* Credits: Mark Nelson http://marknelson.us */
   if ((first == last) || (first == k) || (last == k))
      return false;
   Iterator i1 = first;
   Iterator i2 = last;
   ++i1;
   if (last == i1)
      return false;
   i1 = last;
   --i1;
   i1 = k;
   --i2;
   while (first != i1)
   {
      if (*--i1 < *i2)
      {
         Iterator j = k;
         while (!(*i1 < *j)) ++j;
         std::iter_swap(i1,j);
         ++i1;
         ++j;
         i2 = k;
         std::rotate(i1,j,last);
         while (last != j)
         {
            ++j;
            ++i2;
         }
         std::rotate(k,i2,last);
         return true;
      }
   }
   std::rotate(first,k,last);
   return false;
}

You can then proceed to do the following:

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()));
Beh Tou Cheh
A: 

This guy seems to have done serious work in combinatorics using C# (CodeProject) :

Permutations, Combinations, and Variations using C# Generics

ohadsc