5,693,062 members and growing! (17,633 online)
Email Password   helpLost your password?
General Programming » Algorithms & Recipes » Algorithms     Intermediate License: The Code Project Open License (CPOL)

Combinations in C++

By Wong Shao Voon

An article on finding combinations
VC6, VC7, VC7.1, C++Windows, Win2K, WinXP, Win2003, STL, VS6, Visual Studio, Dev

Posted: 31 Jul 2003
Updated: 21 Feb 2008
Views: 94,141
Bookmarked: 36 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
42 votes for this Article.
Popularity: 5.77 Rating: 3.56 out of 5
15 votes, 40.5%
1
1 vote, 2.7%
2
1 vote, 2.7%
3
5 votes, 13.5%
4
15 votes, 40.5%
5

Introduction

Combination is the way of picking a different unique smaller set from a bigger set, without regard to the ordering (positions) of the elements (in the smaller set). This article teaches you how to find combinations. First, I show you the technique to find combinations. Next, I will go on to explain how to use my source code. The source includes a recursive template version and a non-recursive template version. At the end of the article, I will show you how to find permutations of a smaller set from a bigger set, using both next_combination() and next_permutation().

Before all these, let me first introduce to you the technique of finding combinations.

The Technique

The notations used in this article

  • n : n is the larger sequence from which r sequence is picked.
  • r : r is the smaller sequence picked from n sequence.
  • c : c is the formula for the total number of possible combinations of r, picked from n distinct objects : n! / (r! (n-r)! ).
  • The ! postfix means factorial.

Explanation

Let me explain using a very simple example: finding all combinations of 2 from a set of 6 letters {A, B, C, D, E, F}. The first combination is AB and the last is EF.

The total number of possible combinations is: n!/(r!(n-r)!)=6!/(2!(6-2)!)=15 combinations.

Let me show you all the combinations first:

AB
AC
AD
AE
AF
BC
BD
BE
BF
CD
CE
CF
DE
DF
EF

If you can't spot the pattern, here it is:

AB | AB
A  | AC
A  | AD
A  | AE
A  | AF
---|----
BC | BC
B  | BD
B  | BE
B  | BF
---|----
CD | CD
C  | CE
C  | CF
---|----
DE | DE
D  | DF
---|----
EF | EF

The same thing goes to combinations of any number of letters. Let me give you few more examples and now you can figure them out yourself.

Combinations of 3 Letters from {A, B, C, D, E} (Set of 5 Letters)

The total number of possible combinations is: 10

A B C
A B D
A B E
A C D
A C E
A D E
B C D
B C E
B D E
C D E

Combinations of 4 Letters from {A, B, C, D, E, F} (Set of 6 Letters).

The total number of possible combinations is: 15.

A B C D
A B C E
A B C F
A B D E
A B D F
A B E F
A C D E
A C D F
A C E F
A D E F
B C D E
B C D F
B C E F
B D E F
C D E F

I'm thinking if you would have noticed by now, the number of times, a letter appears. The formula for the number of times, a letter appears in all possible combinations is n!/(r!(n-r)!) * r / n == c * r / n. Using the above example, it would be 15 * 4 / 6 = 10 times. All the letters {A, B, C, D, E, F} appear 10 times as shown. You can count them yourself to prove it.

Source Code Section

Please note that all the combination functions are now enclosed in the stdcomb namespace.

The Recursive Way

I have made a recursive function, char_combination() which, as its name implies, takes in character arrays and processes them. The source code and examples of using char_combination() is in char_comb_ex.cpp. I'll stop to mention that function. For now, our focus, is on recursive_combination(), a template function, which I wrote, using char_combination() as a guideline.

The function defined in combination.h as below:

template <class RanIt, class Func>

void recursive_combination(RanIt nbegin, RanIt nend, int n_column,
          RanIt rbegin, RanIt rend, int r_column,int loop, Func func);

The parameters prefixed with 'n' are associated with n sequence, while r-prefix are r sequence related. As an end user, you need not bother about those parameters. What you need to know is func. func is a function defined by you. If the combination function finds combination recursively, so there must exist a way the user can process each combination. The solution is a function pointer which takes in 2 parameters of type RanIt (stands for Random Iterator). You are the one who defines this function. In this way, encapsulation is achieved. You need not know how recursive_combination() internally works, you just know that it calls func whenever there is a different combination, and you just need to define func() function to process the combination. It must be noted that func() should not write to the 2 iterators passed to it.

The typical way of filling out the parameters is n_column and r_column is always 0, loop is number of elements in r sequence minus that of n sequence, func is the function pointer to your function, (nbegin and nend, rbegin and rend are the self-explanatory; they are the first iterators and the one past the last iterators, of the respective sequences).

Just for your information, the maximum number of depth of recursion done is r+1. In the last recursion (r+1 recursion), each new combination is formed.

Examples of using recursive_combination() are in recv_comb_ex.cpp

The Non-Recursive Way

If you have misgivings about using the recursive method, there is a non-recursive template function for you want to choose. (Actually there are 2.)

The parameters are even simpler than the recursive version. Here's the function definition in combination.h

template <class BidIt>

bool next_combination(BidIt n_begin, BidIt n_end,
       BidIt r_begin, BidIt r_end);
       
template <class BidIt>

bool next_combination(BidIt n_begin, BidIt n_end,
       BidIt r_begin, BidIt r_end, Prediate Equal );

And its reverse counterpart version:

template <class BidIt>

bool prev_combination(BidIt n_begin, BidIt n_end,
       BidIt r_begin, BidIt r_end);
       
template <class BidIt>

bool prev_combination(BidIt n_begin, BidIt n_end,
       BidIt r_begin, BidIt r_end, , Prediate Equal );

The parameters, n_begin and n_end are first and the last iterators for the n sequence. And r_begin and r_end are iterators for the r sequence. Equal is the prediate for comparing equality

You can peruse the source code for these 2 functions in combination.h and its examples in next_comb_ex.cpp and prev_comb_ex.cpp, if you want.

A typical way of using next_combination is as below

do

{
  //Do what you want here.

}
while(next_combination(n.begin(),n.end(),r.begin(),r.end() );

Certain Conditions must be Satisfied in Order for next_combination() to Work

  1. All the objects in the n sequence must be distinct.
  2. For next_combination(),the r sequence must be initialized to the first r-th elements of n sequence in the first call. For example, to find combinations of r=4 out of n=6 {1,2,3,4,5,6}, the r sequence must be initialsed to {1,2,3,4} before the first call.
  3. As for prev_combination(),the r sequence must be initialised to the last r-th elements of n sequence in the first call. For example, to find combinations of r=4 out of n=6 {1,2,3,4,5,6}, the r sequence must be initialsed to {3,4,5,6} before the first call.
  4. The n sequence must not change throughout the process of finding all the combinations, else results are wrong (make sense, right?).
  5. next_combination() and prev_combination() operates on data types with the == operator defined. That is to mean if you want to use next_combination() on sequences of objects instead of sequences of POD (Plain Old Data), the class, from these objects are instantiated, must have an overloaded == operator defined or you can use the prediate versions.

When the above conditions are not satisfied, results are undetermined even if the next_combination() and prev_combination() may return true.

Return Value

When next_combination() returns false, no more next combination can be found, r sequence remains unaltered. Same for prev_combination().

Some information about next_combination() and prev_combination()

  1. The n and r sequences need not be sorted to use next_combination() or prev_combination().
  2. next_combination() and prev_combination() do not use any static variables, so it is alright to find combinations of another sequence of different data type, even when the current finding of combinations of the current sequence have not reached the last combination. In other words, no reset is needed for next_combination() and prev_combination().

Examples of how to use these 2 functions are in next_comb_ex.cpp and prev_comb_ex.cpp.

So what we can do with next_combination()?

With next_combination() and next_permutation() from STL algorithms, we can find permutations!!

The formula for total number of permutations of r sequence, picked from n sequence is : n!/(n-r)!

We can call next_combination() first, then next_permutation() iteratively, that way we will find all the permutations. Typical way of using them is as follows:

do

{
  //do your processing on the new combination here

  while(next_permutation(r2.begin(),r2.end()))
  {
    //do your processing on the new permutation here

  }
}
while(next_combination(n.begin(),n.end(),r.begin(),r.end() ));

However, I must mention that there exists a limitation for the above code. The n and r sequences must be sorted in ascending order in order to work. This is because next_permutation() will return false when it encounters the sequence in descending order. The solution to this problem for unsorted sequences is as follows:

do

{
  //do your processing on the new combination here

  for(cnt i=0;cnt<24;++cnt)
  {
    next_permutation(r2.begin(),r2.end());
    //do your processing on the new permutation here

  }
}
while(next_combination(n.begin(),n.end(),r.begin(),r.end() ));

However this method requires you to calculate the number of permutations beforehand.

So how do I prove they are distinct permutations?

There is a set container class in STL we can use. All the objects in the set container are always in sorted order and there are no duplicate objects. For our purpose, we will use this insert() member function.

pair <iterator, bool> insert(const value_type& _Val);

The insert() member function returns a pair, whose bool component returns true if an insertion is made and false if the set already contains an element whose key had an equivalent value in the ordering, and whose iterator component returns the address where a new element is inserted or where the element is already located.

proof.cpp is written for this purpose, using STL set container to prove that the permutations generated are unique. You can play around with this, but you should first calculate the number of permutations which would be generated. Too many permutations may take ages to complete (partly due to working of the set container) or worse, you may run out of memory!

If you are interested, you can proceed to read the 2nd part of the article: Combinations in C++, Part 2

Downloads

Please build them in release build!

History

  • 30 July 2003 - first release on CodeProject
  • 26 November 2006 - Source code changes and bug fixes.
    • All functions are enclosed in the stdcomb namespace
    • Solved a bug in prev_combination that != operator must be defined for the custom class, unless the data type is a POD.
    • next_combination and prev_combination now runs properly in Visual C++ 8.0, without disabling the checked iterator.
    • next_combination and prev_combination have a predicates version.
  • 21 February 2008 - Added the finding combinations of vectors in the source code

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Wong Shao Voon


I am currently working as a software developer in a company specialized in 3D modelling software. My wish is to write a article on GUI since I am specialized in GUI.

Like many Singaporeans, my hobbies include reading, karaoke, watching movies and anime, play games and jogging.

I wish I have more time to write articles for CodeProject since I have a few ideas(long overdue) to write about. And I always explain the working behind the code in my articles. I hope you like my articles on CodeProject!
Occupation: Software Developer
Location: Singapore Singapore

Other popular Algorithms & Recipes articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 40 (Total in Forum: 40) (Refresh)FirstPrevNext
QuestionCombination of vector elementsmembertuxyboy3:45 4 Feb '08  
GeneralRe: Combination of vector elementsmemberWong Shao Voon21:19 13 Feb '08  
GeneralRe: Combination of vector elements [modified]membertuxyboy21:45 9 Jun '08  
GeneralRe: Combination of vector elementsmemberWong Shao Voon1:36 10 Jun '08  
GeneralRe: Combination of vector elementsmembertuxyboy1:13 12 Jun '08  
Generalpermutaion's signaturememberAlexander Arhipenko0:30 30 Nov '06  
GeneralRe: permutaion's signaturememberWong Shao Voon12:44 30 Nov '06  
GeneralRe: permutaion's signaturememberWong Shao Voon21:26 13 Feb '08  
QuestionQuestion about const expression for combination codemembercomputerpublic16:41 28 Nov '06  
AnswerRe: Question about const expression for combination codememberWong Shao Voon17:15 28 Nov '06  
GeneralRe: Question about const expression for combination codemembercomputerpublic17:35 28 Nov '06  
GeneralRe: Question about const expression for combination codememberWong Shao Voon17:44 28 Nov '06  
GeneralRe: Question about const expression for combination codemembercomputerpublic17:50 28 Nov '06  
GeneralRe: Question about const expression for combination codemembercomputerpublic17:58 28 Nov '06  
GeneralRe: Question about const expression for combination codememberWong Shao Voon18:15 28 Nov '06  
GeneralRe: Question about const expression for combination codememberWong Shao Voon18:01 28 Nov '06  
GeneralQuestion about combination code using numbers instead of lettersmembercomputerpublic18:15 23 Nov '06  
GeneralRe: Question about combination code using numbers instead of lettersmemberWong Shao Voon14:11 25 Nov '06  
GeneralRe: Question about combination code using numbers instead of lettersmembercomputerpublic5:06 27 Nov '06  
QuestionCombinations of vector elements.memberBartosz Bien7:17 28 Oct '06  
AnswerRe: Combinations of vector elements.memberWong Shao Voon19:32 29 Oct '06  
GeneralRe: Combinations of vector elements.memberBartosz Bien5:16 2 Dec '06  
GeneralRe: Combinations of vector elements.memberWong Shao Voon20:01 3 Dec '06