(* file : dictionary.ml * author: Bob Muller * * CS1101 Computer Science I * * Code showing the use of list and tuples to represent dictionaries. * A dictionary is a set of assocations between keys and values: * * "Bob" => 59, "Joe" => 21, "Mary" => 22, ... * * A dictionary requires three main operations: * * empty : unit -> dictionary * * add : key -> value -> dictionary -> dictionary * * find : key -> dictionary -> value * * We'll look at two implementations of dictionaries, one using * a list of (key, value) pairs (aka an association list) and * another using binary search trees. For the former, the add * operation requires only 1 unit of work but the find operation * is slow, requiring on the order of N units of work. * For the binary search tree implementation, both add and find * are fast, requiring on the order of log_2 N units of work on * average. * * We'll use strings for keys and integers for values for now. *) type key = string type value = int (* NOTE: These two implementations are packed up in two modules * Seq and BST. You can try these out in a REPL by using affixing * the module name the operation. E.g., Seq.add, BST.add etc. * * *** Now for the sequential assocation list representation. ****) module Seq = struct type dictionary = (key * value) list (* empty : unit -> dictionary *) let empty () = [] (* add : key -> value -> dictionary -> dictionary * * The call (add key value dictionary) returns a new dictionary * associating key with value. *) let add key value dictionary = (key, value) :: dictionary (* find : key -> dictionary -> value * * The call (find key dictionary) returns that value associated with * key in the dictionary if key actually occurs in the dictionary. If * key isn't in the dictionary, find throws an exception. With this * implementation of dictionaries, the find operation requires N units * of work on average. *) let rec find key dictionary = match dictionary with | [] -> failwith "Sorry no such key" | (key', value) :: dictionary' -> (match key = key' with | true -> value | false -> find key dictionary') let d0 = [("Bob", 59); ("Tom", 21); ("Alice", 22)] end (**** Now for the binary tree representation of dictionaries ****) module BST = struct type dictionary = Empty | Node of (dictionary * string * int * dictionary) (* empty : unit -> dictionary *) let empty () = Empty (* add : key -> value -> dictionary -> dictionary * * The call (add key value dictionary) extends dictionary with * an assocation between key and value. With this implementation * of dictionaries, the add operation requires log_2 N units of * work on average, where N is the number of key/value assocations * in the dictionary. *) let rec add key value dictionary = match dictionary with | Empty -> Node(Empty, key, value, Empty) | Node(left, key', value', right) -> (match key < key' with | true -> let newLeft = add key value left in Node(newLeft, key', value', right) | false -> let newRight = add key value right in Node(left, key', value', newRight)) (* find : key -> dictionary -> value * * The call (find key dictionary) returns that value associated with * key in the dictionary if key actually occurs in the dictionary. If * key isn't in the dictionary, find throws an exception. With this * implementation of dictionaries, the find operation requires log_2 N * units of work on average. *) let rec find key dictionary = match dictionary with | Empty -> failwith "No such luck" | Node(left, key', value, right) -> (match key = key' with | true -> value | false -> (match key < key' with | true -> find key left | false -> find key right)) let d0 = Node( Node(Empty, "Tom", 21, Empty), "Bob", 59, Node(Empty, "Alice", 22, Empty) ) end