# Red/Black Tree API

- [API reference](https://docs.qualcomm.com/doc/80-41102-2/topic/_doxygen_rst_file__doxygen_sources_include_le_redBlackTree_h.html#file-le-redblacktree-h)

A Red-Black Tree is a data structure representing a self-balancing binary search tree. Tree consists of nodes maintaining links to the parent, left and right nodes. Advantage over a linked-list is faster search based on the key comparison. Advantage over a hashtable is simplified memory management (no additional allocation within the library), better scalability up and down, and possibility to easily iterate the set in ascending/descending order.

## Creating and Initializing Red-Black Trees

To create and initialize an RB Tree the user must create an [le\_rbtree\_Tree\_t](https://docs.qualcomm.com/doc/80-41102-2/topic/struct_a00872.html#Documentationa00872) typed object and initialize it using [le\_rbtree\_InitTree()](https://docs.qualcomm.com/doc/80-41102-2/topic/function_a00125_1accb91a387364f9e762c2c394e650af13.html#Documentationa00125_1accb91a387364f9e762c2c394e650af13) routine. At this time the user has to provide a pointer to the comparator function, that provides a way to perform a comparison between objects. The tree **must** be initialized before it can be used.

// provide the comparator function
    static int compare(const void* a, const void* b)
    {
       // return negative, 0, or positive value
    }
    
    // Create the tree.
    le_rbtree_Tree_t MyTree;
    
    // Initialize the tree.
    le_rbtree_InitTree(&MyTree, compare);
    Copy to clipboard

**Elements of  MUST NOT be accessed directly by the user.**

## Creating and Accessing Nodes

Nodes can contain any data in any format and is defined and created by the user. The only requirement for nodes is that it must contain an `le_rbtree_Node_t` link member. The link member must be initialized by calling `le_rbtree_InitNode()` before it is added to the tree; at this time, pointer to the key of this object must be provided. The node can be added to the tree using the function `le_rbtree_Insert()`.

// The node may be defined like this.
    typedef struct
    {
         MyKeyType key;
         dataType someUserData;
         ...
         le_rbtree_Node_t myLink;
    }
    MyNodeClass_t;
    
    void foo (void)
    {
        // Create the node.  Get the memory from a memory pool previously created.
        MyNodeClass_t* myNodePtr = le_mem_ForceAlloc(MyNodePool);
    
        // Initialize the node's link.
        le_rbtree_InitNode(&MyTree, &myNodePtr->key);
    
        // Add the node to the tree by passing in the node's link.
        le_rbtree_Insert(&MyTree, &myNodePtr->myLink);
    }
    Copy to clipboard

## Finding node in a Tree

To find the node in the tree by the given key, use `le_rbtree_Find()` function. To obtain the object itself, use the `CONTAINER_OF` macro defined in le\_basics.h. Here’s a code sample using `CONTAINER_OF` to obtain the node:

// declare and initialize the key
    MyKeyType key = <...>;
    // Assuming MyTree has been created and initialized and is not empty.
    le_rbtree_Node_t* linkPtr = le_rbtree_Find(&MyTree, &key);
    
    // Now we have the link but still need the node to access user data.
    // We use CONTAINER_OF to get a pointer to the node given the node's link.
    if (linkPtr != NULL)
    {
        MyNodeClass_t* myNodePtr = CONTAINER_OF(linkPtr, MyNodeClass_t, myLink);
    }
    Copy to clipboard

The user is responsible for creating and freeing memory for all nodes; the RB Tree module only manages the links in the nodes. The node must be removed from all trees before its memory can be freed.

**The elements of  MUST NOT be accessed directly by the user.**

## Traversing a Tree

Tree can be traversed in an ascending or descending order (in the sense of greater/lesser provided by the comparator function):

// Ascending order
    le_rbtree_Node_t* linkPtr;
    for (linkPtr = le_rbtree_GetFirst(&MyTree);
         linkPtr != NULL;
         linkPtr = le_rbtree_GetNext(&MyTree, linkPtr))
    {
        MyNodeClass_t* myNodePtr = CONTAINER_OF(linkPtr, MyNodeClass_t, myLink);
    }
    
    // Descending order
    le_rbtree_Node_t* linkPtr;
    for (linkPtr = le_rbtree_GetLast(&MyTree);
         linkPtr != NULL;
         linkPtr = le_rbtree_GetPrev(&MyTree, linkPtr))
    {
        MyNodeClass_t* myNodePtr = CONTAINER_OF(linkPtr, MyNodeClass_t, myLink);
    }
    Copy to clipboard

## Removing node from a Tree

To remove a node from a Tree, use [le\_rbtree\_RemoveByKey()](https://docs.qualcomm.com/doc/80-41102-2/topic/function_a00125_1a3948cb60518077253a1bc15c5ea2b714.html#Documentationa00125_1a3948cb60518077253a1bc15c5ea2b714) function:

// Remove the node
    le_rbtree_RemoveByKey(&MyTree, &(myNodePtr->key));
    // Free the object
    le_mem_Release(myNodePtr);
    Copy to clipboard

or [le\_rbtree\_Remove()](https://docs.qualcomm.com/doc/80-41102-2/topic/function_a00125_1ab80711e4cb2c43ca1f60a398805a9834.html#Documentationa00125_1ab80711e4cb2c43ca1f60a398805a9834) function:

// Remove the node
    le_rbtree_Remove(&MyTree, &(myNodePtr->myLink));
    // Free the object
    le_mem_Release(myNodePtr);
    Copy to clipboard

## Thread Safety and Re-Entrancy

All Red-Black Tree function calls are re-entrant and thread safe themselves, but if the nodes and/or Tree object are shared by multiple threads, explicit steps must be taken to maintain mutual exclusion of access. If you’re accessing the same tree from multiple threads, you *must* use a [mutex](https://docs.qualcomm.com/doc/80-41102-2/topic/page_c_mutex.html#Documentationa01187) or some other form of thread synchronization to ensure only one thread accesses the tree at a time.

Copyright (C) Sierra Wireless Inc.

Last Published: Jun 09, 2026

[Previous Topic
Process API](https://docs.qualcomm.com/bundle/publicresource/80-41102-2/topics/process.md) [Next Topic
Call Stack Backtrace Functionality](https://docs.qualcomm.com/bundle/publicresource/80-41102-2/topics/call_stack_backtrace.md)