如何从可变数量的STL向量创建变量的所有排列

时间:2014-02-12 19:55:53

标签: c++ algorithm vector stl

我的{strong>变量数量为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循环,并遍历所有参数来创建所有组合,但向量的数量是可变的。

谢谢。

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

所以,首先,我并没有真正处理int,而是一个自定义对象。 int只是为了简单起见。矢量本身存在于像std::map<std::string, std::vector<int> >这样的地图中。

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

5 个答案:

答案 0 :(得分:1)

0 - &gt; 0,0,0

1 - &gt; 0,0,1

2 - &gt; 0,1,0

3 - &gt; 0,1,1

4 - &gt; 1,0,0

...

7 - &gt; 1,1,1-

8 - &gt; 1,1,2

...

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

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

答案 1 :(得分:1)

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

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

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

假设向量总是相等的长度,改变向量的长度和/或数量只需要改变我们使用的数字和/或数字基数。

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

据推测,这足以使如何将概念扩展到任意数量的向量,每个都是任意大小。

答案 2 :(得分:0)

这是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;
}

答案 3 :(得分:0)

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

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]]);
      }
   }
} 

答案 4 :(得分:0)

以下可能有所帮助:(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));
}