C++中的笛卡尔积
Cartesian Product in c++
几周来我一直在寻找如何编写一段可以应用笛卡尔积的代码。假设我有两个数组:
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)。
请帮助:(
下面是一个使用向量实现笛卡尔积的简单示例。矢量是更好的选择,因为我们不需要担心它的大小,因为它会动态改变它。
#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 我实现上面代码的地方。虽然我不会 post 解决方案直接与您的问题相关,但评论中 posted 的链接已经包含答案,这就是为什么我 posted.
我认为使用 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 要好得多 - 它更快(在开发时间方面)并且可以避免许多错误。
#include <iostream>
#include <iterator>
#include <vector>
#include <utility>
#include <tuple>
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,a)(2,b)(2,c)(2,d)(2,e)(2,f)(3,a)(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)
这是一个实现,其中值的序列是一个参数(而不是像所有其他实现中的 pre-known):
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'.
}
没有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;
}
几周来我一直在寻找如何编写一段可以应用笛卡尔积的代码。假设我有两个数组:
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)。 请帮助:(
下面是一个使用向量实现笛卡尔积的简单示例。矢量是更好的选择,因为我们不需要担心它的大小,因为它会动态改变它。
#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 我实现上面代码的地方。虽然我不会 post 解决方案直接与您的问题相关,但评论中 posted 的链接已经包含答案,这就是为什么我 posted.
我认为使用 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 要好得多 - 它更快(在开发时间方面)并且可以避免许多错误。
#include <iostream>
#include <iterator>
#include <vector>
#include <utility>
#include <tuple>
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,a)(2,b)(2,c)(2,d)(2,e)(2,f)(3,a)(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)
这是一个实现,其中值的序列是一个参数(而不是像所有其他实现中的 pre-known):
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'.
}
没有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;
}