Skip to content

Commit 70d04f0

Browse files
committed
Refactor red-black tree set #2
1 parent 3831cb1 commit 70d04f0

File tree

1 file changed

+41
-29
lines changed

1 file changed

+41
-29
lines changed

src/ordered/red_black_tree_set.zig

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ pub fn RedBlackTreeSet(
133133
/// Returns `error.OutOfMemory` if node allocation fails.
134134
pub fn put(self: *Self, data: T) !void {
135135
// Check if key already exists first to avoid unnecessary allocation
136-
if (self.get(data)) |existing| {
136+
if (self.getNode(data)) |existing| {
137137
existing.data = data;
138138
return;
139139
}
@@ -241,7 +241,7 @@ pub fn RedBlackTreeSet(
241241
///
242242
/// Time complexity: O(log n)
243243
pub fn remove(self: *Self, data: T) ?T {
244-
const node = self.get(data) orelse return null;
244+
const node = self.getNode(data) orelse return null;
245245
const value = node.data;
246246
self.removeNode(node);
247247
self.size -= 1;
@@ -432,13 +432,24 @@ pub fn RedBlackTreeSet(
432432
node.parent = left;
433433
}
434434

435-
/// Returns a pointer to the node containing the data.
435+
/// Returns an immutable pointer to the stored value that compares equal
436+
/// to `data`, or `null` if no such value exists.
436437
///
437-
/// Returns `null` if the data is not found. The returned node pointer can be used
438-
/// to access or modify the data directly.
438+
/// Time complexity: O(log n)
439+
pub fn get(self: *const Self, data: T) ?*const T {
440+
const node = self.getNode(data) orelse return null;
441+
return &node.data;
442+
}
443+
444+
/// Checks whether the tree contains the given value.
439445
///
440446
/// Time complexity: O(log n)
441-
pub fn get(self: *const Self, data: T) ?*Node {
447+
pub fn contains(self: *const Self, data: T) bool {
448+
return self.getNode(data) != null;
449+
}
450+
451+
/// Internal: returns the node pointer for mutation by `put` and `remove`.
452+
fn getNode(self: *const Self, data: T) ?*Node {
442453
var current = self.root;
443454

444455
while (current) |node| {
@@ -452,13 +463,6 @@ pub fn RedBlackTreeSet(
452463
return null;
453464
}
454465

455-
/// Checks whether the tree contains the given value.
456-
///
457-
/// Time complexity: O(log n)
458-
pub fn contains(self: *const Self, data: T) bool {
459-
return self.get(data) != null;
460-
}
461-
462466
fn findMinimum(self: *const Self, node: *Node) *Node {
463467
_ = self; // Mark as intentionally unused
464468
var current = node;
@@ -468,19 +472,25 @@ pub fn RedBlackTreeSet(
468472
return current;
469473
}
470474

471-
pub fn minimum(self: Self, node: ?*Node) ?*Node {
472-
const start = node orelse self.root orelse return null;
473-
return self.findMinimum(start);
475+
/// Returns the smallest value in the tree, or `null` if the tree is empty.
476+
///
477+
/// Time complexity: O(log n)
478+
pub fn minimum(self: *const Self) ?T {
479+
const start = self.root orelse return null;
480+
return self.findMinimum(start).data;
474481
}
475482

476-
pub fn maximum(self: Self, node: ?*Node) ?*Node {
477-
var current = node orelse self.root orelse return null;
483+
/// Returns the largest value in the tree, or `null` if the tree is empty.
484+
///
485+
/// Time complexity: O(log n)
486+
pub fn maximum(self: *const Self) ?T {
487+
var current = self.root orelse return null;
478488

479489
while (current.right) |right| {
480490
current = right;
481491
}
482492

483-
return current;
493+
return current.data;
484494
}
485495

486496
/// Iterator for in-order traversal
@@ -512,7 +522,7 @@ pub fn RedBlackTreeSet(
512522
self.stack.deinit(self.allocator);
513523
}
514524

515-
pub fn next(self: *Iterator) !?*Node {
525+
pub fn next(self: *Iterator) !?T {
516526
if (self.stack.items.len == 0) return null;
517527

518528
const node: *Node = self.stack.pop().?;
@@ -524,7 +534,7 @@ pub fn RedBlackTreeSet(
524534
current = n.left;
525535
}
526536

527-
return node;
537+
return node.data;
528538
}
529539
};
530540

@@ -670,13 +680,13 @@ test "RedBlackTreeSet: minimum and maximum" {
670680
try tree.put(3);
671681
try tree.put(20);
672682

673-
const min = tree.minimum(null);
674-
const max = tree.maximum(null);
683+
const min = tree.minimum();
684+
const max = tree.maximum();
675685

676686
try std.testing.expect(min != null);
677687
try std.testing.expect(max != null);
678-
try std.testing.expectEqual(@as(i32, 3), min.?.data);
679-
try std.testing.expectEqual(@as(i32, 20), max.?.data);
688+
try std.testing.expectEqual(@as(i32, 3), min.?);
689+
try std.testing.expectEqual(@as(i32, 20), max.?);
680690
}
681691

682692
test "RedBlackTreeSet: iterator empty tree" {
@@ -720,15 +730,17 @@ test "RedBlackTreeSet: negative numbers" {
720730
try std.testing.expect(tree.contains(0));
721731
}
722732

723-
test "RedBlackTreeSet: get returns correct node" {
733+
test "RedBlackTreeSet: get returns correct value" {
724734
const allocator = std.testing.allocator;
725735
var tree = RedBlackTreeSet(i32, i32Compare).init(allocator);
726736
defer tree.deinit();
727737

728738
try tree.put(10);
729739
try tree.put(20);
730740

731-
const node = tree.get(10);
732-
try std.testing.expect(node != null);
733-
try std.testing.expectEqual(@as(i32, 10), node.?.data);
741+
const ptr = tree.get(10);
742+
try std.testing.expect(ptr != null);
743+
try std.testing.expectEqual(@as(i32, 10), ptr.?.*);
744+
745+
try std.testing.expect(tree.get(99) == null);
734746
}

0 commit comments

Comments
 (0)