Использование рекурсии и поиска с возвратом для генерации всех возможных комбинаций

я пытаюсь реализовать класс, который будет генерировать все возможные неупорядоченные n-кортежи или комбинации с учетом количества элементов и размера комбинации.

Другими словами, при вызове этого:

NTupleUnordered unordered_tuple_generator(3, 5, print);
unordered_tuple_generator.Start();

print () является функцией обратного вызова, установленной в конструкторе. Результат должен быть:

{0,1,2}
{0,1,3}
{0,1,4}
{0,2,3}
{0,2,4}
{0,3,4}
{1,2,3}
{1,2,4}
{1,3,4}
{2,3,4}

Вот что у меня есть:

class NTupleUnordered {
public:
    NTupleUnordered( int k, int n, void (*cb)(std::vector<int> const&) );
    void Start();
private:
    int tuple_size;                            //how many
    int set_size;                              //out of how many
    void (*callback)(std::vector<int> const&); //who to call when next tuple is ready
    std::vector<int> tuple;                    //tuple is constructed here
    void add_element(int pos);                 //recursively calls self
};

и это реализация рекурсивной функции, Start () - это просто функция быстрого старта, чтобы иметь более чистый интерфейс, она вызывает только add_element (0 );

void NTupleUnordered::add_element( int pos )
{

  // base case
  if(pos == tuple_size)
  {
      callback(tuple);   // prints the current combination
      tuple.pop_back();  // not really sure about this line
      return;
  }

  for (int i = pos; i < set_size; ++i)
  {
    // if the item was not found in the current combination
    if( std::find(tuple.begin(), tuple.end(), i) == tuple.end())
    {
      // add element to the current combination
      tuple.push_back(i);
      add_element(pos+1); // next call will loop from pos+1 to set_size and so on

    }
  }
}

Если бы я хотел сгенерировать все возможные комбинации постоянного размера N, скажем, комбинации размера 3, я мог бы сделать:

for (int i1 = 0; i1 < 5; ++i1) 
{
  for (int i2 = i1+1; i2 < 5; ++i2) 
  {
    for (int i3 = i2+1; i3 < 5; ++i3) 
    {
        std::cout << "{" << i1 << "," << i2 << "," << i3 << "}\n";
    }
  }
}

Если N не является константой, вам понадобится рекурсивная функция, имитирующая указанное выше функция, выполняя каждый цикл for в собственном фрейме. Когда цикл for завершается, программа возвращается к предыдущему кадру, другими словами, с возвратом.

У меня всегда были проблемы с рекурсией, и теперь мне нужно объединить ее с возвратом, чтобы сгенерировать все возможные комбинации. Есть указатели на то, что я делаю не так? Что мне делать или я не замечаю?

P.S: Это задание колледжа, которое также включает в себя в основном то же самое для упорядоченных n-кортежей.

Заранее спасибо!

/////////////////////////////////////////////// //////////////////////////////////////////

Просто хотел продолжить с правильным кодом на тот случай, если кто-то еще задается вопросом о том же.

void NTupleUnordered::add_element( int pos)
{

  if(static_cast<int>(tuple.size()) == tuple_size)
  {
    callback(tuple);
    return;
  }

  for (int i = pos; i < set_size; ++i)
  {
        // add element to the current combination
        tuple.push_back(i);
        add_element(i+1); 
        tuple.pop_back();     
  }
}

И в случае упорядоченных n-кортежей:

void NTupleOrdered::add_element( int pos )
{
  if(static_cast<int>(tuple.size()) == tuple_size)
  {
    callback(tuple);
    return;
  }

  for (int i = pos; i < set_size; ++i)
  {
    // if the item was not found in the current combination
    if( std::find(tuple.begin(), tuple.end(), i) == tuple.end())
    {
        // add element to the current combination
        tuple.push_back(i);
        add_element(pos);
        tuple.pop_back();

    }
  }
}

Спасибо, Джейсон, за ваш обстоятельный ответ!

10
задан Gilles 'SO- stop being evil' 17 September 2012 в 22:40
поделиться