(* Source : https://www.cs.cornell.edu/courses/cs3110/2009sp/lectures/src/lec11.ml *)
(* Red-Black tree. Binary search tree with properties:
* 1. Nodes are colored either red or black.
* 2. The root is black
* 3. Every leaf is black.
* 4. The children of every red node are black.
* 5. Every path from a node to a descendant leaf has the same
* number of black nodes as every other path.
*
* Longest path from root to leaf can be at most 2x longer than
* shortest path because at most every other node can be red (no
* red node with red parents) and same number of black nodes on
* each path, thus search always O(log n).
*)
type color = Red | Black
type 'a rbtree = Node of color * 'a * 'a rbtree * 'a rbtree | Leaf
(* Affichage *)
let next_rb x = match x with
| Leaf -> [], [("style", "invis")], [("style", "invis")]
| Node (c, i, a, b) -> let couleur = if c = Red then "#ff0000" else "#000000" in
[a; b], [("label", string_of_int i);("fillcolor", couleur)], []
let affiche = make_affiche next_rb ["node [shape=circle fontcolor=\"#ffffff\" style=filled]"]
let rec mem x = function
Leaf -> false
| Node (_, y, left, right) -> x = y || (x < y && mem x left) || (x > y && mem x right)
(* Repair violations of the invariant that a red node should have no
* red children. Make this the responsibility of the grandparent of
* the red node having the red parent. There are four cases each of
* which results in a red node with two black children (which may in
* turn violate the constraint above it in the tree. *)
let balance = function
Black, z, Node (Red, y, Node (Red, x, a, b), c), d
| Black, z, Node (Red, x, a, Node (Red, y, b, c)), d
| Black, x, a, Node (Red, z, Node (Red, y, b, c), d)
| Black, x, a, Node (Red, y, b, Node (Red, z, c, d)) ->
Node (Red, y, Node (Black, x, a, b), Node (Black, z, c, d))
| a, b, c, d ->
Node (a, b, c, d)
let insert x s =
(* same as for basic binary search tree except 3 things:
* 1. initially replace a leaf with a red node with two leaves as
* children, 2. balance result of each recursive call (because
* inserting red node may have violated red has no red children
* invariant), 3. force root to be black
*
* Note considerably simpler than imperative version of insert, which
* has left and right rotations in addition to operation similar to
* balance's grandparent update. *)
let rec ins = function
Leaf -> Node (Red, x, Leaf, Leaf)
| Node (color, y, a, b) as s ->
if x < y then balance (color, y, ins a, b)
else if x > y then balance (color, y, a, ins b)
else s
in
match ins s with
Node (_, y, a, b) ->
Node (Black, y, a, b)
| Leaf -> (* guaranteed to be nonempty *)
raise (Failure "RBT insert failed with ins returning leaf")
let rec rbt_of_list = function
| [] -> Leaf
| x :: l -> insert x (rbt_of_list l);;