はじめMath! Javaでコンピュータ数学

第32回集合の数学 集合と要素[後編]

今回は、集合と要素に関するJava言語の演習問題をふたつ用意しました。概念を確認し、Java言語の基本的な文法やクラスライブラリの使い方を練習しましょう。気軽に取り組んでみてください。

問題:集合とJava言語に関する以下の問いに答えてください。

(1)10より小さな自然数のうち、偶数を整数型の配列とArrayListのオブジェクトにセットするプログラムを作ってください。結果が得られたら、偶数の個数を表示し、その後全ての偶数を表示しましょう。

明らかに偶数は2、4、6、8の4つ[1]ですが、10より小さい偶数がいくつあるか「わからない」ものとして解いてみてください。

ArrayListを用いると、配列を用いた場合よりも何が便利になるのか考えながら問題に取り組みましょう。

(2)10より小さな自然数の集合を全体集合とし、⁠1)で作成した偶数の集合の補集合をとるプログラムを、配列の場合とArrayListの場合それぞれで作ってください。

(1)と同様、補集合の要素数を表示した後で各要素を表示させましょう。なお、偶数の集合はあらかじめ与えられているものとし、コード中に埋め込みましょう。

解説

(1)10より小さな自然数のうち、偶数を整数型の配列とArrayListのオブジェクトにセットするプログラムを作ってください。結果が得られたら、偶数の個数を表示し、その後全ての偶数を表示しましょう。

 先ずは配列で目的の処理を行ってみます。

ソースコード:GusuNoHairetsu.java
01: //filename : GusuNoHairetsu.java
02: //10 より小さい自然数のうち、偶数を配列a にセットする。
03: 
04: class GusuNoHairetsu {
05:   public static void main(String[] args) {
06:     //添え字が偶数なら1、奇数なら0 をセット。
07:     int temp[] = new int[10]; //探索リスト
08:     int even = 0; //偶数の数をカウント
09:     for ( int i = 1 ; i 
10:         if (i%2 == 0) {
11:             temp[i] = 1;
12:             ++even;
13:         } else temp[i] = 0;
14:     }
15:     System.out.println("偶数は"+even+"個");
16:     int a[] = new int[even];//偶数の個数分配列を用意
17:     int j = 0;
18:     for (int i = 0; i 
19:         if (temp[i]==1) {
20:             a[j] = i;
21:             ++j;
22:         }
23:     }
24:      for( int i = 0;i&lt10 ; ++i){
25:         System.out.println("a["+i+"] = "+ a[i]);
26:   }// end of main
27: }// end of class GusuNoHairetsu

解説は後回しにして、ArrayListを用いて同じことをさせてみます。

ソースコード:GusuNoArrayList.java
01: //filename : GusuNoArrayList.java
02: //10 より小さい自然数のうち、偶数をArrayList A にセットする。
03: 
04: import java.util.ArrayList;
05: 
06: class GusuNoArrayList {
07:   public static void main(String[] args) {
08:     ArrayList A = new ArrayList();
09:     for ( int i = 1 ; i 
10:         if ( i%2 == 0 ) A.add(i);
11:     System.out.println("偶数は" + A.size() + "個");
12:     for ( int i = 0 ; i 
13:         System.out.println("A("+i+") = " + A.get(i));
14:   }// end of main()
15: }// end of class GusuNoArrayList

実質半分以下に行数が減りました。キーボードを打つ数が減ります。

どちらが良いかというより、⁠どちらが目的に合うか」で配列とArrayListをはじめとするクラス群の使い分けが必要です。今、もし短くてわかりやすいプログラムを作ることが最優先であるとしましょう。その視点でコードをながめると、配列を使用した場合のコードGusuNoHairetsu.javaには次のような短所があります。

  • 一時的なデータの保存場所として、7行目の配列tempが使われる。
  • 偶数の数をカウントするために変数evenが使われる。
  • 繰り返しが3回行われる。

ArrayListクラスを用いることで、繰り返しの数は2回に減りました。計算に1回、表示に1回と目的に応じた最低限の回数です(※2⁠。

配列を用いた場合「10以下の偶数の個数がわからない」という前提ですから、偶数を格納する配列のサイズがあらかじめ決定できません。探索が完了した段階で、発見した偶数の個数に合った配列を宣言し、格納しています。配列の長さをその場その場で変更できない(⁠⁠静的である」といいます)ので生じた不便です。

一方、ArrayListはあらかじめサイズを指定しなくても、データを追加するたびに増えてくれますし、削除すれば減ってくれます(⁠⁠動的である」といいます⁠⁠。

メモリの使用量、アクセス速度において配列の方がArrayListよりも利がありますが、ArrayListをはじめとするクラス群を使うことでプログラムがシンプルになり、トータルでのメモリの節約や実行速度の向上が望めます。何よりも、コードが読み下しやすくなる利点は得難いものです。

(2)10より小さな自然数の集合を全体集合とし、(1)で作成した偶数の集合の補集合をとるプログラムを、配列の場合とArrayListの場合それぞれで作ってください。

先ず、配列を用いた場合を紹介します。少々冗長ですが、読み下しやすく組みました。短くしようと思えば、もっと短くなります。題意に反しないように、可読性を損なわないように、短く書く訓練の題材にしてみると良いでしょう。今回、全体集合と偶数の集合をあらかじめ与えています。2つの集合に重複する要素がないかを逐一チェックし、重複がなければ補集合の要素であるとして保管させています。

ソースコード:HairetsuDeHoshugo.java
01: //filename : HairetsuDeHoshugo.java
02: //10 より小さい自然数を全体集合を表す配列u にセットし、
03: //偶数の集合を表す配列even との補集合をとる。
04: //補集合は配列complementary にセットする。
05: 
06: class HairetsuDeHoshugo {
07:   public static void main(String[] args) {
08:     int u[] = {1,2,3,4,5,6,7,8,9}; //全体集合
09:     int even[] = {2,4,6,8}; //偶数の集合
10:     int count = 0; //補集合の要素数
11:     //int complementary[]  は、補集合の要素数が確定したら宣言
12:     int temp[] = new int[10]; //補集合の要素を一時的に保管
13:     boolean found = false; //同じ要素を見つけたかどうか
14: 
15:     for ( int i_u = 0 ; i_u 
16:       for ( int i_e = 0 ; i_e 
17:         if (u[i_u] == even[i_e]) {
18:           found = true;
19:           break;
20:         }
21:       }
22:       if ( found == false ) {
23:         temp[count] = u[i_u];
24:         ++count;
25:       }
26:       found = false;
27:     }
28: 
29:     System.out.println("補集合の要素は"+count+"個");
30: 
31:     int complementary[] = new int[count];
32:       for (int i = 0 ; i 
33:         complementary[i] = temp[i];
34:         System.out.println("complementary["+i+"] = "+ complementary[i]);
35:     }
36:   }// end of main
37: }// end of class HairetsuDeHoshugo

次にArrayList を用いた場合を示します。

ソースコード:ArrayListDeHoshugo.java
01: //filename : ArrayListDeHoshugo.java
02: //10 より小さい自然数を全体集合を表すArrayList U にセットし、
03: //偶数の集合を表すArrayList Even との補集合をとる。
04: //補集合はArrayList Complementary にセットする。
05: 
06: import java.util.ArrayList;
07: 
08: class ArrayListDeHoshugo {
09:   public static void main(String[] args) {
10:     //初期化
11:     ArrayList U = new ArrayList(); //全体集合
12:     int u[] = {1,2,3,4,5,6,7,8,9};
13:     for (int i = 0 ; i 
14:     ArrayList Even = new ArrayList();//偶数の集合
15:     int even[] = {2,4,6,8};
16:     for (int i = 0 ; i 
17:     ArrayList Complementary = new ArrayList();//補集合
18: 
19:     //補集合をとる
20:     for (int i = 0 ; i 
21:       if ( Even.contains( U.get(i) ) == false )
22:         Complementary.add( U.get(i) );
23:     //結果の表示
24:     System.out.println("補集合の要素は"+Complementary.size()+"個");
25:     for (int i = 0 ; i 
26:       System.out.println("Complementary("+i+") = "+ Complementary.get(i));
27:   }// end of main()
28: }// end of class ArrayListDeHoshugo

トータルで10行しか違いませんが、補集合をとる処理と表示をしているところに注目すると、18行あったものがたったの6行になりました[3]⁠。

せっかくArrayListクラスを使ったのですから、イテレータを紹介しておきます。イテレータは、ArrayListDeHoshugo.java中では、カウンタに用いた変数iの代わりになるものです。⁠逐次参照を楽にする道具」と覚えましょう。ArrayListDeHoshugo.javaでは、添字もあわせて最後に出力していますので、イテレータを用いない方がシンプルになりました。しかし、Java言語を用いた多くのプログラムではArrayListをはじめとするコレクションクラスで逐一データを参照処理する際にイテレータを用いています。単純にデータを取り出すことのみに特化しているため、コードをシンプルに書ける利点があるのです。

コード例を次に示しますので参考にしてください。GusuNoArrayList.javaをイテレータを用いて書き直してみます。

ソースコード:GusuNoArrayListDeIterator.java
01: //filename : GusuNoArrayListDeIterator.java
02: //10 より小さい自然数のうち、偶数をArrayList A にセットする。
03: 
04: import java.util.*;
05: 
06: class GusuNoArrayListDeIterator {
07:   public static void main(String[] args) {
08:     ArrayList A = new ArrayList();
09:     for ( int i = 1 ; i 
10:         if ( i%2 == 0 ) A.add(i);
11:     System.out.println("偶数は" + A.size() + "個");
12:     for ( Iterator I = A.iterator() ; I.hasNext() ; )
13:         System.out.println( "A() = "+ I.next() );
14:   }// end of main()
15: }// end of class GusuNoArrayListDeIterator

4行目でimportするクラスの末尾が*(アスタリスク)になったのは、イテレータを利用するためにArrayListに加えてListクラス(インターフェイス)が必要だからです。逐一書くと次のように2行にわたってキーパンチしなければなりません。

import java.util.ArrayList;
import java.util.List;

ワイルドカードであるアスタリスクを用いて一行で済ませたのです。※4⁠。

おすすめ記事

記事・ニュース一覧