平衡二叉查找树的严格定义:二叉树中任意一个节点的左右子树的高度相差不能大于1。 bash
设计平衡二叉查找树的初衷:为了解决普通二叉查找树在频繁的插入、删除等动态更新的状况下(尤为是插入的一组数据是有序的状况),出现时间复杂度退化的问题。数据结构
可是在实际的开发中,并不能彻底严格的按照定义去作,只要保证平衡便可,也就是让整棵树左右看起来比较对称、比较平衡、更新数据时不要形成一边很高、一边又很低的状况。这样就能让整棵树的高度相对来讲低一些(如树的高度是对数量级的,没必要log2n大不少)。只要能保证这样,就能够说它是一个合格的平衡二叉查找树。性能
红黑树中的节点,一类被标记为黑色,一类被标记为红色。而且要求:spa
近似平衡就是说查找等动态更新的性能不会退化太严重。设计
二叉查找树不少操做的性能都很树的高度成正比,所以只要证实红黑树的高度能比较稳定的趋近log2n就好。3d
而红色节点必须是被黑色节点隔开的,一红一黑,所以红色节点加回去,树的高度应该不大于2log2n。高度仅是大了一倍,性能上降低很少,能够近似O(logn)。code
同时红黑树是近似平衡,所以维护平衡的成本较低,性能比较稳定。对于工程应用来讲,要面对各类异常状况,稳定性很重要,所以红黑树的应用范围较广。cdn
动态数据结构是指支持动态的更新操做,里面存储的数据是时刻在变化的,它支持查询、删除、插入等操做,而且这些操做是很是高效。这样的数据结构才能算做动态数据结构。blog
红黑树规定插入的节点必须是红色的且在修改过程当中不能改变颜色,由于插入红色节点比黑色节点违背规则的可能性更小。插入黑色节点必定会改变黑色高度(违背规则4),而插入红色只有一半机会违背规则3。且3比4更易修正。开发
当插入一个新节点(二叉查找树插入新节点会插到叶子节点上,那么在红黑树上也就是插入到黑色空节点上层了)就可能会破坏红黑树本来结构,打破平衡,那么如何修正呢?
主要有三种方式:改变节点颜色、左旋、右旋。
变色 假设本来只有节点E,而后插入了节点A和S,再插入F:
左旋 一般左旋操做用于将一个向右倾斜的红色连接转为向左连接。
左旋
typedef struct TreeNode {
int key;
struct TreeNode *left;
struct TreeNode *right;
struct TreeNode *father; // 双向链表
BOOL color;
} Node;
复制代码
/*
* 左旋示意图:对节点x进行左旋
* p p
* / /
* x y
* / \ / \
* lx y -----> x ry
* / \ / \
* ly ry lx ly
* 左旋作了三件事:
* 1. 将y的左子节点赋给x的右子节点,并将x赋给y左子节点的父节点(y左子节点非空时)
* 2. 将x的父节点p(非空时)赋给y的父节点,同时更新p的子节点为y(左或右)
* 3. 将y的左子节点设为x,将x的父节点设为y
*/
复制代码
/*
* 左旋示意图:对节点y进行右旋
* p p
* / /
* y x
* / \ / \
* x ry -----> lx y
* / \ / \
* lx rx rx ry
* 右旋作了三件事:
* 1. 将x的右子节点赋给y的左子节点,并将y赋给x右子节点的父节点(x右子节点非空时)
* 2. 将y的父节点p(非空时)赋给x的父节点,同时更新p的子节点为x(左或右)
* 3. 将x的右子节点设为y,将y的父节点设为x
*/
复制代码
具体过程为例: 插入新节点4,如图1(也就是状况①)。此时违反3,所以将它的父节点涂黑,可是若是只涂5,就会形成黑色节点不平衡了,违反了4。所以新节点的父节点5和叔叔节点8都要涂黑。这时758都是黑色(黑色太多了?)将祖父7涂红。这时又变成状况②,把7当作新节点 ,以新节点 为支点作左旋操做。如图2->3。此时27节点仍有问题继续修改,此时那2做为新节点,将父节点7涂黑,祖父节点11涂红。在以11为支点右旋。这样整棵树就又平衡。
从上面的步骤能够看出,若是插入数据最终是状况1,则须要走完二、3步骤;若是插入数据出现的是状况2,则只需走完3;插入后是3,则完成3便可了。
整体:变色->左旋->右旋