return T->root == NULL;
}
+/** Get the first (left-most) node in the tree or NULL */
+struct rb_node *rb_tree_first(struct rb_tree *T);
+
+/** Get the last (right-most) node in the tree or NULL */
+struct rb_node *rb_tree_last(struct rb_tree *T);
+
+/** Get the next node (to the right) in the tree or NULL */
+struct rb_node *rb_node_next(struct rb_node *node);
+
+/** Get the next previous (to the left) in the tree or NULL */
+struct rb_node *rb_node_prev(struct rb_node *node);
+
/** Retrieve the data structure containing a node
*
* \param type The type of the containing data structure
struct rb_node *x = T->root;
while (x != NULL) {
int c = cmp(x, key);
- if (c < 0)
+ if (c < 0) {
x = x->left;
- else if (c > 0)
+ } else if (c > 0) {
x = x->right;
- else
- return x;
+ } else {
+ /* x is the first *encountered* node matching the key. There may
+ * be other nodes in the left subtree that also match the key.
+ */
+ while (true) {
+ struct rb_node *prev = rb_node_prev(x);
+
+ if (prev == NULL || cmp(prev, key) != 0)
+ return x;
+
+ x = prev;
+ }
+ }
}
return x;
/** Sloppily search the tree for a node
*
* This function searches the tree for a given node. If a node with a
- * matching key exists, that first matching node found will be returned.
- * If no node with an exactly matching key exists, the node returned will
- * be either the right-most node comparing less than \p key or the
- * right-most node comparing greater than \p key. If the tree is empty,
- * NULL is returned.
+ * matching key exists, that first encountered matching node found (there may
+ * be other matching nodes in the left subtree) will be returned. If no node
+ * with an exactly matching key exists, the node returned will be either the
+ * right-most node comparing less than \p key or the right-most node comparing
+ * greater than \p key. If the tree is empty, NULL is returned.
*
* \param T The red-black tree to search
*
return y;
}
-/** Get the first (left-most) node in the tree or NULL */
-struct rb_node *rb_tree_first(struct rb_tree *T);
-
-/** Get the last (right-most) node in the tree or NULL */
-struct rb_node *rb_tree_last(struct rb_tree *T);
-
-/** Get the next node (to the right) in the tree or NULL */
-struct rb_node *rb_node_next(struct rb_node *node);
-
-/** Get the next previous (to the left) in the tree or NULL */
-struct rb_node *rb_node_prev(struct rb_node *node);
-
#define rb_node_next_or_null(n) ((n) == NULL ? NULL : rb_node_next(n))
#define rb_node_prev_or_null(n) ((n) == NULL ? NULL : rb_node_prev(n))
validate_search(&tree, i + 1, ARRAY_SIZE(test_numbers) - 1);
}
}
+
+TEST(RBTreeTest, FindFirst)
+{
+ struct rb_test_node nodes[100];
+ struct rb_tree tree;
+
+ rb_tree_init(&tree);
+
+ const int x = 13;
+
+ for (unsigned i = 0; i < ARRAY_SIZE(nodes); i++) {
+ nodes[i].key = x;
+ rb_tree_insert(&tree, &nodes[i].node, rb_test_node_cmp);
+ }
+
+ struct rb_node *n = rb_tree_search(&tree, &x, rb_test_node_cmp_void);
+
+ ASSERT_NE(nullptr, n);
+ EXPECT_EQ(nullptr, rb_node_prev(n));
+ EXPECT_EQ(n, rb_tree_first(&tree));
+}
+
+TEST(RBTreeTest, FindFirstOfMiddle)
+{
+ struct rb_test_node nodes[3 * 33];
+ struct rb_tree tree;
+
+ rb_tree_init(&tree);
+
+ unsigned i;
+ for (i = 0; i < ARRAY_SIZE(nodes) / 3; i++) {
+ nodes[i].key = i * 13;
+ rb_tree_insert(&tree, &nodes[i].node, rb_test_node_cmp);
+ }
+
+ const int x = i * 13;
+ for (/* empty */; i < 2 * ARRAY_SIZE(nodes) / 3; i++) {
+ nodes[i].key = x;
+ rb_tree_insert(&tree, &nodes[i].node, rb_test_node_cmp);
+ }
+
+ for (/* empty */; i < ARRAY_SIZE(nodes); i++) {
+ nodes[i].key = i * 13;
+ rb_tree_insert(&tree, &nodes[i].node, rb_test_node_cmp);
+ }
+
+ struct rb_node *n = rb_tree_search(&tree, &x, rb_test_node_cmp_void);
+
+ ASSERT_NE(nullptr, n);
+
+ struct rb_node *prev = rb_node_prev(n);
+
+ ASSERT_NE(nullptr, prev);
+
+ EXPECT_NE(rb_test_node_cmp(prev, n), 0);
+}