c++ - 递归生成给定子集大小的所有组合 (C++)

标签 c++ algorithm c++11 recursion combinations

观察下面的代码:

#include <vector>
#include <iostream>
#include <string>

template <typename T>
void print_2d_vector(std::vector<std::vector<T>>& v)
{
  for(int i = 0; i < v.size(); i++)
  {
    std::cout << "{";
    for(int j = 0; j < v[i].size(); j++)
    {
      std::cout << v[i][j];
      if(j != v[i].size() - 1)
      {
        std::cout << ", ";
      }
    }
    std::cout << "}\n";
  }
}

template <typename T>
struct permcomb2
{
  std::vector<std::vector<T>> end_set;
  std::vector<T>* data;
  permcomb2(std::vector<T>& param) : data(&param) {}

  void helpfunc(std::vector<T>& seen, int depth)
  {
    if(depth == 0)
    {
      end_set.push_back(seen);
    }
    else
    {
      for(int i = 0; i < (*data).size(); i++)
      {
        seen.push_back((*data)[i]);
        helpfunc(seen, depth - 1);
        seen.pop_back();
      }
    }
  }
};

template <typename T>
std::vector<std::vector<T>> permtest(std::vector<T>& data, int subset_size)
{
  permcomb2<T> helpstruct(data);
  std::vector<T> empty {};
  helpstruct.helpfunc(empty, subset_size);
  return helpstruct.end_set;
}

using namespace std;
int main()
{
  std::vector<std::string> flavors {"Vanilla", "Chocolate", "Strawberry"};
  auto a1 = permtest(flavors, 2);

  cout << "Return all combinations with repetition\n";
  print_2d_vector(a1);
  return 0;
}

运行此代码会产生以下输出:

Return all combinations with repetition
{Vanilla, Vanilla}
{Vanilla, Chocolate}
{Vanilla, Strawberry}
{Chocolate, Vanilla}
{Chocolate, Chocolate}
{Chocolate, Strawberry}
{Strawberry, Vanilla}
{Strawberry, Chocolate}
{Strawberry, Strawberry}

请注意这段代码并没有像它声称的那样做!它不是返回重复给定子集大小(目标)的所有组合,而是返回所有重复给定子集大小的排列。当然,获得组合的一种方法是像我所做的那样生成所有排列,然后循环删除所有排列,只剩下一个是彼此的排列。但我相信这绝对不是最有效的方法。

我见过使用嵌套 for 循环来实现此目的的方法,但这些方法假设子集大小是提前已知的。我试图将它概括为任何子集大小,因此我试图递归地做它。问题是我不太确定我需要如何更改我的递归“helpfunc”以便以一种有效的方式生成所有组合。

澄清一下,预期的输出是这样的:

Return all combinations with repetition
{Vanilla, Vanilla}
{Vanilla, Chocolate}
{Vanilla, Strawberry}
{Chocolate, Chocolate}
{Chocolate, Strawberry}
{Strawberry, Strawberry}

那么,我该如何更改我的代码,以高效的方式获取所有重复组合而不是排列?

最佳答案

确保 helpfunc 循环从我们所在的索引开始,并且只考虑前面的索引。我们不想要后面的那些,因为它们只会是重复的。

#include <vector>
#include <iostream>
#include <string>

template <typename T>
void print_2d_vector(std::vector<std::vector<T>>& v)
{
    for(int i = 0; i < v.size(); i++)
    {
        std::cout << "{";
        for(int j = 0; j < v[i].size(); j++)
        {
            std::cout << v[i][j];
            if(j != v[i].size() - 1)
            {
                sizetd::cout << ", ";
            }
        }
        std::cout << "}\n";
    }
}

template <typename T>
struct permcomb2
{
    std::vector<std::vector<T>> end_set;
    std::vector<T>& data;
    permcomb2(std::vector<T>& param) : data(param) {}

    void helpfunc(std::vector<T>& seen, int depth, int current) // Add one more param for the starting depth of our recursive calls
    {
        if(depth == 0)
        {
            end_set.push_back(seen);
        }
        else
        {
            for(int i = current; i < data.size(); i++) // Set the loop to start at given value
            {
                seen.push_back(data[i]);
                helpfunc(seen, depth - 1, i);
                seen.pop_back();
            }
        }
    }
};

template <typename T>
std::vector<std::vector<T>> permtest(std::vector<T>& data, int subset_size)
{
    permcomb2<T> helpstruct(data);
    std::vector<T> empty {};
    helpstruct.helpfunc(empty, subset_size, 0); // Initialize the function at depth 0
    return helpstruct.end_set;
}

using namespace std;
int main()
{
    std::vector<std::string> flavors {"Vanilla", "Chocolate", "Strawberry"};
    auto a1 = permtest(flavors, 2);

    cout << "Return all combinations with repetition\n";
    print_2d_vector(a1);
    return 0;
}

关于c++ - 递归生成给定子集大小的所有组合 (C++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48123890/

相关文章:

c++ - 从反向迭代器获取 vector 中的索引

c++ - 具有 CRTP 和模板特化的运算符的奇怪行为

C++:带有删除器的类的前向声明,用于可重复的唯一指针

c++ - 如何对列表执行 GroupBy Sum 查询?

C++11 emplace_back on vector<struct>?

java - 有没有更快的方法来搜索累积分布?

algorithm - 快速实体分组(按位置)算法

algorithm - 如何在谷歌地图中找到 'common route'?

没有.cpp文件没有内联函数的c++类?

c++ - 使用迭代器与 const_iterator 调用删除