Nginx学习笔记(十):基数树

前言


       接上篇。。。

基数树ngx_radix_tree_t


       基数树也是一种二叉查找树,它要求存储的每个节点必须以32位整型作为任意两节点的唯一标识。另外,基数树与红黑树不同的一点:ngx_radix_tree_t会负责分配每个节点占用的内存。也因为这一点,基数树不像红黑树灵活,目前在Nginx中应用不广泛。

基数树原理


       基数树具备二叉查找树所有优点,并且不用像红黑树通过自身旋转达到平衡,基数树不用管树的形态是否平衡。也因此,它在插入节点、删除节点的速度会比红黑树快的多。
       为什么基数树可以不管树是否平衡?
       首先,红黑树是通过不同节点key关键字的比较决定树的形态,而基数树的每个节点的key关键字自身已经决定了其在树中的位置。

       具体决定方法:
       先将节点的key关键字转化为二进制,32位,从左至右开始,遇0入左子树,遇1入右子树。这样,ngx_radix_tree_t树的最大深度为32。另外,为了减少树的高度,基数树中有掩码的概念。
        e.g.
        掩码为0xE0000000(十六进制表32位)时,即表示树的高度为3。
        如果此时一个节点的key关键字为0x0FFFFFFF,那么由于掩码的存在,实际上只有前3位有效,该节点的实际的key关键字为0x00000000;
        如果此时一个节点的key关键字为0x20000000,根据掩码决定取其转化为二进制后的前3位为010,因此,该节点的位置是,根节点-->左子树-->右子树-->左子树。用下图至关表示下:

              Nginx学习笔记(十):基数树_第1张图片


        与红黑树不同,红黑树节点不负责分配每个树节点的内存,基数树则负责分配,如下是基数树数据结构:
typedef struct {
    /* 基数树根节点 */
    ngx_radix_node_t  *root;
    /* 内存池,负责基数树节点分配 */
    ngx_pool_t        *pool;
    /* 管理已分配内存,但未使用的节点,这些节点实际上会组成一单链表 */
    ngx_radix_node_t  *free;
    /* 已分配内存中还未使用内存的首地址 */
    char              *start;
    /* 已分配内存中还未使用内存的大小 */
    size_t             size;
} ngx_radix_tree_t;
        其中,需要注意的是,在每次删除一个树节点时,并不释放节点的内存,还是将其放入free指向的单链表中。这样在添加节点时,则首先查看free链表中时候有节点,如果有则优先使用,如果没有则再从内存池pool处分配。

       对基数树的操作也就是创建、删除等常规。这里因为基数树本身用的就不多,暂时对这个东西就只做了解了。

总结


       基数树为每个节点分配内存,以32位整型关键字作为唯一标识,每个关键字都决定在树种的位置。此外,加入掩码决定基数树的高度。删除节点不作内存释放,而是加入空闲链表,以供后续使用。

主要参考


《深入理解Nginx》


你可能感兴趣的:(深入理解Nginx,Nginx学习笔记系列)