0

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!

quantdev
  • 23,517
  • 5
  • 55
  • 88
cotro34
  • 15
  • 4

3 Answers3

5

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).

Paul R
  • 208,748
  • 37
  • 389
  • 560
  • I understand that this is the "what" part of my question, I know that given a set size 3 there are 7 elements in the power set and they correspond to binary representations. I dont know how to do the actual binary counting (which is what you had in your now deleted answer WhozCraig) – cotro34 Aug 26 '14 at 08:35
  • What do you mean by "binary counting" ? The `for` loop above iterates through all the sets, if that's what you mean ? – Paul R Aug 26 '14 at 08:52
  • Yes the for loop counts from 1 to 7, it doesnt actually do anything. I already knew how many sets would be created, I dont know how to actually create them however – cotro34 Aug 26 '14 at 08:59
  • No problem - I guess you're not seeing the connection between bits and set membership - I've added some code now which demonstrates how to display each set. – Paul R Aug 26 '14 at 09:03
  • 1
    Much appreciated, I was seeing the connection, just i am a complete newbie when it comes to operating with bits (only just beginning to learn now), obviously there was some miscommunication! – cotro34 Aug 26 '14 at 09:05
0

Actually creating the sets is pretty easy - just use bitwise operations >>= and & to test a bit at a time. Assuming input vector/array a[] known to have 3 elements and therefore produce a 7 vector output:

std::vector<std::vector<T>> v(7);
for (int n = 1; n <= 7; ++n)   // each output set...
    for (int i = 0, j = n; j; j >>= 1, ++i)  // i moves through a[i],
                                             // j helps extract bits in n 
        if (j & 1)
             v[n-1].push_back(a[i]);
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
0

For compile time size, you may use bitset, something like:

template <std::size_t N>
bool increase(std::bitset<N>& bs)
{
    for (std::size_t i = 0; i != bs.size(); ++i) {
        if (bs.flip(i).test(i) == true) {
            return true;
        }
    }
    return false; // overflow
}

template <typename T, std::size_t N>
void display(const std::array<T, N>& a, const std::bitset<N>& bs)
{
    std::cout << '{';
    const char* sep = "";

    for (std::size_t i = 0; i != bs.size(); ++i) {
        if (bs.test(i)) {
            std::cout << sep << a[i];
            sep = ", ";
        }
    }
    std::cout << '}' << std::endl;
}

template <typename T, std::size_t N>
void display_all_subsets(const std::array<T, N>& a)
{
    std::bitset<N> bs;

    do {
        display(a, bs);
    } while (increase(bs));
}

Live example

Jarod42
  • 203,559
  • 14
  • 181
  • 302