I want to generate all cardinality k subsets of {0, 1, 2, ..., n-1} in C++. In Haskell, I would do:
sets 0 n = [[]]
sets k n = [i:s | i <- [0..n-1], s <- sets (k-1) i]
Or in Python:
def sets(k, n):
    if k == 0:
        return [()]
    return ((i,)+s for i in range(n) for s in sets(k-1, i))
So, for example, (line breaks added for clarity)
ghci> sets 2 8
[[1,0],
 [2,0],[2,1],
 [3,0],[3,1],[3,2],
 [4,0],[4,1],[4,2],[4,3],
 [5,0],[5,1],[5,2],[5,3],[5,4],
 [6,0],[6,1],[6,2],[6,3],[6,4],[6,5],
 [7,0],[7,1],[7,2],[7,3],[7,4],[7,5],[7,6]]
What would be the "C++ way" of doing this? Note that I'm not asking how to solve the problem. I'm asking about what data types would be considered "normal" by C++ programmers.
(For reference, I'm vaguely familiar with C++ and somewhat familiar with C.)
Here's a naive, recursive approach, which implements the classical combinatorial identity:
binom(n + 1, k + 1) = binom(n, k + 1) + binom(n, k)
#include <set>
typedef std::set<int> intset;
std::set<intset> subsets(std::size_t k, intset s)
{
    if (k == 0 || s.empty() || s.size() < k) { return { { } }; }
    if (s.size() == k) { return { s }; }
    auto x = *s.begin();
    s.erase(s.begin());
    std::set<intset> result;
    for (auto & t : subsets(k - 1, s))
    {
        auto r = std::move(t);
        r.insert(x);
        result.insert(std::move(r));
    }
    for (auto & t : subsets(k, s))
    {
        results.insert(std::move(t));
    }
    return result;
}
Usage:
auto ss = subsets(3, {0, 1, 2, 3, 4});
Complete example:
#include <iostream>
#include <string>
#include <prettyprint.hpp>
int main(int argc, char * argv[])
{
    if (argc != 3) return 1;
    auto k = std::stoul(argv[1]);
    auto n = std::stoul(argv[2]);
    intset s;
    for (auto i = 0U; i != n; ++i) s.insert(i);
    std::cout << subsets(k, s) << std::endl;
}
Rosetta Code has an implementation that works by taking the first k entries of permutations of the list 0, 1, ..., n-1. It uses the C++ STL.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With