二叉树是最常见的树,二叉树的每个节点最多只有两个子节点
二叉树的分类
完全二叉树
指二叉树的所有节点按照从左往右填充
就像这样:
满二叉树
是一种完全二叉树,当完全二叉树每个层次都被填满时,就是满二叉树
例如上图中的最后一棵树
堆
堆是一种带有特定排序的完全二叉树,所有节点大于他的所有子节点(大根堆),所有节点小于他的所有子节点(小根堆)
二叉搜索树
二叉搜索树跟大/小根堆相似,堆只要求节点大于(小于)子节
而二叉搜索树要求 左节点 > 节点 > 右节点
平衡二叉树
平衡二叉树是二叉搜索树的一种改进形式,指将树尽可能变“扁”,因为当用搜索树搜索数字的时候,如果遇到十分不平衡(左/右子树远大于另一个)的树的话,会出现查找的时间不理想的情况,所以需要让左右子树尽可能一样高。
平衡二叉搜索树
指将二叉搜索树用平衡树改进,让二叉搜索树在增删查改时能让左右子树尽可能一样高
AVL树(自平衡二叉搜索树)
自动版的平衡二叉树,能够在增加/删除元素时,自动通过左旋,右旋,时他重新平衡
黑红树
大部分人这辈子都不会在工作中自己去实现一颗红黑树,因为其十分复杂,而且STL等库中封装了黑红树,所以只需要知道其原理即可。
黑红树并不严格平衡,他的左右子树层数差距可能很大 ,但是他仍然属于平衡搜索二叉树
在需要大量数据操作时,AVL树的时间复杂度会非常高,而黑红树就是适用于大量查询,插入,删除的数据结构,相当于升级版AVL树,在项目中常使用黑红树,用AVL树很少,黑红树可以代替AVL树
黑红树有以下几条性质:
---------------------------------------------------------------------------------------------------------------------------------
1.节点颜色:每个节点要么是红色,要么是黑色。
2.根节点颜色:根节点是黑色。
3.叶子节点颜色:每个叶子节点(NIL节点,空节点)是黑色的。这里叶子节点指的是树尾端空(NIL或NULL)的节点。
4.红色节点:如果一个节点是红色的,则它的两个子节点都是黑色的,且从根节点到叶子节点的所有路径上不能有 2 个连续的红色节点
5.黑高平衡:从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。这个特性确保了红黑树的高度大致保持在log(n)的级别。
---------------------------------------------------------------------------------------------------------------------------------
黑红树插入:
黑红树插入节点默认为红色
黑红树删除:
删除节点无子节点:
删除节点有一个子节点:
删除节点有两个子节点
树的旋转:
旋转相关内容取自:AVL树的旋转图解和简单实现
旋转
在每一次插入数值之后,树的平衡性都可能被破坏,这时可以通过一个简单的操作来矫正平衡–旋转。
旋转的目的就是减少高度,通过降低整棵树的高度来平衡。哪边的树高,就把那边的树向上旋转。
通过旋转可以降低高度。
所谓的左旋和右旋都是以子树为原点的:如b是a的子树,那么旋转就围绕b来进行。
如果b是a的左子树,那么就围绕b将a向右旋转,看着就像是a直接掉下来了,掉成了b的右子树。
如果b是a的右子树,那么就围绕b将a向左旋转,看着就像是a直接掉下来了,掉成了b的左子树。
插入节点时分四种情况,四种情况对应的旋转方法是不同的:
例如对于被破坏平衡的节点 a 来说:
1.LL 右旋转
就拿最简单的举例了。
一个简单的AVL树:
这时是平衡的,如果在插入一个元素3,就会变成下面这样,破坏平衡:
被破坏了平衡首先要找到是哪个树被破坏了平衡,然后调整这个树。然后继续往上一个一个的调整。
既然是被新插入的节点3破坏的,那么不平衡的树一定在从新插入的节点3到根节点8的路径上。找离新插入的节点最近的不平衡的树进行调整,上图中就是7.
节点7的左子树 高度为1,右子树为空,高度为-1 ,不平衡。根据表格要进行右旋转。
先把7这颗不平衡的树挑出来:
这棵树是最近的不平衡的树,7的左子树5高度为1,右子树为空,所以右子树高度是-1.两者的高度差达到了2,超过了1.
因为左子树5的高度更高,所以要把左子树5向上提一下,这时旋转就很明显了,抓着5向上一提,7就掉到5的右边了,成了5的右子树。
这个过程就是右旋:
这时继续往上找,发现每个节点都符合了平衡条件,所以整棵树就变成了AVL树。
那如果节点5本来就有了右子树呢?照样右旋转,只要把原来5的右子树变成旋转后的7的左子树就行了。因为5的右子树肯定比5大,但是也肯定比7小的:
其实上面最后旋转成的树是下面这样的:
这棵树的根节点是不平衡的,还需要使用后面的双旋转来调整。
使用LR先左旋后右旋调整后是这样的,具体方法看后面的:
2. RR 左旋转
在右子树的右子树上插入节点破坏的平衡需要左旋转来矫正。
左旋转和右旋转类似,都是单旋转,给个流程图。
3. LR 先左旋再右旋
如果在第一个例子中插入的不是3,而是6,就成了下面的样子,依然说破坏了平衡
被破坏平衡的树依然是7,但是这次就不能通过一次旋转解决了,咋转都不行。
要从6开始到7进行先左旋再右旋才可以矫正平衡:
4. RL 先右旋再左旋
当破坏平衡的节点是这个树的右子树的左子树时,要进行先右旋转再左旋转来矫正。
同样是从破坏平衡的那个节点开始旋转,先右旋转后左旋转: