-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathRedBlackTree.fun
254 lines (237 loc) · 9.45 KB
/
RedBlackTree.fun
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
(* From Twelf *)
(* Red/Black Trees *)
(* Author: Frank Pfenning *)
functor RedBlackTree
(type key'
val compare : key' * key' -> order)
:> TABLE where type key = key' =
struct
type key = key'
type 'a entry = key * 'a
datatype 'a dict =
Empty (* considered black *)
| Red of 'a entry * 'a dict * 'a dict
| Black of 'a entry * 'a dict * 'a dict
type 'a Table = 'a dict ref
(* Representation Invariants *)
(*
1. The tree is ordered: for every node Red((key1,datum1), left, right) or
Black ((key1,datum1), left, right), every key in left is less than
key1 and every key in right is greater than key1.
2. The children of a red node are black (color invariant).
3. Every path from the root to a leaf has the same number of
black nodes, called the black height of the tree.
*)
local
fun lookup dict key =
let
fun lk (Empty) = NONE
| lk (Red tree) = lk' tree
| lk (Black tree) = lk' tree
and lk' ((key1, datum1), left, right) =
(case compare(key,key1)
of EQUAL => SOME(datum1)
| LESS => lk left
| GREATER => lk right)
in
lk dict
end
(* val restore_right : 'a dict -> 'a dict *)
(*
restore_right (Black(e,l,r)) >=> dict
where (1) Black(e,l,r) is ordered,
(2) Black(e,l,r) has black height n,
(3) color invariant may be violated at the root of r:
one of its children might be red.
and dict is a re-balanced red/black tree (satisfying all invariants)
and same black height n.
*)
fun restore_right (Black(e, Red lt, Red (rt as (_,Red _,_)))) =
Red(e, Black lt, Black rt) (* re-color *)
| restore_right (Black(e, Red lt, Red (rt as (_,_,Red _)))) =
Red(e, Black lt, Black rt) (* re-color *)
| restore_right (Black(e, l, Red(re, Red(rle, rll, rlr), rr))) =
(* l is black, deep rotate *)
Black(rle, Red(e, l, rll), Red(re, rlr, rr))
| restore_right (Black(e, l, Red(re, rl, rr as Red _))) =
(* l is black, shallow rotate *)
Black(re, Red(e, l, rl), rr)
| restore_right dict = dict
(* restore_left is like restore_right, except *)
(* the color invariant may be violated only at the root of left child *)
fun restore_left (Black(e, Red (lt as (_,Red _,_)), Red rt)) =
Red(e, Black lt, Black rt) (* re-color *)
| restore_left (Black(e, Red (lt as (_,_,Red _)), Red rt)) =
Red(e, Black lt, Black rt) (* re-color *)
| restore_left (Black(e, Red(le, ll as Red _, lr), r)) =
(* r is black, shallow rotate *)
Black(le, ll, Red(e, lr, r))
| restore_left (Black(e, Red(le, ll, Red(lre, lrl, lrr)), r)) =
(* r is black, deep rotate *)
Black(lre, Red(le, ll, lrl), Red(e, lrr, r))
| restore_left dict = dict
fun insert (dict, entry as (key,datum)) =
let
(* val ins : 'a dict -> 'a dict inserts entry *)
(* ins (Red _) may violate color invariant at root *)
(* ins (Black _) or ins (Empty) will be red/black tree *)
(* ins preserves black height *)
fun ins (Empty) = Red(entry, Empty, Empty)
| ins (Red(entry1 as (key1, datum1), left, right)) =
(case compare(key,key1)
of EQUAL => Red(entry, left, right)
| LESS => Red(entry1, ins left, right)
| GREATER => Red(entry1, left, ins right))
| ins (Black(entry1 as (key1, datum1), left, right)) =
(case compare(key,key1)
of EQUAL => Black(entry, left, right)
| LESS => restore_left (Black(entry1, ins left, right))
| GREATER => restore_right (Black(entry1, left, ins right)))
in
case ins dict
of Red (t as (_, Red _, _)) => Black t (* re-color *)
| Red (t as (_, _, Red _)) => Black t (* re-color *)
| dict => dict
end
(* function below from .../smlnj-lib/Util/int-redblack-set.sml *)
(* Need to check and improve some time *)
(* Sun Mar 13 08:22:53 2005 -fp *)
(* Remove an item. Returns true if old item found, false otherwise *)
local
exception NotFound
datatype 'a zipper
= TOP
| LEFTB of ('a entry * 'a dict * 'a zipper)
| LEFTR of ('a entry * 'a dict * 'a zipper)
| RIGHTB of ('a dict * 'a entry * 'a zipper)
| RIGHTR of ('a dict * 'a entry * 'a zipper)
in
fun delete t key =
let
fun zip (TOP, t) = t
| zip (LEFTB(x, b, z), a) = zip(z, Black(x, a, b))
| zip (LEFTR(x, b, z), a) = zip(z, Red(x, a, b))
| zip (RIGHTB(a, x, z), b) = zip(z, Black(x, a, b))
| zip (RIGHTR(a, x, z), b) = zip(z, Red(x, a, b))
(* bbZip propagates a black deficit up the tree until either the top
* is reached, or the deficit can be covered. It returns a boolean
* that is true if there is still a deficit and the zipped tree.
*)
fun bbZip (TOP, t) = (true, t)
| bbZip (LEFTB(x, Red(y, c, d), z), a) = (* case 1L *)
bbZip (LEFTR(x, c, LEFTB(y, d, z)), a)
| bbZip (LEFTB(x, Black(w, Red(y, c, d), e), z), a) = (* case 3L *)
bbZip (LEFTB(x, Black(y, c, Red(w, d, e)), z), a)
| bbZip (LEFTR(x, Black(w, Red(y, c, d), e), z), a) = (* case 3L *)
bbZip (LEFTR(x, Black(y, c, Red(w, d, e)), z), a)
| bbZip (LEFTB(x, Black(y, c, Red(w, d, e)), z), a) = (* case 4L *)
(false, zip (z, Black(y, Black(x, a, c), Black(w, d, e))))
| bbZip (LEFTR(x, Black(y, c, Red(w, d, e)), z), a) = (* case 4L *)
(false, zip (z, Red(y, Black(x, a, c), Black(w, d, e))))
| bbZip (LEFTR(x, Black(y, c, d), z), a) = (* case 2L *)
(false, zip (z, Black(x, a, Red(y, c, d))))
| bbZip (LEFTB(x, Black(y, c, d), z), a) = (* case 2L *)
bbZip (z, Black(x, a, Red(y, c, d)))
| bbZip (RIGHTB(Red(y, c, d), x, z), b) = (* case 1R *)
bbZip (RIGHTR(d, x, RIGHTB(c, y, z)), b)
| bbZip (RIGHTR(Red(y, c, d), x, z), b) = (* case 1R *)
bbZip (RIGHTR(d, x, RIGHTB(c, y, z)), b)
| bbZip (RIGHTB(Black(y, Red(w, c, d), e), x, z), b) = (* case 3R *)
bbZip (RIGHTB(Black(w, c, Red(y, d, e)), x, z), b)
| bbZip (RIGHTR(Black(y, Red(w, c, d), e), x, z), b) = (* case 3R *)
bbZip (RIGHTR(Black(w, c, Red(y, d, e)), x, z), b)
| bbZip (RIGHTB(Black(y, c, Red(w, d, e)), x, z), b) = (* case 4R *)
(false, zip (z, Black(y, c, Black(x, Red(w, d, e), b))))
| bbZip (RIGHTR(Black(y, c, Red(w, d, e)), x, z), b) = (* case 4R *)
(false, zip (z, Red(y, c, Black(w, Red(w, d, e), b))))
| bbZip (RIGHTR(Black(y, c, d), x, z), b) = (* case 2R *)
(false, zip (z, Black(x, Red(y, c, d), b)))
| bbZip (RIGHTB(Black(y, c, d), x, z), b) = (* case 2R *)
bbZip (z, Black(x, Red(y, c, d), b))
| bbZip (z, t) = (false, zip(z, t))
fun delMin (Red(y, Empty, b), z) = (y, (false, zip(z, b)))
| delMin (Black(y, Empty, b), z) = (y, bbZip(z, b))
| delMin (Black(y, a, b), z) = delMin(a, LEFTB(y, b, z))
| delMin (Red(y, a, b), z) = delMin(a, LEFTR(y, b, z))
| delMin (Empty, _) = raise Match
fun joinRed (Empty, Empty, z) = zip(z, Empty)
| joinRed (a, b, z) = let
val (x, (needB, b')) = delMin(b, TOP)
in
if needB
then #2(bbZip(z, Red(x, a, b')))
else zip(z, Red(x, a, b'))
end
fun joinBlack (a, Empty, z) = #2(bbZip(z, a))
| joinBlack (Empty, b, z) = #2(bbZip(z, b))
| joinBlack (a, b, z) = let
val (x, (needB, b')) = delMin(b, TOP)
in
if needB
then #2(bbZip(z, Black(x, a, b')))
else zip(z, Black(x, a, b'))
end
fun del (Empty, z) = raise NotFound
| del (Black(entry1 as (key1, datum1), a, b), z) =
(case compare(key,key1)
of EQUAL => joinBlack (a, b, z)
| LESS => del (a, LEFTB(entry1, b, z))
| GREATER => del (b, RIGHTB(a, entry1, z)))
| del (Red(entry1 as (key1, datum1), a, b), z) =
(case compare(key,key1)
of EQUAL => joinRed (a, b, z)
| LESS => del (a, LEFTR(entry1, b, z))
| GREATER => del (b, RIGHTR(a, entry1, z)))
in
(del(t, TOP); true) handle NotFound => false
end
end (* local *)
(* use non-imperative version? *)
fun insertShadow (dict, entry as (key,datum)) =
let val oldEntry = ref NONE (* : 'a entry option ref *)
fun ins (Empty) = Red(entry, Empty, Empty)
| ins (Red(entry1 as (key1, datum1), left, right)) =
(case compare(key,key1)
of EQUAL => (oldEntry := SOME(entry1);
Red(entry, left, right))
| LESS => Red(entry1, ins left, right)
| GREATER => Red(entry1, left, ins right))
| ins (Black(entry1 as (key1, datum1), left, right)) =
(case compare(key,key1)
of EQUAL => (oldEntry := SOME(entry1);
Black(entry, left, right))
| LESS => restore_left (Black(entry1, ins left, right))
| GREATER => restore_right (Black(entry1, left, ins right)))
in
(oldEntry := NONE;
((case ins dict
of Red (t as (_, Red _, _)) => Black t (* re-color *)
| Red (t as (_, _, Red _)) => Black t (* re-color *)
| dict => dict),
!oldEntry))
end
fun app f dict =
let fun ap (Empty) = ()
| ap (Red tree) = ap' tree
| ap (Black tree) = ap' tree
and ap' (entry1, left, right) =
(ap left; f entry1; ap right)
in
ap dict
end
in
fun new (n) = ref (Empty) (* ignore size hint *)
val insert = (fn table => fn entry => (table := insert (!table, entry)))
val insertShadow =
(fn table => fn entry =>
let
val (dict, oldEntry) = insertShadow (!table, entry)
in
(table := dict; oldEntry)
end)
val lookup = (fn table => fn key => lookup (!table) key)
val delete = (fn table => fn key => (delete (!table) key; ()))
val clear = (fn table => (table := Empty))
val app = (fn f => fn table => app f (!table))
end
end; (* functor RedBlackTree *)