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


90

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

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

回答:


163

配列要素を行順と列順のどちらで格納するかを決定してから、一貫性を保つ必要があります。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;  
 }

7
この答えはより明確だと思います。特に初心者にとっては、関数を1行で記述しない方がよいでしょう... !! とにかくそれは悪い習慣です.. :)
リピス

3
この回答は、適切な多次元配列をサポートしていないコンパイラ(組み込みシステムなど)がある場合にも役立ちます
Alex Marshall

1
同じ質問に正解できる人が多いのは驚きですが、わかりやすい言葉で答えているのはそのうちの1人だけです。これは、答えが得られるのと同じくらい簡単です。しかし、実際にそれに対して良い答えを提供したのはジョンだけです。残りはすべてゴミであり、すでに答えを知っている人だけが簡単に理解できます。エイリアンの代わりに実際に英語で話してくれたジョンに感謝します。一部の人々が教えるのがどれほど悪いか、そしてジョン・ノラーのような優れた教師が他の誰よりもはるかに効果的に単純化してコミュニケーションする方法を知っていることを示しています。
user2948630 2014

6
このマッピングを反転する方法を示すとよいでしょう。1D配列のインデックスがalphaであり、2D配列がNインデックスを使用して両方向に次元を持っている場合、x, y@ JohnKnoellerによるとalpha=x+N*y。これを反転する方法は、設定x=alpha%Ny= (alpha-alpha%N)/Nです。
ティム

私はほぼ毎日ここに来ます!
フェリペグティエレス

23

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

index = indexX * arrayWidth + indexY;

または、

index = indexY * arrayHeight + indexX;

arrayWidthX軸とarrayHeightY軸に沿って測定されると仮定)

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

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

int xy[10][10];

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


17

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

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 ]; }

1
あなたMAXXMAXY値が紛らわしい、名前の最大値のためにしているxyされているMAXX - 1MAXY - 1、それぞれ。おそらくSIZE_X、そしてSIZE_Yもっと良いかもしれませんか?
caf 2010年

3
[y * maxx + x]は列の順序であり、行の順序ではありません。この方法でMatlabの作品ですが、Cの配列は、通常の仕事の方法ではありません
ジョンKnoeller

@everyone:データに触れたままにしておきますが、純粋にこれら2つのget / set関数が同じ式を使用している場合を除いて、これと同じように行うことができます。(保証付き!)
imacake 2011年

ここではマクロの方が適切な場合があるため、低レベルのデータアクセスと思われるものに不要な関数呼び出しを積み重ねることはありません(特に、疑似2次元配列の1次元インデックス作成は最適化手法である場合があるため)
krs013

コードがクラスメンバーであると仮定すると、このコードはインライン化されます。それ以外の場合は、明示的なインラインであるMUCHマクロよりも良いです。
Kornel Kisielewicz 2014

7

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

3

行の主要な例を使用する:

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

使用する言語でデータを取得できるようにデータを保存することが重要です。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から始まり、それに応じて調整して、保存されたデータを取得できます。

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


-2

単純なポインタを配置して、2D配列にアクセスできるはずです。配列[x] [y]は、p [0x * width + 0y] [0x * width + 1y] ... [0x * width + n-1y] [1x * width + 0y]などのようにポインターに配置されます。 。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.