7.Recursive

再帰とは

再帰(Recursion)とは,再帰的な構造を持つアルゴリズムのことです。再帰的な構造とは,自分自身の定義の中に,自分自身を含む構造です。再帰の代表的な例として階乗やユークリッドの互除法の再帰的定義がよく用いられます。それぞれについて学習していきます。

階乗

整数nの階乗は記号!を用いてn!と書きます。実際の計算は次のように行われます。

n! = n × (n-1) × (n-2) × ... × 2 × 1 

この式を再帰的定義に書き換えると,次のようになります。

n! = n × (n-1)!  (ただし,0!=1)

次の階乗のsketch、Factorial.pdeは10の階乗を行う例

  1. 繰り返し構文を使ったメソッド factorial_for
  2. 再帰するメソッド factorial_recursive
// 繰り返し構文を用いたメソッド
long factorial_for(long i){
  if(i < 0){
    println("Error! Invarid input.<using for>");
    return -1;
  } else {
    long result = 1;
    for (int j = 1; j <= i; ++j){
      result *= j;
    }
    return result;
  }
}
// 再帰を用いたメソッド
long factorial_recursive(long i){
  if(i < 0){
    println("Error! Invarid input.<using recursive>");
    return -1;
  } else if(i == 0){
    return 1;
  } else {
    return i * factorial_recursive(i - 1);
  }
}

void setup(){
  long num    = 0;
  // using for
  println("using for       : factorial(" + num + ") = "
           + factorial_for(num) );
  // using recursive
  println("using recursive : factorial(" + num + ") = "
           + factorial_recursive(num) );
  num    = 10;
  // using for
  println("using for       : factorial(" + num + ") = "
           + factorial_for(num) );
  // using recursive
  println("using recursive : factorial(" + num + ") = "
           + factorial_recursive(num) );
  num    = -10;
  // using for
  println("using for       : factorial(" + num + ") = "
           + factorial_for(num) );
  // using recursive
  println("using recursive : factorial(" + num + ") = "
           + factorial_recursive(num) );

}

ユークリッドの互除法

8王妃問題を解く

再帰を活用するメリットとデメリット

再帰を活用するメリットは,「(場合によっては)問題をシンプルに記述できること」です。しかし,再帰は電子計算機で実行するアルゴリズムとしてはやっかいな問題,デメリットを抱えています。

そのデメリットを話す前に,計算量の2つの種類について言及しておきます。計算量は「時間計算量」と「空間計算量」という2つに区別できます。時間計算量は,これまで何度か取り扱って来た計算量の考え方で,そのアルゴリズムの実行にどれだけ手数がかかるかを表す量です。これに対して空間計算量は,そのアルゴリズムの実行にどれだけの記憶容量が必要かを表す量です。

再帰のアルゴリズムは,自分自身を1回呼ぶ度に,自分自身を実行するために必要なメモリを用意します。再帰の回数が多くなれば,必要なメモリ容量も多くなります。つまり,再帰のアルゴリズムのデメリットとは空間計算量が大きくなることです。再帰のアルゴリズムは潤沢にメモリがあることを前提とした手段なのです。

かつて,コンピュータがごくわずかなメモリしか持っていなかった時代のプログラミング言語が,再帰を言語の仕組みとして用意しなかった理由の一つは,再帰が簡単にメモリを食いつぶす方法だったからでしょう。現在,パーソナルコンピュータのメモリは数ギガバイトを持つようになったため,この問題が大きく扱われることはあまりありません。ただ,再帰を使ったプログラムによってはメモリを圧迫しますので,利用にあたっては慎重になりましょう。

そのため,再帰アルゴリズムを使用するべき場合とは,コードを劇的にシンプルにできる場合に限ると考えておくべきです。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA


Related Post

11.List11.List

List構造 コレクションクラス List構造は、要素を順番付けして管理するデータ構造です。 「ArrayList」「LinkedList」の2種類があります。 要素がインデックス(番号)順に並んでいるので、番号を指定して要素の取得、挿入、更新、削除ができます。また、Iteratorや拡張for構文を使って先頭から順番に要素を取得することも出来ます。 ArrayListは要素の取得が早いが挿入や削除が遅い、LinkedListは要素の挿入や削除は早いが取得が遅いという特徴があります。 List構造は、要素の重複は可能です。 リスト(ArrayList) ArrayList は配列を扱う一般的なクラスです。 下記などのメソッドが用意されています。 list.add(o) – オブジェクト o を配列の末尾に追加する list.add(n, o) – オブジェクトを […]

14.REST and JSON14.REST and JSON

REST RESTは「REpresentational State Transfer」の略で、大まかに言えば、アドレス(URL)とHTTPのメソッド(GETなど)を組み合わせて、サーバー上のデータを操作する仕組みです。 RESTは、Roy Fieldingという方が、2000年に発表した博士論文で提唱されたアーキテクチャスタイルです。Roy FieldingさんはHTTP仕様の策定者の一人であったことから、HTTPはRESTの基準をよく満たしています。 RESTの例として、WordPress JSON REST API (WP API, http://wp-api.org/) あります。それを利用して、Javaなどから最新の記事の取得、記事の投稿、写真の添付などが可能です。 JSON JSON(ジェイソン、JavaScript Object Notation)は、JavaScriptにおけるオブジェクトの表記法をベースとした軽量なデータ記述言語である。 JSONの紹介 […]