将二维数组映射到一维数组

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%Ny= (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 ]; 

【讨论】:

您的MAXXMAXY 值的命名容易混淆,因为xy 的最大值分别为MAXX - 1MAXY - 1。也许SIZE_XSIZE_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] 等.

【讨论】:

以上是关于将二维数组映射到一维数组的主要内容,如果未能解决你的问题,请参考以下文章

使用循环将值从 C++ 中的一维数组添加到二维数组中

LC2022. 将一维数组转变成二维数组

c语言怎么把二维数组的字符串给到一维数组?

将某个二维数组索引下的数据移动到一维数组

《LeetCode之每日一题》:253.将一维数组转变成二维数组

将二维数组压缩成一维数组