blog

アルゴリズムレビュー:BFSによるバイナリツリー階層走査

BFS、幅/広さ優先。これは、各層を上から下へ走査してから次の層を走査するというものです。BFSを理解したら、問題の分析を始めます。 もう一度、この問題の再帰的な解法を考えてみましょう。再帰というと、...

May 17, 2020 · 3 min. read
シェア

、バイナリーツリーのDFSについて例題を通して学びましたが、これは実際には一方向にずっとトラバースしていくものです。ツリー内のデータに、高さに従って1層ずつアクセスすることはできるでしょうか?もちろんできます。本節のBFSは、幅優先探索とも呼ばれます。

今でも例を通して説明しています。

トピック分析

バイナリツリーが与えられた場合、そのノード値を階層的に走査して返します。

二分木が与えられている[3,9,20,null,null,15,7],
 3 
 / \ 
 9 20 
 / \ 
 15 7
階層走査の結果を返す:[[3],[9,20],[15,7]]


BFS入門

BFS、まず幅を広げること。これは、各層を上から下へ走査してから次の層を走査するということです。ツリーが次のようなものだとします:

BFSによると、アクセス順は以下の通り:

BFSを理解することから、この問題の分析が始まります。

再帰的解法

もう一度、この問題の再帰的な解決策を考えてみましょう。再帰というと、一般的にはまずDFSを思い浮かべます。バイナリツリーの先行順序探索を実行すると同時に、ノードが配置されている階層のレベルを記録して、各レベルの配列を定義し、アクセスされたノードの値を対応するレベルの配列に配置します。



与えられた2進木が[3,9,20,null,null,15,7]だとします:

以上の分析に基づき、コードは以下の通り:

func levelOrder(root *TreeNode) [][]int {
 return dfs(root, 0, [][]int{})
}
func dfs(root *TreeNode, level int, res [][]int) [][]int {
	if root == nil {
		return res
	}
	if len(res) == level {
		res = append(res, []int{root.Val})
	} else {
		res[level] = append(res[level], root.Val)
	}
	res = dfs(root.Left, level+1, res)
	res = dfs(root.Right, level+1, res)
 return res
}

BFSの解法

上記の解決策は、実はバイナリーツリーBFSを実装するためにDFSメソッドを使用することと等価です。では、この問題を解決するためにBFSメソッドを直接使用することはできるのでしょうか?もちろん、Queueデータ構造を使うことができます。ルートノードをキューに初期化し、テールを消費してヘッドを挿入することでBFSを完成させます。



手順を以下に示します:

以上の分析に基づき、コードは以下の通り:

func levelOrder(root *TreeNode) [][]int {
	var result [][]int
	if root == nil {
		return result
	}
 // 双方向キューを定義する
	queue := list.New()
 // ルートノードへのヘッダー挿入
	queue.PushFront(root)
 // 幅の広い検索を実行する
	for queue.Len() > 0 {
		var current []int
		listLength := queue.Len()
		for i := 0; i < listLength; i++ {
		  // テールを消費する
 // queue.Remove(queue.Back()).(*TreeNode)最後の要素を取り除き、TreeNode型に変換する。
			node := queue.Remove(queue.Back()).(*TreeNode)
			current = append(current, node.Val)
			if node.Left != nil {
			  //ヘッダーを挿入する
				queue.PushFront(node.Left)
			}
			if node.Right != nil {
				queue.PushFront(node.Right)
			}
		}
		result = append(result, current)
	}
	return result
}

私が書いたすべての解答と各問題の完全な図解をeBookにまとめました。

Read next

JavaScriptで文字列を結合する4つの方法

ここでは、文字列を組み合わせる4つの方法を紹介します。私のお気に入りの方法は、テンプレート文字列を使うことです。なぜかって?なぜなら、その方が読みやすいからです。引用符をエスケープするためのバックスラッシュも、厄介なスペースセパレーターも、紛らわしいプラス演算子もありません。 1. テンプレート文字列 他の言語から来た人なら、文字列補間という用語になじみがあるでしょう。これはまさにテンプレート ...

May 17, 2020 · 5 min read