radix tree

Principles refer to "Introduction to Algorithms"

Note: Code setting, the maximum number of digits to support index is 32 bits, of course, it can be modified to support 64 and 32-bit indexes

First define some constants

#define MAX_BITS 0x80000000 
#define INT_BITS 32  //32位下的int

Then define a radix tree class

template <typename T, int bits, int height> // bits represents the number of bits of the index, height represents the height, temporarily supports 32-bit 
class radix_tree {
 public :
     struct _Nodetype;
    typedef union _Autotype {
        _Nodetype *DeepNodes; // The next layer of 
        T * slots;
    }Autotype;
    typedef struct _Nodetype {
        _Nodetype() { autov.DeepNodes = NULL; }
        _Nodetype(_Nodetype *node) { autov.DeepNodes = node; }
        _Nodetype(T *s) { autov.slots = s; }
        car type car;
    }Nodetype, *pNodetype;
    radix_tree() {
        root = new Nodetype((pNodetype)NULL);
    }
    ~radix_tree() {
        
    }
    void radix_insert( int index, T key); // When the T type is applied, it is a pointer, pointing to the object 
    T radix_search( int index);
     void radix_delete( int index); // lazy deletion 
    void radix_empty();//Not implemented, suggested A dual thread pool is used, one for nodes and one for data, which is convenient for this function to reclaim memory
 private :
     int radix_mask( int h);
     int radix_index( const  int index, int h);
    pNodetype root;
};

About class member implementation

The radix_mask member is responsible for dynamically generating a mask according to the number of layers in the tree. For example, in this example, an 18-bit index value is used, and then the tree height is defined as 3, then the mask of the first layer is 0x3F000, the mask of the second layer is 0xFC0, and the mask of the third layer is 0x3F

template <typename T, int bits, int height>
int radix_tree<T, bits, height>::radix_mask(int h) {//1到height层
    int slotbits = bits / height, skipbits = INT_BITS - bits + (h - 1)*slotbits, tMask = 0;
    if (h<1 || h>height) return -1;
    while (skipbits < INT_BITS - bits + slotbits*h) {
        tMask |= (MAX_BITS >> skipbits);
        skipbits ++ ;
    }
    return tMask;
}

The radix_index member is responsible for extracting the offset value in the index. For example, an 18-bit index, in the first layer, the mask is 0x3F000, then the 6-bit offset value extracted through this mask is used to find

template <typename T, int bits, int height>
int radix_tree<T, bits, height>::radix_index(const int index, int h) {
    int slotbits = bits / height, lowerMask = radix_mask(height), mask;
    if (h<1 || h>height) return -1;
    mask = radix_mask(h);//更新mask
    return (index & mask) >> (bits / height*(height - h)) & lowerMask;
}

The radix_insert member is inserted into the specified position through the provided index value

template <typename T, int bits, int height>
void radix_tree<T, bits, height>::radix_insert(int index, T key) {
    pNodetype node = root;
     for ( int tree_h = 1 ; tree_h < height; tree_h++) { // Directory, no data 
        if (node->autov.DeepNodes == NULL)
            node->autov.DeepNodes = new Nodetype[pow(2, bits / height)];
        node = &node->autov.DeepNodes[radix_index(index, tree_h)];
    }
    // Enter data 
    if (node->autov.slots== NULL)
        node->autov.slots = new T[pow(2, bits / height)];
    node->autov.slots[radix_index(index, height)] = key;
}

radix_search member , the principle is the same as the radix_insert member, but it is not responsible for allocation, only for search

template <typename T, int bits, int height>
T radix_tree<T, bits, height>::radix_search(int index) {
    pNodetype node = root;
    for (int tree_h = 1; tree_h < height; tree_h++) {
        if (node->autov.DeepNodes == NULL)
            return -1;
        node = &node->autov.DeepNodes[radix_index(index, tree_h)];
    }
    //查询数据
    if (node == root || node->autov.slots == NULL)
        return -1;
    return node->autov.slots[radix_index(index, height)];
}

radix_delete member , using lazy deletion, only changes the found node data to -1, and does not delete the node, because in practical applications, each data is a pointer, pointing to the corresponding object, so there is no negative number

template <typename T, int bits, int height>
void radix_tree<T, bits, height>::radix_delete(int index) {
    if (radix_search(index))
        radix_insert(index, -1);
}

radix_empty member , delete all nodes and data

template <typename T, int bits, int height>
 void radix_tree<T, bits, height> ::radix_empty() {
     // It is recommended to use thread pool to allocate all, so it is convenient to release 
//This is not implemented, the idea is to use dual thread pool , one is used to allocate nodes, and the other is used for the highest-level data nodes. When this is released, the data thread pool is first released as a whole, and then the node thread pool is released as a whole
}

 

Separate definition template classes must be instantiated in advance

template class radix_tree< int , 18 , 3 >; // index is an 18-bit integer, 3 is the tree height

 

All code is tested and the result is correct.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325210986&siteId=291194637