PythonでBFS(幅優先探索)を使って木構造のノードを表示するプログラム
木構造のノードを幅優先探索(BFS:Breadth First Search)で表示したい場合、専用のクラスを作成し、その中にルートノードの設定、要素の追加、特定要素の検索、BFSトラバーサルの実行といったメソッドを実装します。作成したクラスのインスタンスを生成すれば、これらのメソッドを自由に呼び出して利用できます。
本記事では、対話型のメニュー形式で動作するサンプルプログラムを通じて、その実装方法を詳しく解説します。
サンプルコード
class Tree_struct:
def __init__(self, data=None):
self.key = data
self.children = []
def set_root(self, data):
self.key = data
def add_node(self, node):
self.children.append(node)
def search_node(self, key):
if self.key == key:
return self
for child in self.children:
temp = child.search_node(key)
if temp is not None:
return temp
return None
def bfs_operation(self):
queue = [self]
while queue != []:
popped = queue.pop(0)
for child in popped.children:
queue.append(child)
print(popped.key, end=' ')
my_instance = None
print('Menu (assume no duplicate keys)')
print('add <data> at root')
print('add <data> below <data>')
print('bfs')
print('quit')
while True:
my_input = input('What operation would you do ? ').split()
operation = my_input[0].strip().lower()
if operation == 'add':
data = int(my_input[1])
new_node = Tree_struct(data)
suboperation = my_input[2].strip().lower()
if suboperation == 'at':
my_instance = new_node
elif suboperation == 'below':
position = my_input[3].strip().lower()
key = int(position)
ref_node = None
if my_instance is not None:
ref_node = my_instance.search_node(key)
if ref_node is None:
print('No such key')
continue
ref_node.add_node(new_node)
elif operation == 'bfs':
if my_instance is None:
print('The tree is empty')
else:
print('Breadth First Search traversal is : ', end='')
my_instance.bfs_operation()
print()
elif operation == 'quit':
break実行結果
Menu (assume no duplicate keys) add <data> at root add <data> below <data> bfs quit What operation would you do ? add 6 at root What operation would you do ? add 4 below 6 What operation would you do ? add 9 below 4 What operation would you do ? bfs Breadth First Search traversal is : 6 4 9 What operation would you do ? quit
プログラムの解説
必要な属性を持つ「Tree_struct」クラスを定義しています。
コンストラクタ「__init__」では、データを格納する変数と、子ノードを管理するための空リストを初期化します。
「set_root」メソッドは、木のルート値を設定するために用意されています。
「add_node」メソッドは、指定したノードの子として新しい要素を追加します。
「search_node」メソッドは、再帰的に子ノードをたどりながら、指定されたキーを持つノードを検索します。見つからなければNoneを返します。
「bfs_operation」メソッドは、キュー(FIFO)を利用して幅優先探索を実行します。ノードを取り出す順番に、上の階層から順にキーの値を出力していきます。
インスタンス変数「my_instance」は最初にNoneで初期化され、木がまだ存在しない状態を表現しています。
whileループの中でユーザーからの入力を受け付け、実行したい操作を選択できる対話型の設計になっています。
ユーザーの選択内容に応じて、ノードの追加・BFSトラバーサル・終了のいずれかの処理が実行されます。
処理結果は随時コンソールに出力され、木の状態を確認できます。
BFSのポイント
幅優先探索では、リストの先頭から要素を取り出し(pop(0))、その子ノードを末尾に追加していくことで、木を上の階層から順番に走査できます。このサンプルでは、ルート「6」→子「4」→孫「9」の順に出力されており、深さ方向ではなく横方向に探索が進んでいることが確認できます。
-
Pythonで二分木の指定ノードの右隣ノードを見つけるプログラム
二分木が与えられ、さらに特定のノード「u」へのポインタも渡されたとします。このとき、u のすぐ右側に位置するノード(必ず同じ階層に存在する)を見つける必要があります。対象のノードは葉ノードの場合もあれば、内部ノードの場合もあります。 例として、次のような二分木が入力されたとしましょう。 ここで u = 6 とすると、出力は 8 になります。ノード 6 の右隣にはノード 8 が存在するため、値 8 が返されるというわけです。 解決のためのアプローチ この問題は、両端キュー(deque)を使った幅優先探索(BFS)、いわゆるレベル順走査によって解くことができます。手順は以下の通りです。 ルー
-
Pythonで同じラベルを持つサブツリー内のノード数を求めるプログラム
ここでは、n個のノードからなる根付きの一般木を考えます。ノードには0からn-1までの番号が振られており、各ノードには小文字の英字ラベルが割り当てられています。ラベルは配列labelsとして与えられ(labels[i]がi番目のノードのラベル)、木は辺リストで表現されます。各辺eは[u, v]という形式で、uが親、vが子であることを意味します。 求めたいのは、サイズnの配列Aです。A[i]には「i番目のノードと同じラベルを持つ、そのサブツリー内のノードの総数」を格納します。 例えば、入力が次のような場合を考えてみましょう。 n = 5、label = ccaca のとき、出力は [3, 2,