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

コンピュータIIIB(Javaアルゴリズム)第3回

目次
3.1 2重ループ
3.1.1 2重ループとは
3.2 2重ループの例
3.2.1 エラトステネスのふるい
3.2.2 集合としての配列
3.3 演習3
3.4 レポート課題
3.5 参考文献
索引

3.1 2重ループ

3.1.1 2重ループとは

繰返しの繰返し、すなわち、繰返し文の中にさらに繰返し文を書くこともできます。 このような制御構造を、2重ループと呼ぶことがあります。 3重ループやそれ以上も考えられます。

一般的に、2重ループではループ制御変数を2つ用意します。 変数が ij ならば、 i を外側のループ制御変数とし、 j を内側のループ制御変数とします。

次のプログラムは、出力を4回繰り返すことを3回繰り返すものです。 変数 ij がどのように変化するかを見てください。

/*  1*/ class DoubleLoop {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i, j;
/*  4*/         for (i = 0; i < 3; i++) {
/*  5*/             for (j = 0; j < 4; j++) {
/*  6*/                 System.out.println("i = " + i + ", j = " + j + ".");
/*  7*/             }
/*  8*/         }
/*  9*/     }
/* 10*/ }
asiaa1:~/comp3b b08a001$ java DoubleLoop
i = 0, j = 0.
i = 0, j = 1.
i = 0, j = 2.
i = 0, j = 3.
i = 1, j = 0.
i = 1, j = 1.
i = 1, j = 2.
i = 1, j = 3.
i = 2, j = 0.
i = 2, j = 1.
i = 2, j = 2.
i = 2, j = 3.
asiaa1:~/comp3b b08a001$

2重ループでは、内側の繰返しの回数を変えることもできます。 次のプログラムでは、出力を0回繰り返し、1回繰り返し、…としています。

/*  1*/ class TriangleLoop {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i, j;
/*  4*/         for (i = 0; i < 5; i++) {
/*  5*/             for (j = 0; j < i; j++) {
/*  6*/                 System.out.println("i = " + i + ", j = " + j + ".");
/*  7*/             }
/*  8*/         }
/*  9*/     }
/* 10*/ }
asiaa1:~/comp3b b08a001$ java TriangleLoop
i = 1, j = 0.
i = 2, j = 0.
i = 2, j = 1.
i = 3, j = 0.
i = 3, j = 1.
i = 3, j = 2.
i = 4, j = 0.
i = 4, j = 1.
i = 4, j = 2.
i = 4, j = 3.
asiaa1:~/comp3b b08a001$

3.2 2重ループの例

3.2.1 エラトステネスのふるい

2重ループの例として、第1回の授業のアンケートの問題を考えます。 ここで、問題をもう一度書きます。

100以下の素数(25個)をすべて求めるプログラムが書けるかどうか答えてください。 ここで、素数とは1と自分以外に約数を持たない数のことです。 2, 3, 5などが素数です。 プログラミングの方針はいくつか考えられます。 例えば、2 * 2, 2 * 3, 3 * 3, ... のように掛け算を次々と実行し、それらの計算結果は素数でないという方針だと、次のようになります。 まず、添字が2から100までの配列要素に1を格納します。

a[2] = 1; a[3] = 1; ...; a[100] = 1;

次に、添字が2の倍数である配列要素に0を格納します。

a[2 * 2] = 0; a[2 * 3] = 0; ...; a[2 * 50] = 0;

続いて、添字が3の倍数である配列要素に0を格納します。

a[3 * 2] = 0; a[3 * 3] = 0; ...; a[3 * 33] = 0;

さらに、添字が4の倍数である配列要素に0を格納します。

a[4 * 2] = 0; a[4 * 3] = 0; ...; a[4 * 25] = 0;

この作業を、添字が50の倍数の場合まで行います。 最後に、値が1である配列要素の添字をすべて出力します。

このプログラムは次のようになります。

/*  1*/ class PrimeNumber {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i, j;
/*  4*/         int[] a = new int[101];
/*  5*/         for (i = 2; i <= 100; i++) {
/*  6*/             a[i] = 1;
/*  7*/         }
/*  8*/         for (i = 2; i <= 100 / 2; i++) {
/*  9*/             for (j = 2; j <= 100 / i; j++) {
/* 10*/                 a[i * j] = 0;
/* 11*/             }
/* 12*/         }
/* 13*/         for (i = 2; i <= 100; i++) {
/* 14*/             if (a[i] == 1) {
/* 15*/                 System.out.println(i);
/* 16*/             }
/* 17*/         }
/* 18*/     }
/* 19*/ }
asiaa1:~/comp3b b08a001$ java PrimeNumber
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
asiaa1:~/comp3b b08a001$

よく考えると、4の倍数を素数でないと決めるのは無駄です。 なぜなら、4の倍数は2の倍数なので、すでに素数でないと決められているからです。 上記のプログラムは、いくつかの改良の余地があります。

素数を求めるこのアルゴリズムは、 エラトステネスのふるい と呼ばれています。

3.2.2 集合としての配列

配列は、数学における集合と見なすことができます。 つまり、配列

{10, 20, 30, 40, 50}

を、要素が 10, 20, 30, 40, 50 の集合と考えるのです。 偶然にも、配列の初期化で使われる記号 {...} と、集合を表す記号 {...} は同じなので、理解しやすいと思います。 配列と集合の違いは、配列は要素の重複が許されるのに対して、集合は要素の重複が許されないことです。

集合の基本演算には、

などがあげられます。

集合AとBの和集合は、A∪Bと表され、AかBの少なくとも一方に属する要素の集合です。 例えば、

{10, 20, 30, 40, 50}∪{10, 30, 50, 70, 90} = {10, 20, 30, 40, 50, 70, 90}

となります。

集合AとBの共通部分は、A∩Bと表され、AとBの両方に属する要素の集合です。 例えば、

{10, 20, 30, 40, 50}∩{10, 30, 50, 70, 90} = {10, 30, 50}

となります。

次のプログラムは、集合 A = {10, 20, 30, 40, 50} と B = {10, 30, 50, 70, 90} の和集合を出力するプログラムです。 A の要素をすべて出力してから、A に属さない B の要素を出力しています。

/*  1*/ class ArrayUnion {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i, j;
/*  4*/         boolean found;
/*  5*/         int[] a = {10, 20, 30, 40, 50};
/*  6*/         int[] b = {10, 30, 50, 70, 90};
/*  7*/         for (i = 0; i < a.length; i++) {
/*  8*/             System.out.println(a[i]);
/*  9*/         }
/* 10*/         for (i = 0; i < b.length; i++) {
/* 11*/             found = false;
/* 12*/             for (j = 0; j < a.length; j++) {
/* 13*/                 if (b[i] == a[j]) {
/* 14*/                     found = true;
/* 15*/                     break;
/* 16*/                 }
/* 17*/             }
/* 18*/             if (!found) {
/* 19*/                 System.out.println(b[i]);
/* 20*/             }
/* 21*/         }
/* 22*/     }
/* 23*/ }
asiaa1:~/comp3b b08a001$ java ArrayUnion
10
20
30
40
50
70
90
asiaa1:~/comp3b b08a001$

3.3 演習3

集合 A = {10, 20, 30, 40, 50} と B = {10, 30, 50, 70, 90} の共通部分を出力するプログラムを作成してください。 A に属する B の要素を出力する、と考えるとよいでしょう。

asiaa1:~/comp3b b08a001$ java ArrayIntersection
10
30
50
asiaa1:~/comp3b b08a001$

3.4 レポート課題

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


3.5 参考文献


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

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