数据结构和算法学习(9)-红黑树
来源:互联网 发布:网络问政直通车 编辑:程序博客网 时间:2024/05/16 09:51
普通的二叉搜索树作为数据存储工具的优势是可以快速的找到一个给定关键字的数据项,并且可以快速的插入和删除数据项。
然而二叉搜索树的缺点在于,如果树中插入的数值如果是随机数据,则执行效果很好,但是如果插入的数据是有序的,或者是逆序的时候,二叉树变成了非平衡二叉树,就不具备快速查找、插入和删除的能力了
解决非平衡二叉树问题的方法就是——红-黑树,它实际上就是增加了某些特点的二叉搜索树
平衡树和非平衡树
向一个只有根节点的树插入一组有序数据,其关键字为升序或者降序排列时,会导致节点均排列在一条直线上,没有分支
若关键字为升序,每一个节点都大于上一个插入的节点,则每个节点都是上一个节点的右子节点
若关键字未降序,每一个节点都小于上一个插入的节点,则每个节点都是上一个节点的左子结点
节点都在树的一侧,树会变得极不平衡
时间复杂度降低
当树没有分支时,就变成了链表,数据排列变成了一维
和在链表中一样,需要平均查找一般的数据项才能找到所需的数据项,查找的速度下降到O(N),而不是平衡树的O(logN),所以对于已经有序的数据可以使用链表
大部分情况是树部分不平衡,比起完全不平衡的情况要好一点,但是在这种情况下的查找时间不是最佳的
一棵树特别不平衡不太可能,但存在会有一部分有序数据使树部分非平衡,搜索部分不平衡树的时间介于O(N)和O(logN)之间,主要取决于树的不平衡程度
平衡的补救
为了能以较快的时间来搜索一棵树,需要保证树总是平衡的,或者大部分是平衡的,也就是说树的每个节点的左子树和右子树的后代数目应该大致相等
红-黑树的平衡是在插入的过程中取得的。对于一个要插入的数据项,会检查是否破坏熟的特征,如果破快的话,会根据需要改变树的结构,通过维持数的特征,保证树的平衡
补救平衡的主要依靠树的节点的旋转操作完成
红-黑树的特征
红-黑树有两个特征,一个相对简单,另一个比较复杂
节点都有颜色
之所以称作红-黑树是因为每一个节点的颜色或者是黑色或者是红色。当然也可以是另外两种任意颜色。有颜色便于标记。
可以在节点类中增加一个字段,用布尔型来表示颜色的信息
红-黑规则
当插入或者删除一个节点时,必须要遵循一定的规则,如果遵循了这些规则,树就是平衡的
1.每一个节点不是红色的就是黑色的
2.根总是黑色的
3.如果节点是红色的,则它的子节点必须是黑色的(反之不比为真)
4.从跟到叶结点或者空子节点的路径必须包含相同数目的黑色节点
修正违规情况
如果树中节点的颜色违规的话,有两种可能的修正措施
1.改变节点的颜色
2.执行旋转操作
旋转
所谓的旋转是通过改变节点的位置关系来达到平衡树的目的
任何节点都可以作为旋转中的顶端节点,只要它有适当的子节点
如果要做右旋,顶端节点必须有一个左子结点;类似的,如果要做左旋,顶端节点必须要只有一个右子节点
简单旋转
左旋
下列是算法导论对于左旋的实现
LEFT-ROTATE(T, x)
1 y ← right[x] ▹ Set y.
2 right[x] ← left[y] ▹ Turn y's left subtree into x's right subtree.
3 p[left[y]] ← x
4 p[y] ← p[x] ▹ Link x's parent to y.
5 if p[x] = nil[T]
6 then root[T] ← y
7 else if x = left[p[x]]
8 then left[p[x]] ← y
9 else right[p[x]] ← y
10 left[y] ← x ▹ Put x on y's left.
11 p[x] ← y
右旋
右旋的操作类似左旋横向移动节点
移动子树
插入节点
插入节点的步骤相信大家在二叉树中已经有所了解
此处红黑树的节点插入与二叉树不同之处在于多了颜色变换以及旋转的过程
需要考虑的几个复杂过程分别是:
1.在下行过程中的颜色变换
同普通的二叉搜索树所做的基本一样,沿着根部朝插入点移动,通过与每一层节点的关键字大小比较来决定向左走还是向右走
在红黑树中由于多了旋转和颜色变换,插入会变得更加复杂
在查找过程中为了不违反颜色规则,必要的时候需要进行颜色变换:
当查找到一个有两个红色子节点的黑色节点时,必须要把子节点变为黑色,而把父节点变为红色,除非父节点为根节点
2.插入节点之后的旋转
新数据项的插入可能会违背红-黑规则,所以在插入之后对规则的检查是必须的
有大概如下三种可能(插入节点总是红色):
1:祖父节点是黑色
2:祖父节点是红色,插入节点是父节点的外侧子孙节点
3:祖父节点是红色,插入节点是父节点的内侧子孙节点
对于情况一,插入是完成的
对于情况二:
1.改变祖父节点的颜色
2.改变父节点的颜色
3.一祖父节点为顶旋转,向插入节点上升的方向
对于情况三:
1.改变祖父节点的颜色
2.改变插入节点的颜色
3.以父节点为顶旋转,向插入节点上升的方向
4.以祖父节点为顶旋转,向插入节点上升的方向
3.在向下过程中的旋转
同样分为两种情况
一.作为外侧子孙节点
1.改变祖父节点的颜色
2.改变父节点的颜色
3.以祖父节点为顶旋转,向插入节点上升的方向
二.作为内侧子孙节点
1.改变祖父节点的颜色
2.改变插入节点的颜色
3.以父节点为顶旋转,向插入节点上升的方向
4.以祖父节点为顶旋转,向插入节点上升的方向
删除节点
删除节点一向是最复杂的步骤
节点删除后还要再次保证红黑树的正确性,所以复杂性要大于二叉搜索树
为了应对这个复杂问题,可以标记要删除的节点而不真正的删除它
红黑树的效率
同二叉搜索树一致,红黑树的查找、插入和删除的时间复杂度为O(log2N)
- 数据结构和算法学习(9)-红黑树
- 学习数据结构和算法
- 数据结构和算法学习
- 数据结构和算法学习(1)-概述
- 数据结构和算法学习(5)-链表
- 数据结构和算法学习(6)-递归
- 数据结构和算法学习(11)-哈希表
- 数据结构和算法学习(12)-堆
- 数据结构和算法学习笔记
- 算法和数据结构学习笔记
- 数据结构和算法学习笔记
- 数据结构和算法学习01-数据结构和算法简介
- 数据结构和算法学习(4)-栈和队列
- 数据结构和算法学习(2)-时间复杂度
- 数据结构和算法学习(3)-简单排序
- 数据结构和算法学习(7)-高级排序
- 数据结构和算法学习(8)-二叉树
- 数据结构和算法学习(10)- 2-3-4树
- struts-cleanup作用
- 封装
- QT移植
- 小知识点
- android拷贝数据库
- 数据结构和算法学习(9)-红黑树
- js获取页面元素的位置
- 编码解码
- Xcode 【用Alcatraz去管理插件(新版本采用第二种终端执行方法即可)】
- HDU2846
- java redis学习备忘
- java与C语言在字符串结束符上的区别
- 最长递增子序列-动态规划
- Windows 内存绘图导出RGB