配列
多次元配列
前の記事では、構成要素が直線状に並んだ配列を説明しました。構成要素自体が配列となっている複雑な構造の配列を、多次元配列と呼びます。
多次元配列
配列が構成要素型になっている配列が2次元配列です。そして、2次元配列が構成要素型となっている配列が3次元配列になります。これらを1次元配列と区別して多次元配列(multidimensional array)と言います。
2次元配列
まずは、多次元配列の中で最も単純な構造のint型の2次元配列を考えてみましょう。その実態は次のようになります。
『int 型を構成要素型とする配列』を構成要素とする配列
この配列の型は int[][] であり、以下に示すどれを使用しても宣言できます。
- int[][] x;
- int[] x[]; 『int 型を構成要素型とする配列』を構成要素とする配列の宣言
- int x[][];
具体的な例を考えていきましょう。『int 型を構成要素型とする要素数3の配列』を構成要素とする要素数2の配列
本体の生成を同時に行うと、配列変数の宣言は以下のようになります。
int[][] x = new int[3][2];
この宣言によって生成される配列xのイメージを表したのが次の図になります。
3次元配列
続いて、3次元配列です。例えば、long型の3次元配列の型はlong[][][]になります。ここでは、以下の配列を考えてみましょう。
long[][][] y = new long[2][3][4];
ここで宣言されたyの型は、次のようになります。
『long型を構成要素型とする配列を構成要素型とする配列』を構成要素型とする配列
2次元配列xと、3次元配列yの構成要素型は、それぞれ次のようになっています。
- x…int 型を構成要素型とする配列
- y…long 型を構成要素型とする配列を構成要素型とする配列
これらの配列を、それ以上分解できない要素にまで分解すると、配列xはint型となり、配列yはlong型となります。このような型を要素型(element type)と呼び、要素型レベルの構成要素を要素(element)と呼びます。そして、全要素の個数が要素数です。
プログラム例
2次元配列を生成して全要素を0から99の乱数で格納するプログラムを以下に示します。
//Array2D.java
//二次元配列を生成して全要素を乱数で埋め尽くす
import java.util.Random;
import java.util.Scanner;
public class Array2D {
public static void main(String[] args){
Random rand = new Random();
Scanner stdIn = new Scanner(System.in);
System.out.print("行数:"); //行数を読み込む
int h = stdIn.nextInt();
System.out.print("列数:"); //列数を読み込む
int w = stdIn.nextInt();
int[][] x = new int[h][w];
for(int i = 0; i < h; i++)
for(int j = 0; j < w; j++){
x[i][j] = rand.nextInt(100);
System.out.println("x[" + i + "][" + j + "] = " + x[i][j]);
}
stdIn.close();
}
}
もう一つのプログラムでは、2つの行数の和を求めて表示するプログラムになっています。
//Matrix.java
//2行3列の行数を加算する
public class Matrix {
public static void main(String[] args){
int[][] a = {{1,2,3}, {4,5,6}};
int[][] b = {{6,3,4}, {5,1,2}};
int[][] c = {{0,0,0},{0,0,0}};
for(int i = 0; i < 2; i++)
for(int j = 0; j < 3; j++)
c[i][j] = a[i][j] + b[i][j];
System.out.println("行列a:");
for(int i = 0; i < 2; i++){
for(int j = 0; j < 3; j++)
System.out.printf("%3d", a[i][j]);
System.out.println();
}
System.out.println("行列b:");
for(int i = 0; i < 2; i++){
for(int j = 0; j < 3; j++)
System.out.printf("%3d", b[i][j]);
System.out.println();
}
System.out.println("行列c:");
for(int i = 0; i < 2; i++){
for(int j = 0; j < 3; j++)
System.out.printf("%3d", c[i][j]);
System.out.println();
}
}
}
多次元配列の内部
多次元配列の内部を詳しく説明していきます。まずは、配列変数の宣言と本体の生成を個別に行います。以下のように宣言、処理を分解します。
int[][] x;
x = new int[2][];
x[0] = new int[2];
x[1] = new int[2];
実に4段階も分解でき、2次元配列の内部構造が複雑なことを示します。以下の図を見ながら理解を深めましょう。
- 2次元配列xの宣言になります。int[][]型のxは、配列本体ではなく、配列変数です。
2. 配列本体を生成するとともに、xがそれを参照するように代入を行います。ここで生成するのは、以下の配列になります。
構成要素型がint[]型で構成要素数が2の配列
3. 配列本体を生成するとともに、x[0]がそれを参照するように代入を行います。ここで生成するのは、以下の配列になります。
構成要素型がint[]型で構成要素数が2の配列
4. 配列本体を生成するとともに、x[1]がそれを参照するように代入を行います。ここで生成するのは、以下の配列になります。
構成要素型がint[]型で構成要素数が2の配列
凸凹な2次元配列の内部
上記の配列xの構成要素であるx[0]とx[1]は、それぞれが独立した配列変数です。そのため、配列の要素数は同一である必要はありません。生成する個々の配列の要素数を異なるものにすれば、凸凹な配列になります。
//UnevennessArray.java
//凹凸な2次元配列
public class UnevennessArray {
public static void main(String[] args){
int[][] c;
c = new int[3][];
c[0] = new int[5];
c[1] = new int[3];
c[2] = new int[4];
for(int i = 0; i < c.length; i++){
for(int j = 0; j < c[i].length; j++)
System.out.printf("%3d", c[i][j]);
System.out.println();
}
}
}
変数cが参照するのは、以下の配列です。
- c…構成要素型がint[]型で構成要素数が3の配列
そして、各構成要素 c[0]、c[1]、c[2]は、以下の配列を参照します。
- c[0]…構成要素型がint[]型で構成要素数が5の配列
- c[1]…構成要素型がint[]型で構成要素数が3の配列
- c[2]…構成要素型がint[]型で構成要素数が4の配列
初期化子
以下の例を見てましょう。配列aに対して初期化子が与えられています。この初期化子は、縦横に並べて宣言すると読みやすくなります。
int[][]a = {
{1, 2, 3}, //0行目の要素に対する初期化子
{4, 5, 6}, //1行目の要素に対する初期化子
};
0行目と1行目の間のコンマはなくても構いません、しかし、以下のメリットがあります。
- 初期化子を縦に並べた際の見かけ上のバランスがとれる。
- 行単位での初期化子の追加・削除が容易になる。