Codegym University コースの一部としてのメンターによる講義の抜粋。フルコースにお申し込みください。


「こんにちは、アミーゴ!」

「こんにちは、リシ!」

「あなたはすでに配列についてある程度のことは知っていますし、いくつかのタスクも解決できたと思います。しかし、すべてを知っているわけではありません。たとえば、配列に関するもう 1 つの興味深い事実があります。配列は 1 次元 (線形) であるだけではありません。 ).二次元にすることもできます。」

「えっと…それはどういう意味ですか?」

「これは、配列のセルが列 (または行) だけでなく、長方形のテーブルも表すことができることを意味します。

int[][]name = new int[width][height];

"ここで、nameは配列変数の名前、widthはテーブルの幅 (セル単位)、heightはテーブルの高さです。例を見てみましょう。

int[][] data = new int[2][5];
data[1][1] = 5;
2 列 5 行の 2 次元配列を作成します。
セル(1,1)に5を書き込みます。

「メモリ内では次のようになります。

2次元配列

「ところで、2 次元配列の場合は、高速初期化も使用できます。

// Lengths of months of the year in each quarter
int[][] months = { {31, 28, 31}, {30, 31, 30}, {31, 31, 30}, {31, 30, 31} };

「ふーん...興味深いですね。最初の内側の括弧が 1 つの要素を表し、次が 2 番目の要素を表すと想像すると... では、2 次元配列は配列の配列のようなものですか?」

「あなたはなんと賢い生徒でしょう! その通りです。最初の要素は 1 次元配列{31, 28, 31}、2 番目の要素は{30, 31, 30}、というように続きます。しかし、これについては、このレッスンの少し後で戻ります。それまでは、次のことを考えてみてください。行と列を含むテーブルとしての 2 次元配列。各交点にセルが形成されます。

「頭の中でイメージはできました。ところで、これらの 2 次元配列は何に使われますか?」

「プログラマは 2 次元配列を必要とすることがよくあります。よく見ると、チェス、チェッカー、三目並べ、海戦など、ほとんどすべてのボード ゲームが既製の 2 次元配列を使用して実装されています。」

海戦

「分かりました! チェスや海戦の場は 2 次元配列に完全に適合します!」

「はい、ただしセル座標として数値を使用する必要があります。「ポーン e2-e4」ではなく、「ポーン (5,2) -> (5,4)」です。プログラマーにとってはさらに簡単です。 」

配列内の要素の配置: (x, y) または (y, x)

「2 次元配列を作成すると、興味深いジレンマが生じます。 を使用して配列を作成するとき、new int [2][5];テーブルは「25」ですか、それとも「2 列 5 行」ですか?

「言い換えれば、最初に幅を指定してから高さを指定しているのか、それともその逆で、最初に高さを指定してから幅を指定しているのか、完全には明らかではありません。」

「はい、これがジレンマです。そして明確な答えはありません。」

"何をすべきか?"

「まず、 2 次元配列が実際にメモリにどのように格納されているかを理解することが重要です。当然のことながら、コンピュータのメモリには実際にはテーブルがありません。メモリ内の各場所には、0、1、2、という連続した数値アドレスがあります。 ... 私たちにとって、これは 2 × 5 のテーブルですが、メモリ内では単なる 10 個のセルであり、それ以上のものはありません。行や列に分割されることはありません。」

「それはわかりました。では、幅と高さのどちらの寸法が最初に来るかをどのように判断するのでしょうか?」

「最初のオプションを考えてみましょう。最初に幅、次に高さです。」 このアプローチを支持する議論は次のとおりです。誰もが学校で数学を学び、座標のペアは「x」(つまり、水平軸)として書かれることを学びます。次に「y」(垂直方向の寸法)。そして、これは単なる学校の基準ではなく、数学において一般に受け入れられている基準です。彼らが言うように、数学について議論することはできません。」

「そうですか? そうですね、もし戦えないなら、まず幅、そして高さですか?」

「 『最初に高さ、次に幅』を支持する興味深い議論があります。この議論は、2 次元配列の高速初期化から来ています。結局のところ、配列を初期化したい場合は、次のようなコードを記述します。」

// Matrix of important data
int[][] matrix = { {1, 2, 3, 4, 5}, {1, 2, 3, 4, 5} };

「それで、それは私たちに何をもたらすのでしょうか?」

「何か気づきましたか?これがあったらどうしますか?」

// Matrix of important data
int[][] matrix = {
  {1, 2, 3, 4, 5},
  {1, 2, 3, 4, 5}
};

「コードにデータを 1 行ずつ書き込むと、2 行 5 列のテーブルが得られます。」

「なるほど。2 が高さ、5 が幅です...それではどのオプションを使用すればよいでしょうか?」

「どちらが便利かを決めるのはあなた次第です。最も重要なことは、同じプロジェクトに取り組むすべてのプログラマーが同じアプローチに固執することです。」

「初期化された 2 次元配列がコードに多数含まれるプロジェクトに取り組んでいる場合、そこにあるものはすべて高速データ初期化に基づいている可能性が高く、つまり、標準の「高さ x 幅」になります。

「多くの数学を必要とし、座標を扱うプロジェクト (ゲーム エンジンなど) に携わっている場合、コードは「幅 x 高さ」アプローチを採用する可能性が高くなります。

2次元配列の配置方法

「さて、レッスンの最初に気づいた 2 次元配列の特殊な機能を覚えていますか?」

「そうです! 2 次元配列は実際には配列の配列だということでした!」

「その通りです。」言い換えると、通常の配列の場合、配列変数が配列要素を格納するコンテナへの参照を格納する場合、2 次元配列の場合は状況が少し爆発します。 -array 変数は、1 次元配列への参照を格納するコンテナへの参照を格納します。何百回も説明するよりも、実際に動作しているのを一度見てみる方が良いでしょう。」

2次元配列の配置方法

「左側には 2 次元配列オブジェクトへの参照を格納する 2 次元配列変数があります。中央には2次元配列オブジェクトがあり、そのセルには 1 次元配列が格納されます。 2 次元配列の行です。そして右側には4つの 1 次元配列、つまり 2 次元配列の行が表示されます。これが 2 次元配列の実際の動作方法です。」

「素晴らしいですね!でも、それは私たちに何をもたらしてくれるのでしょう?」

「『コンテナのコンテナ』には『行の配列』への参照が格納されるため、非常に迅速かつ簡単に行を交換できます。『コンテナのコンテナ』を取得するには、インデックスを 2 つではなく 1 つ指定するだけです。例:

int[][] data = new int[2][5];
int[] row1 = data[0];
int[] row2 = data[1];

「以下のコードを見てください。これを使用して行を交換できます。」

// Matrix of important data
int[][] matrix = {
  {1, 2, 3, 4, 5},
  {5, 4, 3, 2, 1}
};

int[] tmp = matrix[0];
matrix[0] = matrix[1];
matrix[1] = tmp;
2 次元配列に





matrix[0]は、最初の行への参照が格納されます。
参照を交換します。

結果として、matrix配列は次のようになります。
{
  {5, 4, 3, 2, 1},
  {1, 2, 3, 4, 5}
};

「わかりました。2 つの普通のアイテムを交換するのと同じように機能します。」

「そのとおりです。2 次元配列のセルを参照するが、配列名の後にインデックスを 1 つだけ指定する場合、セルに通常のセルへの参照が格納されているコンテナのコンテナを参照していることになります。次元配列。」

「すべてが論理的で明確に思えます。講義をありがとう、リシ!」

「どういたしまして。賢く実践してください。」