一. 二叉树概述
二叉树是递归定义的,其节点有左右子树之分
1.1 二叉树特性:
- 每个节点最多只有两颗子树,节点的度最大为2
- 左子树和右子树是有顺序的,次序不能颠倒
- 即使某个节点只有一个子树,也要区分左右子树
1.2 二叉树基本形态:
逻辑上二叉树有五种基本形态:
- 空二叉树
- 只有一个根节点的二叉树
- 只有左子树
- 只有右子树
- 完全二叉树
二. 二叉查找树BST
二叉查找树 – BST树:Binary Search Tree,或二叉搜索树
2.1 BST特性:
- BST树要么是一颗空树
- BST树要么满足以下3个条件的二叉树:
1. 节点的左子树所包含的节点的值都小于该节点的值
2. 节点的右子树所包含的节点的值都大于等于该节点的值
3. 左子树和右子树也都是BST树
一颗典型的二叉查找树
2.2 BST优点
二叉查找树这样数据结构有什么好处呢?
我们来试着查找值为11的节点:
a. 查看根节点8
b. 由于11>8,因此查看8节点的右孩子12
c. 由于11<12, 因此查看12节点的左孩子10
d. 由于11>10,因此查看10节点的右孩子11,发现11节点正是需要查找的节点
这种查找方式正是二分查找的思想,查找所需的最大次数等于二叉查找树的高度
2.3 BST缺点
二叉查找树的插入类似于查找,通过一层一层比较大小,找到新节点适合插入的位置
但是二叉查找树存在缺陷:当插入的数据过于特殊,二叉查找树会变瘸,导致空间浪费和查找效率变低
我们来试着看下面的情况:
a. 假设最初的二叉查找树只有3个节点,如图
b. 依次插入如下4个节点:7,6,5,4,结果会变为:
这样的形态虽然也符合二叉查找树的特性,但是浪费空间,查找性能大打折扣
那如何解决二叉查找树因为插入节点而导致的不平衡呢?
这就要用到平衡二叉树了
三. 平衡二叉树
平衡二叉树 – 本质上仍是一颗二叉搜查找树BST
3.1 平衡二叉树特性:
- AVL树首先是二叉查找树BST
- 带有平衡条件:任何节点的左右子树的高度之差的绝对值(平衡因子)最多为1
3.2 平衡二叉树常用实现:
平衡二叉树的常用实现方法有红黑树、AVL树、替罪羊树、Treap、伸展树等
四. 红黑树
红黑树(Red Black Tree) 是一种近似平衡二叉查找树,在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能
4.1 红黑树特性
- 节点是红色或者黑色
- 根节点是黑色
- 每个叶子节点都是黑色的空节点(NULL节点)
- 每个红色节点的两个子节点都是黑色(从根到每个叶子节点的所有路径上不能有两个连续的红色节点)
- 从任一节点到该节点的每个叶子节点的所有路径都包含相同数目的黑色节点
这些约束强制了红黑树的关键性质: 红黑树从根到叶子的最长路径不会超过最短路径的两倍,所以红黑树只是近似的平衡二叉树,牺牲了些许平衡性换来的是增删操作的简单性
4.2 红黑树调整
当插入或删除节点时,红黑树的规则有可能被打破,这时候需要做出一些调整,继续维持红黑树的规则
调整一般分两类:
- 颜色调整:改变某个节点的颜色
- 结构调整:改变树的结构 – 左旋和右旋
a. 插入的节点为红色
为什么插入节点会被着色为红色,而不是黑色呢?
因为着色为黑色会违背红黑树特性的最后一条,所以每次插入的都是红色节点
b. 左旋
左旋:逆时针旋转红黑树的两个节点,使得父节点被自己的右孩子取代,而自己成为自己的左孩子。说起来很怪异,看下图:
图中,身为右孩子的Y取代了X的位置,而X变成了自己的左孩子,而x < b < y,所以b的位置也要移动
c. 右旋
右旋:顺时针旋转红黑树的两个节点,使得父节点被自己的左孩子取代,而自己成为自己的右孩子。看下图:
图中,身为左孩子的Y取代了X的位置,而X变成了自己的右孩子,而y < c < x,所以c的位置也要移动
五. 红黑树插入
5.1 场景一
该树为空树,直接在根节点处插入一个红色节点,违反红黑树规则1,需要变色调整 – 将节点颜色改为黑色
5.2 场景二
插入节点的父节点为黑色,没有违反任何红黑树规则,不需要做调整
5.3 场景三
插入节点为红色,插入节点的父节点为红色,则一定存在:
- 根据规则4,插入节点一定有祖节点,且为黑色