【Python】階層的なデータ構造の探索(ツリー探索)
ツリー構造の紹介
ツリーは、階層的に情報を整理するためのデータ構造であり、ノード(節点)とエッジ(辺)から構成されています。ツリーの最上部のノードをルートと呼び、各ノードは他のノードとエッジで繋がっています。ツリーは、例えば、ファイルシステムのディレクトリ構造、組織図、XMLデータの構造など、さまざまな場面で利用されます。
探索手法の概要
ツリー探索には主に2つの基本的な手法が存在します。深さ優先探索(DFS)と幅優先探索(BFS)です。
DFSは、ツリーの深い部分を先に探索する手法であり、スタックを使用して実行されます。一方、BFSは、ツリーの広い部分を先に探索する手法であり、キューを使用します。
深さ優先探索 (DFS) の例
深さ優先探索(DFS)は、現在のノードからできるだけ深く探索し、行き止まりに達したら、バックトラッキングして他の経路を探索します。
# 深さ優先探索の実装例
class Node:
def __init__(self, value):
self.value = value
self.children = []
def add_child(self, node):
self.children.append(node)
def dfs(root):
# ノードを処理
print(root.value)
# 子ノードを再帰的に探索
for child in root.children:
dfs(child)
# ツリーの作成
root = Node("A")
b = Node("B")
c = Node("C")
root.add_child(b)
root.add_child(c)
b.add_child(Node("D"))
c.add_child(Node("E"))
# 深さ優先探索の実行
dfs(root)
上記のコードでは、ツリーのルートから始まり、各ノードを再帰的に探索してその値を出力します。
幅優先探索 (BFS) の例
幅優先探索(BFS)は、まず現在のノードの子ノードをすべて探索し、その後、次のレベルのノードを探索します。キューを使って探索するため、最短経路を見つける際に有用です。
# 幅優先探索の実装例
from collections import deque
def bfs(root):
queue = deque([root]) # キューに最初のノードを追加
while queue:
node = queue.popleft() # キューからノードを取り出す
print(node.value) # ノードを処理
# 子ノードをキューに追加
for child in node.children:
queue.append(child)
# 幅優先探索の実行
bfs(root)
この例では、キューにノードを追加していき、各レベルのノードを順番に処理していきます。
再帰的探索
再帰的探索では、関数が自分自身を呼び出して探索を行います。特に、深さ優先探索(DFS)は再帰的に実行されることが多いです。再帰を使うと、スタックを自分で管理する必要がなくなり、シンプルなコードになります。
例えば、深さ優先探索は以下のように再帰的に実行できます。
# 再帰的なDFSの実行例(上記と同じDFS関数を使用) dfs(root)
非再帰的探索
非再帰的探索では、明示的にスタックやキューを使用して探索を行います。再帰を使う代わりに、これらのデータ構造を用いることで、探索の流れを明示的に制御することができます。非再帰的なDFSの例は、スタックを使用して実装することができます。
# 非再帰的DFSの実装例
def non_recursive_dfs(root):
stack = [root] # スタックに最初のノードを追加
while stack:
node = stack.pop() # スタックからノードを取り出す
print(node.value) # ノードを処理
# 子ノードをスタックに追加(逆順にすることでDFS順に)
for child in reversed(node.children):
stack.append(child)
# 非再帰的DFSの実行
non_recursive_dfs(root)