[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

情報処理技法(Javaプログラミング)I 第10回

目次
索引

配列(2)

配列要素の挿入と削除

前回、配列は、一度用意すると要素数は変えられないと言いました。 要素数を5個に決めたら、ずっと5個のままです。 しかし、配列に要素を挿入したり、配列から要素を削除したい場合もあるでしょう。 この問題を解決するには、次のような方法が考えられます。

ここでは、大きな配列を用意する方法について説明します。 配列をコピーする方法については、次の小節で説明します。

大きな配列の最初の部分を使うには、配列の要素数とは別に、データの個数を覚えておきます。 例えば、データの個数を変数 count で表します。 そして、for文などで、配列の要素数 a . length の代わりに、 count を使います。

次のプログラムでは、配列の要素数は10, データの個数は5として、すべてのデータを出力しています。

/*  1*/ class ArrayStack { // 配列によるスタック
/*  2*/     public static void main (String[] args) {
/*  3*/         int[] a = {10, 11, 12, 13, 14, 0, 0, 0, 0, 0}; // 要素数は10
/*  4*/         int i, count = 5; // データの個数は5
/*  5*/         for (i = 0; i < count; i++) { // データの個数回繰り返す
/*  6*/             System.out.println("a[" + i + "] = " + a[i]);
/*  7*/         }
/*  8*/     }
/*  9*/ }
24102a1:java1 k12x1001$ java ArrayStack
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
a[0] = 10
a[1] = 11
a[2] = 12
a[3] = 13
a[4] = 14
24102a1:java1 k12x1001$

この配列にデータ15を挿入するには、 a [ count ]にデータ15を格納し、 count を1増加させます。 つまり、

a = {10, 11, 12, 13, 14, 0, 0, 0, 0, 0}, count = 5.

a = {10, 11, 12, 13, 14, 15, 0, 0, 0, 0}, count = 6.

に変更します。

/*  1*/ class ArrayPush { // 配列へのプッシュ
/*  2*/     public static void main (String[] args) {
/*  3*/         int[] a = {10, 11, 12, 13, 14, 0, 0, 0, 0, 0};
/*  4*/         int i, count = 5;
/*  5*/         a[count] = 15; // データを挿入
/*  6*/         count++; // データの個数を1増加
/*  7*/         for (i = 0; i < count; i++) {
/*  8*/             System.out.println("a[" + i + "] = " + a[i]);
/*  9*/         }
/* 10*/     }
/* 11*/ }
24102a1:java1 k12x1001$ java ArrayPush
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
a[0] = 10
a[1] = 11
a[2] = 12
a[3] = 13
a[4] = 14
a[5] = 15
24102a1:java1 k12x1001$

元の配列から最後のデータ14を削除するには、 count を1減少させます。 つまり、

a = {10, 11, 12, 13, 14, 0, 0, 0, 0, 0}, count = 5.

a = {10, 11, 12, 13, 0, 0, 0, 0, 0, 0}, count = 4.

に変更します。 なお、 a [ count ]を0にしていますが、本当は必要ありません。

/*  1*/ class ArrayPop { // 配列からのポップ
/*  2*/     public static void main (String[] args) {
/*  3*/         int[] a = {10, 11, 12, 13, 14, 0, 0, 0, 0, 0};
/*  4*/         int i, count = 5;
/*  5*/         count--; // データの個数を1減少
/*  6*/         a[count] = 0; // やらなくてもよい
/*  7*/         for (i = 0; i < count; i++) {
/*  8*/             System.out.println("a[" + i + "] = " + a[i]);
/*  9*/         }
/* 10*/     }
/* 11*/ }
24102a1:java1 k12x1001$ java ArrayPop
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
a[0] = 10
a[1] = 11
a[2] = 12
a[3] = 13
24102a1:java1 k12x1001$

配列のコピー

整数(int型)の変数 x から変数 y にコピーするには、代入文 y = x; でできます。 しかし、配列 a の要素から配列 b の要素にコピーするには、 b = a; ではできません。

b[0] = a[0];
b[1] = a[1];
b[2] = a[2];
...

のように、一つ一つ配列要素をコピーする必要があります。

配列のコピー
配列のコピー

次のプログラムは、配列 a の要素から配列 b の要素にコピーし、 b の要素を出力するものです。

/*  1*/ class ArrayCopy { // 配列のコピー
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         int[] a = {10, 11, 12, 13, 14};
/*  5*/         int[] b = new int[a.length]; // 同じ要素数の配列を生成
/*  6*/         for (i = 0; i < a.length; i++) {
/*  7*/             b[i] = a[i]; // 要素ごとにコピー
/*  8*/         }
/*  9*/         for (i = 0; i < b.length; i++) {
/* 10*/             System.out.println("b[" + i + "] = " + b[i]);
/* 11*/         }
/* 12*/     }
/* 13*/ }
24102a1:java1 k12x1001$ java ArrayCopy
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
b[0] = 10
b[1] = 11
b[2] = 12
b[3] = 13
b[4] = 14
24102a1:java1 k12x1001$

5行目で、配列 a と同じ要素数の配列 b を宣言し、生成します。 6行目から8行目のfor文でコピーが行われます。 繰り返しの回数として a . length と書いていますが、配列 a b の要素数は同じなので、 b . length と書いてもよいです。

配列をコピーする方法で、この配列にデータ15を挿入するには、まず、要素数が1個多い配列を新たに生成します。 そして、元の配列から新しい配列にコピーして、新しい配列の最後にデータ15を格納します。 つまり、

a = {10, 11, 12, 13, 14}

から

b = {10, 11, 12, 13, 14, 15}

を作成します。

/*  1*/ class ArrayInsert { // 配列への挿入
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         int[] a = {10, 11, 12, 13, 14};
/*  5*/         int[] b = new int[a.length + 1]; // 1個多く生成
/*  6*/         for (i = 0; i < a.length; i++) { // すべてコピー
/*  7*/             b[i] = a[i];
/*  8*/         }
/*  9*/         b[a.length] = 15; // データを挿入
/* 10*/         for (i = 0; i < b.length; i++) {
/* 11*/             System.out.println("b[" + i + "] = " + b[i]);
/* 12*/         }
/* 13*/     }
/* 14*/ }
24102a1:java1 k12x1001$ java ArrayInsert
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
b[0] = 10
b[1] = 11
b[2] = 12
b[3] = 13
b[4] = 14
b[5] = 15
24102a1:java1 k12x1001$

配列をコピーする方法で、元の配列から最後のデータ14を削除するには、まず、要素数が1個少ない配列を新たに生成します。 そして、元の配列から新しい配列にコピーします。 ただし、元の配列の最後の要素はコピーしません。 つまり、

a = {10, 11, 12, 13, 14}

から

b = {10, 11, 12, 13}

を作成します。

/*  1*/ class ArrayDelete { // 配列からの削除
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         int[] a = {10, 11, 12, 13, 14};
/*  5*/         int[] b = new int[a.length - 1]; // 1個少なく生成
/*  6*/         for (i = 0; i < a.length - 1; i++) { // 最後以外をコピー
/*  7*/             b[i] = a[i];
/*  8*/         }
/*  9*/         for (i = 0; i < b.length; i++) {
/* 10*/             System.out.println("b[" + i + "] = " + b[i]);
/* 11*/         }
/* 12*/     }
/* 13*/ }
24102a1:java1 k12x1001$ java ArrayDelete
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
b[0] = 10
b[1] = 11
b[2] = 12
b[3] = 13
24102a1:java1 k12x1001$

配列への入力

ここでは、配列の初期化ではなく、プログラムの実行時に、配列にデータを入力する方法を考えてみます。 この場合、データの個数があらかじめ分かっているかどうかで、配列の使い方が変わります。 あらかじめ分かっていない場合は、まず、大きめの配列を用意します。 そして、 count などの変数でデータの個数を数えながら、入力されたデータを配列に挿入していきます。 データの終わりを判定するために、何か特別な値(例えば0)が入力されたら入力終了と見なします。

/*  1*/ import java.io.*;
/*  2*/
/*  3*/ class ArrayInput { // 配列への入力
/*  4*/     public static void main (String[] args) throws IOException {
/*  5*/         InputStreamReader isr = new InputStreamReader(System.in);
/*  6*/         BufferedReader br = new BufferedReader(isr);
/*  7*/         int[] a = new int[10]; // データは10個まで
/*  8*/         int i, input, count = 0; // 最初は0個
/*  9*/         System.out.println("データは" + a.length + "個までです。");
/* 10*/         System.out.println("終了は0を入力してください。");
/* 11*/         while (true) { // 無限ループ
/* 12*/             System.out.print("a[" + count + "] = ? ");
/* 13*/             input = Integer.parseInt(br.readLine()); // 入力
/* 14*/             if (input == 0) { // 0なら終了
/* 15*/                 break;
/* 16*/             }
/* 17*/             a[count] = input; // 挿入
/* 18*/             count++; // 1増加
/* 19*/         }
/* 20*/         for (i = 0; i < count; i++) {
/* 21*/             System.out.println("a[" + i + "] = " + a[i]);
/* 22*/         }
/* 23*/     }
/* 24*/ }
24102a1:java1 k12x1001$ java ArrayInput
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
データは10個までです。
終了は0を入力してください。
a[0] = ? 10
a[1] = ? 11
a[2] = ? 12
a[3] = ? 13
a[4] = ? 14
a[5] = ? 0
a[0] = 10
a[1] = 11
a[2] = 12
a[3] = 13
a[4] = 14
24102a1:java1 k12x1001$

あらかじめデータの個数が分かっている場合は、まず、データの個数を入力させます。 そして、その要素数の配列を生成し、配列要素を一つずつ入力させます。 この場合は、終了を表す特別な値を使わなくてもよいです。

/*  1*/ import java.io.*;
/*  2*/
/*  3*/ class ArrayInput2 { // 配列への入力2
/*  4*/     public static void main (String[] args) throws IOException {
/*  5*/         InputStreamReader isr = new InputStreamReader(System.in);
/*  6*/         BufferedReader br = new BufferedReader(isr);
/*  7*/         int i, input;
/*  8*/         System.out.print("データの個数を入力してください: ");
/*  9*/         input = Integer.parseInt(br.readLine()); // 入力
/* 10*/         int[] a = new int[input]; // 個数が分かってから配列を生成
/* 11*/         for (i = 0; i < a.length; i++) { // データの個数回繰り返す
/* 12*/             System.out.print("a[" + i + "] = ? ");
/* 13*/             input = Integer.parseInt(br.readLine()); // 入力
/* 14*/             a[i] = input; // 挿入
/* 15*/         }
/* 16*/         for (i = 0; i < a.length; i++) {
/* 17*/             System.out.println("a[" + i + "] = " + a[i]);
/* 18*/         }
/* 19*/     }
/* 20*/ }
24102a1:java1 k12x1001$ java ArrayInput2
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
データの個数を入力してください: 5
a[0] = ? 10
a[1] = ? 11
a[2] = ? 12
a[3] = ? 13
a[4] = ? 14
a[0] = 10
a[1] = 11
a[2] = 12
a[3] = 13
a[4] = 14
24102a1:java1 k12x1001$

並列配列

次のような表の形のデータは、データをまとめるときによく使われます。

表の形のデータ
No. 0 1 2 3 4
項目A 10 11 12 13 14
項目B 20 21 22 23 24
項目C 30 31 32 33 34

このような表の形のデータは、配列をいくつか用意し、添字を使って配列要素を結び付けるとうまく処理できます。 このように使われる配列を 並列配列 parallel array )とよびます。

この場合なら、項目Aを配列 a に格納し、項目Bを配列 b に格納し、項目Cを配列 c に格納します。 すると、0番目のデータは、項目Aが a [0], 項目Bが b [0], 項目Cが c [0] となります。 1番目のデータは、項目Aが a [1], 項目Bが b [1], 項目Cが c [1] などとなるわけです。

プログラムでは、タブ \t を使って、表に近い形でこのデータを出力しています。

/*  1*/ class ParallelArrays { // 並列配列
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         int[] a = {10, 11, 12, 13, 14}; // 項目A
/*  5*/         int[] b = {20, 21, 22, 23, 24}; // 項目B
/*  6*/         int[] c = {30, 31, 32, 33, 34}; // 項目C
/*  7*/         System.out.println("No.\t項目A\t項目B\t項目C");
/*  8*/         for (i = 0; i < a.length; i++) {
/*  9*/             System.out.print(i + "\t"); // タブ
/* 10*/             System.out.print(a[i] + "\t"); // タブ
/* 11*/             System.out.print(b[i] + "\t"); // タブ
/* 12*/             System.out.println(c[i]); // 改行
/* 13*/         }
/* 14*/     }
/* 15*/ }
24102a1:java1 k12x1001$ java ParallelArrays
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
No.     項目A   項目B   項目C
0       10      20      30
1       11      21      31
2       12      22      32
3       13      23      33
4       14      24      34
24102a1:java1 k12x1001$

並列配列の例として、以下の単価と数量の合計金額を計算します。

単価と数量
No. 0 1 2 3 4
単価 200 500 400 100 600
数量 3 1 2 7 1

まず、配列 unitPrices quantities を初期化して、 i 番目の単価が unitPrices [ i ], 数量が quantities [ i ] になるようにします。 i 番目の金額 price は、 unitPrices [ i ] * quantities [ i ] で求められます。 合計金額を計算するには、この price の値を totalPrice に足していきます。

プログラムは次の通りです。

/*  1*/ class TotalPrice { // 合計金額
/*  2*/     public static void main (String[] args) {
/*  3*/         int i, price, totalPrice = 0;
/*  4*/         int[] unitPrices = {200, 500, 400, 100, 600}; // 単価
/*  5*/         int[] quantities = {3, 1, 2, 7, 1}; // 数量
/*  6*/         System.out.println("No.\t単価\t数量\t金額");
/*  7*/         for (i = 0; i < unitPrices.length; i++) {
/*  8*/             price = unitPrices[i] * quantities[i]; // 金額の計算
/*  9*/             totalPrice += price; // 合計の計算
/* 10*/             System.out.print(i + "\t");
/* 11*/             System.out.print(unitPrices[i] + "\t");
/* 12*/             System.out.print(quantities[i] + "\t");
/* 13*/             System.out.println(price);
/* 14*/         }
/* 15*/         System.out.println("合計\t\t\t" + totalPrice);
/* 16*/     }
/* 17*/ }
24102a1:java1 k12x1001$ java TotalPrice
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
No.     単価    数量    金額
0       200     3       600
1       500     1       500
2       400     2       800
3       100     7       700
4       600     1       600
合計                    3200
24102a1:java1 k12x1001$

演習10

ある小学校では、児童数が次の通りであるとします。

ある小学校の児童数
学年 1年 2年 3年 4年 5年 6年
男子 50 54 59 58 57 51
女子 53 55 56 52 50 50

このデータを配列 boys girls に格納して、学年ごとの児童数と全児童数を計算するプログラムを作成してください。

ヒント: 配列に格納するときは、「0年生」が0人いることにすれば、うまくいきます。 for文も、0から始める必要はありません。

24102a1:java1 k12x1001$ java ElementarySchool
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
学年    男子    女子    合計
1年     50      53      103
2年     54      55      109
3年     59      56      115
4年     58      52      110
5年     57      50      107
6年     51      50      101
合計                    645
24102a1:java1 k12x1001$

余力のある人は、全体の男子児童数と女子児童数も計算してください。

24102a1:java1 k12x1001$ java ElementarySchool2
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
学年    男子    女子    合計
1年     50      53      103
2年     54      55      109
3年     59      56      115
4年     58      52      110
5年     57      50      107
6年     51      50      101
合計    329     316     645
24102a1:java1 k12x1001$

レポート課題

今日の演習10の答案(Javaプログラム)をメールで提出してください。 差出人は学内のメール・アドレス(k12x1001@cis.twcu.ac.jpなど)とし、宛先はkonishi@cis.twcu.ac.jpとします。 メールの本文には、学生番号、氏名、科目名、授業日(12月5日)を明記してください。


参考文献


[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

2014年12月5日更新
小西 善二郎 <konishi@cis.twcu.ac.jp>
Copyright (C) 2014 Zenjiro Konishi. All rights reserved.