第 4 回 配列

前回の復習

前回は、 boolean 型、制御構文、メソッドについて学びました。

補足

前回のサンプルプログラムは二数の最大公約数を求めるものでしたが、 どうしてあのプログラムでそれが求まるかわかったでしょうか。 そのような (少し考えないとわからないような) 問題の解法を アルゴリズム と呼びます。 前回はユークリッドの互除法と呼ばれるアルゴリズムを用いました。

main もメソッドです。最初に呼び出されるという特別な性質があります。

今回の内容

今回はフィボナッチ数列と呼ばれる数列を計算するサンプルを題材に、配列や再帰について学びます。

フィボナッチ数列
a0 = a1 = 1
an = an-1 + an-2 (n > 1)

配列

大量のデータを扱うために変数を大量に用意するのは (ソースを書くときにも実行するときにも) 非効率的です。 配列を使えば、大量のデータを並べて管理できます。

配列には同じ型のデータを複数入れることができます。 n 個のマスがある入れ物だと考えてください。 それぞれの場所には 0 から n-1 までの数字が割り当てられていて、区別することができます。 この数字を インデックス と呼びます。

長さ n の配列を作るには、以下の構文に従います。

データ型名[] 配列名 = new データ型名[n];

その i 番目は、配列名[i] で使えます。

それではフィボナッチ数列を計算するプログラムのひとつめを見てみましょう。 このサンプルでは、数列の添え字が小さいものから順に計算していきます。

class sample4a{
  public static void main(String[] args){
    int[] a = new int[8]; // int 型・長さ 8 の配列を作る

    a[0] = 1; // a の 0 番目に 1 を代入
    a[1] = 1;

    for(int i = 2; i < a.length; i++){ // a.length で配列の長さを得ることができる 
      a[i] = a[i-1] + a[i-2];
    }

    for(int i = 0; i < a.length; i++){
      System.out.println(a[i]);
    }
  }
}

実行結果は以下のようになると思います。

1
1
2
3
5
8
13
21

再帰

class sample4b{
  public static void main(String[] args){
    int n = Integer.parseInt(args[0]);
    System.out.println(fib(n));
  }

  // フィボナッチ数列を再帰的に計算するメソッド
  public static int fib(int n){
    if(n > 1) return fib(n - 1) + fib(n - 2);
    else return 1;
  }
}

これを以下のように実行してください。

g0*****@ux001>java sample4b 8
21

main メソッドの引数

main メソッドの引数は String 型の配列です。 この配列には、実行時にコマンドラインから与えられた文字列が入ります。

以下のように実行したときは、 args[0] == "8", args[1] == "apple", args[2] == "90" (いずれも String 型) となります。 これを整数として使うために上のサンプルでは Integer.parseInt() というメソッドで変換しています。

g0*****@ux001>java sample4b 8 apple 90

再帰

再帰的とはあるものを定義するためにそれ自身に言及する状態をいいます。 フィボナッチ数列はそもそも再帰的に定義されているので、 プログラムを書くときもそのように書くのが自然です。

再帰的なメソッドを書くときは注意が必要で、 少し間違えると、自分を永久恒久に呼び出し続けて実行が終わらなくなります。 このように終了しなくなったプログラムを 無限ループ などと呼ぶことがあります。

課題

今回、二つの方法でフィボナッチ数列を計算しましたが、 どちらの方法がより実行効率のよい方法でしょうか。考えてみてください。 大きな添え字について実際に計算させてみましょう。