目录
别名:二叉查找树、二叉排序树。可实现对数据的查找和排序。
特点:
若左子树非空,则左子树上所有结点的值均小于根结点的值;
若右子树非空,则右子树上所有结点的值均大于根结点的值;
其左右子树本身也是一棵二叉搜索树。
因此其中序遍历是递增序列。
二叉搜索树的查找:
算法步骤:
1)若二叉搜索树为空,查找失败,返回空指针;
2)若二叉搜索树非空,将待查找关键字x与根结点的关键字T->data比较;
若x==T->data,查找成功,返回根结点指针;
若x<T->data,则递归查找左子树;
若x>T->data,则递归查找右子树。(递归算法需要注意终止条件比如寻找到符合条件的值或者 树为空)
时间复杂度:
二叉搜索树的查找时间复杂度与树的形态有关,可分为最好情况、最坏情况和平均情况。造成不同情况的原因与输入顺序有关,解决方案:打乱输入顺序或利用算法调平(推荐)。
最好情况:
二叉搜索树形态与二分查找的判定树相似,如上图。每次查找缩小一半搜索范围,查找路径最多从根到叶子,比较次数最多为树的高度logn,最好情况的平均查找长度为O(logn)。
最坏情况:
二叉树形态为单支树,即只有左子树或右子树。如上图,每次查找的搜索范围缩小为n-1,即退化为顺序查找,最坏情况的平均查找的长度为O(n)。
平均情况:
n个结点的二叉搜索树有n!棵(有的形态相同),可以证明平均情况下,二叉搜索树的平均查找长度也是O(logn)。
空间复杂度:
空间复杂度为O(1)。不使用辅助空间。
二叉搜索树的插入:
由于二叉搜索树的中序遍历有序性,在插入某个元素时需要先查找待插入关键字的插入位置,如果没有查找成功,则将其作为新叶子节点插入最后一个结点的左孩子或右孩子。
算法步骤:
1)若二叉树为空,创建一个新结点s,将待插入关键字放入新结点的数据域,s结点作为根结点,左右子树为空。
2)若二叉树非空,将待查找关键字x与根结点的关键字T->data比较:
若x<T->data,将x插入左子树;
若x>T->data,将x插入右子树。(利用递归算法实现)
若x==T->data,可根据具体需求操作:一种是直接返回,另一种是给每个结点增加一个域num,初始为num=1;相等时num++。(排名问题一般采取这种方式)
时间复杂度:
由于二叉搜索树的插入需要先寻找插入位置,插入本身只需要O(1)时间,因此插入位置的时间复杂度为O(logn)。
二叉搜索树的创建:
二叉搜索树的创建从空树开始,按照输入关键字的顺序依次进行插入操作。
算法步骤:
1)初始化二叉树为空树,T=NULL;
2)输入关键字x,将x插入二叉搜索树T;
3)重复步骤2),直到关键字输入完毕。
时间复杂度:
创建二叉树的过程需要用到查找操作,创建n个关键字的二叉树的时间复杂度为O(nlogn)。
二叉搜索树的删除:
在执行删除操作之前也需要进行查找操作,找到待删除的结点。根据删除结点位置的不同,删除操作的处理方式也不同:
1)被删除的结点左子树或右子树为空,则令其子树子承父业即可。
2)被删除的结点左子树和右子树非空,根据二叉搜索树的中序有序性,删除该结点时,利用其直接前驱或直接后继代替其位置,然后删除其直接前驱或直接后继。如下图,删除p时,若采用直接前驱代替,则将S代替p的位置,S的左子树继承S的位置;若采用直接后继代替,则将S代替p的位置,继承S的位置。
直接前驱:结点p的左子树的最右结点。即沿着p的左子树一直访问其右子树,直至没有右子树,就得到了最右结点。
直接后继:结点p的右子树的最左结点。
算法步骤:
1)在二叉树中查找待删除关键字的位置,p指向待删除结点,f指向p的双亲结点,查找失败时,则返回。
2)查找成功时:
被删除的结点左子树或右子树为空,则令其子树子承父业即可。
被删除的结点左右子树非空,令其直接前驱或直接后继代替,再删除直接前驱或直接后继。
时间复杂度:
二叉树的删除主要是查找的过程需要O(logn)时间,删除过程中如果需要找到被删除结点的前驱或后继也需要O(logn)时间,二叉树的删除时间复杂度为O(2logn),由于时间复杂度不包含常数因此为O(logn)。