【问题标题】:How to Create All Permutations of Variables from a Variable Number of STL Vectors [duplicate]如何从可变数量的 STL 向量创建变量的所有排列 [重复]
【发布时间】:2014-03-11 09:20:26
【问题描述】:

我有一个 变量 编号 std::vectors<int>,假设在这个例子中我有 3 个向量:

std::vector<int> vect1 {1,2,3,4,5};
std::vector<int> vect2 {1,2,3,4,5};
std::vector<int> vect3 {1,2,3,4,5};

向量的值在这里并不重要。此外,这些向量的长度是可变的。

从这些向量中,我想创建向量值的每个排列,所以:

{1, 1, 1}
{1, 1, 2}
{1, 1, 3}
...
...
...
{3, 5, 5}
{4, 5, 5}
{5, 5, 5}

然后我会将每个组合插入到键值对映射中,以供我的应用程序进一步使用。

什么是完成此任务的有效方法?我通常只使用for 循环,并遍历所有参数以创建所有组合,但向量的数量是可变的。

谢谢。

编辑:我将包括更多细节。

所以,首先,我并不是在处理ints,而是一个自定义对象。 ints 只是为了简单起见。向量本身存在于像 std::map&lt;std::string, std::vector&lt;int&gt; &gt; 这样的地图中。

我的最终目标是拥有一个std::vector&lt; std::map&lt; std::string, int &gt; &gt;,它本质上是名称-值对的所有可能组合的集合。

【问题讨论】:

  • “向量的数量是可变的”——假设你有一个向量向量是否公平?
  • 嗯,这是一张矢量地图,其中每个矢量都有一个特殊的名称,我正在跟踪。
  • 您能否包含地图的代码,以及向量的具体顺序(例如按键上的字母顺序?)
  • @Dukeling 那个帖子可能会解决我的问题,我会尝试用 C++ 实现并发布它。马特,向量没有我关心的顺序。我将在编辑中发布更多详细信息。
  • @Dukeling:虽然这个问题可能几乎是重复的,但完全可以做到这一点的代码不会像那里给出的任何答案那样任何东西。跨度>

标签: c++ algorithm vector stl


【解决方案1】:

“我需要生成 X 的所有排列”形式的许多(也许是大多数)问题可以通过创造性地使用简单计数来解决(这也不例外)。

让我们从一个简单的例子开始:每个 5 个元素的 3 个向量。对于我们的答案,我们会将这些向量的索引视为 3 位、以 5 为底的数字。该数字的每个数字都是其中一个向量的索引。

因此,要生成所有组合,我们只需从 0 数到 53 (125)。我们将每个数字转换为 3 个以 5 为底的数字,并将这些数字用作向量的索引以获得排列。当我们达到 125 时,我们已经枚举了这些向量的所有排列。

假设向量总是等长,改变向量的长度和/或数量只是改变我们使用的位数和/或基数的问题。

如果向量的长度不等,我们只需生成一个结果,其中并非所有数字都在同一个基数中。例如,给定三个长度为 7、4 和 10 的向量,我们仍然会从 0 计数到 7x4x10 = 280。我们将生成最低有效位为 N%10。我们将生成下一个最不显着的 (N/10)%4。

大概这足以使如何将概念扩展到任意数量的任意大小的向量变得相当明显。

【讨论】:

    【解决方案2】:

    0 - > 0,0,0

    1 - > 0,0,1

    2 - > 0,1,0

    3 - > 0,1,1

    4 - > 1,0,0

    ...

    7 - > 1,1,1

    8 - > 1,1,2

    ...

    地图应该将一个线性整数转换成一个组合(即:a1、a2、a3...一个组合),允许您从每个向量中选择一个元素来获得答案。

    无需从初始向量中复制任何值。您可以使用数学公式得出每个向量的正确答案。该公式将取决于您的输入向量的某些属性(有多少个?它们的长度是否相同?它们有多长?等等...)

    【讨论】:

      【解决方案3】:

      以下可能会有所帮助:(https://ideone.com/1Xmc9b)

      template <typename T>
      bool increase(const std::vector<std::vector<T>>& v, std::vector<std::size_t>& it)
      {
          for (std::size_t i = 0, size = it.size(); i != size; ++i) {
              const std::size_t index = size - 1 - i;
              ++it[index];
              if (it[index] == v[index].size()) {
                  it[index] = 0;
              } else {
                  return true;
              }
          }
          return false;
      }
      
      template <typename T>
      void do_job(const std::vector<std::vector<T>>& v, std::vector<std::size_t>& it)
      {
          // Print example.
          for (std::size_t i = 0, size = v.size(); i != size; ++i) {
              std::cout << v[i][it[i]] << " ";
          }
          std::cout << std::endl;
      }
      
      template <typename T>
      void iterate(const std::vector<std::vector<T>>& v)
      {
          std::vector<std::size_t> it(v.size(), 0);
      
          do {
              do_job(v, it);
          } while (increase(v, it));
      }
      

      【讨论】:

        【解决方案4】:

        这是 Lother 和 Jerry Coffin 所描述内容的显式实现,在 for 循环中使用有用的 div 函数来迭代不同长度的向量。

        #include <cstdlib> // ldiv
        #include <iostream>
        #include <map>
        #include <string>
        #include <vector>
        using namespace std;
        
        vector<int> vect1 {100,200};
        vector<int> vect2 {10,20,30};
        vector<int> vect3 {1,2,3,4};
        
        typedef map<string,vector<int> > inputtype;
        inputtype input;
        vector< map<string,int> > output;
        
        int main()
        {
          // init vectors
          input["vect1"] = vect1;
          input["vect2"] = vect2;
          input["vect3"] = vect3;
        
          long N = 1; // Total number of combinations
          for( inputtype::iterator it = input.begin() ; it != input.end() ; ++it )
            N *= it->second.size();
        
          // Loop once for every combination to fill the output map.
          for( long i=0 ; i<N ; ++i )
          {
            ldiv_t d = { i, 0 };
            output.emplace_back();
            for( inputtype::iterator it = input.begin() ; it != input.end() ; ++it )
            {
              d = ldiv( d.quot, input[it->first].size() );
              output.back()[it->first] = input[it->first][d.rem];
            }
          }
        
          // Sample output
          cout << output[0]["vect1"] << endl; // 100
          cout << output[0]["vect2"] << endl; // 10
          cout << output[0]["vect3"] << endl; // 1
          cout << output[N-1]["vect1"] << endl; // 200
          cout << output[N-1]["vect2"] << endl; // 30
          cout << output[N-1]["vect3"] << endl; // 4
        
          return 0;
        }
        

        【讨论】:

          【解决方案5】:

          使用向量数组而不是单独的变量。然后使用以下递归算法:-

          permutations(i, k, vectors[], choices[]) {
              if (i < k) {
                  for (int x = 0; x < vectors[i].size(); x++) {
                      choices[i] = x;
                      permutations(i + 1, k, vectors, choices);
                  }
              } else {
                  printf("\n %d", vectors[choices[0]]);
                  for (int j = 1; j < k; j++) {
                      printf(",%d", vectors[choices[j]]);
                  }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-10-11
            • 2020-09-28
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多