二叉搜索树
所谓二叉搜索树,可提供对数时间的元素插入和访问,二叉搜索树的节点放置规则是:任何节点的键值大于其左子树中的每一个节点的键值,并小于其右子树中的每一个节点的键值,因此,从根节点一直往左走,直至无左路可走,即得最小元素,从根结点一直往右走,直至无右路可走,即得最大元素,如图所示:
平衡二叉搜索树
也许因为输入值不够随机,也许因为经过某些插入或删除操作,二叉搜索树可能会失去平衡,造成搜寻效率低落的情况,如图所示:
所谓树形平衡是否,并没有一个绝对的衡量标准,平衡的大致意思是:没有任何一个节点过深(深度过大)
AVL tree
AVL tree是一个加上了额外条件的二叉搜索树,其平衡条件的建立是为了确保整棵树的深度为O(logN),直观上的最佳平衡条件是每个节点的左右子树有着相同的高度,我们很难保证插入新元素而又保持这样的平衡条件,AVL tree于是退而求其次,要求任何节点的左右子树高度相差1,这是一个较弱的条件,但任然能保证对数深度平衡条件
如图所示:
假设该最深节点为X,由于节点最多拥有两个子节点,而所谓"平衡被破坏"意味着 X的左右两颗子树的高度相差2,我们可以分为下面四种情况
- 插入点位于X的左子节点的左子树—左左
- 插入点位于X的左子节点的右子树—左右
- 插入点位于X的右子节点的左子树—右左
- 插入点位于X的右子节点的右子树—右右
情况1,4彼此对称,称为外侧插入,可以采用单旋转操作调整解决,情况2,3彼此对称,称为内侧插入,可以采用双旋转操作调整
如图所示:
单旋转
在外侧插入的情况下,插入前平衡,插入后不平衡的唯一情况如图所示:
图所示的是左左外侧插入,至于右右外侧插入,情况如出一辙
双旋转
左侧为内侧插入所造成的不平衡状态, 单旋转无法解决这种问题,如图所示,左右内侧插入和右左内侧插入,情况如出一辙
RB-tree
所谓RB-tree,不仅是一个二叉搜索树,而且必须满足以下规则:
- 每个节点不是红色就是黑色(图中深色底纹代表黑色,浅色底纹代表红色)
- 根结点为黑色
- 如果结点为红,其子节点必须为黑
- 任一节点至NULL(树尾端)的任何路径,所含之黑节点必须相同
根据规则4,新增节点必须为红,根据规则3,新增节点之父节点必须为黑,当新节点根据二叉搜索树的规则到达其插入点,却未能符合上述条件时,就必须调整颜色并旋转树型,如图所示:
插入节点
假设我们为RB-tree分别插入3,8,35,75,根据二叉搜索树的规则,这四个新节点的落脚点应该如图所示,它们都破坏了RB-tree的规则,因此我们必须调整树型
假设新节点为X,其父节点为P,祖父节点为G,伯父节点(父节点之兄弟节点)为S,曾祖父节点为GG,根据二叉搜索树的规则,新节点X必为叶节点,根据红黑树规则4,X必为红,若P为红(这就违反了规则3),则G必为黑(原为RB-tree,必须遵循规则3),于是,根据X的插入位置及外围节点(S和GG)的颜色,有了以下四种考虑:
- S为黑色且X为外侧插入,我们先对P,G做一次单旋转,再更改P,G颜色,即可重新满足红黑树的规则3
- S为黑且X为内侧插入,我们必须先对P,X做一次单旋转并更改G,X颜色,再将结果对G做一次单旋转,即可满足红黑树规则
- 状况3:S为红且X为外侧插入,先对P和G做一次单旋转,并改变X的颜色,此时如果GG为黑,一切搞定,但如果GG为红,则问题就比较复杂一些,见状况4
- 状况4:S为红且X为外侧插入,对此情况,先对P和G做一次单旋转,并改变X的颜色,此时如果GG为红,还得持续往上做,直到不再有父子连续为红的情况
为了避免状况4“父子节点皆为红色”:我们可以施加一个自上而下的程序:假设新增节点为A,那么只要看见某节点x的两个子节点皆为红色,就把X改为红色,并把两个子节点改为黑色,如图所示: