【问题标题】:How to convert an M-dimensional array to an N-dimensional array?如何将 M 维数组转换为 N 维数组?
【发布时间】:2020-05-15 08:09:31
【问题描述】:

arr2D[i][j]arr1D[i * k + j]启发,看了this post及其下的cmets,想知道一个可以改变任意数组维度的算法。

让我试着把它形式化:

输入:

  1. 一个M-维容器A

  2. 容器尺寸D(大小)

  3. 目标维度N

输出:

如果是N > 0,则返回一个与A内容相同的N维容器B,否则返回错误代码。

注意:

您可以为 N 维容器选择任何最佳尺寸。

编辑:

我不需要任何完全可用的代码。请问有没有这样的算法?

【问题讨论】:

  • 我认为这类似于将数字表示从一个基数转换为另一个基数。唯一的区别是每个维度的基础可能不同。例如,您可以将十进制数 1234 视为 4 维数组中的索引,其中每个维度的大小为 10。
  • 任何代码要显示?
  • 显示你迄今为止尝试过的内容。
  • 出于实际目的,仅提供 X 维访问的线性 std::vector 的模板化包装器就足够了,唯一的问题是当底层向量必须不同大小时该怎么办。
  • @ArdentCoder 我在 C++ 中添加了转换的答案 ...

标签: c++ arrays algorithm templates multidimensional-array


【解决方案1】:

将 [100] 转换为 [10][10]:

#include <iostream>

typedef int (*parray)[10];

parray foo (int *in) {
    return (parray)in;
}

int main()
{
    int in[100];
    in[55] = 42;
    int (*out)[10] = foo(in);
    std::cout << out[5][5] << std::endl;

    return 0;
}

【讨论】:

  • 至少违反了严格的别名规则,因此 UB。
  • 这个我还是看不懂,可能是那个typedef和function。你能解释一下吗?
  • 正如@Jarod 指出的那样,除了作为 SO 练习之外,您不想这样做。它使用强制转换将 100 个整数从 100x1 重新映射到 10x10。数组只是底层的地址算法。
  • 哦,我明白了@stark 谢谢。你知道为什么这个问题被否决了吗?
  • 不知道。我有点惊讶我没有得到任何东西。
【解决方案2】:

你原来的M维容器是A

我们要创建一个新的N 维容器B,它将容纳A 的所有内容。

首先,我们必须找出一个映射,以便我们可以轻松地在 AB 中找到相同的元素。

让我们用一些例子来推断映射是怎样的:

(1) M = 2, N = 1

A: a * b    B: c
we can set the dimension c to be a * b, thus we have
A[i][j] = B[i * c + j]

(2) M = 3,N = 1

A: a * b * c    B: d
d = a * b * c
A[i][j][k] = B[(i * b * c) + (j * c) + k]

(3) M = 3,N = 2

A: a * b * c    B: d * e
d = a, e = b * c
A[i][j][k] = B[i][j * c + k]

(4) M = 4,N = 1

A: a * b * c * d    B: e
e = a * b * c * d
A[i][j][k][l] = B[(i * b * c * d) + (j * c * d) + (k * d) + l]

(5) M = 5,N = 4

A: a * b * c * d * e    B: u * v * w * x
u = a, v = b, w = c, x = d * e
A[i][j][k][l][m] = B[i][j][k][(l * e) + m]

(6) M = 5,N = 2

A: a * b * c * d * e    B: f * g
f = a, g = b * c * d * e
A[i][j][k][l][m] = B[i][(j * c * d * e) + (k * d * e) + (l * e) + m]

如果 A 有 M 个维度 a1, a2, ..., aM 并且 B 有 N 个维度 b1, b2, ..., bN,我们可以说:

如果 M > N,那么对于所有 0

这样我们就知道如何创建 B 以及它的每个维度的大小。

使用示例中显示的映射函数,您可以轻松地将任何M-dimension 矩阵转换为N-dimension 矩阵。

如果M &lt; N,你可以做同样的事情,但方向相反。

【讨论】:

  • 如果 M 有 k 个因子并且 N > k 怎么办?
  • 因子是指尺寸吗?在我的回答中,已经有对此的解释。如果M 的维度小于N,您只需在相反的方向上做同样的事情。这种方法最适合MN 的任何维度。
  • ig 所以,但由于格式和一些修剪的解释,我无法完全理解它
  • 添加了一些例子,希望对您有所帮助。
【解决方案3】:

由于您不需要代码,让我解释一下如何使用模板来完成。

假设您有一个大小为 n_{0},...,n_{d-1} 的 D 维数组,您始终可以通过合并其中两个乘以大小来删除一个维度。示例: a[5][4][3] 包含 60 个元素,因此 b[20][3] 或 c[5][12] (对于简单的情况,因为您甚至可以构造 d[15][4] 和任何排列)可以很容易地包含与 a 相同的元素,索引的映射也很明显......

现在使用 C++ 做这件事要复杂得多,但您需要:可变参数模板和模板元编程。

可变参数模板用于定义您喜欢的任何维度的数组类型,模板元编程用于定义将 D 维数组映射到 N 维数组的运算符。 (我可能会说这并不容易,但在模板元编程中是一个非常难的好练习)。

【讨论】:

  • 如果 M 有 k 个因子并且 N > k 怎么办?
  • M[a][b] 可以简单地投影到 M[1][1][1][a][b] 中,不是吗?
  • 是的@jean-baptisteyunès。我一直在寻找一种最佳方式来做到这一点。您已经展示了一个简单的解决方案,但我想知道这是否也是最佳解决方案?
  • 最优是什么意思?最后,机器中的一切都是平的,因此只需使用坐标来索引线性结构。
  • 哦@jean-baptisteyunès 我没想到。我会为您对此评论的回答投赞成票。
【解决方案4】:

因此,您只想在不更改任何数据的情况下重新格式化您的矩阵。正如我在评论中暗示的那样,最简单的方法是使用一维数组中间步骤将 M 维转换为 N 维。

这里的其他答案在同一轨道上,但缺乏整个数学......他们只有一些小维度的例子,没有通用方程,所以这里是:

要在A[A0][A1]...[A(M-1)]X[A0*A1*...*A(M-1)] 之间进行转换,其中A0,A1,...A(M-1) 是容器的尺寸(分辨率),只需执行以下操作:

// M-D -> 1D
x = a0
   +a1*A0
   +a2*A0*A1
   ...
   +a(M-1)*A0*A1*...*A(M-2);

// 1D -> M-D   
q=x;
a0 = q%A0; q/=A0;
a1 = q%A1; q/=A1;
a2 = q%A2; q/=A2;
...
a(M-1) = q%A(M-1); q/=A(M-1);

其中a0,a1,...a(M-1)x 是数组中的索引。

您实际上不需要将 M-D 数组转换为 1D,然后再转换回 N-D 就足以转换索引,所以:

for (a0=0;a0<A0;a0++)
 for (a1=0;a1<A1;a1++)
  ...
   for (a(M-1)=0;a(M-1)<A(M-1);a(M-1)++)
      {
      // M-D -> 1D
      x = a0
         +a1*A0
         +a2*A0*A1
         ...
         +a(M-1)*A0*A1*...*A(M-2);
      // 1D -> N-D   
      q=x;
      b0 = q%B0; q/=B0;
      b1 = q%B1; q/=B1;
      b2 = q%B2; q/=B2;
      ...
      b(N-1) = q%B(N-1); q/=B(N-1);
      // copy A -> B
      B[b0][b1]...[b(N-1)] = A[A0][A1]...[A(M-1)];
      }

不要忘记尺寸必须是:

A0*A1*...*A(M-1) <= B0*B1*...*B(N-1)

否则您将访问数组超出其边界,因为A 中的数据将不适合B

如果你有动态维度,你可以使用:

【讨论】:

  • 哇,我没有看到动态嵌套的 for 循环。看起来很有趣!
猜你喜欢
  • 2016-07-02
  • 2011-07-05
  • 2019-07-09
  • 2011-08-24
  • 2015-07-16
  • 2019-04-03
  • 1970-01-01
  • 1970-01-01
  • 2021-04-04
相关资源
最近更新 更多