authorgravatar for shawn@git.icuShawn Landden <shawn@git.icu> 2018-08-05 15:11:29-07:00
committergravatar for shawn@git.icuShawn Landden <shawn@git.icu> 2018-08-06 22:18:44-07:00
log5d2abf4402bdbd70eb95cf0d516ce12ff4202101
tree51c8d3ce5c93b2a9cd7985275916c36ddb486bb4
parentaa232089f2beaa273458a9fa75b2ba5c70f71805

std: add red-black tree implementation

This is to be used with @fieldParentPtr(); Example: const rb = @import("std").rb; const Number = struct { node: rb.Node, value: i32, }; fn number(node: *rb.Node) *Number { @fieldParentPtr(Number, "node", node); } fn compare(l: *rb.Node, r: *rb.Node) rb.Compare { var left = number(l); var right = number(r); if (left.value < right.value) { return rb.Compare.LessThan; } else if (left.value == right.value) { return rb.Compare.Equal; } else if (left.value > right.value) { return rb.Compare.GreaterThan; } unreachable; } -- A version that caches rb.Tree.first() could be added in the future.

2 files changed, 547 insertions(+), 0 deletions(-)

std/index.zig+1
......@@ -32,6 +32,7 @@ pub const mem = @import("mem.zig");
3232pub const net = @import("net.zig");
3333pub const os = @import("os/index.zig");
3434pub const rand = @import("rand/index.zig");
35pub const rb = @import("rb.zig");
3536pub const sort = @import("sort.zig");
3637pub const unicode = @import("unicode.zig");
3738pub const zig = @import("zig/index.zig");
std/rb.zig created+546
......@@ -0,0 +1,546 @@
1const assert = @import("std").debug.assert;
2
3const Color = enum(u1) {
4 Black,
5 Red,
6};
7const Red = Color.Red;
8const Black = Color.Black;
9
10const Compare = enum {
11 LessThan,
12 Equal,
13 GreaterThan,
14};
15
16const ReplaceError = error {
17 NotEqual,
18};
19
20/// Insert this into your struct that you want to add to a red-black tree.
21/// Do not use a pointer. Turn the *rb.Node results of the functions in rb
22/// (after resolving optionals) to your structure using @fieldParentPtr(). Example:
23///
24/// const Number = struct {
25/// node: rb.Node,
26/// value: i32,
27/// };
28/// fn number(node: *Node) Number {
29/// return @fieldParentPtr(Number, "node", node);
30/// }
31pub const Node = struct {
32 left: ?*Node,
33 right: ?*Node,
34 parent_and_color: usize, /// parent | color
35
36 pub fn next(constnode: *Node) ?*Node {
37 var node = constnode;
38
39 if (node.right) |right| {
40 var n = right;
41 while (n.left) |left|
42 n = left;
43 return n;
44 }
45
46 while (true) {
47 var parent = node.get_parent();
48 if (parent) |p| {
49 if (node != p.right)
50 return p;
51 node = p;
52 } else
53 return null;
54 }
55 }
56
57 pub fn prev(constnode: *Node) ?*Node {
58 var node = constnode;
59
60 if (node.left) |left| {
61 var n = left;
62 while (n.right) |right|
63 n = right;
64 return n;
65 }
66
67 while (true) {
68 var parent = node.get_parent();
69 if (parent) |p| {
70 if (node != p.left)
71 return p;
72 node = p;
73 } else
74 return null;
75 }
76 }
77
78 pub fn is_root(node: *Node) bool {
79 return node.get_parent() == null;
80 }
81
82 fn is_red(node: *Node) bool {
83 return node.get_color() == Red;
84 }
85
86 fn is_black(node: *Node) bool {
87 return node.get_color() == Black;
88 }
89
90 fn set_parent(node: *Node, parent: ?*Node) void {
91 node.parent_and_color = @ptrToInt(parent) | (node.parent_and_color & 1);
92 }
93
94 fn get_parent(node: *Node) ?*Node {
95 const mask: usize = 1;
96 comptime {
97 assert(@alignOf(*Node) >= 2);
98 }
99 return @intToPtr(*Node, node.parent_and_color & ~mask);
100 }
101
102 fn set_color(node: *Node, color: Color) void {
103 const mask: usize = 1;
104 node.parent_and_color = (node.parent_and_color & ~mask) | @enumToInt(color);
105 }
106
107 fn get_color(node: *Node) Color {
108 return @intToEnum(Color, @intCast(u1, node.parent_and_color & 1));
109 }
110
111 fn set_child(node: *Node, child: ?*Node, is_left: bool) void {
112 if (is_left) {
113 node.left = child;
114 } else {
115 node.right = child;
116 }
117 }
118
119 fn get_first(nodeconst: *Node) *Node {
120 var node = nodeconst;
121 while (node.left) |left| {
122 node = left;
123 }
124 return node;
125 }
126
127 fn get_last(node: *Node) *Node {
128 while (node.right) |right| {
129 node = right;
130 }
131 return node;
132 }
133};
134
135pub const Tree = struct {
136 root: ?*Node,
137 compare_fn: fn(*Node, *Node) Compare,
138
139 pub fn first(tree: *Tree) ?*Node {
140 var node: *Node = tree.root orelse return null;
141
142 while (node.left) |left| {
143 node = left;
144 }
145
146 return node;
147 }
148
149 pub fn last(tree: *Tree) ?*Node {
150 var node: *Node = tree.root orelse return null;
151
152 while (node.right) |right| {
153 node = right;
154 }
155
156 return node;
157 }
158
159 /// Duplicate keys are not allowed. The item with the same key already in the
160 /// tree will be returned, and the item will not be inserted.
161 pub fn insert(tree: *Tree, node_const: *Node) ?*Node {
162 var node = node_const;
163 var maybe_key: ?*Node = undefined;
164 var maybe_parent: ?*Node = undefined;
165 var is_left: bool = undefined;
166
167 maybe_key = do_lookup(node, tree, &maybe_parent, &is_left);
168 if (maybe_key) |key| {
169 return key;
170 }
171
172 node.left = null;
173 node.right = null;
174 node.set_color(Red);
175 node.set_parent(maybe_parent);
176
177 if (maybe_parent) |parent| {
178 parent.set_child(node, is_left);
179 } else {
180 tree.root = node;
181 }
182
183 while (node.get_parent()) |*parent| {
184 if (parent.*.is_black())
185 break;
186 // the root is always black
187 var grandpa = parent.*.get_parent() orelse unreachable;
188
189 if (parent.* == grandpa.left) {
190 var maybe_uncle = grandpa.right;
191
192 if (maybe_uncle) |uncle| {
193 if (uncle.is_black())
194 break;
195
196 parent.*.set_color(Black);
197 uncle.set_color(Black);
198 grandpa.set_color(Red);
199 node = grandpa;
200 } else {
201 if (node == parent.*.right) {
202 rotate_left(parent.*, tree);
203 node = parent.*;
204 parent.* = node.get_parent().?; // Just rotated
205 }
206 parent.*.set_color(Black);
207 grandpa.set_color(Red);
208 rotate_right(grandpa, tree);
209 }
210 } else {
211 var maybe_uncle = grandpa.left;
212
213 if (maybe_uncle) |uncle| {
214 if (uncle.is_black())
215 break;
216
217 parent.*.set_color(Black);
218 uncle.set_color(Black);
219 grandpa.set_color(Red);
220 node = grandpa;
221 } else {
222 if (node == parent.*.left) {
223 rotate_right(parent.*, tree);
224 node = parent.*;
225 parent.* = node.get_parent().?; // Just rotated
226 }
227 parent.*.set_color(Black);
228 grandpa.set_color(Red);
229 rotate_left(grandpa, tree);
230 }
231 }
232 }
233 // This was an insert, there is at least one node.
234 tree.root.?.set_color(Black);
235 return null;
236 }
237
238 pub fn lookup(tree: *Tree, key: *Node) ?*Node {
239 var parent: *Node = undefined;
240 var is_left: bool = undefined;
241
242 return do_lookup(key, tree, &parent, &is_left);
243 }
244
245 pub fn remove(tree: *Tree, nodeconst: *Node) void {
246 var node = nodeconst;
247 // as this has the same value as node, it is unsafe to access node after newnode
248 var newnode: ?*Node = nodeconst;
249 var maybe_parent: ?*Node = node.get_parent();
250 var color: Color = undefined;
251 var next: *Node = undefined;
252
253 // This clause is to avoid optionals
254 if (node.left == null and node.right == null) {
255 if (maybe_parent) |parent| {
256 parent.set_child(null, parent.left == node);
257 } else
258 tree.root = null;
259 color = node.get_color();
260 newnode = null;
261 } else {
262 if (node.left == null) {
263 next = node.right.?; // Not both null as per above
264 } else if (node.right == null) {
265 next = node.left.?; // Not both null as per above
266 } else
267 next = node.right.?.get_first(); // Just checked for null above
268
269 if (maybe_parent) |parent| {
270 parent.set_child(next, parent.left == node);
271 } else
272 tree.root = next;
273
274 if (node.left != null and node.right != null) {
275 const left = node.left.?;
276 const right = node.right.?;
277
278 color = next.get_color();
279 next.set_color(node.get_color());
280
281 next.left = left;
282 left.set_parent(next);
283
284 if (next != right) {
285 var parent = next.get_parent().?; // Was traversed via child node (right/left)
286 next.set_parent(node.get_parent());
287
288 newnode = next.right;
289 parent.left = node;
290
291 next.right = right;
292 right.set_parent(next);
293 } else {
294 next.set_parent(maybe_parent);
295 maybe_parent = next;
296 newnode = next.right;
297 }
298 } else {
299 color = node.get_color();
300 newnode = next;
301 }
302 }
303
304 if (newnode) |n|
305 n.set_parent(maybe_parent);
306
307 if (color == Red)
308 return;
309 if (newnode) |n| {
310 n.set_color(Black);
311 return;
312 }
313
314 while (node == tree.root) {
315 // If not root, there must be parent
316 var parent = maybe_parent.?;
317 if (node == parent.left) {
318 var sibling = parent.right.?; // Same number of black nodes.
319
320 if (sibling.is_red()) {
321 sibling.set_color(Black);
322 parent.set_color(Red);
323 rotate_left(parent, tree);
324 sibling = parent.right.?; // Just rotated
325 }
326 if ((if (sibling.left) |n| n.is_black() else true) and
327 (if (sibling.right) |n| n.is_black() else true)) {
328 sibling.set_color(Red);
329 node = parent;
330 maybe_parent = parent.get_parent();
331 continue;
332 }
333 if (if (sibling.right) |n| n.is_black() else true) {
334 sibling.left.?.set_color(Black); // Same number of black nodes.
335 sibling.set_color(Red);
336 rotate_right(sibling, tree);
337 sibling = parent.right.?; // Just rotated
338 }
339 sibling.set_color(parent.get_color());
340 parent.set_color(Black);
341 sibling.right.?.set_color(Black); // Same number of black nodes.
342 rotate_left(parent, tree);
343 newnode = tree.root;
344 break;
345 } else {
346 var sibling = parent.left.?; // Same number of black nodes.
347
348 if (sibling.is_red()) {
349 sibling.set_color(Black);
350 parent.set_color(Red);
351 rotate_right(parent, tree);
352 sibling = parent.left.?; // Just rotated
353 }
354 if ((if (sibling.left) |n| n.is_black() else true) and
355 (if (sibling.right) |n| n.is_black() else true)) {
356 sibling.set_color(Red);
357 node = parent;
358 maybe_parent = parent.get_parent();
359 continue;
360 }
361 if (if (sibling.left) |n| n.is_black() else true) {
362 sibling.right.?.set_color(Black); // Same number of black nodes
363 sibling.set_color(Red);
364 rotate_left(sibling, tree);
365 sibling = parent.left.?; // Just rotated
366 }
367 sibling.set_color(parent.get_color());
368 parent.set_color(Black);
369 sibling.left.?.set_color(Black); // Same number of black nodes
370 rotate_right(parent, tree);
371 newnode = tree.root;
372 break;
373 }
374
375 if (node.is_red())
376 break;
377 }
378
379 if (newnode) |n|
380 n.set_color(Black);
381 }
382
383 /// This is a shortcut to avoid removing and re-inserting an item with the same key.
384 pub fn replace(tree: *Tree, old: *Node, newconst: *Node) !void {
385 var new = newconst;
386
387 // I assume this can get optimized out if the caller already knows.
388 if (tree.compare_fn(old, new) != Compare.Equal) return ReplaceError.NotEqual;
389
390 if (old.get_parent()) |parent| {
391 parent.set_child(new, parent.left == old);
392 } else
393 tree.root = new;
394
395 if (old.left) |left|
396 left.set_parent(new);
397 if (old.right) |right|
398 right.set_parent(new);
399
400 new.* = old.*;
401 }
402
403 pub fn init(tree: *Tree, f: fn(*Node, *Node) Compare) void {
404 tree.root = null;
405 tree.compare_fn = f;
406 }
407};
408
409fn rotate_left(node: *Node, tree: *Tree) void {
410 var p: *Node = node;
411 var q: *Node = node.right orelse unreachable;
412 var parent: *Node = undefined;
413
414 if (!p.is_root()) {
415 parent = p.get_parent().?;
416 if (parent.left == p) {
417 parent.left = q;
418 } else {
419 parent.right = q;
420 }
421 q.set_parent(parent);
422 } else {
423 tree.root = q;
424 q.set_parent(null);
425 }
426 p.set_parent(q);
427
428 p.right = q.left;
429 if (p.right) |right| {
430 right.set_parent(p);
431 }
432 q.left = p;
433}
434
435fn rotate_right(node: *Node, tree: *Tree) void {
436 var p: *Node = node;
437 var q: *Node = node.left orelse unreachable;
438 var parent: *Node = undefined;
439
440 if (!p.is_root()) {
441 parent = p.get_parent().?;
442 if (parent.left == p) {
443 parent.left = q;
444 } else {
445 parent.right = q;
446 }
447 q.set_parent(parent);
448 } else {
449 tree.root = q;
450 q.set_parent(null);
451 }
452 p.set_parent(q);
453
454 p.left = q.right;
455 if (p.left) |left| {
456 left.set_parent(p);
457 }
458 q.right = p;
459}
460
461fn do_lookup(key: *Node, tree: *Tree, pparent: *?*Node, is_left: *bool) ?*Node {
462 var maybe_node: ?*Node = tree.root;
463
464 pparent.* = null;
465 is_left.* = false;
466
467 while (maybe_node) |node| {
468 var res: Compare = tree.compare_fn(node, key);
469 if (res == Compare.Equal) {
470 return node;
471 }
472 pparent.* = node;
473 if (res == Compare.GreaterThan) {
474 is_left.* = true;
475 maybe_node = node.left;
476 } else if (res == Compare.LessThan) {
477 is_left.* = false;
478 maybe_node = node.right;
479 } else {
480 unreachable;
481 }
482 }
483 return null;
484}
485
486const testNumber = struct {
487 node: Node,
488 value: usize,
489};
490
491fn testGetNumber(node: *Node) *testNumber {
492 return @fieldParentPtr(testNumber, "node", node);
493}
494
495fn testCompare(l: *Node, r: *Node) Compare {
496 var left = testGetNumber(l);
497 var right = testGetNumber(r);
498
499 if (left.value < right.value) {
500 return Compare.LessThan;
501 } else if (left.value == right.value) {
502 return Compare.Equal;
503 } else if (left.value > right.value) {
504 return Compare.GreaterThan;
505 }
506 unreachable;
507}
508
509test "populate, remove, and replace, depulicate keys" {
510 var tree: Tree = undefined;
511 var ns: [10]testNumber = undefined;
512 ns[0].value = 42;
513 ns[1].value = 41;
514 ns[2].value = 40;
515 ns[3].value = 39;
516 ns[4].value = 38;
517 ns[5].value = 39;
518 ns[6].value = 3453;
519 ns[7].value = 32345;
520 ns[8].value = 392345;
521 ns[9].value = 4;
522
523 var dup: testNumber = undefined;
524 dup.value = 32345;
525
526 tree.init(testCompare);
527 _ = tree.insert(&ns[1].node);
528 _ = tree.insert(&ns[2].node);
529 _ = tree.insert(&ns[3].node);
530 _ = tree.insert(&ns[4].node);
531 _ = tree.insert(&ns[5].node);
532 _ = tree.insert(&ns[6].node);
533 _ = tree.insert(&ns[7].node);
534 _ = tree.insert(&ns[8].node);
535 _ = tree.insert(&ns[9].node);
536 tree.remove(&ns[3].node);
537 assert(tree.insert(&dup.node) == &ns[7].node);
538 try tree.replace(&ns[7].node, &dup.node);
539
540 var num: *testNumber = undefined;
541 num = testGetNumber(tree.first().?);
542 while (num.node.next() != null) {
543 assert(testGetNumber(num.node.next().?).value > num.value);
544 num = testGetNumber(num.node.next().?);
545 }
546}