测试每个订单中的每个功能组合

时间:2017-06-11 00:24:40

标签: c++ function permutation

我有很多功能,a.processb.processc.process ...,让他们称呼abc ...所有人都以std::string为参数并返回std::string

给定一个初始std::string s,我想生成abc ...组合的所有可能输出...按任意顺序调用并给出{{ 1}}作为初始输入。

例如,我想计算sa(s)b(s)c(s)a(b(s))a(c(s)),{{1 }},b(a(s))b(c(s))c(a(s))

我想我可以创建一个函数来生成列表的每个排列,比如Python c(b(s)),但我有两个主要问题:

  • 我不想要每一个排列,我想要每个顺序的每一个排列。

  • 更重要的是,我不知道如何将函数存储在数组中,就像在Python中一样。

此外,我需要每个可能的输出都带有生成它的函数组合,因此对于上面给出的示例,我知道输出按以下顺序排列:a(b(c(s)))itertools.permutations"a""b""c""ab""ac""ba""bc""ca"等。

我怎样才能在C ++中实现它?

4 个答案:

答案 0 :(得分:1)

要在数组中存储函数,您需要使用function pointers。这样的事情可以做到:

typedef string (*t_fnPtr)(string);
t_fnPtr fnPtrArray[10]; //Initialize this with your functions

然后,只需生成数组的所有组合并将其应用于字符串即可。请看this question

答案 1 :(得分:1)

我只是将Sid's answer充实到实际代码中。与Galik's answer不同,这不会产生重复

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

using Fn = std::string (*)(std::string);

std::string apply_all(const std::vector<Fn>& fns, std::string s)
{
    for(auto fn : fns)
        s = fn(s);
    return s;
}

int main()
{
    std::string s = /* some string */;
    std::vector<Fn> functions{/* initialize with functions */};
    int n = functions.size();

    for(int r = 1; r <= n; r++)
    {
        std::vector<bool> v(n);
        std::fill(v.begin(), v.begin() + r, true);  // select r functions

        // permute through all possible selections of r functions
        do {
            std::vector<Fn> selected;
            for(int i = 0; i < n; ++i)
                if(v[i])
                    selected.push_back(functions[i]);

            std::sort(selected.begin(), selected.end());

            // permute through the r functions
            do {
                std::cout << apply_all(selected, s) << std::endl;
            } while(std::next_permutation(selected.begin(), selected.end()));
        } while(std::prev_permutation(v.begin(), v.end()));
    }
}

Live example

答案 2 :(得分:0)

一些想法和伪代码

函数指针数组,每个函数一个。

typedef std::string (*Func)(std::string const&);
Func const func_array[] = {&a, &b, &c};
int const n = sizeof array / sizeof array[0];  // number of functions

我们需要

 n choose 1 to get 1-element combinations a, b, c
 n choose 2 to get 2-element combinations ab, ac, bc
 n choose 3 to get 3-element combinations abc

此外,对于每种组合,我们都需要所有可能的排列。即。

 For all k = 1 to n, 
   All permutations of (All combinations of n-choose-k) 

草图

for i = 0 to 2^(n-1):
  xi = elements of func_array corresponding to the '1' bits in i
    used std::next_permutation() to generate all permutations of xi

请参阅https://en.wikipedia.org/wiki/Power_sethttp://en.cppreference.com/w/cpp/algorithm/next_permutation

答案 3 :(得分:0)

如果我已经理解了这个问题,可能是这样的。它使用std::next_permutation迭代进程的每个排序,并且对于每个排序,它选择每个子列表或进程在输入上操作(连续):

std::string process_1(std::string const& s)
    { return s + 'a'; }

std::string process_2(std::string const& s)
    { return s + 'b'; }

std::string process_3(std::string const& s)
    { return s + 'c'; }

int main(int, char** argv)
{
    using process = std::string(*)(std::string const&);


    std::vector<process> processes;

    processes.push_back(process_1);
    processes.push_back(process_2);
    processes.push_back(process_3);

    std::vector<std::string> outputs;

    std::sort(std::begin(processes), std::end(processes));

    do
    {
        for(auto p = std::begin(processes); p != std::end(processes); ++p)
        {
            std::string s = "";
            for(auto p1 = p; p1 != std::end(processes); ++p1)
                s = (*p1)(s);

            outputs.push_back(s);
        }
    }
    while(std::next_permutation(std::begin(processes), std::end(processes)));

    for(auto const& o: outputs)
        std::cout << o << '\n';
}

<强>输出:

abc
bc
c
acb
cb
b
bac
ac
c
bca
ca
a
cab
ab
b
cba
ba
a

注意:看来这种方法会产生一些重复。现在应该有一种聪明的数学方法来消除它,但是你可以随时保持std::set<std::vector<process>>来记录已经尝试过的所有组合,以确保没有重复。或者只是从输出中删除重复项。