前回につづいて、「与えられた木が二分探索木か判定するアルゴリズム」について。
二分木が二分探索木であると判定するには、すべての節が制約を満足しているか調べればよいと前回の記事に書いた。これは幅優先探索でも実現できる。
次のコードは幅優先探索ですべての節が制約を満足しているか調べるものである。
import collections
def is_binary_tree_bst_bfs(tree: BstNode) -> bool:
QueueEntry = collections.namedtuple('QueueEntry', ('node', 'lower', 'upper'))
bfs_queue = collections.deque([QueueEntry(tree, float('-inf'), float('inf'))])
while bfs_queue:
entry = bfs_queue.popleft()
if entry.node:
if not (entry.lower <= entry.node.data <= entry.upper):
return False
bfs_queue.append(QueueEntry(entry.node.left, entry.lower, entry.node.data))
bfs_queue.append(QueueEntry(entry.node.right, entry.node.data, entry.upper))
return True
is_binary_tree_bst_bfs
は根の節を受け取り QueueEntry
オブジェクトにしてキュー (bfs_queue
) につめる。 QueueEntry
オブジェクトは BstNode
オブジェクトと、その節を二分探索木として成立させるための下限値 (lower
) と上限値 (upper
) を含む namedtuple
である。
ループの中でデキューして節を取得し、その値が lower
以上かつ upper
以下であるかチェックする。この条件を満足しなければ False
を返す。満足していれば、「左の子」「右の子」とキューに詰めて、ループを継続する。ループを最後まで回せたら True
を返す。
この方法では木を最後まで巡回せずとも False
を返せる。このことから前回のコードより実行効率が高いと期待したが、サンプルデータに対してこのコードを走らせると前回のコードより遅かった (約30倍くらいの実行時間になる)。