【问题标题】:c++ iterate through all neighbor permutationsc ++遍历所有邻居排列
【发布时间】:2015-06-04 12:14:02
【问题描述】:

我有一个包含 N 个对象的向量,我想遍历该向量的所有相邻排列。我所说的邻居排列是一种排列,其中原始向量的只有两个元素会被改变: 如果我有一个带有'a','b','c','d' 的向量,那么:

'b','a','c','d' //is good
'a','c','b','d' //is good
'b','a','d','c' //is not good (2 permutations)

如果我使用std::next_permutation(myVector.begin(), myVector.end(),那么我将获得所有可能的排列,而不仅仅是“邻居”排列...

您知道如何实现吗?

【问题讨论】:

标签: c++ permutation


【解决方案1】:

最初,我想我会过滤 hamming distance 大于 2 的排列。

但是,如果您真的只需要通过交换一对来生成所有向量,那么这样做会更有效:

for(int i = 0; i < n; i++)
    for(int j = i + 1; j < n; j++)
        // swap i and j

根据您是否需要收集所有结果,您应该在交换之前制作一个副本或向量,或者在处理完当前排列后再次交换 i 和 j。

收集所有结果:

std::vector< std::vector<T> > neighbor_permutations;
for(int i = 0; i < n; i++) {
    for(int j = i + 1; j < n; j++) {
        std::vector<T> perm(v);
        std::swap(perm[i], perm[j]);
        neighbor_permutations.push_back(perm);
    }
}

更快的版本 - 不收集结果:

for(int i = 0; i < n; i++) {
    for(int j = i + 1; j < n; j++) {
        std::swap(v[i], v[j]);
        process_permutation(v);
        std::swap(v[i], v[j]);
    }
}

【讨论】:

  • 实际上的想法是避免遍历所有现有的排列(40320 仅用于 8 个元素...),而只是我需要的排列(28 用于 8 个元素)
  • 抱歉,如果您建议迭代所有排列,然后修剪这些排列,那么开销是巨大的!
  • 您的编辑好多了:).. 但与另一个答案相同:据我所知,如果我使用 std::swap 它实际上会修改我的向量,所以我每次都会有邻居前一个向量而不是原始向量..所以我应该每次都取消交换元素吗?
  • 这取决于您是否需要收集所有结果。如果是,则复制向量,交换 i 和 j,并将其存储在某处。如果不是,则在完成当前排列后再次交换 i 和 j
【解决方案2】:

也许把它分成两部分是个好主意:

  • 如何生成“邻居排列”

  • 如何迭代它们


关于第一个,写一个函数很容易:

std::vector<T> make_neighbor_permutation(
    const std::vector<T> &orig, std::size_t i, std::size_t j);

交换 ij。我从你的问题中不明白是否存在 j = i + 1 的附加约束,在这种情况下你可以删除一个参数。


有了这个函数,你现在需要一个迭代器来迭代 ij 的所有合法组合(同样,我不确定你的解释问题。可能有 n - 1 个值)。

使用boost::iterator_facade 很容易做到这一点。您只需要定义一个迭代器,该迭代器接收原始迭代器的构造函数,并将 i(可能还有 j)设置为初始值。随着它的增加,它需要更新索引(或索引)。解引用方法需要调用上述函数。

【讨论】:

  • 看起来很不错。但据我了解,如果我使用std::swap,它实际上会修改我的向量,所以我每次都会有前一个向量的邻居而不是原始向量的邻居。所以我应该每次都取消交换元素吗?
  • 我建议你复制向量,然后在副本上进行交换。请注意,签名声明它是const,顺便说一句。
  • 您的意思是对于每个排列我都应该复制我的向量?取消交换元素不是更快吗?
  • 我的意思是迭代器应该获取ctor中的向量,并复制它。之后,您可以取消交换副本,或者每次迭代都制作一个副本。前者更快,但如果值得费心,我会介绍一下。最重要的部分是修改原始向量。恕我直言,这将非常令人困惑。
【解决方案3】:

另一种获取方式,试一试。

 int main()
    {
        std::vector<char> vec={'b','a','c','d'};
        std::vector<int> vec_in={1,1,0,0};

        do{
             auto it =std::find(vec_in.begin(),vec_in.end(),1);
             if( *(it++) ==1)
             {
                 for(auto &x : vec)
                 {
                     std::cout<<x<<" ";
                 }
                 std::cout<<"\n";
             }

        } while(std::next_permutation(vec_in.begin(),vec_in.end()),  
                std::next_permutation(vec.begin(),vec.end()) );
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-23
    • 2011-01-01
    • 2020-03-05
    • 2014-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多