JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptでアッカーマン数を計算する方法(再帰関数の実装例)


アッカーマン関数とは

アッカーマン関数(Ackermann Function)は、再帰関数の古典的な例として知られる数学関数です。最大の特徴は、原始再帰関数ではないという点にあります。これは、for文やwhile文のような単純なループ処理だけでは表現できないことを意味します。

また、この関数は入力値の増加に対して値が極めて急速に大きくなることでも有名です。値の増大に伴い、再帰呼び出しのツリー(コールスタック)も爆発的に深くなるため、再帰の挙動や計算量の理論を学ぶ題材としてよく取り上げられます。

問題

2つの数 mn を第1引数・第2引数として受け取るJavaScript関数を作成します。この関数は、以下の定義に従ってアッカーマン数 A(m, n) を返す必要があります。

A(m,n) = n + 1                 (m = 0 のとき)
A(m,n) = A(m-1, 1)             (m > 0 かつ n = 0 のとき)
A(m,n) = A(m-1, A(m, n-1))     (m > 0 かつ n > 0 のとき)

実装例

上記の定義をそのまま再帰処理として書き下したのが、次のJavaScriptコードです。

const m = 2;
const n = 3;

const ackermann = (m, n) => {
    if (m === 0) {
        return n + 1;
    }
    if (n === 0) {
        return ackermann(m - 1, 1);
    }
    return ackermann(m - 1, ackermann(m, n - 1));
};

console.log(ackermann(m, n)); // 出力: 9

この例では A(2, 3) = 9 が出力されます。条件分岐の構造が数学的な定義とほぼ1対1に対応しているため、再帰関数の基本的な考え方を理解するのに最適なサンプルといえます。

注意点:爆発的な計算量

アッカーマン関数の値は、入力が少し大きくなるだけで天文学的な規模に達します。例えば A(4, 2) は 265536 − 3(約10の19728乗)という巨大な数になります。そのため、m = 12 のような大きな値を指定すると、現実的な時間内に計算が完了しません。

さらに、深い再帰呼び出しによって「Maximum call stack size exceeded」というスタックオーバーフローエラーが発生する可能性もあります。動作確認を行う場合は、m ≤ 3 程度の小さな値にとどめておくのが安全です。


  1. JavaScriptの「for...in」ステートメントとは?オブジェクトのプロパティをループ処理する方法を解説

    JavaScriptのfor...in文は、オブジェクトが持つすべてのプロパティ(列挙可能なプロパティ)を順番に取り出して処理するためのループ構文です。オブジェクト内の各キー(プロパティ名)にアクセスしながら、対応する値を取得したい場合に非常に便利です。for...inの基本的な構文for (let 変数名 in オブジェクト) { // 各プロパティに対して実行したい処理 }ループ変数には、各反復ごとにオブジェクトのプロパティ名(キー)が文字列として代入されます。値そのものを取得するには、「オブジェクト[変数名]」のようにブラケット記法を使ってアクセスします。サンプルコード以下は、for

  2. JavaScriptで数字パターンを表示する方法【初心者向けサンプルコード】

    本記事では、テキスト入力欄とボタンを備えたJavaScript・HTMLプログラムの作成方法を解説します。ユーザーが入力欄に任意の数値(例:5)を入力してボタンをクリックすると、画面に以下のような数字パターンが表示される仕組みです。(n = 5 の場合の出力例)01 01 02 01 02 03 01 02 03 04 01 02 03 04 05仕組みのポイントこのパターンは二重ループ(ネストしたforループ)を使うことで実現できます。外側のループが「行」を制御し、内側のループがその行に表示する「数字の個数」を制御します。i 行目には 1 から i までの数字が順番に出力されるため、行が進む