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

情報処理IIIA(Javaプログラミング入門)第5回

目次 索引
5.1 データの出力
5.2 反復
5.2.1 while
5.2.2 for
5.2.3 多重ループ
5.3 演習5
5.4 レポート課題

5.1 データの出力

これまで、端末エミュレータにデータを出力するには、 System.out.println( data ); を使ってきました。 文字列をそのまま出力するには、 data の部分にその文字列をダブルクオート( " )で囲んで書き、変数の値を出力するには、そこにその変数名を書きました。 演算子 + で結びますと、それらを混在させることができます。

/* 1*/ class IntToString {
/* 2*/     public static void main (String[] args) {
/* 3*/         int x = 100;
/* 4*/         System.out.println("x");
/* 5*/         System.out.println(x);
/* 6*/         System.out.println("x = " + x);
/* 7*/     }
/* 8*/ }
b00a001@Ampere:~/java% java IntToString
x
100
x = 100
b00a001@Ampere:~/java%

実は、この演算子 + は文字列の連結です。 一方だけが文字列のときは、他方を文字列に変換して連結するという約束になっています。

System.out.println( data ); は、出力の後に改行します。 改行してほしくないときは、 System.out.print( data ); と書きます。 また、改行だけしてほしいときは、 System.out.println(); とします。

注意: 端末エミュレータへの出力は一文字ずつ行なわれるわけではなく、ある程度の文字数になるか改行があるとまとめて行なわれます。 System.out.print( data ); と書いてあるのに何も出力されないときは、改行 System.out.println(); を忘れていないか確認してください。


5.2 反復

5.2.1 while

前回の授業では、選択というプログラムの構成要素を紹介しました。 今日は、 反復iteration )について説明します。

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

while (condition) {
    statement; ...
}

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

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

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

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

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

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

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

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

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

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

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

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

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

次のプログラムは、1+2+...+100を計算するものです。 変数 i の値を1ずつ増加させながら、変数 sum にそれまでの合計を格納していきます。

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

5.2.2 for

反復の種類の中には、何らかの変数( ループ変数 とよびます)を増加(あるいは減少)させながら繰り返すというものがあります。 for 文を用いますと、このような反復をコンパクトに書き表すことができます。 for 文は次のような形をとります。

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

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

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

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

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

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

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

となります。

また、1+2+...+100を計算するプログラムは次のようになります。

/* 1*/ class Summation2 {
/* 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*/ }

5.2.3 多重ループ

for 文の中に、さらに for 文を書くこともできます。 このような、「反復の反復」となる構造は、 多重ループnested loop )とよばれます。 多重ループでは、ループ変数が衝突しないように注意する必要があります。

次のプログラムは、2重のループの中で、ループ変数の値を出力するものです。 ループ変数は、 ij の2つです。 この2つの変数の値がどう変化するかに注目してください。

/* 1*/ class NestedLoop {
/* 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*/ }
b00a001@Ampere:~/java% java NestedLoop
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
b00a001@Ampere:~/java%

多重ループは、「長方形」のように実行されるとは限りません。 より複雑な多重ループも考えられます。

次のプログラムは、記号を使って旗のような三角形を出力するものです。 三角形の大きさは、コマンドライン引数で与えます。

/* 1*/ class FillPennant {
/* 2*/     public static void main (String[] args) {
/* 3*/         int i, j;
/* 4*/         int size = Integer.parseInt(args[0]);
/* 5*/         for (i = 0; i < size; i++) {
/* 6*/             for (j = 0; j < size - i; j++) {
/* 7*/                 System.out.print("*");
/* 8*/             }
/* 9*/             System.out.println();
/*10*/         }
/*11*/     }
/*12*/ }
b00a001@Ampere:~/java% java FillPennant 5
*****
****
***
**
*
b00a001@Ampere:~/java% java FillPennant 7
*******
******
*****
****
***
**
*
b00a001@Ampere:~/java%

5行目の for によって、 size の値だけ行が作られます。 そして、6行目の for によって、 size - i の値だけ記号が出力されます。 6行目の反復回数が、 i の値によって変わることに注意してください。

行を追うごとに記号を減らすわけですから、ループ変数 i をカウントダウン方式にしますと、多少分かりやすくなります。

/* 1*/ class FillPennant2 {
/* 2*/     public static void main (String[] args) {
/* 3*/         int i, j;
/* 4*/         int size = Integer.parseInt(args[0]);
/* 5*/         for (i = size; i > 0; i--) {
/* 6*/             for (j = 0; j < i; j++) {
/* 7*/                 System.out.print("*");
/* 8*/             }
/* 9*/             System.out.println();
/*10*/         }
/*11*/     }
/*12*/ }

そのほかに、多重ループを「長方形」のように実行しておき、記号を出力するか否かを ij の値に基づいて決定するという方法もあります。 記号を出力する条件は、 j < size - i とも i < size - j とも書けますが、ここでは i + j < size とします。 また、記号を出力しない場合はスペースを出力します。

/* 1*/ class FillPennant3 {
/* 2*/     public static void main (String[] args) {
/* 3*/         int i, j;
/* 4*/         int size = Integer.parseInt(args[0]);
/* 5*/         for (i = 0; i < size; i++) {
/* 6*/             for (j = 0; j < size; j++) {
/* 7*/                 if (i + j < size) {
/* 8*/                     System.out.print("*");
/* 9*/                 } else {
/*10*/                     System.out.print(" ");
/*11*/                 }
/*12*/             }
/*13*/             System.out.println();
/*14*/         }
/*15*/     }
/*16*/ }

5.3 演習5

次のように、コマンドライン引数 r を受け取り、記号を使って「半径」 r のひし形を出力するJavaプログラムを作成してください。 r は負でない整数と仮定してください。

b00a001@Ampere:~/java% java FillDiamond 2
  *
 ***
*****
 ***
  *
b00a001@Ampere:~/java% java FillDiamond 3
   *
  ***
 *****
*******
 *****
  ***
   *
b00a001@Ampere:~/java%

このプログラムにはいくつかの方針が考えられます。 以下にその例を示しますが、自分で考えてもかまいません。

上下分割
ひし形を上下に分け、それぞれについて、何行目にスペース何個と記号何個を出力するか式を立てる。
座標変換
ひし形の中心に座標の原点を置く。 座標 ( x , y ) において、 x + yx - y がともに - r 以上 r 以下ならば記号を出力し、そうでなければスペースを出力する。 なお、プログラム中の式 -r は、 r の正負の反転を意味する。
d1距離
ひし形の中心からの d 1 距離が r 以下ならば記号を出力し、そうでなければスペースを出力する。 ここで2点間の d 1 距離とは、 x 座標の差と y 座標の差の合計。 なお、数 k の絶対値は、式 Math.abs(k) で与えられる。

5.4 レポート課題

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


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

2001年10月18日更新
konishi@twcu.ac.jp
Copyright (C) 2001 Zenjiro Konishi. All rights reserved.