Skip to content

Latest commit

 

History

History
 
 

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

README.md

木構造(ツリー構造)の探索アルゴリズムは、ツリー内のすべてのノードを特定の順序で訪問する方法です。主に深さ優先探索(DFS: Depth-First Search)と幅優先探索(BFS: Breadth-First Search)の2つに大別されます。さらに、DFSには前順(Pre-order), 中順(In-order), 後順(Post-order) という3つの主要な方法があります。


1. 深さ優先探索(DFS: Depth-First Search)

DFSは、できるだけ深くツリーの枝を辿ってからバックトラックする探索方法です。

1.1 前順(Pre-order Traversal)

順序:

  1. 現在のノードを訪問
  2. 左の子ノードを再帰的に訪問
  3. 右の子ノードを再帰的に訪問

:

    A
   / \
  B   C
 / \
D   E

前順: A → B → D → E → C

メリット:

  • ノードを訪れた順序でコピーを作成するのに適している。
  • 構造全体を保持したままシリアライズ(保存)するのに便利。

デメリット:

  • ソートされたデータを得ることはできない(特に二分探索木では中順が必要)。

活用方法:

  • ツリー構造のクローン作成、ディレクトリのコピー操作。

1.2 中順(In-order Traversal)

順序:

  1. 左の子ノードを再帰的に訪問
  2. 現在のノードを訪問
  3. 右の子ノードを再帰的に訪問

:

    A
   / \
  B   C
 / \
D   E

中順: D → B → E → A → C

メリット:

  • 二分探索木(BST) では、中順探索を行うとソート済みの順序でノードを取得できる

デメリット:

  • バランスの悪いツリーの場合、探索が非効率になることがある。

活用方法:

  • BSTにおけるデータのソートと検索、数式の評価(中置記法)。

1.3 後順(Post-order Traversal)

順序:

  1. 左の子ノードを再帰的に訪問
  2. 右の子ノードを再帰的に訪問
  3. 現在のノードを訪問

:

    A
   / \
  B   C
 / \
D   E

後順: D → E → B → C → A

メリット:

  • ノードの削除やメモリ解放の処理に適している(子ノードを先に処理するため)。
  • ディレクトリやファイルを削除する際の手順に対応。

デメリット:

  • ソートには適さない。
  • ノードの構造を保持するのが難しい。

活用方法:

  • ディレクトリの削除、数式の評価(後置記法)。

2. 幅優先探索(BFS: Breadth-First Search)

BFSは、各レベルのノードを順番に訪問します。最初に根ノードを訪問し、その後は子ノードをレベルごとに広がって探索します。

:

    A
   / \
  B   C
 / \
D   E

BFS: A → B → C → D → E

メリット:

  • 最短経路の探索に適している(グラフ理論でも利用される)。
  • ツリーのレベルごとの情報を得るのに便利。

デメリット:

  • メモリ使用量が多くなる(全てのノードをキューに保持するため)。
  • 深さが大きいツリーでは非効率。

活用方法:

  • 最短経路問題(例: ダイクストラ法の前処理)、ネットワーク探索、AIの状態探索(パズル解法など)。

3. DFSとBFSの比較

項目 深さ優先探索(DFS) 幅優先探索(BFS)
メモリ スタック(再帰的)、省メモリ キュー使用、大量メモリ必要
実装 再帰的、スタックを使う キューを使った反復的実装が多い
最短経路 保証しない 最短経路を保証
用途 パズル、木構造解析、再帰的問題 グラフ探索、最短経路、レベル探索

4. 実装例(Python)

深さ優先探索(中順)

class Node:
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None

def in_order_traversal(node):
    if node:
        in_order_traversal(node.left)
        print(node.value, end=' ')
        in_order_traversal(node.right)

# ツリーの構築
root = Node('A')
root.left = Node('B')
root.right = Node('C')
root.left.left = Node('D')
root.left.right = Node('E')

in_order_traversal(root)
# 出力: D B E A C

幅優先探索(BFS)

from collections import deque

def bfs(root):
    queue = deque([root])
    while queue:
        node = queue.popleft()
        print(node.value, end=' ')
        if node.left:
            queue.append(node.left)
        if node.right:
            queue.append(node.right)

bfs(root)
# 出力: A B C D E

5. どのアルゴリズムを選ぶべきか?

  • ソートが必要 → 中順探索(In-order)
  • 最短経路を探す → 幅優先探索(BFS)
  • ツリーのコピーや保存 → 前順探索(Pre-order)
  • ノードの削除や後処理 → 後順探索(Post-order)
  • メモリ制限が厳しい場合 → 深さ優先探索(DFS)