定义
二叉查找树(Binary Search Tree, BST),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树:
- 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉排序树。
二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作.
根据二叉排序树的定义,可知左子树结点值 < 根结点值 < 右子树结点值,所以对二叉排序树进行中序遍历,可以得到一个递增的有序序列。
二叉排序树的查找
思路:从根结点开始,沿某个分支逐层向下进行比较的过程。若二叉排序树非空,则将给定值与根结点的关键字比较,若相等,则查找成功;若不相等,则当根结点的关键字值大于给定关键字值时,在根结点的左子树中查找,否则在根结点的右子树中查找。
算法
BSTNode * BST_Search(BiTree T, ElemTpye key, BSTNode * &p)
{
// 查找函数返回指向关键字值为key的结点指针,若不存在,返回Null
p = NULL; // p指向被查找结点的双亲,用于插入和删除操作中
while(T != NULL && key != T->data)
{
p = T;
if(key < T->data) = T = T->lchild;
else T = T->rchild;
}
return T;
}
二叉排序树的插入
插入过程:若原二叉排序树非空,则直接插入结点;否则,若关键字k小于根结点关键字,则插入左子树,若关键字k大于根结点关键字,则插入右子树。
算法:
int BST_Insert(BiTree &T, KeyType k)
{
//在二叉排序树T中插入一个关键字为k 的结点
if(T == NULL)
{
T = (BiTree) malloc(sizeof(BSTNode));
T->key = k;
T-lchild = T->rchild = NULL;
return 1; // 返回1,表示成功
}
else if(k==T->key) // 树中存在相同关键字的结点
return 0;
else if(k<T->key)
return BST_Insert(T->lchild, k);
else
return BST_Insert(T->rchild, k);
}
二叉排序树的构造
过程: 每读入一个元素,就建立一个新结点,若二叉排序树非空,则将新结点的值与根结点比较,若小于根结点的值,则插入左子树,否则插入右子树;若二叉排序树为空,将新结点作为二叉排序树的根结点。
算法:
void Create_BST(BiTree &T, KeyType str[], int n)
{
// 用关键字数组str[]建立一个二叉排序树
T = NULL;
int i = 0;
while(i<n)
{
BST_Insert(T, str[i]);
i++;
}
}
二叉排序树的删除
过程
- 若被删除结点z是叶结点,则直接删除,不会破坏二叉排序树的性质
- 若结点z只有一棵左子树或右子树,则让z的子树成为z父结点的子树,替代z的位置
- 若结点z有左、右两棵子树,则令z的直接后继(或直接前驱)替代z,然后从二叉排序树中删去这个直接后继(或直接前驱),这样就转换成了第一或第二种情况。
查找效率分析
对于高度为h的二叉排序树,其插入和删除操作的运行时间都为
O(h)。
但在最坏的情况下,即构造二叉树的输入序列是有序的,则会形成一个倾斜的单支树,此时二叉树的性能显著变坏。
所以:
- 若二叉排序树为单支树,则平均查找长度和链表相同,为O(n);
- 若二叉排序树的左右子树高度相差不超过1,则这样的二叉树被称为平衡二叉树,它的平均查找长度为O(log2 n)
我的个人博客:https://www.lex666.online