ligo/vendors/Red-Black_Trees/RedBlack.ml

87 lines
2.5 KiB
OCaml

(* Red-black trees according to the following classic paper:
Chris Okasaki, Red-Black Trees in a Functional
Setting. J. Funct. Program. 9(4): 471-477 (1999)
*)
type colour = Red | Black
type 'a t =
Ext
| Int of colour * 'a t * 'a * 'a t
let empty = Ext
let is_empty m = (m = empty)
let blacken = function
Ext -> Ext
| Int (_, left, root, right) -> Int (Black, left, root, right)
let balance colour left root right =
match colour, left, root, right with
Black, Int (Red, Int (Red, a, x, b), y, c), z, d
| Black, Int (Red, a, x, Int (Red, b, y, c)), z, d
| Black, a, x, Int (Red, Int (Red, b, y, c), z, d)
| Black, a, x, Int (Red, b, y, Int (Red, c, z, d)) ->
Int (Red, Int (Black, a, x, b), y, Int (Black, c, z, d))
| _ -> Int (colour, left, root, right)
type choice = Old | New
let choose ~old ~new' = function
Old -> old
| New -> new'
exception Physical_equality
let add ~cmp choice elt tree =
let rec insert = function
Ext -> Int (Red, Ext, elt, Ext) (* A leaf *)
| Int (colour, left, root, right) ->
let diff = cmp elt root in
if diff = 0 then
let root' = choose ~new':elt ~old:root choice
in if root == root' then raise Physical_equality
else Int (colour, left, root', right)
else if diff < 0 then
balance colour (insert left) root right
else balance colour left root (insert right)
in try blacken (insert tree) with
Physical_equality -> tree
exception Not_found
let rec find ~cmp elt = function
Ext -> raise Not_found
| Int (_, left, root, right) ->
let diff = cmp elt root in
if diff = 0 then root
else if diff < 0 then find ~cmp elt left
else find ~cmp elt right
let find_opt ~cmp elt tree =
try Some (find ~cmp elt tree) with Not_found -> None
(* Inorder iterators *)
let rec iter f = function
Ext -> ()
| Int (_, left, root, right) -> iter f left; f root; iter f right
let rec inorder acc = function
Ext -> acc
| Int (_, left, root, right) -> inorder (root :: inorder acc right) left
let elements t = inorder [] t
let rec fold_inc f ~init = function
Ext -> init
| Int (_, left, root, right) ->
fold_inc f ~init:(f ~elt:root ~acc:(fold_inc f ~init left)) right
let rec fold_dec f ~init = function
Ext -> init
| Int (_, left, root, right) ->
fold_dec f ~init:(f ~elt:root ~acc:(fold_dec f ~init right)) left