1.1 概述
伸展树或者分裂树,由Daniel Sleator和Robert Tarjan创造,它的优势在于不需要记录用于平衡树的冗余信息。
伸展树是一种二叉排序树,它能再O(log n)内完成插入、查找和删除操作。lighttpd源码里关于伸展树的代码不多
(对伸展树的操作只提供了4个函数),但是因为伸展树本身相对比较复杂,因此在此作为一章来解析,对伸展树理
解较深的读者可以直接跳过本章内容。
本节相关部分源码:
splaytree.h
splaytree.c
1.2 伸展树基础知识
1.2.1 伸展树介绍
假想这么一种情况,我们想要对一个二叉查找树执行一系列的查找操作,后续会在缓存器设计中看到,为了使整个
查找时间更短,哪些查评率比较高的节点就应该经常处于比较靠近树根的位置,于是最直观的想法就是将每次查找访问节
点之后对该树进行重构,将被查找的节点搬移到树根,这种自调整形式的二叉查找树就是伸展树,他会沿着从某个被访问
节点到树根之间的路径,通过一系列的旋转把这个被访问节点搬移到树根。
伸展树通过一系列的旋转把当前被访问节点搬移到树根,以便下次再次访问该节点时加快速度(直接访问根节点就被命
中或离树根很近的位置)。为了将当前被访问节点搬移到树根,我们需要将沿着查找路径做自底向上的旋转,直至该节点为
树根为止(伸展树定义的旋转是成对进行的,伸展操作不单是把当前访问节点搬移到树根,而且还把查找路径上的每个节点
的深度都大致减掉一半)。
参考博客https://blog.csdn.net/mu0206mu/article/details/70185944
1.3 lighttpd中伸展树实现源码解析
1.3.1 结构定义
伸展树的数据结构定义在对应的splaytree.c 头文件内,结构如清单
typedef struct tree_node {
struct tree_node * left, * right;
int key;
/*记录该节点下有多少个子孙节点(并把自己也计算在内)*/
int size; /* maintained to be the number of nodes rooted here */
void *data;
} splay_tree;
splaytree.h头文件内还有一个计算节点大小(即size字段值)的宏,正如lighttpd开发者注释的那样,该宏比直接使用
x->size更好
1.3.2 函数操作
1.splay_tree * splaytree_splay (splay_tree *t, int key);
该函数实现伸展树的伸展操作(采用的是自顶向下且简化实现方式),函数在伸展树t中查找t->key等于key的节点(当然在查找的过程中会进行伸展操作,同时为保证size元素的正确要对其进行更新),如果找到则返回改节点(该节点经过伸展后变成根节点),否则返回空。
2.splay_tree * splaytree_insert(splay_tree *t, int key, void *data);
该函数首先在伸展树t中查找t->key为key的节点,如果找到则直接返回该节点,函数结束;否则新建立一个节点,其t->key
为key,附加数据由参数data指针提供,然后将该节点作为新根节点插入伸展树t并作为返回值返回。
3.splay_tree * splaytree_delete(splay_tree *t, int key);
该函数从伸展树t中删除t-key为key的节点(如果该节点存在)。
4.splay_tree * splaytree_size(splay_tree *t);
该函数返回伸展树的节点数目
参考文档 lighttpd源码分析 高群凯著
下载路径:https://download.csdn.net/download/caofengtao1314/10576306