赞
踩
二叉查找树的一个局限性就是有可能退化成一个链表,这种情况下二叉查找树的效率就会急剧下降变成0(n)。而AVL树可以很好地解决BST的这种困境。
任何两个子树的高度差最大是1,这样的二叉树叫做AVL树。
(1)AVL的左右子树高度之差的绝对值不超过1。
(2)树中的每个左子树和右子树都是AVL。
(3)每个节点都有一个平衡因子,任一节点的平衡因子至多为1。
(4)平衡二叉树的高度和结点数量之间的关系是O(logn)。
平衡因子 = | 左子树高度 - 右子树高度 |
AVL树为了维持自身平衡性,在插入元素时,计算了每个节点的平衡因子是否大于1,如果大于,那么就将进行相应的旋转操作以维持平衡性。
一种二叉查找树,但是在每个节点增加一个存储位表示节点的颜色,可以是红色或者黑色,通过对任何一条从根到叶子的路径上各个节点着色的方式的限制,红黑树确保没有一条 路径会比其他路径长两倍。是一种弱平衡二叉树(由于是弱平衡,相同节点的情况下,AVL树的高度低于红黑树),相对于严格要求的AVL树而言,红黑树旋转的次数变少,因此在搜索、删除、插入操作多的情况,可以使用红黑树。
算法导论:一棵有n个内节点的红黑树高度至多为2lg(n+1),则h=O(log(n))
0)在红黑树中,叶子结点指空结点NULL。
1)每个结点要么是红的,要么是黑的。
2)根结点是黑的。
3)每个叶结点,即空结点(NIL)是黑的。(首尾必黑)
4)如果一个结点是红的,那么它的俩个儿子都是黑的。(不存在连续2红)
5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。(黑色完美平衡)
5-1)右5知,如果一个结点存在黑子结点,那么该结点肯定有两个子结点
AVL是严格的平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多;
红黑树并不追求“完全平衡”——它只要求部分地达到平衡要求,降低了对旋转的要求,从而提高了性能。红黑树能够以O(logn) 的时间复杂度进行搜索、插入、删除操作。此外,由于它的设计,任何不平衡都会在三次旋转之内解决。
类型 | 平衡度 | 调整频率 | 适用场景 |
---|---|---|---|
AVL树 | 高 | 高 | 查询多,增/删少 |
红黑树 | 低 | 低 | 增/删频繁 |
所以简单说,如果你的应用中,搜索的次数远远大于插入和删除,那么选择AVL树,Windows NT内核中广泛存在.
如果搜索,插入删除次数几乎差不多,应选择红黑树。即,有时仅为了排序(建立-遍历-删除),不查找或查找次数很少,R-B树合算一些。
3、红黑树的应用
广泛用于C++的STL中,map和set都是用红黑树实现的.
著名的linux进程调度Completely Fair Scheduler,用红黑树管理进程控制块,进程的虚拟内存区域都存储在一颗红黑树上,每个虚拟地址区域都对应红黑树的一个节点,左指针指向相邻的地址虚拟存储区域,右指针指向相邻的高地址虚拟地址空间.
IO多路复用epoll的实现采用红黑树组织管理sockfd,以支持快速的增删改查.
ngnix中,用红黑树管理timer,因为红黑树是有序的,可以很快的得到距离当前最小的定时器.
java中TreeMap、hashmap、concurrenthashmap(1.8)的实现.
b树(balance tree)和b+树应用在数据库索引,可以认为是m叉的多路平衡查找树,但是从理论上讲,二叉树查找速度和比较次数都是最小的,为什么不用二叉树呢?
因为我们要考虑磁盘IO的影响,它相对于内存来说是很慢的。数据库索引是存储在磁盘上的,当数据量大时,就不能把整个索引全部加载到内存了,只能逐一加载每一个磁盘页(对应索引树的节点)。所以我们要减少IO次数,对于树来说,IO次数就是树的高度,而“矮胖”就是b树的特征之一,它的每个节点最多包含m个孩子,m称为b树的阶,m的大小取决于磁盘页的大小。
第一次磁盘IO,把9所在节点读到内存,9节点中含有value,刚好要搜索结点9,则在此处返回了不必再深入树的下层。然而目标是5,小于9,跳转到小于9对应的节点;
第二次磁盘IO,还是读节点到内存,在内存中把5依次和2、6比较,定位到2、6中间区域对应的节点;
第三次磁盘IO就不上图了,跟第二步一样,然后就找到了目标5。
b+树,是b树的一种变体,查询性能更好。
考虑磁盘IO的影响,它相对于内存来说是很慢的。数据库索引是存储在磁盘上的,当数据量大时,就不能把整个索引全部加载到内存了,只能逐一加载每一个磁盘页(对应索引树的节点)。所以我们要减少IO次数,对于树来说,IO次数就是树的高度,而“矮胖”就是b树的特征之一,m的大小取决于磁盘页的大小。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。