将二维数组映射到一维数组
Posted
技术标签:
【中文标题】将二维数组映射到一维数组【英文标题】:Map a 2D array onto a 1D array 【发布时间】:2011-01-10 04:48:56 【问题描述】:我想用一维数组表示一个二维数组。一个函数将传递两个索引 (x,y) 和要存储的值。这两个索引将代表一维数组的单个元素,并相应地设置它。我知道一维数组需要有arrayWidth × arrayHeight的大小,但我不知道如何设置每个元素。
例如,如何区分 (2,4,3) 和 (4,2,3)?我尝试将数组设置为 x*y,但 2*4 和 4*2 会导致数组中的相同点,我需要它们不同。
【问题讨论】:
【参考方案1】:您需要决定数组元素是以行顺序还是列顺序存储,然后保持一致。 http://en.wikipedia.org/wiki/Row-major_order
C 语言对多维数组使用行顺序
为了用一维数组模拟这个,你将行索引乘以宽度,然后添加列索引:
int array[width * height];
int SetElement(int row, int col, int value)
array[width * row + col] = value;
【讨论】:
我觉得这个答案比较清楚,尤其是初学者最好不要一行写函数...!!无论如何,这是不好的做法.. :) 当您的编译器(例如嵌入式系统)没有适当的多维数组支持时,此答案也很有用 令人惊讶的是,有多少人可以正确回答同一个问题,但只有一个人以易于理解的方式说出来。这是一个很简单的答案。然而,约翰是唯一一个真正为它提供一个好的答案的人。其余的都是垃圾,只有已经知道答案的人才能轻松理解。谢谢约翰,实际上是用英语而不是外星人说话。只是表明有些人在教学方面有多糟糕,以及像 John Knoeller 这样的优秀教师是如何比其他人更有效地简化和沟通的。 如果一维数组的索引是alpha
,并且二维数组在两个方向上的维度为N
,索引为x, y
,那么它会很好地展示如何反转这个映射:然后根据@JohnKnoeller,alpha=x+N*y
。反转这种情况的方法是设置x=alpha%N
和y= (alpha-alpha%N)/N
。
我几乎每天都来这里!【参考方案2】:
将二维数组索引重新计算为一维数组索引的典型公式是
index = indexX * arrayWidth + indexY;
你也可以使用
index = indexY * arrayHeight + indexX;
(假设arrayWidth
沿X轴测量,arrayHeight
沿Y轴测量)
当然,可以想出许多不同的公式来提供替代的唯一映射,但通常没有必要。
在 C/C++ 语言中,内置的多维数组存储在内存中,因此最后一个索引变化最快,这意味着对于声明为的数组
int xy[10][10];
元素xy[5][3]
紧跟在内存中的xy[5][4]
之后。您可能还想遵循该约定,根据您认为是两个公式中“最后一个”的索引(X 或 Y)选择上述两个公式之一。
【讨论】:
【参考方案3】:示例:我们想要表示一个 SIZE_X 和 SIZE_Y 大小的二维数组。这意味着我们将有 MAXY 个连续的 MAXX 行。因此集合函数是
void set_array( int x, int y, int val ) array[ x * SIZE_Y + y ] = val;
得到的是:
int get_array( int x, int y ) return array[ x * SIZE_Y + y ];
【讨论】:
您的MAXX
和MAXY
值的命名容易混淆,因为x
和y
的最大值分别为MAXX - 1
和MAXY - 1
。也许SIZE_X
和SIZE_Y
会更好?
[y * maxx + x] 是列顺序,而不是行顺序。这是 matlab 的工作方式,但不是数组在 C 中的正常工作方式。
@everyone:除非你保持数据被触及,但纯粹是这两个 get/set 函数,并且它们使用相同的公式,你可以像这样或那样做。 (保证!)
宏在这里可能更合适,因此您不会在应该是低级数据访问的情况下堆叠不必要的函数调用(特别是因为伪二维数组中的一维索引有时是优化技术。
假设代码是类成员,这段代码将被内联。否则显式内联比宏好。【参考方案4】:
正如其他人所说的按行顺序排列的 C 映射
#include <stdio.h>
int main(int argc, char **argv)
int i, j, k;
int arr[5][3];
int *arr2 = (int*)arr;
for (k=0; k<15; k++)
arr2[k] = k;
printf("arr[%d] = %2d\n", k, arr2[k]);
for (i=0; i<5; i++)
for (j=0; j< 3; j++)
printf("arr2[%d][%d] = %2d\n", i, j ,arr[i][j]);
输出:
arr[0] = 0
arr[1] = 1
arr[2] = 2
arr[3] = 3
arr[4] = 4
arr[5] = 5
arr[6] = 6
arr[7] = 7
arr[8] = 8
arr[9] = 9
arr[10] = 10
arr[11] = 11
arr[12] = 12
arr[13] = 13
arr[14] = 14
arr2[0][0] = 0
arr2[0][1] = 1
arr2[0][2] = 2
arr2[1][0] = 3
arr2[1][1] = 4
arr2[1][2] = 5
arr2[2][0] = 6
arr2[2][1] = 7
arr2[2][2] = 8
arr2[3][0] = 9
arr2[3][1] = 10
arr2[3][2] = 11
arr2[4][0] = 12
arr2[4][1] = 13
arr2[4][2] = 14
【讨论】:
【参考方案5】:使用行主要示例:
A(i,j) = a[i + j*ld]; // where ld is the leading dimension
// (commonly same as array dimension in i)
// matrix like notation using preprocessor hack, allows to hide indexing
#define A(i,j) A[(i) + (j)*ld]
double *A = ...;
size_t ld = ...;
A(i,j) = ...;
... = A(j,i);
【讨论】:
【参考方案6】:以可以使用所用语言检索数据的方式存储数据非常重要。 C 语言以行优先顺序存储(所有第一行都在前,然后是所有第二行,...),每个索引从 0 运行到它的维度 1。所以数组 x[2][3] 的顺序是 x[0][0], x[0][1], x[0][2], x[1][0], x[1][ 1],x[1][2]。因此在 C 语言中,x[i][j] 与一维数组项 x1dim[i*3 +j] 存储在相同的位置。如果数据是这样存储的,用C语言就很容易检索。
Fortran 和 MATLAB 是不同的。它们以列优先顺序存储(所有第一列首先出现,然后是所有第二行,......)并且每个索引都从 1 运行到它的维度。所以索引顺序是 C 的倒数,所有索引都大 1。如果按 C 语言顺序存储数据,FORTRAN 可以使用 X_FORTRAN(j+1, i+1) 找到 X_C_language[i][j]。例如,X_C_language[1][2] 等于 X_FORTRAN(3,2)。在一维数组中,该数据值位于 X1dim_C_language[2*Cdim2 + 3],与 X1dim_FORTRAN(2*Fdim1 + 3 + 1) 的位置相同。请记住 Cdim2 = Fdim1,因为索引的顺序是相反的。
MATLAB 与 FORTRAN 相同。除了索引通常从 1 开始之外,Ada 与 C 相同。任何语言都将具有这些 C 或 FORTRAN 顺序之一的索引,并且索引将从 0 或 1 开始,并且可以相应地进行调整以获取存储的数据。
对不起,如果这个解释令人困惑,但我认为程序员知道它是准确且重要的。
【讨论】:
【参考方案7】:您应该能够使用简单的指针访问二维数组。数组[x][y] 将在指针中排列为 p[0x * width + 0y][0x * width + 1y]...[0x * width + n-1y][1x * width + 0y] 等.
【讨论】:
以上是关于将二维数组映射到一维数组的主要内容,如果未能解决你的问题,请参考以下文章