【问题标题】:How to generate the cartesian product of a jagged array?如何生成锯齿状数组的笛卡尔积?
【发布时间】:2011-04-29 14:40:26
【问题描述】:

我在弄清楚如何生成锯齿状数组的笛卡尔积时遇到了一些麻烦。我已经用谷歌搜索了,但我似乎找不到迭代语言的实现。所以我试图自己弄清楚,但我遇到了一个障碍。让我们更清楚地定义问题

假设我有一个数组,看起来像这样

A = { {1}, {2, 3}, {4, 5, 6} }

我如何从那里去

B = { {1, 2, 4}, {1, 2, 5}, {1, 2, 6}, {1, 3, 4}, {1, 3, 5}, {1, 3, 6} }

编辑:现在这只是一个例子,第一个数组可以包含动态数量的数组,每个数组都是动态大小的。

如果 x 是外部数组中的元素个数,并且 y[] 是长度为 x 的动态数组,则元素包含内部数组中的元素个数。那么A的x就变成了B的y,B的x就是y在A的乘法和。(未证明,从例子中假设)

由于 A 的 x 是动态的,因此函数必须是递归的。这是我的尝试。

int** cartesian (int** A, int x, int* y, int* newx, int* newy) {
  *newy = x;
  *newx = 1;
  for (int i = 0; i < x; i++)
    *newx *= y[i];
  int** B = malloc(sizeof(int) * *newx * *newy);

  int xi = 0;
  int* tmp_prod = malloc(sizeof(int) * x);
  recurse(x, 0, y, A, &xi, tmp_prod, B);
  free(tmp_prod);

  return B;
}

void recurse(int x, int xi, int* y, int** A, int* newx, int* temp_inner, int** B) {
  if (xi < x) {
    for (int i = 0; i < y[xi]; i++) {
      temp_inner[xi] = A[xi][i];
      recurse(x, xi + 1, y, A, newx, temp_inner, B);
    }
  } else {
    for (int i = 0; i < x; i++) {
      B[*newx][i] = temp_inner[i];
    }
    (*newx)++;
  }
}

这是我所得到的。递归函数建立一个a[递归深度]的一个元素的临时数组,然后当它达到最大深度时,它分配那个B,并增加Bs迭代器,回溯并选择a[递归深度]的下一个元素,等c.

问题是段错误,我不知道为什么。

【问题讨论】:

  • 我想你想要你想要的B = { {1, 2, 4}, {1, 2, 5}, {1, 2, 6}, {1, 3, 4}, {1, 3, 5}, {1, 3, 6} }(注意最后两个元组中中间元素的变化。)
  • 哦,是的。当然。我在帖子里改了。谢谢!
  • 你从哪里得到这个问题陈述?
  • 我自己在我正在开发的一个程序中遇到了它。在写下我的问题的简化版本时,我犯了一个错误。不过,我不确定这个问题是否是解决我更大问题的正确方法
  • 您能否更详细地解释您的意思?就我对集合论的理解而言,我想做的是笛卡尔积(不幸的是,这只是一门入门级的大学课程)。同样不幸的是,我不是指无序 n 元组的意思,但我当然希望输出的每个内部数组的第一个元素来自输入的第一个数组。

标签: c cartesian-product


【解决方案1】:

问题出在你分配 B 的方式上。你需要将它分配为一个 newx 指向 int 的指针数组,然后将每个元素分配为一个 newy的数组> 整数。

int** B = malloc(sizeof(int*) * *newx);
for (unsigned int i = 0 ; i < *newx; i++) {
   B[i] = malloc(sizeof(int) * *newy);
}

但我仍然坚持我之前使用迭代解决方案的回答。

【讨论】:

  • 哇,非常感谢!它立即起作用了! :D 是的,它不那么浪费并且在概念上更简单。我明天试试看。
【解决方案2】:

你一开始说你找不到迭代实现,所以作为对你问题的一种回答,我会提供一个。

从包含与集合一样多的整数的数组开始,从 0 开始。 每个整数代表一个集合。

const unsigned int x = 3;
unsigned int *ar = calloc(x, sizeof(unsigned int));

现在,就像您的数组是里程表一样向上计数,但是当每个数字达到相应集合中的元素数量时,每个数字都会滚动。

然后,您可以使用数组中的索引从集合中读取元素:

{0, 0, 0} = {1, 2, 4}
{0, 0, 1} = {1, 2, 5}
...
{0, 1, 2} = {1, 3, 6}

而 0、1、2 是整个数组再次翻转之前的最后一个。

【讨论】:

  • 部分问题是我不知道我有多少套。
  • 我以为 x 是套数。您只需使用 calloc(x, sizeof(unsigned int)) 分配数组。我已经相应地改变了我的答案。
  • 我在看到它如何逃脱递归调用时遇到了一些麻烦,我想我必须尝试实现它。感谢您抽出宝贵时间 =)
猜你喜欢
  • 2021-05-06
  • 2016-10-08
  • 1970-01-01
  • 2015-11-08
  • 2021-09-05
  • 2011-12-26
  • 2016-05-07
  • 2011-03-01
  • 2021-07-16
相关资源
最近更新 更多