Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonで後順走査(ポストオーダー)の結果から二分探索木を構築する方法

二分探索木(BST)の後順走査(ポストオーダー走査)の結果が与えられたとき、そのシーケンスから元の木を復元する方法を解説します。

例えば、後順走査の結果が [9,15,7,20,3] である場合、構築される木は次のようになります。

Pythonで後順走査(ポストオーダー)の結果から二分探索木を構築する方法

基本となる考え方

通常、木を一意に復元するには中順走査(インオーダー走査)の結果も必要です。しかし、二分探索木では中順走査の結果が必ず昇順にソートされた順序になるという重要な性質があります。この性質を利用すれば、後順走査の結果だけで木を構築できます。

アルゴリズムの手順

  • 中順走査のリスト = 後順走査のリストをソートしたもの として求める
  • build_tree() メソッドを定義し、inorder(中順)と postorder(後順)を引数として受け取る
  • inorder リストが空でない場合、以下を実行する
    • root := postorder の末尾の値でノードを作成し、その要素をリストから削除する
    • ind := inorder リスト内での root のデータのインデックス位置
    • root の右部分木 := build_tree(inorder[ind+1:], postorder) を呼び出して構築
    • root の左部分木 := build_tree(inorder[:ind], postorder) を呼び出して構築
  • root を返す

実装例

それでは、実際のPythonコードを見てみましょう。

class TreeNode:
    def __init__(self, data, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right

def print_tree(root):
    if root is not None:
        print_tree(root.left)
        print(root.data, end=', ')
        print_tree(root.right)

class Solution(object):
    def buildTree(self, inorder, postorder):
        if inorder:
            root = TreeNode(postorder.pop())
            ind = inorder.index(root.data)
            root.right = self.buildTree(inorder[ind+1:], postorder)
            root.left = self.buildTree(inorder[:ind], postorder)
            return root

ob1 = Solution()
postorder = [3,9,20,15,7]
inorder = list(sorted([3,9,20,15,7]))
print_tree(ob1.buildTree(inorder, postorder))

入力

[9,3,15,20,7]
[9,15,7,20,3]

出力

[3,7,9,15,20]

ポイントの解説

このアルゴリズムの鍵となるのは、後順走査では「左部分木 → 右部分木 → 根」の順でノードが訪問される点です。つまり、リストの末尾の要素が必ず根になります。

また、pop() で末尾から順に取り出すため、右部分木を先に構築してから左部分木を構築する必要がある点にも注意してください。これは、後順走査のリストを末尾から見ていくと「根 → 右部分木 → 左部分木」の順で現れるためです。

計算量についても触れておくと、各ノードで index() による線形探索を行うため、時間計算量は O(n²) となります。ハッシュマップで値からインデックスへの対応を事前に構築しておけば、O(n) まで改善可能です。

  1. Pythonで二分木を反転する方法:再帰を使った実装を解説

    二分木の反転とは二分木が与えられたとき、その左右の子ノードを入れ替えて「鏡像」のような木を作ることを二分木の反転(Invert Binary Tree)と呼びます。これはアルゴリズムの学習やコーディング面接でも頻出のトピックです。例えば、次のような二分木があったとします。これを反転すると、すべてのノードの左部分木と右部分木が入れ替わり、以下のような木になります。解き方:再帰的アプローチこの問題は再帰を使うと非常にシンプルに解けます。考え方は以下の3ステップです。ルートが None(null)であれば、そのまま返す(ベースケース)現在のノードの左ポインタと右ポインタを入れ替える左部分木と右部分木

  2. Pythonでソート済み配列を高さバランスの二分探索木に変換する方法

    ソートされた配列 A が与えられたとき、そこから高さバランスの取れた二分探索木(BST)を生成することを考えます。ここで「高さバランスの取れた二分木」とは、すべてのノードにおいて、左右の部分木の深さの差が常に1以下であるような二分木のことを指します。例として、配列が [-10, -3, 0, 5, 9] の場合、出力の一例は [0, -3, 9, -10, null, 5] のようになります。解法のアプローチこの問題は、配列の中央要素をルートに選ぶというシンプルな発想で解くことができます。具体的な手順は以下の通りです。配列 A が空の場合は、Null(None)を返します。配列の中央の要素を見