Search code examples
c++binarycountingpowerset

Using binary counting to count all subsets of an array


So if I am given an array such as

a = {1, 2, 3} 

We know that the given subarrays (non contiguous included) are (this represents the power set)

{1} {2} {3} {1,2,3} {1,2} {1,3} {2,3}

I also know that these subsets can be represented by counting in binary from

000 -> 111 (0 to 7), where each 1 bit means we 'use' this value from the array
e.g. 001 corresponds to the subset {3}

I know that this method can somehow be used to generate all subsets, but im not really sure how this can be implemented in c++

So basically what I am asking is how can (if it can) binary counting be used to generate power sets?

Any other methods for generating a power set are also much appreciated!


Solution

  • For your example with 3 set elements you can just do this:

    for (s = 1; s <= 7; ++s)
    {
         // ...
    }
    

    Here's a demo program:

    #include <iostream>
    
    int main()
    {
        const int num_elems = 3;                      // number of set elements
        const int elems[num_elems] = { 1, 2, 3 };     // mapping of set element positions to values
    
        for (int s = 1; s < (1 << num_elems); ++s)    // iterate through all non-null sets
        {
            // print the set
            std::cout << "{";
            for (int e = 0; e < num_elems; ++e)       // for each set element
            {
                if (s & (1 << e))                     // test for membership of set
                {
                    std::cout << " " << elems[e];
                }
            }
            std::cout << " }" << std::endl;
        }
        return 0;
    }
    

    Compile and test:

    $ g++ -Wall sets.cpp && ./a.out
    
    { 1 }
    { 2 }
    { 1 2 }
    { 3 }
    { 1 3 }
    { 2 3 }
    { 1 2 3 }
    

    Note that it's a common convention to make the least significant bit correspond to the first set element.

    Note also that we are omitting the null set, s = 0, as you don't seem to want to include this.

    If you need to work with sets larger than 64 elements (i.e. uint64_t) then you'll need a better approach - you can either expand the above method to use multiple integer elements, or use std::bitset or std::vector<bool>, or use something like @Yochai's answer (using std::next_permutation).