練習問題 9.2 二分探索木を使ったテーブル

二分探索木を使ったテーブルを、シグネチャとして TABLE2 を与えたモジュールとして実装しなさい。そして、各関数が機能していることを確かめなさい。

解答

module Tree =
    struct
        type ('a, 'b) t = Lf | Br of 'a * 'b * ('a, 'b) t * ('a, 'b) t

        let empty = Lf

        let rec size = function
            Lf -> 0
            | Br (_, _,  left, right) -> 1 + size left + size right

        let rec depth = function
            Lf -> 0
            | Br (_, _, left, right) -> 1 + max (depth left) (depth right)

        let rec add key datum t = 
            match t with
            Lf -> Br(key, datum, Lf, Lf)
            | (Br (key', datum', left, right) as whole) when key = key' -> whole
            | Br (key', datum', left, right) when key < key' -> Br (key', datum', add key datum left, right)
            | Br (key', datum', left, right) -> Br (key', datum', left, add key datum right)

        let rec retrieve key = function
            Lf -> None
            | Br (key', datum, left, right) ->
                    if key = key' then Some datum
                    else
                        if key < key'
                        then retrieve key left
                        else retrieve key right
        
        let rec dump = function
            Lf -> []
            | Br (key, datum, left, right) ->
                    (key, datum) :: (dump left) @ (dump right)
    end;;

module type TABLE2 =
    sig
        type ('a, 'b) t

        val empty : ('a, 'b) t

        val size : ('a, 'b) t -> int

        val depth : ('a, 'b) t -> int

        val add : 'a -> 'b -> ('a, 'b) t -> ('a, 'b) t

        val retrieve : 'a -> ('a, 'b) t -> 'b option

        val dump : ('a, 'b) t -> ('a * 'b) list
        
    end;;
        
module AbsTree : TABLE2 = Tree;;

実行例

# let tr = AbsTree.empty;;
val tr : ('a, 'b) AbsTree.t = <abstr>

# let tr = AbsTree.add "l" "love" tr;;
val tr : (string, string) AbsTree.t = <abstr>

# let tr = AbsTree.add "p" "pineapple" tr;;
val tr : (string, string) AbsTree.t = <abstr>

# AbsTree.size tr;;
- : int = 2

# AbsTree.depth tr;;
- : int = 2

# let tr = AbsTree.add "a" "apple" tr;;
val tr : (string, string) AbsTree.t = <abstr>

# AbsTree.retrieve "p" tr;;
- : string option = Some "pineapple"

# AbsTree.dump tr;;
- : (string * string) list =
  [("l", "love"); ("a", "apple"); ("p", "pineapple")]

解答中、シグネチャ「TABLE2」の定義については、本文中のモジュール Table に使った定義そのままである。