読者です 読者をやめる 読者になる 読者になる

再帰的データ型(二分木)

さっそくデータ型を定義。大きさと深さを求める関数も定義。

# type 'a tree = Lf | Br of 'a * 'a tree * 'a tree;;
type 'a tree = Lf | Br of 'a * 'a tree * 'a tree
# let rec size = function
    Lf -> 0
  | Br (_, left, right) -> 1 + size left + size right;;
val size : 'a tree -> int = <fun>
# let rec depth = function
    Lf -> 0
  | Br (_, left, right) -> 1 + max (depth left) (depth right);;
val depth : 'a tree -> int = <fun>
# let tree = Br (1, Br (2, Br (4, Lf, Lf),
                           Br (5, Lf, Lf)),
                    Br (3, Br (6, Lf, Lf),
                           Br (7, Lf, Lf)));;
val tree : int tree =
  Br (1, Br (2, Br (4, Lf, Lf), Br (5, Lf, Lf)),
   Br (3, Br (6, Lf, Lf), Br (7, Lf, Lf)))
# size tree;;
- : int = 7
# depth tree;;
- : int = 3

このような木を生成する関数を書いてみる。

# let rec comptree x = function
    0 -> Lf
  | n -> Br (x, comptree x (n-1), comptree x (n-1));;
val comptree : 'a -> int -> 'a tree = <fun>
# comptree 'a' 3;;
- : char tree =
Br ('a', Br ('a', Br ('a', Lf, Lf), Br ('a', Lf, Lf)),
 Br ('a', Br ('a', Lf, Lf), Br ('a', Lf, Lf)))
# let comptree' n =
    let rec get_tree x = function
      0 -> Lf
    | n -> Br (x, get_tree (2*x) (n-1), get_tree (2*x+1) (n-1))
    in
    get_tree 1 n;;
val comptree' : int -> int tree = <fun>
# comptree' 3;;
- : int tree =
Br (1, Br (2, Br (4, Lf, Lf), Br (5, Lf, Lf)),
 Br (3, Br (6, Lf, Lf), Br (7, Lf, Lf)))

二分木の要素を列挙する関数

# let tree = comptree' 3;;
val tree : int tree =
  Br (1, Br (2, Br (4, Lf, Lf), Br (5, Lf, Lf)),
   Br (3, Br (6, Lf, Lf), Br (7, Lf, Lf)))
# let preorder tree = 
    let rec preord t l =
      match t with
        Lf -> l
      | Br (x, left, right) -> x :: (preord left (preord right l))
    in
    preord tree [];;
val preorder : 'a tree -> 'a list = <fun>
# preorder tree;;
- : int list = [1; 2; 4; 5; 3; 6; 7]
# let inorder tree = 
    let rec inord t l =
      match t with
        Lf -> l
      | Br (x, left, right) -> inord left (x :: inord right l)
    in
    inord tree [];;
val inorder : 'a tree -> 'a list = <fun>
# inorder tree;;
- : int list = [4; 2; 5; 1; 6; 3; 7]
# let postorder tree =
    let rec postord t l =
      match t with
        Lf -> l
      | Br (x, left, right) -> postord left (postord right (x :: l))
    in postord tree [];;
val postorder : 'a tree -> 'a list = <fun>
# postorder tree;;
- : int list = [4; 5; 2; 6; 7; 3; 1]

二分木を左右反転させる関数

# let rec reflect = function
      Lf -> Lf
    | Br (x, left, right) -> Br (x, reflect right, reflect left);;
val reflect : 'a tree -> 'a tree = <fun>
# reflect tree;;
- : int tree =
Br (1, Br (3, Br (7, Lf, Lf), Br (6, Lf, Lf)),
 Br (2, Br (5, Lf, Lf), Br (4, Lf, Lf)))
# preorder (reflect tree);;
- : int list = [1; 3; 7; 6; 2; 5; 4]
# inorder (reflect tree);;
- : int list = [7; 3; 6; 1; 5; 2; 4]
# postorder (reflect tree);;
- : int list = [7; 6; 3; 5; 4; 2; 1]

これらより、以下が導かれる。

  • preorder (reflect tree) = reverse (postorder tree)
  • inorder (reflect tree) = reverse (inorder tree)
  • postorder (reflect tree) = reverse (preorder tree)