有序表
特点:有序表的任意操作的时间复杂度的指标都相同,只是常数项时间不同。
搜索二叉树
任意节点,它的左子树的任意节点都比这个节点小,它的右子树的任意节点都比这个节点大。按照中序遍历,搜索二叉树得到的结果是顺序递增的。因为搜索二叉树本身的性质,它不存在相同的两个节点。
搜索二叉树的几种常用操作
查找:确定一个节点是不是在搜索二叉树上,只需要从根节点开始遍历,将输入的值与经过的节点的值进行比较,相等证明该节点存在直接返回;小于进入节点的左子树;大于进入节点的右子树。直到遇到的节点为空,说明输入的值不在搜索二叉树上。
增加:前面的过程与查找基本相同,当碰到与输入的值相等的节点使,证明该值已经存在于二叉树,返回false;否则继续比较,比较过程于后续操作于查找相同。当遇到一个节点为空时,将输入的值插到该位置。
将值为4的节点插入到左边的搜索二叉树中
插入结果如上图。
删除:搜索二叉树删除时较为复杂,确定要删除的节点存在后,根据节点所处的位置可以分为4种情况:
- 要删除的节点为叶子节点,直接删除;
- 节点只有左孩子,没有右孩子,将该节点的父节点的左指针指向它的左孩子;
- 节点只有右孩子,没有左孩子,将该节点的父节点的右指针指向它的右孩子;
- 节点既有左孩子,又有右孩子,将该节点的后继节点代替到该节点。如果这个后继节点存在右孩子,将右孩子挂在后继节点的父节点的左孩子的位置,否则直接替代即可。
可以根据下面的图来理解搜索二叉树的删除情况(除最后一项所有的删除操作都是在第一幅图的基础上)。
如果要删除叶子节点4,直接删除即可。
如果要删除节点8,用节点7取代节点8.
如果要删除节点5,用节点4取代节点5。
如果要删除节点6,用节点7取代节点6。
如果在删除节点6时,节点7不是叶子节点,删除过程如下图。
要说明的是,如果要删除的节点既有左孩子又有右孩子,那么它的后继节点不可能存在左孩子。因为如果一个节点的孩子都存在,那么这个节点一定是它的右孩子本身或者右子树中处于最左的节点。
具有平衡性的树
左旋和右旋
左旋和右旋是调整树的平衡的基础操作。
如果一棵树不平衡(一般出现在插入新数据后),那么它可能有以下四种情况:
- LL型:一个节点的左子树的高度大于右子树,且是由左子树的左子树造成的,通过右旋调整。
- RR型:一个节点的右子树的高度大于左子树,且是由右子树的右子树造成的,通过左旋调整。
- LR型:一个节点的左子树的高度大于右子树,且是由左子树的右子树造成的,通过先左旋后右旋调整。
- RL型:一个节点的右子树的高度大于左子树,且是由右子树的左子树造成的,通过先右旋后左旋调整。
LR型是要把R代表的节点转成头节点,RL型同理。
RR型于RL型的调整操作大致与LL型和LR型的调整操作相同。
AVL树
AVL tree 是自平衡搜索二叉树,它对平衡性的判定于平衡二叉树相同,即一个节点的两个子树的高度的差值的绝对值不能超过1。
AVL树的基本操作
插入:AVL树的插入操作与搜索二叉树的插入相同,但在插入新节点后需要考虑整颗树的平衡情况。所以需要从插入位置开始向上回溯,判断经过的节点是否平衡。如果发现存在不平衡的节点,根据之前提到的可能出现的4种不平衡的情况,对该节点进行左旋或右旋的操作。
在情况最糟糕的情况下,每个节点都需要进行修改,此时执行一次插入操作的时间复杂度也不会超过O(logN),首先不论左旋还是右旋都是常数项的操作,其次二叉树的高度为logN向下取整,也就是说在添加新节点后回溯所要经过的节点个数不会超过logN,二者相乘得到这个结果。
删除:删除时有以下几种情况
- 要删除的节点是叶节点,直接删除;
- 要删除的节点有替代的节点,那么必须从替代节点的位置开始向上回溯,进行平衡操作。
SB树(Size Balance Tree)
SB树和AVL树的原理基本相同,但在平衡性的判断方面SB树没有AVL树严苛,减少了调整平衡性的代价。而且SB树的实现要比AVL树简单。
SB树的平衡性:
一颗树的子树的节点数的个数,不能小于它的兄弟的子树的节点数的个数。
SB树如果不平衡(一般出现在插入新数据后),那么它可能有以下四种情况:
- LL型:1的子树的个数大于C的子树的个数,通过右旋调整。
- RR型:4的子树的个数大于B的子树的个数,通过左旋调整。
- LR型:2的子树的个数大于C的子树的个数,通过先左旋后右旋调整。
- RL型:3的子树的个数大于B的子树的个数,通过先右旋后左旋调整。
调整过程与之前提到的过程相同,但在这次调整结束后,还应该对调整后得到的树的各个节点进行判断,节点的左孩子和右孩子有没有发生变化,如果发生变化,就要继续递归执行调整操作。
SB树的基本操作
增加:先执行搜索二叉树的添加操作,如果添加后造成二叉树的不平衡,根据情况的不同进行上述平衡操作。需要注意的是,在递归执行调整操作的过程中,节点可能会出现“换头”,即本来的节点可能会变成之前节点的左孩子或右孩子。
删除:SB树删除一个节点后一定可以保证平衡,所以在执行搜索二叉树的删除后,不需要再进行调整,这也是SB树比AVL树实现简单的原因。