Keito

© 2024 Keito

技術ブログとポートフォリオ

配列の逆順(再帰)

線形再帰パターンで分割統治の考え方を学び、両端から中央へ向かう処理を理解しよう

O(n)
時間計算量(線形)
O(n)
空間計算量
初級〜中級
難易度
線形再帰
手法

🔄 実行設定

現在の配列:
[1, 2, 3, 4, 5]
配列長:5要素
予想交換回数:2
予想実行時間:< 1ms

📚 推奨配列

📊 統計情報

交換回数: 2
最大深度: 2
再帰呼び出し: 3
時間計算量: O(5)

🔄 反復実装との比較

反復結果: [5, 4, 3, 2, 1]
再帰: 教育的、反復: 実用的
🔄

アルゴリズムを実行してください

左側の設定パネルから配列を設定し、「配列逆順実行」ボタンを押してください

💻 実装例(JavaScript)

function reverseArray(array, start = 0, end = array.length - 1) {
    // ベースケース:start >= end なら処理終了
    if (start >= end) {
        return;
    }
    
    // 両端の要素を交換
    const temp = array[start];
    array[start] = array[end];
    array[end] = temp;
    
    // 内側の範囲に対して再帰呼び出し
    reverseArray(array, start + 1, end - 1);
}

// 使用例
const numbers = [1, 2, 3, 4, 5];
console.log("逆順前:", numbers);
reverseArray(numbers);
console.log("逆順後:", numbers); // [5, 4, 3, 2, 1]

// より明示的な実装
function reverseArrayExplicit(array, start, end) {
    console.log(`reverseArray(${start}, ${end}) 呼び出し`);
    
    if (start >= end) {
        console.log(`ベースケース: start=${start}, end=${end}`);
        return;
    }
    
    console.log(`交換: array[${start}] ↔ array[${end}]`);
    [array[start], array[end]] = [array[end], array[start]];
    
    reverseArrayExplicit(array, start + 1, end - 1);
}

// 反復実装(比較用)
function reverseArrayIterative(array) {
    let start = 0;
    let end = array.length - 1;
    
    while (start < end) {
        [array[start], array[end]] = [array[end], array[start]];
        start++;
        end--;
    }
}

// 関数型実装(副作用なし)
function reverseArrayFunctional(array) {
    if (array.length <= 1) return array;
    
    return [
        array[array.length - 1],
        ...reverseArrayFunctional(array.slice(1, -1)),
        array[0]
    ];
}

// 計算量分析
// 時間計算量: O(n) - n/2回の交換
// 空間計算量: O(n) - 再帰スタック
// 再帰の深さ: floor(n/2)

🔄 再帰 vs 反復 vs 関数型

再帰実装

  • • 分割統治の考え方が直感的
  • • 数学的定義に忠実
  • • 教育的価値が高い
  • • スタック使用量 O(n)
  • • 関数型プログラミングと相性良

反復実装

  • • メモリ効率が良い O(1)
  • • スタックオーバーフロー回避
  • • 実用的で高速
  • • 理解が容易
  • • 実装がシンプル

関数型実装

  • • 副作用なし(純粋関数)
  • • 元配列を変更しない
  • • 関数合成に適している
  • • テストしやすい
  • • メモリ使用量は多い