問題 55
(中級 🌟🌟) 完全平衡二分木を構成せよ。
完全平衡二分木では、すべてのノードについて「左部分木と右部分木のノード数の差が1以下」という性質が成り立つ。
与えられたノード数に対して、すべての完全平衡二分木を構成する関数 cbalTree
を実装せよ。すべての解をバックトラックで生成すること。
注意
完全平衡二分木は(高さ)平衡二分木とは異なる。
import LeanBook.BinTree
/-- 2分木のノード数 -/
def BinTree.nodes {α : Type} : BinTree α → Nat
| .empty => 0
| .node _ l r => 1 + l.nodes + r.nodes
/-- 2分木が完全平衡か判定 -/
def BinTree.isCBalanced {α : Type} : BinTree α → Bool
| .empty => true
| .node _ l r =>
Int.natAbs ((l.nodes : Int) - (r.nodes : Int)) ≤ 1 && l.isCBalanced && r.isCBalanced
/-- List型のモナドインスタンス -/
instance : Monad List where
pure x := [x]
bind l f := l.flatMap f
map f l := l.map f
/-- ノード数が `x` の完全平衡二分木をすべて構成する -/
partial def cbalTree (x : Nat) : List (BinTree Unit) :=
match x with
| 0 => [.empty]
| n + 1 => do
let q := n / 2
let r := n % 2
let indices := List.range (q+r+1) |>.drop q
let i ← indices
let left ← cbalTree i
let right ← cbalTree (n - i)
pure (BinTree.node () left right)
-- `cbalTree` で生成される木の数を確認
#guard (cbalTree 3).length = 1
#guard (cbalTree 4).length = 4
#guard (cbalTree 7).length = 1
-- `cbalTree` で生成される木はすべて完全平衡
#guard (cbalTree 3)|>.map BinTree.isCBalanced |>.and
#guard (cbalTree 4)|>.map BinTree.isCBalanced |>.and
#guard (cbalTree 5)|>.map BinTree.isCBalanced |>.and
#guard (cbalTree 6)|>.map BinTree.isCBalanced |>.and