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

コンピュータIIB(Javaプログラミング入門)第5回

目次 索引
5.1 反復
5.1.1 while文
5.1.2 for文
5.1.3 反復の使用例
5.2 演習5
5.3 レポート課題
for文  while文  繰返し文  反復  無限ループ  ループ制御変数  ループ文 

5.1 反復

5.1.1 while文

前回の授業では、選択というプログラムの構成要素を紹介しました。 今日は、 反復iteration ) について説明します。 反復を表す文は、 繰返し文repetitive statement ) 、または ループ文loop statement ) とよばれます。

反復にはいくつか種類がありますが、「何々が成り立つ間、何々を繰り返す」というものが基本です。 この種の反復には while文while statement ) を使います。 while 文は以下の形をとります。

while (condition) {
    statement; ...
}

条件 condition が成り立っている間、文 statement ; ... が繰り返し実行されます。

ここで、Good afternoon!と10回出力するプログラムを考えます。 はじめは数え上げ方式です。 これは、変数 i に0を代入しておき、Good afternoon!と一回出力するごとに i の値を1増やすということを、 i の値が10未満の間繰り返すものです。

/*  1*/ class TenAfternoons {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         i = 0;
/*  5*/         while (i < 10) {
/*  6*/             System.out.println("Good afternoon!");
/*  7*/             i++;
/*  8*/         }
/*  9*/     }
/* 10*/ }
b04a001@AsiaA1:~/java% java TenAfternoons
Good afternoon!
Good afternoon!
Good afternoon!
Good afternoon!
Good afternoon!
Good afternoon!
Good afternoon!
Good afternoon!
Good afternoon!
Good afternoon!
b04a001@AsiaA1:~/java%

5行目から8行目までの while 文は次のように実行されます。

1. 変数iの値は0。条件i < 10が成り立つので、Good afternoon!と出力し、iの値を1増やす。
2. 変数iの値は1。条件i < 10が成り立つので、Good afternoon!と出力し、iの値を1増やす。
...
10. 変数iの値は9。条件i < 10が成り立つので、Good afternoon!と出力し、iの値を1増やす。
11. 変数iの値は10。条件i < 10は成り立たないので、このwhile文の実行を終える。

次はカウントダウン方式です。 これは、変数 i に10を代入しておき、Good afternoon!と一回出力するごとに i の値を1減らすということを、 i の値が正の間繰り返すものです。

/*  1*/ class TenAfternoons2 {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         i = 10;
/*  5*/         while (i > 0) {
/*  6*/             System.out.println("Good afternoon!");
/*  7*/             i--;
/*  8*/         }
/*  9*/     }
/* 10*/ }

5行目から8行目までの while 文は次のように実行されます。

1. 変数iの値は10。条件i > 0が成り立つので、Good afternoon!と出力し、iの値を1減らす。
2. 変数iの値は9。条件i > 0が成り立つので、Good afternoon!と出力し、iの値を1減らす。
...
10. 変数iの値は1。条件i > 0が成り立つので、Good afternoon!と出力し、iの値を1減らす。
11. 変数iの値は0。条件i > 0は成り立たないので、このwhile文の実行を終える。

数え上げ方式とカウントダウン方式のどちらがよいかは、問題によって変わります。 数え上げ方式のほうがよく使われますが、カウントダウン方式が適切な場合もあります。

注意: 上記のプログラムで、7行目を書き忘れたとしましょう。

/*  1*/ class InfiniteAfternoons {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         i = 10;
/*  5*/         while (i > 0) {
/*  6*/             System.out.println("Good afternoon!");
/*  7*/         }
/*  8*/     }
/*  9*/ }

このプログラムを実行しますと、変数 i の値は10のままですので、条件 i > 0 がずっと成り立ち、永遠にGood afternoon!と出力され続けることになります。 このような、いつまでも続く繰り返しを、 無限ループinfinite loop ) とよびます。 反復を使うときは、無限ループにならないように気をつける必要があります。 なお、誤って無限ループに陥ったときは、Ctrl-Cで強制終了してください。

注意: 繰り返しの回数を0にしますと、0回繰り返す、つまり、一度も実行されなくなります。

/*  1*/ class NoAfternoons {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         i = 0;
/*  5*/         while (i < 0) {
/*  6*/             System.out.println("Good afternoon!");
/*  7*/             i++;
/*  8*/         }
/*  9*/     }
/* 10*/ }

このプログラムを実行しますと、条件 i < 0 は初めから成り立ちませんので、何も出力されないのです。

5.1.2 for文

反復の種類の中には、繰り返す回数が明確なものがあります。 この場合、 ループ制御変数loop control variable ) とよばれる変数を増加(あるいは減少)させながら繰り返すのが一般的です。 for文for statement ) を用いますと、このような反復をコンパクトに書き表すことができます。 for 文は次のような形をとります。

for (statement1; condition; statement2) {
    statement3; ...
}

まず文 statement1 が一度だけ実行されます。 そして条件 condition が成り立っている間、文 statement3 ; ...statement2 が繰り返し実行されます。 while 文を使ってこの for 文を書きますと、次のようになります。

statement1;
while (condition) {
    statement3; ...
    statement2;
}

for 文を用いますと、Good afternoon!と10回出力するプログラムは次のように書けます。 数え上げ方式については、

/*  1*/ class TenAfternoons3 {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         for (i = 0; i < 10; i++) {
/*  5*/             System.out.println("Good afternoon!");
/*  6*/         }
/*  7*/     }
/*  8*/ }

です。 カウントダウン方式は、

/*  1*/ class TenAfternoons4 {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         for (i = 10; i > 0; i--) {
/*  5*/             System.out.println("Good afternoon!");
/*  6*/         }
/*  7*/     }
/*  8*/ }

となります。

while 文と for 文には本質的な差はありません。 繰返しの回数がはっきりしているときには for 文、そうでないときには while 文を使うのがよいでしょう。

5.1.3 反復の使用例

反復の使用例として、はじめに 1+2+…+100 の計算を行います。

この問題は、レジの計算をまねることで解決できます。 つまり、それまでの合計を表す変数 sum を用意して、初期値を 0 とします。 そして、 sum の値を 1 増やし、2 増やし、…と繰り返し、100 増やした時点の sum の値が答になるわけです。 アルゴリズムは次のようになります。

  1. ループ制御変数 i を宣言する。
  2. 合計を表す変数 sum を宣言し、初期値を 0 とする。
  3. 変数 i の値を 1 から 100 まで増加させながら、以下を繰り返す。{
  4.     変数 sum の値を i 増やす。
  5. sum の値を出力する。

プログラムは以下のようになります。

/*  1*/ class Summation100 {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i, sum = 0;
/*  4*/         for (i = 1; i <= 100; i++) {
/*  5*/             sum = sum + i;
/*  6*/         }
/*  7*/         System.out.println(sum);
/*  8*/     }
/*  9*/ }
b04a001@AsiaA1:~/java% java Summation100
5050
b04a001@AsiaA1:~/java%

次の例は、360 の約数をすべて求めるものです。

360 の約数が、1 から 360 までの間にあることは、数学的に分かっています。 したがって、1 から 360 までの数一つ一つに対して、360 がその数で割り切れるかどうかを判断すれば、約数がもれなく見つけられます。 アルゴリズムは次のようになります。

  1. ループ制御変数 i を宣言する。
  2. 変数 i の値を 1 から 360 まで増加させながら、以下を繰り返す。{
  3.     もし 360 が i で割り切れるならば、{
  4.         式 i の値を出力する。
  5.     }

プログラムは以下のようになります。

/*  1*/ class Divisors360 {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         for (i = 1; i <= 360; i++) {
/*  5*/             if (360 % i == 0) {
/*  6*/                 System.out.println(i);
/*  7*/             }
/*  8*/         }
/*  9*/     }
/* 10*/ }
b04a001@AsiaA1:~/java% java Divisors360
1
2
3
4
5
6
8
9
10
12
15
18
20
24
30
36
40
45
60
72
90
120
180
360
b04a001@AsiaA1:~/java%

最後の例は、塗り潰した正方形を描くアプレットです。 塗り潰した正方形(長方形)を描くには、 g.fillRect( ... ); を使うことはすでに説明しました。 ここではこれを用いず、自分で正方形を塗り潰すことにします。 例として、授業で最初に紹介したアプレットを考えます。

/*  1*/ import java.applet.*;
/*  2*/ import java.awt.*;
/*  3*/ 
/*  4*/ public class BlackBox extends Applet {
/*  5*/     public void paint (Graphics g) {
/*  6*/         g.setColor(Color.black);
/*  7*/         g.fillRect(50, 50, 100, 100);
/*  8*/     }
/*  9*/ }
A filled square
図 5.1  塗り潰した正方形

正方形は、上から順にすきまなく水平線を引いていけば、塗り潰すことができます。 この場合は、

        g.fillRect(50, 50, 100, 100);

の代わりに

        g.drawLine(50, 50, 150, 50);
        g.drawLine(50, 51, 150, 51);
        g.drawLine(50, 52, 150, 52);
        ...
        g.drawLine(50, 150, 150, 150);

を実行すればよいわけです。

アルゴリズムは次のようになります。

  1. ループ制御変数 i を宣言する。
  2. 変数 i の値を 0 から 100 まで増加させながら、以下を繰り返す。{
  3.     座標 (50, 50+ i ) から (150, 50+ i ) まで線分を描く。

プログラムは以下のようになります。

/*  1*/ import java.applet.*;
/*  2*/ import java.awt.*;
/*  3*/
/*  4*/ public class FillSquare extends Applet {
/*  5*/     public void paint (Graphics g) {
/*  6*/         int i;
/*  7*/         for (i = 0; i <= 100; i++) {
/*  8*/             g.drawLine(50, 50 + i, 150, 50 + i);
/*  9*/         }
/* 10*/     }
/* 11*/ }

正方形は、左から順に垂直な線を引いても塗り潰せます。 上記の正方形ですと、

        g.fillRect(50, 50, 100, 100);

の代わりに

        g.drawLine(50, 50, 50, 150);
        g.drawLine(51, 50, 51, 150);
        g.drawLine(52, 50, 52, 150);
        ...
        g.drawLine(150, 50, 150, 150);

を実行することになります。

アルゴリズムは次のようになります。

  1. ループ制御変数 i を宣言する。
  2. 変数 i の値を 0 から 100 まで増加させながら、以下を繰り返す。{
  3.     座標 (50+ i , 50) から (50+ i , 150) まで線分を描く。

プログラムは以下のようになります。

/*  1*/ import java.applet.*;
/*  2*/ import java.awt.*;
/*  3*/
/*  4*/ public class FillSquare2 extends Applet {
/*  5*/     public void paint (Graphics g) {
/*  6*/         int i;
/*  7*/         for (i = 0; i <= 100; i++) {
/*  8*/             g.drawLine(50 + i, 50, 50 + i, 150);
/*  9*/         }
/* 10*/     }
/* 11*/ }

5.2 演習5

以下の幾何学模様を for 文を用いて描きます。

A geometrical pattern
図 5.2  幾何学模様(SquareNest)

この模様は、

        g.drawRect(10, 10, 180, 180);
        g.drawRect(20, 20, 160, 160);
        g.drawRect(30, 30, 140, 140);
        ...
        g.drawRect(90, 90, 20, 20);

を実行すれば描けます。

アルゴリズムは次のようにします。

  1. ループ制御変数 i を宣言する。
  2. 変数 i の値を 0 から 8 まで増加させながら、以下を繰り返す。{
  3.     左上の座標が (10+10× i , 10+10× i ) で縦横が 180−20× i の正方形を描く。

このアルゴリズムをプログラムにしてください。

余力のある人は、以下の幾何学模様を for 文を用いて描いてください。

A geometrical pattern
図 5.3  幾何学模様(SquareSpiral)

5.3 レポート課題

今日の演習5に従ってJavaプログラムを作成し、そのプログラムをkonishi@twcu.ac.jpあてにメールで提出してください。 メールには、学生番号、氏名、科目名、授業日(5/14)を明記してください。


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

2004年5月14日更新
konishi@twcu.ac.jp
Copyright (C) 2004 Zenjiro Konishi. All rights reserved.