Solution (source code)

= Solution

Represent a <binary search tree> by:
``
sml
datatype ('k, 'v) dict = Empty
    | Branch of ('k, 'v) dict * 'k * 'v * ('k, 'v) dict;
``
Assume the provided `lookup d key` returns `NONE` or `SOME value`, and `update d (key, value)` returns the updated <binary search tree>. Traverse the first dictionary, retaining only a key with the same value in the second:
``
sml
fun intersection equal d1 d2 =
    let
        fun visit Empty result = result
          | visit (Branch (left, key, value, right)) result =
              let
                  val r1 = visit left result
                  val r2 =
                      case lookup d2 key of
                          NONE => r1
                        | SOME other =>
                            if equal (value, other)
                            then update r1 (key, value)
                            else r1
              in
                  visit right r2
              end
    in
        visit d1 Empty
    end;
``
For equality-type values, call `intersection (op =) d1 d2`. An explicit value comparison parameter also handles values for which <Standard ML> does not define built-in equality. This distinguishes absent keys from defined values without reserving a sentinel value.

Every inserted entry belongs to both input dictionaries with the same value, so the result agrees with each. Conversely, each common equal-valued entry is visited in `d1`, found in `d2`, and inserted. Any dictionary agreeing with both can contain only those entries. Thus \b[the result is exactly the largest common dictionary], not merely an intersection of key sets. If `d1` has $m$ entries, lookup height is $h_2$, and maximum result-tree height during insertion is $h_r$, the <time complexity> is $O(m(1+h_2+h_r))$ for constant-cost comparisons. Logarithmic heights require a balancing assumption; an ordinary unbalanced <binary search tree> can have linear height.