I want to write the maximal clique algorithm for use with an adjacency matrix. I'm following a video which explains how to code and implement the algorithm using Python. I'm currently trying to code the powerset function at 2 minutes into the video.
def powerSet(elts):
if len(elts) == 0:
return [[]]
else:
smaller = powerSet(elts[1:])
elt = [elts[0]]
withElt = []
for s in smaller:
withElt.append(s + elt)
allofthem = smaller + withElt
return allofthem
print powerSet([1, 2, 3, 4, 5])
I want to rewrite this in C++. I'm not sure if I should be using arrays or not. So far I have coded the below but I don't know how to return an empty array inside an empty array (when the elts
list
is of size 0).
I wrote an isEmpty
function for the array since I cant use len(elts)
like in Python. My approach is probably not the best approach to take so I am open to any advice.
UPDATE:
array powerSet(int elts[])
{
if (isEmpty(elts)==1)
{
return {{}};
}
}
In my int main I have:
list<int> elts;
list<int>::iterator i;
for (i=elts.begin(); i != elts.end(); ++i)
cout << *i << " ";
cout << endl;
powerSet(elts);
I don't know what to do from here.
The code should use either an array
/list
/vector
that we call 'elts' (short for elements).
Then firstly, it should add the empty list []
, then the rest of the power set (all shown in the video).
So for example, in the case that elts = [1,2,3,4]
, my code should return:
`[ [],[4],[3],[4,3],[2],[4,2],[3,2],[4,3,2],[1],[4,1],[3,1],[4,3,1],[2,1],[4,2,1],[3,2,1],[4,3,2,1] ] `
I don't know how to use array
/list
/vector
to do the above.
Here's a fairly literal translation of the Python code
#include <vector>
using std::vector;
#include <iostream>
using std::cout;
//def powerSet(elts):
vector<vector<int>> powerSet(const vector<int>& elts)
{
// if len(elts) == 0:
if (elts.empty()) {
// return [[]]
return vector<vector<int>>(
1, // vector contains 1 element which is...
vector<int>()); // ...empty vector of ints
}
// else:
else {
// smaller = powerSet(elts[1:])
vector<vector<int>> smaller = powerSet(
vector<int>(elts.begin() +1, elts.end()));
// elt = [elts[0]]
int elt = elts[0]; // in Python elt is a list (of int)
// withElt = []
vector<vector<int>> withElt;
// for s in smaller:
for (const vector<int>& s: smaller) {
// withElt.append(s + elt)
withElt.push_back(s);
withElt.back().push_back(elt);
}
// allofthem = smaller + withElt
vector<vector<int>> allofthem(smaller);
allofthem.insert(allofthem.end(), withElt.begin(), withElt.end());
// return allofthem
return allofthem;
}
}
This uses vector<int>
for the set of integers. And then a vector
of this, i.e. vector<vector<int>>
is a list of sets of integers. You specifically asked about one thing
I don't know how to return an empty array inside an empty array (when the
elts
list
is of size 0).
The first return
statement returns a list with one element, the empty set, using a vector
constructor, whose first argument n
is the number of elements in the vector
, and whose second argument is the element to repeat n
times. An equivalent but more long-winded alternative is
vector<vector<int>> powerSetOfEmptySet;
vector<int> emptySet;
powerSetOfEmptySet.push_back(emptySet);
return powerSetOfEmptySet;
I've tried to keep the code simple and avoid too many esoteric C++ features. Hopefully you can work through it with the aid of a good reference. One C++ idiom I have used is appending one vector to another as in allofthem.insert(allofthem.end(), withElt.begin(), withElt.end());
.
Also in C++, which is "closer to the metal" than Python, you would probably use just one vector
in place of the three vectors smaller
, withElt
and allofthem
. This leads to the shorter and more optimal code below.
//def powerSet(elts):
vector<vector<int>> powerSet(const vector<int>& elts)
{
// if len(elts) == 0:
if (elts.empty()) {
// return [[]]
return vector<vector<int>>(1, vector<int>());
}
// else:
else {
// smaller = powerSet(elts[1:])
vector<vector<int>> allofthem = powerSet(
vector<int>(elts.begin() +1, elts.end()));
// elt = [elts[0]]
int elt = elts[0]; // in Python elt is a list (of int)
// withElt = []
// for s in smaller:
// withElt.append(s + elt)
// allofthem = smaller + withElt
const int n = allofthem.size();
for (int i=0; i<n; ++i) {
const vector<int>& s = allofthem[i];
allofthem.push_back(s);
allofthem.back().push_back(elt);
}
// return allofthem
return allofthem;
}
}
Test code below
int main()
{
const int N = 5;
vector<int> input;
for(int i=1; i<=N; ++i) {
input.push_back(i);
}
vector<vector<int>> ps = powerSet(input);
for(const vector<int>& set:ps) {
cout << "[ ";
for(int elt: set) {
cout << elt << " ";
}
cout << "]\n";
}
return 0;
}
As a footnote, I was pleasantly surprised as to how straightforward it was to translate from Python into C++. I had read that it might make sense to use Python to write (or prototype) algorithms, and then rewrite in a language such as C++ as necessary, but, as the proverb goes, seeing is believing.
Here is a version of the program that works with C++98. I reverted the basic C++11 features that I used (>>
in template declarations and range-based for
).
#include <vector>
using std::vector;
#include <iostream>
using std::cout;
vector<vector<int> > powerSet(const vector<int>& elts)
{
if (elts.empty()) {
return vector<vector<int> >(1, vector<int>());
}
else {
vector<vector<int> > allofthem = powerSet(
vector<int>(elts.begin() +1, elts.end()));
int elt = elts[0];
const int n = allofthem.size();
for (int i=0; i<n; ++i) {
const vector<int>& s = allofthem[i];
allofthem.push_back(s);
allofthem.back().push_back(elt);
}
return allofthem;
}
}
int main()
{
const int N = 5;
vector<int> input;
for(int i=1; i<=N; ++i) {
input.push_back(i);
}
vector<vector<int> > ps = powerSet(input);
for(vector<vector<int> >::const_iterator i=ps.begin(); i!=ps.end(); ++i) {
const vector<int>& set = *i;
cout << "[ ";
for(vector<int>::const_iterator j=set.begin(); j!=set.end(); ++j) {
int elt = *j;
cout << elt << " ";
}
cout << "]\n";
}
return 0;
}