再帰処理完全マスターガイド – 初心者でもわかる再帰関数の基本から応用まで
![]() |
20万件以上の案件から、副業に最適なリモート・週3〜の案件を一括検索できるプラットフォーム。プロフィール登録でAIスカウトが自動的にマッチング案件を提案。市場統計や単価相場、エージェントの口コミも無料で閲覧可能なため、本業を続けながら効率的に高単価の副業案件を探せます。フリーランスボード |
| |
週2〜3日から働ける柔軟な案件が業界トップクラスの豊富さを誇るフリーランスエージェント。エンド直契約のため高単価で、週3日稼働でも十分な報酬を得られます。リモートや時間フレキシブルな案件も多数。スタートアップ・ベンチャー中心で、トレンド技術を使った魅力的な案件が揃っています。専属エージェントが案件紹介から契約交渉までサポート。利用企業2,000社以上の実績。ITプロパートナーズ |
| |
10,000件以上の案件を保有し、週3日〜・フルリモートなど柔軟な働き方に対応。高単価案件が豊富で、報酬保障制度(60%)や保険料負担(50%)など正社員並みの手厚い福利厚生が特徴。通勤交通費(月3万円)、スキルアップ費用(月1万円)の支給に加え、リロクラブ・freeeが無料利用可能。非公開案件80%以上、支払いサイト20日で安心して稼働できます。Midworks |
目次
再帰処理とは?初心者向け解説
再帰処理(Recursion)とは、関数が自分自身を呼び出すプログラミング技法です。複雑な問題を小さな同じ構造の問題に分割して解決する、エレガントで強力な手法として広く使われています。
再帰処理を学ぶメリット
- コードの簡潔性:複雑なロジックを短く表現可能
- 問題解決能力の向上:分割統治法の理解が深まる
- アルゴリズム理解:木構造やグラフの操作に必須
- 関数型プログラミング:関数型言語での重要な概念
再帰処理の基本構造
再帰の必須要素
- ベースケース(基底条件):再帰を終了する条件
- 再帰ケース:問題を小さくして自分自身を呼び出す
def countdown(n):
if n <= 0: # ベースケース
print("終了!")
return
print(n)
countdown(n - 1) # 再帰ケース
countdown(3) # 3, 2, 1, 終了!
再帰の動作イメージ
countdown(3)
├─ print(3)
├─ countdown(2)
├─ print(2)
├─ countdown(1)
├─ print(1)
├─ countdown(0)
└─ print("終了!")
基本的な再帰パターン
1. 数学的再帰:階乗計算
def factorial(n):
if n <= 1:
return 1
return n * factorial(n - 1)
print(factorial(5)) # 120
2. フィボナッチ数列
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(6)) # 8
3. 配列の要素合計
def sum_array(arr):
if len(arr) == 0:
return 0
return arr[0] + sum_array(arr[1:])
print(sum_array([1, 2, 3, 4])) # 10
4. 文字列の逆順
def reverse_string(s):
if len(s) <= 1:
return s
return s[-1] + reverse_string(s[:-1])
print(reverse_string("hello")) # olleh
データ構造での再帰活用
1. 二分木の操作
class TreeNode:
def __init__(self, val=0):
self.val = val
self.left = None
self.right = None
def tree_sum(root):
if root is None:
return 0
return root.val + tree_sum(root.left) + tree_sum(root.right)
def tree_height(root):
if root is None:
return 0
return 1 + max(tree_height(root.left), tree_height(root.right))
2. リンクリストの操作
class ListNode:
def __init__(self, val=0):
self.val = val
self.next = None
def print_list(head):
if head is None:
return
print(head.val)
print_list(head.next)
def reverse_list(head):
if head is None or head.next is None:
return head
new_head = reverse_list(head.next)
head.next.next = head
head.next = None
return new_head
3. ディレクトリ構造の探索
import os
def count_files(path):
if os.path.isfile(path):
return 1
if os.path.isdir(path):
total = 0
for item in os.listdir(path):
total += count_files(os.path.join(path, item))
return total
return 0
アルゴリズムでの再帰応用
1. 二分探索
def binary_search(arr, target, left=0, right=None):
if right is None:
right = len(arr) - 1
if left > right:
return -1
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] > target:
return binary_search(arr, target, left, mid - 1)
else:
return binary_search(arr, target, mid + 1, right)
2. クイックソート
def quicksort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quicksort(left) + middle + quicksort(right)
3. マージソート
def mergesort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = mergesort(arr[:mid])
right = mergesort(arr[mid:])
return merge(left, right)
def merge(left, right):
result = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result.extend(left[i:])
result.extend(right[j:])
return result
動的プログラミングとメモ化
メモ化なしのフィボナッチ(非効率)
def fib_slow(n):
if n <= 1:
return n
return fib_slow(n - 1) + fib_slow(n - 2) # O(2^n)
メモ化ありのフィボナッチ(効率的)
def fib_memo(n, memo={}):
if n in memo:
return memo[n]
if n <= 1:
return n
memo[n] = fib_memo(n - 1, memo) + fib_memo(n - 2, memo)
return memo[n] # O(n)
# Python のデコレータを使用
from functools import lru_cache
@lru_cache(maxsize=None)
def fib_cached(n):
if n <= 1:
return n
return fib_cached(n - 1) + fib_cached(n - 2)
実践的な再帰問題
1. 組み合わせ生成
def combinations(arr, k):
if k == 0:
return [[]]
if len(arr) == 0:
return []
with_first = [[arr[0]] + combo for combo in combinations(arr[1:], k - 1)]
without_first = combinations(arr[1:], k)
return with_first + without_first
2. 迷路の経路探索
def find_path(maze, start, end, visited=None):
if visited is None:
visited = set()
if start == end:
return [start]
if start in visited or maze[start[0]][start[1]] == 1:
return None
visited.add(start)
for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
next_pos = (start[0] + dx, start[1] + dy)
if 0 <= next_pos[0] < len(maze) and 0 <= next_pos[1] < len(maze[0]):
path = find_path(maze, next_pos, end, visited)
if path:
return [start] + path
visited.remove(start)
return None
3. JSON の深い比較
def deep_equal(obj1, obj2):
if type(obj1) != type(obj2):
return False
if isinstance(obj1, dict):
if len(obj1) != len(obj2):
return False
for key in obj1:
if key not in obj2 or not deep_equal(obj1[key], obj2[key]):
return False
return True
elif isinstance(obj1, list):
if len(obj1) != len(obj2):
return False
return all(deep_equal(a, b) for a, b in zip(obj1, obj2))
else:
return obj1 == obj2
よくある間違いと対策
間違い1:ベースケースの不備
# 悪い例:無限再帰
def bad_countdown(n):
print(n)
bad_countdown(n - 1) # 終了条件がない
# 良い例:適切なベースケース
def good_countdown(n):
if n <= 0: # ベースケース
return
print(n)
good_countdown(n - 1)
間違い2:スタックオーバーフロー
# 問題:深い再帰でスタックオーバーフロー
def deep_recursion(n):
if n == 0:
return 0
return 1 + deep_recursion(n - 1)
# 解決策:反復的な実装
def iterative_solution(n):
result = 0
for i in range(n):
result += 1
return result
間違い3:非効率な重複計算
# 悪い例:指数時間計算量
def inefficient_fib(n):
if n <= 1:
return n
return inefficient_fib(n - 1) + inefficient_fib(n - 2)
# 良い例:メモ化で線形時間
def efficient_fib(n, memo={}):
if n in memo:
return memo[n]
if n <= 1:
memo[n] = n
else:
memo[n] = efficient_fib(n - 1, memo) + efficient_fib(n - 2, memo)
return memo[n]
再帰 vs 反復の使い分け
再帰が適している場面
# 木構造の処理
def count_nodes(root):
if root is None:
return 0
return 1 + count_nodes(root.left) + count_nodes(root.right)
# 分割統治アルゴリズム
def power(base, exp):
if exp == 0:
return 1
if exp % 2 == 0:
half = power(base, exp // 2)
return half * half
return base * power(base, exp - 1)
反復が適している場面
# 単純な繰り返し処理
def sum_range(n):
total = 0
for i in range(1, n + 1):
total += i
return total
# メモリ使用量を抑えたい場合
def factorial_iterative(n):
result = 1
for i in range(1, n + 1):
result *= i
return result
パフォーマンス最適化テクニック
1. 末尾再帰最適化(概念)
# 通常の再帰
def factorial_normal(n):
if n <= 1:
return 1
return n * factorial_normal(n - 1)
# 末尾再帰風(Python は最適化しない)
def factorial_tail(n, acc=1):
if n <= 1:
return acc
return factorial_tail(n - 1, n * acc)
2. 再帰の深さ制限
import sys
def safe_recursion(n, max_depth=1000):
if n <= 0 or max_depth <= 0:
return 0
return 1 + safe_recursion(n - 1, max_depth - 1)
# システムの再帰制限を変更(注意して使用)
sys.setrecursionlimit(10000)
学習ステップとマスタープラン
初級レベル(1-2週間)
- 基本的な再帰の概念理解
- 階乗、フィボナッチなどの数学的再帰
- 配列・文字列の再帰処理
- ベースケースの重要性を理解
中級レベル(1-2ヶ月)
- 木構造・グラフの再帰処理
- 分割統治アルゴリズム
- バックトラッキング
- メモ化の概念と実装
上級レベル(3-6ヶ月)
- 動的プログラミングとの組み合わせ
- 複雑な再帰アルゴリズムの設計
- パフォーマンス最適化
- 関数型プログラミングでの応用
実践練習問題
- 基礎練習:ユークリッドの互除法、べき乗計算
- 中級練習:二分木の操作、迷路探索
- 上級練習:N-Queen問題、数独ソルバー
まとめ
再帰処理は、プログラミングにおける強力で美しい手法です。適切に使用することで、複雑な問題を簡潔かつエレガントに解決できます。重要なのは、ベースケースを明確にし、問題を適切に分割することです。
また、再帰の特性を理解し、パフォーマンスや メモリ使用量を考慮した実装を心がけることが大切です。メモ化や動的プログラミングと組み合わせることで、効率的なアルゴリズムを構築できるようになります。継続的な練習を通じて、再帰思考を身につけていきましょう。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座
![]() |
20万件以上の案件から、副業に最適なリモート・週3〜の案件を一括検索できるプラットフォーム。プロフィール登録でAIスカウトが自動的にマッチング案件を提案。市場統計や単価相場、エージェントの口コミも無料で閲覧可能なため、本業を続けながら効率的に高単価の副業案件を探せます。フリーランスボード |
| |
週2〜3日から働ける柔軟な案件が業界トップクラスの豊富さを誇るフリーランスエージェント。エンド直契約のため高単価で、週3日稼働でも十分な報酬を得られます。リモートや時間フレキシブルな案件も多数。スタートアップ・ベンチャー中心で、トレンド技術を使った魅力的な案件が揃っています。専属エージェントが案件紹介から契約交渉までサポート。利用企業2,000社以上の実績。ITプロパートナーズ |
| |
10,000件以上の案件を保有し、週3日〜・フルリモートなど柔軟な働き方に対応。高単価案件が豊富で、報酬保障制度(60%)や保険料負担(50%)など正社員並みの手厚い福利厚生が特徴。通勤交通費(月3万円)、スキルアップ費用(月1万円)の支給に加え、リロクラブ・freeeが無料利用可能。非公開案件80%以上、支払いサイト20日で安心して稼働できます。Midworks |







