mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-11 05:34:11 +03:00
353 lines
9.1 KiB
Plaintext
353 lines
9.1 KiB
Plaintext
interface RBTree exposes [ Dict, empty, size, singleton, isEmpty, insert, remove, update, fromList, toList, balance ] imports []
|
|
|
|
# The color of a node. Leaves are considered Black.
|
|
NodeColor : [ Red, Black ]
|
|
|
|
Dict k v : [ Node NodeColor k v (Dict k v) (Dict k v), Empty ]
|
|
|
|
Key k : Num k
|
|
|
|
Maybe a : [ Just a, Nothing ]
|
|
|
|
# Create an empty dictionary.
|
|
empty : Dict k v
|
|
empty =
|
|
Empty
|
|
|
|
# Create a dictionary with one key-value pair.
|
|
singleton : Key k, v -> Dict (Key k) v
|
|
singleton = \key, value ->
|
|
# Root node is always Black
|
|
Node Black key value Empty Empty
|
|
|
|
# {-| Determine the number of key-value pairs in the dictionary. -}
|
|
size : Dict k v -> I64
|
|
size = \dict ->
|
|
sizeHelp 0 dict
|
|
|
|
sizeHelp : I64, Dict k v -> I64
|
|
sizeHelp = \n, dict ->
|
|
when dict is
|
|
Empty ->
|
|
n
|
|
|
|
Node _ _ _ left right ->
|
|
sizeHelp (sizeHelp (n+1) right) left
|
|
|
|
isEmpty : Dict k v -> Bool
|
|
isEmpty = \dict ->
|
|
when dict is
|
|
Empty ->
|
|
True
|
|
|
|
Node _ _ _ _ _ ->
|
|
False
|
|
|
|
insert : Key k, v, Dict (Key k) v -> Dict (Key k) v
|
|
insert = \key, value, dict ->
|
|
when insertHelp key value dict is
|
|
Node Red k v l r ->
|
|
Node Black k v l r
|
|
|
|
x ->
|
|
x
|
|
|
|
insertHelp : (Key k), v, Dict (Key k) v -> Dict (Key k) v
|
|
insertHelp = \key, value, dict ->
|
|
when dict is
|
|
Empty ->
|
|
# New nodes are always red. If it violates the rules, it will be fixed
|
|
# when balancing.
|
|
Node Red key value Empty Empty
|
|
|
|
Node nColor nKey nValue nLeft nRight ->
|
|
when Num.compare key nKey is
|
|
LT ->
|
|
balance nColor nKey nValue (insertHelp key value nLeft) nRight
|
|
|
|
EQ ->
|
|
Node nColor nKey value nLeft nRight
|
|
|
|
GT ->
|
|
balance nColor nKey nValue nLeft (insertHelp key value nRight)
|
|
|
|
balance : NodeColor, k, v, Dict k v, Dict k v -> Dict k v
|
|
balance = \color, key, value, left, right ->
|
|
when right is
|
|
Node Red rK rV rLeft rRight ->
|
|
when left is
|
|
Node Red lK lV lLeft lRight ->
|
|
Node
|
|
Red
|
|
key
|
|
value
|
|
(Node Black lK lV lLeft lRight)
|
|
(Node Black rK rV rLeft rRight)
|
|
|
|
_ ->
|
|
Node color rK rV (Node Red key value left rLeft) rRight
|
|
|
|
_ ->
|
|
when left is
|
|
Node Red lK lV (Node Red llK llV llLeft llRight) lRight ->
|
|
Node
|
|
Red
|
|
lK
|
|
lV
|
|
(Node Black llK llV llLeft llRight)
|
|
(Node Black key value lRight right)
|
|
|
|
_ ->
|
|
Node color key value left right
|
|
|
|
|
|
remove : Key k, Dict (Key k) v -> Dict (Key k) v
|
|
remove = \key, dict ->
|
|
# Root node is always Black
|
|
when removeHelp key dict is
|
|
Node Red k v l r ->
|
|
Node Black k v l r
|
|
|
|
x ->
|
|
x
|
|
|
|
|
|
|
|
# The easiest thing to remove from the tree, is a red node. However, when searching for the
|
|
# node to remove, we have no way of knowing if it will be red or not. This remove implementation
|
|
# makes sure that the bottom node is red by moving red colors down the tree through rotation
|
|
# and color flips. Any violations this will cause, can easily be fixed by balancing on the way
|
|
# up again.
|
|
removeHelp : Key k, Dict (Key k) v -> Dict (Key k) v
|
|
removeHelp = \targetKey, dict ->
|
|
when dict is
|
|
Empty ->
|
|
Empty
|
|
|
|
Node color key value left right ->
|
|
if targetKey < key then
|
|
when left is
|
|
Node Black _ _ lLeft _ ->
|
|
when lLeft is
|
|
Node Red _ _ _ _ ->
|
|
Node color key value (removeHelp targetKey left) right
|
|
|
|
_ ->
|
|
when moveRedLeft dict is
|
|
Node nColor nKey nValue nLeft nRight ->
|
|
balance nColor nKey nValue (removeHelp targetKey nLeft) nRight
|
|
|
|
Empty ->
|
|
Empty
|
|
|
|
_ ->
|
|
Node color key value (removeHelp targetKey left) right
|
|
else
|
|
removeHelpEQGT targetKey (removeHelpPrepEQGT targetKey dict color key value left right)
|
|
|
|
|
|
|
|
|
|
|
|
removeHelpPrepEQGT : Key k, Dict (Key k) v, NodeColor, (Key k), v, Dict (Key k) v, Dict (Key k) v -> Dict (Key k) v
|
|
removeHelpPrepEQGT = \_, dict, color, key, value, left, right ->
|
|
when left is
|
|
Node Red lK lV lLeft lRight ->
|
|
Node
|
|
color
|
|
lK
|
|
lV
|
|
lLeft
|
|
(Node Red key value lRight right)
|
|
|
|
_ ->
|
|
when right is
|
|
Node Black _ _ (Node Black _ _ _ _) _ ->
|
|
moveRedRight dict
|
|
|
|
Node Black _ _ Empty _ ->
|
|
moveRedRight dict
|
|
|
|
_ ->
|
|
dict
|
|
|
|
|
|
|
|
|
|
# When we find the node we are looking for, we can remove by replacing the key-value
|
|
# pair with the key-value pair of the left-most node on the right side (the closest pair).
|
|
removeHelpEQGT : Key k, Dict (Key k) v -> Dict (Key k) v
|
|
removeHelpEQGT = \targetKey, dict ->
|
|
when dict is
|
|
Node color key value left right ->
|
|
if targetKey == key then
|
|
when getMin right is
|
|
Node _ minKey minValue _ _ ->
|
|
balance color minKey minValue left (removeMin right)
|
|
|
|
Empty ->
|
|
Empty
|
|
else
|
|
balance color key value left (removeHelp targetKey right)
|
|
|
|
Empty ->
|
|
Empty
|
|
|
|
|
|
|
|
|
|
getMin : Dict k v -> Dict k v
|
|
getMin = \dict ->
|
|
when dict is
|
|
# Node _ _ _ ((Node _ _ _ _ _) as left) _ ->
|
|
Node _ _ _ left _ ->
|
|
when left is
|
|
Node _ _ _ _ _ -> getMin left
|
|
_ -> dict
|
|
|
|
_ ->
|
|
dict
|
|
|
|
|
|
moveRedLeft : Dict k v -> Dict k v
|
|
moveRedLeft = \dict ->
|
|
when dict is
|
|
# Node clr k v (Node lClr lK lV lLeft lRight) (Node rClr rK rV ((Node Red rlK rlV rlL rlR) as rLeft) rRight) ->
|
|
# Node clr k v (Node lClr lK lV lLeft lRight) (Node rClr rK rV rLeft rRight) ->
|
|
Node clr k v (Node _ lK lV lLeft lRight) (Node _ rK rV rLeft rRight) ->
|
|
when rLeft is
|
|
Node Red rlK rlV rlL rlR ->
|
|
Node
|
|
Red
|
|
rlK
|
|
rlV
|
|
(Node Black k v (Node Red lK lV lLeft lRight) rlL)
|
|
(Node Black rK rV rlR rRight)
|
|
|
|
_ ->
|
|
when clr is
|
|
Black ->
|
|
Node
|
|
Black
|
|
k
|
|
v
|
|
(Node Red lK lV lLeft lRight)
|
|
(Node Red rK rV rLeft rRight)
|
|
|
|
Red ->
|
|
Node
|
|
Black
|
|
k
|
|
v
|
|
(Node Red lK lV lLeft lRight)
|
|
(Node Red rK rV rLeft rRight)
|
|
|
|
_ ->
|
|
dict
|
|
|
|
moveRedRight : Dict k v -> Dict k v
|
|
moveRedRight = \dict ->
|
|
when dict is
|
|
Node _ k v (Node _ lK lV (Node Red llK llV llLeft llRight) lRight) (Node _ rK rV rLeft rRight) ->
|
|
Node
|
|
Red
|
|
lK
|
|
lV
|
|
(Node Black llK llV llLeft llRight)
|
|
(Node Black k v lRight (Node Red rK rV rLeft rRight))
|
|
|
|
Node clr k v (Node _ lK lV lLeft lRight) (Node _ rK rV rLeft rRight) ->
|
|
when clr is
|
|
Black ->
|
|
Node
|
|
Black
|
|
k
|
|
v
|
|
(Node Red lK lV lLeft lRight)
|
|
(Node Red rK rV rLeft rRight)
|
|
|
|
Red ->
|
|
Node
|
|
Black
|
|
k
|
|
v
|
|
(Node Red lK lV lLeft lRight)
|
|
(Node Red rK rV rLeft rRight)
|
|
|
|
_ ->
|
|
dict
|
|
|
|
removeMin : Dict k v -> Dict k v
|
|
removeMin = \dict ->
|
|
when dict is
|
|
Node color key value left right ->
|
|
when left is
|
|
Node lColor _ _ lLeft _ ->
|
|
when lColor is
|
|
Black ->
|
|
when lLeft is
|
|
Node Red _ _ _ _ ->
|
|
Node color key value (removeMin left) right
|
|
|
|
_ ->
|
|
when moveRedLeft dict is
|
|
Node nColor nKey nValue nLeft nRight ->
|
|
balance nColor nKey nValue (removeMin nLeft) nRight
|
|
|
|
Empty ->
|
|
Empty
|
|
|
|
_ ->
|
|
Node color key value (removeMin left) right
|
|
|
|
_ ->
|
|
Empty
|
|
_ ->
|
|
Empty
|
|
|
|
|
|
# Update the value of a dictionary for a specific key with a given function.
|
|
update : Key k, (Maybe v -> Maybe v), Dict (Key k) v -> Dict (Key k) v
|
|
update = \targetKey, alter, dictionary ->
|
|
when alter (get targetKey dictionary) is
|
|
Just value ->
|
|
insert targetKey value dictionary
|
|
|
|
Nothing ->
|
|
remove targetKey dictionary
|
|
|
|
get : Key k, Dict (Key k) v -> Maybe v
|
|
get = \targetKey, dict ->
|
|
when dict is
|
|
Empty ->
|
|
Nothing
|
|
|
|
Node _ key value left right ->
|
|
when Num.compare targetKey key is
|
|
LT ->
|
|
get targetKey left
|
|
|
|
EQ ->
|
|
Just value
|
|
|
|
GT ->
|
|
get targetKey right
|
|
|
|
fromList : List {key : Num k, value : v } -> Dict (Num k) v
|
|
fromList = \xs ->
|
|
List.walkRight xs (\{key, value}, dict -> insert key value dict) empty
|
|
|
|
foldr : (k, v, b -> b), b, Dict k v -> b
|
|
foldr = \func, acc, t ->
|
|
when t is
|
|
Empty ->
|
|
acc
|
|
|
|
Node _ key value left right ->
|
|
foldr func (func key value (foldr func acc right)) left
|
|
|
|
# Convert a dictionary into an association list of key-value pairs, sorted by keys.
|
|
toList : Dict k v -> List { key : k, value : v }
|
|
toList = \dict ->
|
|
foldr (\key, value, list -> List.append list {key,value}) [] dict
|