カテゴリー
Java

Java(Step7-3)

メソッド

配列を扱うメソッド

メソッドは、引数として配列を受け取ることもでき、返却することもできます。

最大値を求めるメソッド

身長と体重を読み込んで配列に格納して、それぞれの最大値を求めるプログラムを作りましょう。

//MaxOfHeightWeight.java
//最も背が高い人の身長と最も重い人の体重を求める
import java.util.Scanner;

public class MaxOfHeightWeight {
    //配列のaの最大値を求めて返却
    static int maxOf(int[] a){
        int max = a[0];
        for(int i = 1; i < a.length; i++)
            if(a[i] > max)
                max = a[i];
        return max;
    }

    public static void main(String[] args){
        Scanner stdIn = new Scanner(System.in);

        System.out.print("人数は:");
        int ninzu = stdIn.nextInt();

        int[] height = new int[ninzu];
        int[] weight = new int[ninzu];

        System.out.println("身長と体重を入力してください。");

        for(int i = 0; i < ninzu; i++){
            System.out.print((i + 1) + "番目の身長:");
            height[i] = stdIn.nextInt();
            System.out.print((i + 1) + "番目の体重:");
            weight[i] = stdIn.nextInt();
        }
        System.out.println("最も身長が高い人の身長:" + maxOf(height) + "cm");
        System.out.println("最も太っている人の体重:" + maxOf(weight) + "kg");
        stdIn.close();

    }
}
MaxOfHeightWeight.java実行結果

maxOf メソッドは、配列の要素の最大値を求めて返却するメソッドです。配列を受け取るための仮引数は、int[] a と宣言されています。

呼び出されたmaxOf メソッドでは、配列変数である仮引数 a が、受け取った参照で初期化されます。その結果、配列変数 a は配列 height の本体を参照することになります。

線形探索

配列から目的とするキー値と同じ値を持つ要素を見つけ出す線形探索を以前作成しましたが、それを独立したメソッドとして実現させましょう。

//LinearSearch2.java
//線形探索
import java.util.Scanner;

public class LinearSearch2 {
   //配列aの要素からKeyと一致する最も先頭の要素を線形探索
   static int linearSearch(int[] a, int key){
       for(int i = 0; i < a.length; i++)
        if(a[i] == key)
            return i;  //探索成功
        return -1;  //探索失敗
   } 

   public static void main(String[] args){
       Scanner stdIn = new Scanner(System.in);

       System.out.print("要素数:");
       int num = stdIn.nextInt();
       int[] x = new int[num];

       for(int i = 0; i < num; i++){
           System.out.print("x[" + i + "]:");
           x[i] = stdIn.nextInt();
       }

       System.out.print("探す値:");
       int ky = stdIn.nextInt();

       int idx = linearSearch(x, ky);

       if(idx == -1)
          System.out.println("その値の要素は存在しません。");
       else
          System.out.println("その値はx[" + idx + "]にあります。");
       stdIn.close();
   }
}
LinearSearch2.java実行結果

線形探索を行うのが、linearSearch2 メソッドです。配列 a から key と一致する要素の中から最も先頭側に位置する要素を線形探索します。探索に成功した場合は、見つけた要素のインデックスを返し、失敗した場合は、 -1 を返します。

使い捨ての配列

以下のプログラムを考えてみましょう。(k は適当な値)

int[] a = (1, k, K + 5, 2 * k);
int[] i = linearSearch(a,3); //値が3である要素を探す

先頭から順に、初期化された配列 a の要素中に値3が存在するかどうか調べます。ここでは、値3があるか調べるだけであり、終わったら配列 a が不要になります。このような使い捨ての配列にわざわざ参照する配列変数を割り当てる必要はないです。以下のように実現できるからです。

int i = linearSearch(new int[](1, k, k + 5, 2 + k), 3);

配列の要素の並びを逆転する

配列の要素の並びを逆転する独立したメソッドを実現したプログラムを作りましょう。

//ReverseArray2.java
//配列の要素に値を読み込んで並びを反転する
import java.util.Scanner;

public class ReverseArray2 {
    //配列の要素a[idx1]とa[idx2]を交換
    static void swap(int[] a, int idx1, int idx2){
        int t = a[idx1]; a[idx1] = a[idx2]; a[idx2] = t;
    }    

    //配列aの要素の並びを逆転
    static void reverse(int[] a){
        for(int i = 0; i < a.length / 2; i++)
            swap(a, i ,a.length - i - 1);
    }

    public static void main(String[] args){
        Scanner stdIn = new Scanner(System.in);

        System.out.print("要素数:");
        int num = stdIn.nextInt();

        int[] x = new int[num];

        for(int i = 0; i < num; i++){
            System.out.print("x[" + i + "]:");
            x[i] = stdIn.nextInt();
        }

        reverse(x);

        System.out.println("要素の並びを逆転しました。");
        for(int i = 0; i < num; i++)
            System.out.println("x[" + i + "] = " + x[i]);
        stdIn.close();
    }
}
ReverseArray2.java実行結果

並べ替えを行うのがメソッド reverse です。配列の要素の並びを逆転させるには2要素の交換を「要素数 / 2」回行います。交換を行うのが swap メソッドです。このメソッドが仮引数として受け取る a[idx1]と a[idx2]の値を交換します。

2つの配列の比較

これまでのメソッドは、単一の配列を扱うものでした。複数の配列の処理を行うメソッドを作りましょう。以下に示すのは、2つの配列が等しいかどうかを判定するプログラムです。

//ArrayEqual2.java
//2つの配列が等しいかどうかを判定
import java.util.Scanner;

public class ArrayEqual2 {
    //2つの配列a、bの全要素は等しいか?
    static boolean equals(int[] a, int[] b){
        if(a.length != b.length)
            return false;
        for(int i = 0; i < a.length; i++)
            if(a[i] != b[i])
                return false;
        return true;
    }    

    public static void main(String[] args){
        Scanner stdIn = new Scanner(System.in);

        System.out.print("配列aの要素数:");
        int na = stdIn.nextInt();

        int[] a = new int[na];

        for(int i = 0; i < na; i++){
            System.out.print("a[" + i + "]:");
            a[i] = stdIn.nextInt();
        }

        System.out.print("配列bの要素数:");
        int nb = stdIn.nextInt();

        int[] b = new int[nb];

        for(int i = 0; i < nb; i++){
            System.out.print("b[" + i + "]:");
            b[i] = stdIn.nextInt();
        }

        System.out.println("配列aとbは" + (equals(a, b) ? "等しいです。" : "等しくありません。"));
        stdIn.close();  
    }
}
ArrayEqual2.java実行結果

メソッド equals の判定は、以下の3つのステップで行います。

  1. 2つの配列 a、b の要素数を比較します。要素数が異なれば、配列が等しくないのがわかるため、false を返します。
  2. for文内では、2つの配列を先頭から走査し、a[i]と b[i]の値をを比較します。その過程で異なる要素を見つけると、return文より、falseを返します。
  3. プログラムの流れが最後まで到達するということは、for文が中断されなかったということなので、2つの配列が等しいと判断でき、trueが返ります。

配列を返すメソッド

メソッドは配列を受け取るだけでなく、返却することもできます。そのメソッドを作りましょう。

//GenIdxArray.java
//全要素がインデックスと同じ値を持つ配列の生成
import java.util.Scanner;

public class GenIdxArray {
    //全要素がインデックスと同じ値をもつ要素数nの配列を生成して返却
    static int[] idxArray(int n){
        int[] a = new int[n];
        for(int i = 0; i < n; i++)
            a[i] = i;
        return a;
    }

    public static void main(String[] args) {
        Scanner stdIn = new Scanner(System.in);

        System.out.print("要素数は:");
        int n = stdIn.nextInt();
        int [] x = idxArray(n);

        for(int i = 0; i < n; i++)
            System.out.println("x[" + i + "] = " + x[i]);
        stdIn.close();
    }
}
GenIdxArray.java実行結果

メソッド idxArrayは、仮引数 n にint型整数値を受け取ります。メソッド本体で行うのは以下のことです。

  • 要素数が n である配列 a を生成。
  • 配列 a の全要素にインデックスと同じ値を代入。
  • a すなわち配列本体への参照を返却。

多重定義

よく似たメソッドの1つ1つに異なる名前を与えるとプログラムに色々な名前で溢れかえります。異なるメソッドに同じ名前を与える多重定義について説明します。

メソッドの多重定義

Javaでは、1つのクラスに宙に同じ名前のメソッドが複数存在することが許されます。同じ名前のメソッドを同一クラス内に複数宣言することをメソッドを多重定義(overload)と表現します。ただし、同じシグネチャ(signature)のメソッドは多重定義できないという制約があります。以下の図で示しています。

メソッドのシグネチャ

2つのint型の最大値を求めるメソッドと3つのint型の最大値を求めるメソッドを多重定義したプログラムを以下に示します。

//MaxOverload.java
//2値と3値の最大値を求めるメソッド(多重定義)
import java.util.Scanner;

public class MaxOverload {
   //a、bの最大値を返却
   static int max(int a, int b){
       return a > b ? a : b;
   } 

   //a、b、cの最大値を返却
   static int max(int a, int b, int c){
       int max = a;
       if(b > max) max = b;
       if(c > max) max = c;
       return max;
   }

   public static void main(String[] args){
       Scanner stdIn = new Scanner(System.in);

       System.out.print("xの値:"); int x = stdIn.nextInt();
       System.out.print("yの値:"); int y = stdIn.nextInt();
       System.out.print("zの値:"); int z = stdIn.nextInt();

       System.out.println("x、yの最大値は" + max(x, y) + "です。");
       System.out.println("x、y、zの最大値は" + max(x, y, z) + "です。");
       stdIn.close();
   }
}
MaxOverload.java実行結果

メソッド呼び出し時にどのメソッドを呼び出すかといった指定は不要です。適したメソッドが自動的に呼び出されます。このように類似した処理を行うメソッドを多重定義すれば、プログラムが多くのメソッド名で溢れるのを阻止できます。