二叉树是一种很好的存储结构,通过二叉树衍生的更高级的如红黑树,AVL,SBT等在各个领域程序,算法中都常会见到它的身影。
二叉查找树是具有以下性质的二叉树:
1、若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
2、若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
3、它的左、右子树也分别为二叉查找树;
4、没有键值相等的节点。
二叉查找树的优势在于它的时间复杂度较低,为O(log n)。
它的搜索,插入,删除的复杂度等于树高,期望O(log n),最坏O(n)(数列有序,树退化成线性表)。
二叉查找树的查找算法 树b中查找x的过程(伪代码):
if (b是空树)
搜索失败
else {
if (x == b的根结点数据域值)
查找成功
else if (x < b的根结点数据域值)
搜索左子树,重新上面搜索方法(递归)
else
搜索右子树,重新上面搜索方法(递归)
}
二叉查找树的插入算法 向b中插入节点x的过程(伪代码):
if (b是空树)
s节点作为根节点插入
else {
if (s节点域值 == b根节点域值)
return
//已经有这个节点域值了
else if (s节点域值 < b根节点域值)
s节点插入左子树中(递归)
else
s节点插入右子树中(递归)
}
二叉查找树的删除算法 删除节点p,删除分为三种情况:
1、若节点p为叶子节点(PL左子树和PR右子树均为空树),则直接修改双亲节点的指针。
2、若节点p只有左子树PL或右子树PR,只要让PL或PR成为其双亲节点的PL或PR(原p节点所在的子树位置)
3、若节点p的左右子树均不为空,需要调整,有两种做法:一、让节点p的左子树作为双亲节点f的左/右子树(根据节点p为双亲节点f的左子树还是右子树而定),节点p的右子树作为p左子树的最右下节点s的右子树;二、让节点p的直接前驱(或直接后继)(即左子树最右或右子树最左节点)替代节点p,然后在从二叉树中删除它的直接前驱(或直接后继) 实现过程:
if (右子树为空) {
节点p = 节点p的左子树
} else if (左子树为空) {
节点p = 节点p的右子树
} else {
//左右子树均不为空 获取左子树最右节点s
节点p->data = 节点s ->data
删除直接前驱s(删除方法同理,可用递归)
}
通过上面我们可以知道二叉查找树的查询复杂度更树的深度有关,深度越大,查询的复杂度也越大。为了提高查询效率,对二叉查找树进行了优化,产生了平衡二叉树,所有叶子的深度趋于平衡。
常见的平衡树有:AVL树、红黑树、Treap树等。这些树的高度为O(log n)。