定义
二叉搜索树(Binary Search Tree),又称为二叉排序树(Binary Sort Tree), 简称为BST。它具有以下性质:
①. 任何一个结点大于它左子树所有结点的值,小于它右子树所有结点的值
②. 任何一个结点的左右子树也是二叉搜索树
③. 中序遍历结果是一个非递减序列
相关操作以及时间复杂度分析
查找(Find)
在二叉搜索树中,查找操作从根结点出发分以下四个步骤:
①. 当前结点是否为空,如果空则返回该结点的父亲结点,说明在这棵树上无法查找到对应的值,返回的结点正好是查找的值应该插入的位置。
②. 当前结点是否是查找的值,若是则查找结束返回该结点;
③. 如果查找的值小于当前结点存储的值,则往左子树继续查找;
④. 如果查找的值大于当前结点存储的值,则往右子树继续查找;
看起来和二分查找差不多,或许很多人认为时间复杂度也是O(logn);但是由于二分查找是对线性表操作,线性表的判定树是唯一的,因此查找算法时间复杂度稳定O(logn);而BST的判定树不唯一,就如下图所示,他们的中序遍历都是一样的结果,但是查找时间复杂度完全不同:
通常描述BST查找时间复杂度的用ASL(Average Search Length, 平均查找长度),上图中:
ASLa = 1/6 *(1+2+2+3+3+3) = 14/6;
ASLb = 1/6 *(1+2+3+4+5+6) = 21/6;
显然图a的BST中查找时间复杂度比图b少;因此BST具体时间复杂度依赖于具体的BST;但是有个平均时间复杂度,平均时间复杂度是O(logn),这里不做证明;
插入(Insert)
插入操作是BST中,十分关键的操作,因为BST的建立完全靠这个操作。插入操作也依赖查找,因为需要定位插入的位置,使得插入之后,整个二叉树仍然满足定义。在查找中,如果没有找到结点,那么它会返回待插入的父亲结点位置p; 如果p结点为空,说明该BST树没有根节点,则待插入数据就是这BST树的根结点;如果p不为空,则比较待插入的数据,如果小于p的数据,则接入到p的左孩子;如果大于p的数据,则接入到p的右孩子;这样就完成了插入操作;
因为插入也依赖于查找的时间,所以时间复杂度也和查找一样的。
删除(Delete)
删除操作是BST中最难的一个操作。在删除的时候,要考虑维持整个二叉树依然保持BST的定义,因此会在删除的时候遇到以下三种情况:
①. 当删除的结点是叶子结点(即左右孩子都为空),则直接删除,对BST的性质没有任何影响;
②. 当删除的结点只有左孩子结点或者右孩子结点的时候,分类讨论如下:
只有左孩子结点: 将左孩子直接接到删除结点的父亲结点f的左孩子链域上;
只有右孩子结点: 将右孩子直接接到删除结点的父亲结点f的右孩子链域上;
③. 当删除的结点既有左孩子又有右孩子的时候,有两种办法:
方法1:如果删除结点p是其父亲结点的左孩子,则将p的左孩子接到父亲结点的左孩子上,将p的右孩子接到p左子树的最右结点(最右结点的定义是从子树的根结点出发,知道找不到下一个右孩子,则为最右结点),同理可推删除右孩子刚好和左孩子相对称。
方法2:如果删除结点是其父亲结点的右孩子