diff --git a/lab05/kvtree/kvtree.ml b/lab05/kvtree/kvtree.ml new file mode 100644 index 0000000..4b048ca --- /dev/null +++ b/lab05/kvtree/kvtree.ml @@ -0,0 +1,140 @@ +module type OrderedType = sig + type t + val compare : t -> t -> int +end + +module type S = sig + type k + type ('k, 'v) t + exception Not_found + + val empty : (k, 'v) t + val is_empty : (k, 'v) t -> bool + val insert : k -> 'v -> (k, 'v) t -> (k, 'v) t + val find_opt : k -> (k, 'v) t -> 'v option + val delete : k -> (k, 'v) t -> (k, 'v) t + val of_list : (k * 'v) list -> (k, 'v) t + val size : (k, 'v) t -> int + val find : k -> (k, 'v) t -> 'v + val to_list : (k, 'v) t -> (k * 'v) list + val to_string : ((k * 'v) -> string) -> (k, 'v) t -> string +end + +module Make(Ord: OrderedType) = struct + (** [k] is the key of a key-value pair *) + type k = Ord.t + + (** [t] is a key-value tree where each N has a key, value, left and right *) + type ('k, 'v) t = L | N of k * 'v * (k, 'v) t * (k, 'v) t;; + + (** [Not_found] exception if a given key cannot be found in the tree *) + exception Not_found;; + + (** empty tree *) + let empty = L;; + + (** [is_empty t] takes a kvtree [t] and checks if it is empty or not *) + let is_empty t = t = L;; + + (** [insert k v t] takes a comparator [], key [k], value [v], + * and a kvtree [t] to insert the key and value [k, v] into the tree [t]. *) + let rec insert k v t = + match t with + | L -> N (k, v, L, L) + | N (k', v', l, r) when Ord.compare k k' < 0 -> + N (k', v', insert k v l, r) + | N (k', v', l, r) when Ord.compare k k' > 0 -> + N (k', v', l, insert k v r) + | _ -> t;; + + (** [find_opt k t] takes a key [k] and a kvtree [t] and returns + * an Optional value found from the given key [k]. *) + let rec find_opt k t = + match t with + | L -> None + | N (k', _, l, _) when Ord.compare k k' < 0 -> + find_opt k l + | N (k', _, _, r) when Ord.compare k k' > 0 -> + find_opt k r + | N (_, v, _, _) -> Some v;; + + (** [largest t] finds the largest key in a given kvtree [t] + * and retursn the key value pair [k, v] *) + let rec largest t = + match t with + | L -> failwith "largest: empty tree" + | N (k, v, _, L) -> (k, v) + | N (_, _, _, r) -> largest r;; + + (** [smallest t] finds the smallest key in a given kvtree [t] + * and retursn the key value pair [k, v] *) + let rec smallest t = + match t with + | L -> failwith "smallest: empty tree" + | N (k, v, L, _) -> (k, v) + | N (_, _, l, _) -> smallest l;; + + (** [delete k t] takes a key [k] and deletes it from a given + * kvtree [t]. *) + let rec delete k t = + match t with + | L -> L + | N (k', v, l, r) when Ord.compare k k' < 0 -> + N (k', v, delete k l, r) + | N (k', v, l, r) when Ord.compare k k' > 0 -> + N (k', v, l, delete k r) + | N (_, _, l, L) -> l + | N (_, _, L, r) -> r + | N (_, _, l, r) -> + let (ks, vs) = largest l in + N (ks, vs, delete ks l, r);; + + (** [of_list l] takes a list of pairs [l] and creates a + * kvtree in the order specefied by the comparator [] to compare + * keys *) + let of_list l = + List.fold_left (fun acc (k, v) -> insert k v acc) L l;; + + (** [size t] takes a kvtree [t] and returns the size of the tree + * i.e. number of Ns *) + let rec size t = + match t with + | L -> 0 + | N (_, _, l, r) -> + 1 + size l + size r;; + + (** [find k t] takes a key [k] and a kvtree [t] and returns + * a value found from the given key [k]. *) + let rec find k t = + match t with + | L -> raise Not_found + | N (k', _, l, _) when Ord.compare k k' < 0 -> + find k l + | N (k', _, _, r) when Ord.compare k k' > 0 -> + find k r + | N (_, v, _, _) -> v;; + + (** [to_list t] takes a key-value tree [t] and returns + * a list representation of the key-value pairs *) + let to_list t = + let rec aux acc t = + match t with + | L -> acc + | N (k, v, l, r) -> + aux ((k, v) :: (aux acc r)) l + in + aux [] t;; + + (** [to_string f t] takes a function [f] to "convert" a + * key-value pair to a string, and applies that to all + * key-value pairs in a given tree [t]. *) + let to_string f t = + let rec aux acc t = + match t with + | L -> "#" + | N (k, v, l, r) -> + Printf.sprintf "^(%s, %s, %s)" (f (k, v)) (aux acc l) (aux acc r) + in + aux "" t;; + +end diff --git a/lab05/kvtree/kvtree.mli b/lab05/kvtree/kvtree.mli new file mode 100644 index 0000000..503e6cd --- /dev/null +++ b/lab05/kvtree/kvtree.mli @@ -0,0 +1,23 @@ +module type OrderedType = sig + type t + val compare : t -> t -> int +end + +module type S = sig + type k + type ('k, 'v) t + exception Not_found + + val empty : (k, 'v) t + val is_empty : (k, 'v) t -> bool + val insert : k -> 'v -> (k, 'v) t -> (k, 'v) t + val find_opt : k -> (k, 'v) t -> 'v option + val delete : k -> (k, 'v) t -> (k, 'v) t + val of_list : (k * 'v) list -> (k, 'v) t + val size : (k, 'v) t -> int + val find : k -> (k, 'v) t -> 'v + val to_list : (k, 'v) t -> (k * 'v) list + val to_string : ((k * 'v) -> string) -> (k, 'v) t -> string +end + +module Make(Ord: OrderedType) : S with type k = Ord.t diff --git a/lab05/kvtree/tests.ml b/lab05/kvtree/tests.ml new file mode 100644 index 0000000..eed9c6d --- /dev/null +++ b/lab05/kvtree/tests.ml @@ -0,0 +1,39 @@ +(* This is a minimal test file. Your program must pass these tests in order + to get any credit for your work. + In utop: + #directory "_build";; + #load "kvtree.cmo";; + #use "tests.ml";; + run ();; + *) +module M = Kvtree.Make(Int);; + +let t = M.of_list [(3, "three"); (2, "two"); (7, "seven"); (6, "six"); (8, "eight")] +let l = [(2, "two"); (3, "three"); (6, "six"); (7, "seven"); (8, "eight")] +let s = + "^(3, three, ^(2, two, #, #), ^(7, seven, ^(6, six, #, #), ^(8, eight, #, #)))" + +let t2 = M.of_list [(3, 'a')] +let s2 = "^(3, a, #, #)" + +let t3 = M.insert 2 'b' t2 +let s3 = "^(3, a, ^(2, b, #, #), #)" + +let t4 = M.of_list [(3, "3"); (7, "7"); (5, "5"); (6, "6"); (8, "8"); (9, "9")] +let s4 = "^(3, 3, #, ^(7, 7, ^(5, 5, #, ^(6, 6, #, #)), ^(8, 8, #, ^(9, 9, #, #))))" +let t5 = M.delete 7 t4 +let s5a = "^(3, 3, #, ^(6, 6, ^(5, 5, #, #), ^(8, 8, #, ^(9, 9, #, #))))" +let s5b = "^(3, 3, #, ^(8, 8, ^(5, 5, #, ^(6, 6, #, #)), ^(9, 9, #, #)))" + +let run () = + assert (M.size t = 5); + assert (M.find 7 t = "seven"); + assert (M.find_opt 7 t = Some "seven"); + assert (M.to_list t = l); + assert (M.to_string (fun (k, v) -> Printf.sprintf "%d, %s" k v) t = s); + assert (M.to_string (fun (k, v) -> Printf.sprintf "%d, %c" k v) t2 = s2); + assert (M.to_string (fun (k, v) -> Printf.sprintf "%d, %c" k v) t3 = s3); + assert (M.to_string (fun (k, v) -> Printf.sprintf "%d, %s" k v) t4 = s4); + assert ( + let s = M.to_string (fun (k, v) -> Printf.sprintf "%d, %s" k v) t5 in + s = s5a || s = s5b)