web-dev-qa-db-ja.com

2D配列を1D配列にマッピングします

2D配列を1D配列で表現したい。関数は、2つのインデックス(x、y)と保存する値を渡します。これらの2つのインデックスは、1D配列の単一の要素を表し、それに応じて設定します。 1D配列にはarrayWidth×arrayHeightのサイズが必要であることは知っていますが、各要素の設定方法はわかりません。

たとえば、(2,4,3)と(4,2,3)を区別するにはどうすればよいですか?配列をx * yとして設定しようとしましたが、2 * 4と4 * 2は配列内の同じスポットになり、それらを異なるものにする必要があります。

78
Blackbinary

配列要素を行順で保存するか列順で保存するかを決定し、一貫性を保つ必要があります。 http://en.wikipedia.org/wiki/Row-major_order

C言語は多次元配列に行順序を使用します

これを1次元配列でシミュレートするには、行インデックスに幅を掛け、列インデックスを次のように追加します。

 int array[width * height];

 int SetElement(int row, int col, int value)
 {
    array[width * row + col] = value;  
 }
140
John Knoeller

2D配列インデックスを1D配列インデックスに再計算するための一般的な式は次のとおりです。

index = indexX * arrayWidth + indexY;

または、使用することができます

index = indexY * arrayHeight + indexX;

arrayWidthはX軸に沿って測定され、arrayHeightはY軸に沿って測定されると仮定します)

もちろん、代替の一意のマッピングを提供する多くの異なる式を思い付くことができますが、通常は必要はありません。

C/C++言語では、組み込みの多次元配列がメモリに格納されるため、最後のインデックスが最も速く変化します。つまり、

int xy[10][10];

メモリ内の要素xy[5][3]の直後にxy[5][4]が続きます。同様に、この規則に従って、2つの「最後」のインデックス(XまたはY)に応じて上記の2つの式のいずれかを選択することもできます。

16
AnT

例:SIZE_XおよびSIZE_Yサイズの2D配列を表現したい。これは、MAXXサイズの連続したMAXY行があることを意味します。したがって、集合関数は

void set_array( int x, int y, int val ) { array[ x * SIZE_Y + y ] = val; }

Getは次のようになります。

int get_array( int x, int y ) { return array[ x * SIZE_Y + y ]; }
15

他の人が言ったように、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
6
Sammy

行メジャーの例を使用:

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);
1
Anycorn

使用する言語で取得できるようにデータを保存することが重要です。 C言語は、0からそのディメンション1までのすべてのインデックスを使用して、行優先順(最初の行がすべて最初に、次に2番目の行がすべて...)で格納されます。したがって、配列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]は1次元配列エントリx1dim [i * 3 + j]と同じ場所に格納されます。データがそのように格納されている場合、C言語で簡単に取得できます。

FortranとMATLABは異なります。列優先の順序で格納され(最初の列がすべて最初に、次に2番目の行がすべて...)、すべてのインデックスが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)と同じです。 1次元配列では、そのデータ値はX1dim_C_language [2 * Cdim2 + 3]にあり、これはX1dim_FORTRAN(2 * Fdim1 + 3 + 1)と同じ位置です。インデックスの順序が逆になっているため、Cdim2 = Fdim1であることを忘れないでください。

MATLABはFORTRANと同じです。 AdaはCと同じです。ただし、インデックスは通常1から始まります。どの言語でもCまたはFORTRANのいずれかの順序でインデックスが付けられ、インデックスは0または1から始まり、それに応じて調整して保存データを取得できます。

この説明がわかりにくい場合は申し訳ありませんが、プログラマーが知ることは正確で重要だと思います。

1
Mark