笛卡尔积c ++

时间:2015-04-04 20:53:11

标签: c++ cartesian-product

我一直在寻找如何提出我可以应用笛卡尔积的代码。假设我有两个数组:

int M[2]= {1,2};
int J[3] = {0,1,2};

因此代码将采用这两个数组应用规则M X J 因此我们将得到对(1,0)(1,1)(1,2)(2,0)(2,1)(2,2)并且我希望将新结果保存到新数组中数组中的每个索引都包含一对,例如c [0] =(1,0)。 请帮助:(

5 个答案:

答案 0 :(得分:4)

#include <iostream>
#include <iterator>
#include <vector>
#include <utility>

template<typename Range1, typename Range2, typename OutputIterator>
void cartesian_product(Range1 const &r1, Range2 const &r2, OutputIterator out) {
    using std::begin; using std::end;

    for (auto i = begin(r1);i != end(r1); ++i) {
        for (auto j = begin(r2); j != end(r2); ++j) {
            *out++ = std::make_tuple(*i, *j);
        }
    }
}

int main() {
    std::vector<int> a{1,2,3};
    std::vector<char> b{'a','b','c','d','e','f'};

    std::vector<std::tuple<int, char>> c;
    cartesian_product(a, b, back_inserter(c));

    for (auto &&v : c) {
        std::cout << "(" << std::get<int>(v) << "," << std::get<char>(v) << ")";
    }
}

打印:

  

(1,A)(1,B)(1,C)(1,d)(1,E)(1,F)(2,)(2,B)(2,C)(2 ,d)(2,E)(2,F)(3,)(3,b)(3,C)(3,d)(3,E)(3,F)

您还可以将该功能应用于您的案例:

template<typename T, int N> constexpr int size(T (&)[N]) { return N; }

int main() {
    int M[2] = {1,2};
    int J[3] = {0,1,2};

    std::tuple<int, int> product[size(M) * size(J)];

    cartesian_product(M, J, product);

    for (auto &&v : product) {
        std::cout << "(" << std::get<0>(v) << "," << std::get<1>(v) << ")";
    }
}

输出结果为:

  

(1,0)(1,1)(1,2)(2,0)(2,1)(2,2)

http://coliru.stacked-crooked.com/a/3ce388e10c61a3a4

答案 1 :(得分:1)

这是使用矢量实现笛卡尔积的简单示例。向量是更好的选择,因为我们不需要担心它的大小,因为它会动态地改变它。

#include <iostream>
#include <vector>
#include <utility>
using namespace std;

int main() {
    int M[2]= {1,2};
    int J[3] = {0,1,2};
    vector<pair<int,int>> C;

    for (int i = 0; i < sizeof(M)/sizeof(M[0]); i++)
    {
        for (int j = 0; j < sizeof(J)/sizeof(J[1]); j++)
        {
            C.push_back(make_pair(M[i],J[j]));
        }  
    }

    /*
    for (vector<int>::iterator it = C.begin(); it != C.end(); it++)
    {
        cout << *it << endl;
    }

    */

    for (int i = 0; i < C.size(); i++)
    {
        cout << C[i].first << "," << C[i].second << endl;
    }
}

以下是我实现上述代码的link。虽然我不会直接发布与您的问题相关的解决方案,但评论中发布的链接已经包含了我发布的答案。

答案 2 :(得分:1)

我认为使用c ++二维数组是个坏主意,但如果你愿意,你可能会使用这个代码

    #include <iostream>    
    int** cartesian_prod( int* s1, int* s2, int s1size, int s2size )
    {
        int ressize = s1size*s2size;
        int** res = new int*[ressize];
        for ( int i = 0; i < s1size; i++ )
            for ( int j = 0; j < s2size; j++ )
            {
                res[i*s2size+j] = new int[2];
                res[i*s2size+j][0] = s1[i];
                res[i*s2size+j][1] = s2[j];
            }
        return res;
    }
    int main() {
        int M[2]= {1,2};
        int J[3] = {0,1,2};
        int** res;
        int Msize = sizeof(M)/sizeof(M[0]);
        int Jsize = sizeof(J)/sizeof(J[1]);
        res = cartesian_prod(M, J, Msize, Jsize);
        for ( int i = 0; i < Msize*Jsize; i++ )
            std::cout << res[i][0] << " " << res[i][1] << std::endl;
        for (int i = 0; i < Msize*Jsize; i++)
            delete[] res[i];
        delete[] res;
        return 0;
    }

但处理std :: vector要好得多 - 它在开发时间方面要快得多,并且可以避免许多错误。

答案 3 :(得分:0)

这里是一个实现,其中值的序列是一个参数(而不是在所有其他实现中都是众所周知的):

void CartesianRecurse(vector<vector<int>> &accum, vector<int> stack,
    vector<vector<int>> sequences, int index)
{
    vector<int> sequence = sequences[index];
    for (int i : sequence)
    {       
        stack.push_back(i);
        if (index == 0)
            accum.push_back(stack);
        else
            CartesianRecurse(accum, stack, sequences, index - 1);
        stack.pop_back();
    }
}
vector<vector<int>> CartesianProduct(vector<vector<int>> sequences)
{
    vector<vector<int>> accum;
    vector<int> stack;
    if (sequences.size() > 0)
        CartesianRecurse(accum, stack, sequences, sequences.size() - 1);
    return accum;
}

main() {
    vector<vector<int>> sequences = { {1,2,7},{3,4},{5,6} };
    vector<vector<int>> res = CartesianProduct(sequences);
    // now do something with the result in 'res'.
}

答案 4 :(得分:0)

没有 for 循环的解决方案。

#include<array>
#include<iostream>
#include<tuple>
#include<utility>

template
<typename T, typename Tuple, std::size_t... I>
auto cartesian_product_base(
                         const T& a,
                         const Tuple& t,
                         std::index_sequence<I...>) {
    return std::make_tuple(std::make_pair(a, std::get<I>(t))...);
}

template
<typename T, typename... Ts, std::size_t... I>
std::array<T, sizeof...(Ts) + 1> to_array(std::tuple<T, Ts...> t, std::index_sequence<I...>) {
    return {std::get<I>(t)...};
}

template
<typename Tuple1, typename Tuple2, std::size_t... I>
auto cartesian_product_impl(
                         const Tuple1& t1,
                         const Tuple2& t2,
                         std::index_sequence<I...>) {
    return std::tuple_cat(cartesian_product_base(
                                 std::get<I>(t1),
                                 t2,
                                 std::make_index_sequence<std::tuple_size<Tuple2>::value>{})...);
}

template
<typename T1, std::size_t N1, typename T2, std::size_t N2>
auto cartesian_product(
                     const std::array<T1, N1>& a1,
                     const std::array<T2, N2>& a2) {
    return to_array(
                    cartesian_product_impl(a1, a2, std::make_index_sequence<N1>{}),
                    std::make_index_sequence<N1 * N2>{});
}

using namespace std;

int main() {
    array<int, 2> M = {1, 2};
    array<int, 3> J = {0, 1, 2};
    auto C = cartesian_product(M, J);
    cout << C.size() << endl;
    cout << "{";
    for (size_t i = 0; i != C.size(); ++i) {
        if (i != 0) {
            cout << ", ";
        }
        cout << "(" << C[i].first << ", " << C[i].second << ")";
    }
    cout << "}" << endl;
}