迭代任何大小的子集

时间:2009-11-05 20:10:11

标签: c++ algorithm

我可以遍历大小为1的子集

for( int a = 0; a < size; a++ ) {

或大小为2的子集

for( int a1 = 0; a1 < size; a1++ ) {
    for( int a2 = a1+1; a2 < size; a2++ ) {

或3

for( int a1 = 0; a1 < size; a1++ ) {
for( int a2 = a1+1; a2 < size; a2++ ) {
   for( int a3 = a2+1; a3 < size; a3++ ) {

但是如何为大小为n的子集执行此操作?

根据Adam Rosenfield的回答

这是完成这项工作的
void iterate(int *a, int i, int size, int n)
{
 int start = 0;
 if( i > 0 ) start = a[i-1]+1;
 for(a[i] = start; a[i] < n; a[i]++) {
  if(i == n-1) {
      // a is the array of indices of size n
      for( int k = 0; k < size; k++ ) {
          printf("%d ",a[k]);
      }
      printf("\n");
  }
        else
            iterate(a, i+1, size, n);
    }
}

5 个答案:

答案 0 :(得分:7)

您可以使用递归:

void iterate(int *a, int i, int size, int n)
{
    for(a[i] = 0; a[i] < size; a[i]++)
    {
        if(i == n-1)
            DoStuff(a, n);  // a is the array of indices of size n
        else
            iterate(a, i+1, size, n);
    }
}
...
// Equivalent to 4 nested for loops
int a[4];
iterate(a, 0, size, 4);

答案 1 :(得分:2)

你可能会通过一些递归来做到这一点。

答案 2 :(得分:1)

这是我用于类似问题的东西。它不使用递归;相反,它使用索引向量。

#include <vector>

template<class T>
class MultiForVar {
std::vector<T> _begin, _end, _vars;
inline int dim(){return _vars.size();}
public:
MultiForVar(std::vector<T> begin, std::vector<T> end) : _begin(begin), _end(end), _vars(_begin)
{
  assert(begin.size() == end.size() and "Starting and ending vector<T> not the same size!" );
}
MultiForVar& operator ++()
{
  ++_vars[dim()-1];
  for(int d = dim()-1; d > 0; --d)
  {
    if( _vars[d] >= _end[d] )
    {
      _vars[d] = _begin[d];
      ++_vars[d-1];
    }
  }
  return *this;
}
bool done()
{
  /*for(int d = 0; d < dim(); ++d)
    if( _vars[d] < _end[d] )
      return false;
  return true;*/
  return (_vars[0] >= _end[0]);
}
T operator[](int d)
{
  return _vars.at(d);
}
int numDimensions(){
  return dim();
}
std::vector<T>& getRaw(){
  return _vars;
}

};

答案 3 :(得分:1)

如果我理解你正确的问题,另一种方法是使用逐位运算符:

for(int i = 0; i < 1<<size; i++) {
    for(int j = 0; j < size; j++) {
       if(i & 1<<j) printf("%d ", a[j]);
    }
    printf("\n");
}

答案 4 :(得分:1)

你需要构建原始集的powerset。自从我写完以来已经有一段时间了,但是psuedocode看起来像是

Powerset(a, size)
{
   if(size == 0) return emptyset

   subseta = Powerset(a, size-1) // Powerset of everything except last element
   subsetb = appendToAll(a[size-1], subseta) // appends the last element to every set in subseta
   return union(subseta, subsetb)
}