B树
二叉树的深度较大,在查找时会造成I/O读写频繁,查询效率低下,所以引入了多叉树的结构,也就是B树。关于B树的由来,这里阐述了B-tree名字来源以及相关的开源地址。
(叶节点可以看成是一种外部节点,不包含任何关键字信息)
1、根节点在不为叶子节点的情况下儿子数为 2 ~ M2、除 根结点以外的非叶子结点的儿子数为 M/2(向上取整) ~ M3、拥有 K 个孩子的非叶子节点包含 k-1 个 keys( 关键字),且递增排列4、所有叶子结点在同一层,即深度相同
B+树
B+ 树通常用于数据库和操作系统的文件系统中。特点是能够保持数据稳定有序,其插入与修改拥有较稳定的对数时间复杂度。B+ 树元素自底向上插入。
1、拥有 K 个孩子的非叶子节点包含 k 个keys(关键字),且递增排列。每个关键字不保存数据,只用来索引。
2、所有的 叶子结点中包含了 全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。3、所有的 非叶子结点可以看成是 索引部分,结点中仅含有其子树(根结点)中最大(或最小)关键字4、非叶子结点的子树指针P[i],指向关键字值属于[ K[i], K[i+1] )的子树5、为所有叶子结点增加一个 链指针
红黑树
一棵二叉树如果满足下面的红黑性质,则为一棵红黑树:
1、每个结点或是红的,或是黑的。
2、根结点是黑的。3、每个叶结点 (NIL) 是黑的。4、如果一个结点是红的,则它的两个儿子都是黑的。5、对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。
红黑树引入了“颜色”的概念。引入“颜色”的目的在于使得红黑树的平衡条件得以简化。正如著名的密码学专家Bruce Schneier所说的那样,“Being Partly balanced can be good enough”,红黑树并不追求“完全平衡”——它只要求部分地达到平衡要求,降低了对旋转的要求,从而提高了性能。
关于红黑树的插入和删除可以自行查阅一些资料,因为不常用到,就不深究了。我扫了一下,发现这个还不错。
AVL树
关于AVL树,之前写过一篇文章《数据结构——AVL树》,可以直接看这里,就不再熬诉。
B树和B+树的区别1、一棵n个结点的AVL树的其高度保持在0(log2(n)),不会超过3/2log2(n+1)
2、一棵n个结点的AVL树的平均搜索长度保持在0(log2(n)).3、一棵n个结点的AVL树删除一个结点做平衡化旋转所需要的时间为0(log2(n)).
B/B+树用在磁盘文件组织、数据索引和数据库索引中。其中B+树比B 树更适合实际应用中操作系统的文件索引和数据库索引,因为:
举个例子,假设磁盘中的一个盘块容纳16bytes,而一个关键字2bytes,一个关键字具体信息指针2bytes。一棵9阶B-tree(一个结点最多8个关键字)的内部结点需要2个盘快。而B+ 树内部结点只需要1个盘快。当需要把内部结点读入内存中的时候,B 树就比B+ 树多一次盘块查找时间(在磁盘中就是盘片旋转的时间)。
2、B+-tree的查询效率更加稳定
3、B树在元素遍历的时候效率较低
红黑树的应用及和B树区别
应用:
1、广泛用在C++的STL中。map和set都是用红黑树实现的。
2、著名的 linux进程调度Completely Fair Scheduler,用红黑树管理 进程控制块3、epoll在内核中的实现,用红黑树管理事件块4、 nginx中,用红黑树管理 timer等5、 Java的TreeMap实现等等
和B树比较
AVL树和红黑树
红黑树的算法时间复杂度和AVL相同,但统计性能比AVL树更高。
1、红黑树和AVL树都能够以O(log2 n)的时间复杂度进行搜索、插入、删除操作。
2、由于设计,红黑树的任何不平衡都会在三次旋转之内解决。AVL树增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。
在查找方面:
所以,综上:
B树(M阶)的插入和删除AVL是一种高度平衡的二叉树,维护这种高度平衡所付出的代价比从中获得的效率收益还大,故而实际的应用不多,更多的地方是用追求局部而不是非常严格整体平衡的红黑树。当然,如果场景中对插入删除不频繁,只是对查找特别有要求,AVL还是优于红黑的。
注意点:
实例(这里 M = 5),所以 [M/2] - 1 = 2, M - 1 = 4
1、初始状态2、插入E,K,Q
3、插入M
4、插入F,W,L,T
5、插入Z时
6、插入D,P,R,X,Y
7、最后,插入S
插入操作完成。
删除
1、初始状态2、删除元素H
3、删除T
4、删除R
在这个实例中,右相邻兄弟结点中比较丰满(3 > 2),所以先向父节点借一个元素W下移到该叶子结点中,代替原来S的位置,S前移;然后X在相邻右兄弟结点中上移到父结点中,最后在相邻右兄弟结点中删除X,后面元素前移。如果其某个相邻兄弟结点中比较丰满(元素个数 > [M/2] - 1),则可以向父结点借一个元素,然后将最丰满的相邻兄弟结点中上移最后或最前一个元素到父节点中
5、删除E
即,将父节点中的元素D下移到已经删除E而只有F的结点中,然后将含有D和F的结点和含有A,C的相邻兄弟结点进行合并成一个结点。首先,移动父结点中的元素(该元素在两个需要合并的两个结点元素之间)下移到其子结点中;
然后将这两个结点进行合并成一个结点。