aboutsummaryrefslogtreecommitdiffstats
path: root/Documentation/rbtree.txt
diff options
context:
space:
mode:
Diffstat (limited to 'Documentation/rbtree.txt')
-rw-r--r--Documentation/rbtree.txt121
1 files changed, 79 insertions, 42 deletions
diff --git a/Documentation/rbtree.txt b/Documentation/rbtree.txt
index b9d9cc57be18..c42a21b99046 100644
--- a/Documentation/rbtree.txt
+++ b/Documentation/rbtree.txt
@@ -1,7 +1,10 @@
+=================================
Red-black Trees (rbtree) in Linux
-January 18, 2007
-Rob Landley <rob@landley.net>
-=============================
+=================================
+
+
+:Date: January 18, 2007
+:Author: Rob Landley <rob@landley.net>
What are red-black trees, and what are they for?
------------------------------------------------
@@ -56,7 +59,7 @@ user of the rbtree code.
Creating a new rbtree
---------------------
-Data nodes in an rbtree tree are structures containing a struct rb_node member:
+Data nodes in an rbtree tree are structures containing a struct rb_node member::
struct mytype {
struct rb_node node;
@@ -78,7 +81,7 @@ Searching for a value in an rbtree
Writing a search function for your tree is fairly straightforward: start at the
root, compare each value, and follow the left or right branch as necessary.
-Example:
+Example::
struct mytype *my_search(struct rb_root *root, char *string)
{
@@ -110,7 +113,7 @@ The search for insertion differs from the previous search by finding the
location of the pointer on which to graft the new node. The new node also
needs a link to its parent node for rebalancing purposes.
-Example:
+Example::
int my_insert(struct rb_root *root, struct mytype *data)
{
@@ -140,11 +143,11 @@ Example:
Removing or replacing existing data in an rbtree
------------------------------------------------
-To remove an existing node from a tree, call:
+To remove an existing node from a tree, call::
void rb_erase(struct rb_node *victim, struct rb_root *tree);
-Example:
+Example::
struct mytype *data = mysearch(&mytree, "walrus");
@@ -153,7 +156,7 @@ Example:
myfree(data);
}
-To replace an existing node in a tree with a new one with the same key, call:
+To replace an existing node in a tree with a new one with the same key, call::
void rb_replace_node(struct rb_node *old, struct rb_node *new,
struct rb_root *tree);
@@ -166,7 +169,7 @@ Iterating through the elements stored in an rbtree (in sort order)
Four functions are provided for iterating through an rbtree's contents in
sorted order. These work on arbitrary trees, and should not need to be
-modified or wrapped (except for locking purposes):
+modified or wrapped (except for locking purposes)::
struct rb_node *rb_first(struct rb_root *tree);
struct rb_node *rb_last(struct rb_root *tree);
@@ -184,12 +187,45 @@ which the containing data structure may be accessed with the container_of()
macro, and individual members may be accessed directly via
rb_entry(node, type, member).
-Example:
+Example::
struct rb_node *node;
for (node = rb_first(&mytree); node; node = rb_next(node))
printk("key=%s\n", rb_entry(node, struct mytype, node)->keystring);
+Cached rbtrees
+--------------
+
+Computing the leftmost (smallest) node is quite a common task for binary
+search trees, such as for traversals or users relying on a the particular
+order for their own logic. To this end, users can use 'struct rb_root_cached'
+to optimize O(logN) rb_first() calls to a simple pointer fetch avoiding
+potentially expensive tree iterations. This is done at negligible runtime
+overhead for maintanence; albeit larger memory footprint.
+
+Similar to the rb_root structure, cached rbtrees are initialized to be
+empty via:
+
+ struct rb_root_cached mytree = RB_ROOT_CACHED;
+
+Cached rbtree is simply a regular rb_root with an extra pointer to cache the
+leftmost node. This allows rb_root_cached to exist wherever rb_root does,
+which permits augmented trees to be supported as well as only a few extra
+interfaces:
+
+ struct rb_node *rb_first_cached(struct rb_root_cached *tree);
+ void rb_insert_color_cached(struct rb_node *, struct rb_root_cached *, bool);
+ void rb_erase_cached(struct rb_node *node, struct rb_root_cached *);
+
+Both insert and erase calls have their respective counterpart of augmented
+trees:
+
+ void rb_insert_augmented_cached(struct rb_node *node, struct rb_root_cached *,
+ bool, struct rb_augment_callbacks *);
+ void rb_erase_augmented_cached(struct rb_node *, struct rb_root_cached *,
+ struct rb_augment_callbacks *);
+
+
Support for Augmented rbtrees
-----------------------------
@@ -241,7 +277,8 @@ user should have a single rb_erase_augmented() call site in order to limit
compiled code size.
-Sample usage:
+Sample usage
+^^^^^^^^^^^^
Interval tree is an example of augmented rb tree. Reference -
"Introduction to Algorithms" by Cormen, Leiserson, Rivest and Stein.
@@ -259,12 +296,12 @@ This "extra information" stored in each node is the maximum hi
information can be maintained at each node just be looking at the node
and its immediate children. And this will be used in O(log n) lookup
for lowest match (lowest start address among all possible matches)
-with something like:
+with something like::
-struct interval_tree_node *
-interval_tree_first_match(struct rb_root *root,
- unsigned long start, unsigned long last)
-{
+ struct interval_tree_node *
+ interval_tree_first_match(struct rb_root *root,
+ unsigned long start, unsigned long last)
+ {
struct interval_tree_node *node;
if (!root->rb_node)
@@ -301,13 +338,13 @@ interval_tree_first_match(struct rb_root *root,
}
return NULL; /* No match */
}
-}
+ }
-Insertion/removal are defined using the following augmented callbacks:
+Insertion/removal are defined using the following augmented callbacks::
-static inline unsigned long
-compute_subtree_last(struct interval_tree_node *node)
-{
+ static inline unsigned long
+ compute_subtree_last(struct interval_tree_node *node)
+ {
unsigned long max = node->last, subtree_last;
if (node->rb.rb_left) {
subtree_last = rb_entry(node->rb.rb_left,
@@ -322,10 +359,10 @@ compute_subtree_last(struct interval_tree_node *node)
max = subtree_last;
}
return max;
-}
+ }
-static void augment_propagate(struct rb_node *rb, struct rb_node *stop)
-{
+ static void augment_propagate(struct rb_node *rb, struct rb_node *stop)
+ {
while (rb != stop) {
struct interval_tree_node *node =
rb_entry(rb, struct interval_tree_node, rb);
@@ -335,20 +372,20 @@ static void augment_propagate(struct rb_node *rb, struct rb_node *stop)
node->__subtree_last = subtree_last;
rb = rb_parent(&node->rb);
}
-}
+ }
-static void augment_copy(struct rb_node *rb_old, struct rb_node *rb_new)
-{
+ static void augment_copy(struct rb_node *rb_old, struct rb_node *rb_new)
+ {
struct interval_tree_node *old =
rb_entry(rb_old, struct interval_tree_node, rb);
struct interval_tree_node *new =
rb_entry(rb_new, struct interval_tree_node, rb);
new->__subtree_last = old->__subtree_last;
-}
+ }
-static void augment_rotate(struct rb_node *rb_old, struct rb_node *rb_new)
-{
+ static void augment_rotate(struct rb_node *rb_old, struct rb_node *rb_new)
+ {
struct interval_tree_node *old =
rb_entry(rb_old, struct interval_tree_node, rb);
struct interval_tree_node *new =
@@ -356,15 +393,15 @@ static void augment_rotate(struct rb_node *rb_old, struct rb_node *rb_new)
new->__subtree_last = old->__subtree_last;
old->__subtree_last = compute_subtree_last(old);
-}
+ }
-static const struct rb_augment_callbacks augment_callbacks = {
+ static const struct rb_augment_callbacks augment_callbacks = {
augment_propagate, augment_copy, augment_rotate
-};
+ };
-void interval_tree_insert(struct interval_tree_node *node,
- struct rb_root *root)
-{
+ void interval_tree_insert(struct interval_tree_node *node,
+ struct rb_root *root)
+ {
struct rb_node **link = &root->rb_node, *rb_parent = NULL;
unsigned long start = node->start, last = node->last;
struct interval_tree_node *parent;
@@ -383,10 +420,10 @@ void interval_tree_insert(struct interval_tree_node *node,
node->__subtree_last = last;
rb_link_node(&node->rb, rb_parent, link);
rb_insert_augmented(&node->rb, root, &augment_callbacks);
-}
+ }
-void interval_tree_remove(struct interval_tree_node *node,
- struct rb_root *root)
-{
+ void interval_tree_remove(struct interval_tree_node *node,
+ struct rb_root *root)
+ {
rb_erase_augmented(&node->rb, root, &augment_callbacks);
-}
+ }