二叉排序树,又称二叉查找树(BST,Binary Search Tree)
一棵二叉树或者是空二叉树,或者是具有如下性质的二叉树:
- 左子树上所有结点的关键字均小于根结点的关键字;
- 右子树上所有结点的关键字均大于根结点的关键字;
- 左子树和右子树又各是一棵二叉排序树;
左子树结点值<根结点值<右子树结点值
进行中序遍历,可以得到一个递增的有序序列
二叉排序树可用于元素的有序组织,搜索
二叉排序树的查找
- 若树非空,则目标值与根结点的值比较;
- 若相等,则查找成功;
- 若小于根结点,则在左子树上查找,否则在右子树查找;
- 查找成功,返回结点指针;查找失败返回NULL
例:查找关键字为30的结点
代码:
最坏空间复杂度O(1)
//二叉排序树结点
typedef struct BSTNode {
int key;
struct BSTNode* lchild, * rchild;
}BSTNode,*BSTree;
//在二叉排序树中查找值为key的结点
BSTNode* BST_Search(BSTree T, int key) {
while (T != NULL && key != T->key) { //若树空或等于根结点值,则接受循环
if (key < T->key)
T = T->lchild;//小于,则在左子树上查找
else
T = T->rchild;//大于,则在右子树上查找
}
return T;
}
查找失败的情况 :
在二叉排序树中查找值为key的结点(递归实现)
最坏空间复杂度O(h)
//在二叉排序树中查找值为key的结点(递归实现)
BSTNode* BSTSearch(BSTree T, int key) {
if(T==NULL)
return NULL;//查找失败
if (key == T->key)
return T;//查找成功
else if (key < T->key)
return BSTSearch(T->lchild, key);//在左子树中找
else
return BSTSearch(T->rchild, key);//在右子树中找
}
二叉排序树的插入
若原二叉排序树为空,则直接插入结点;否则,若关键字k小于根结点值,则插入到左子树,若关键字k大于根结点值,则插入到右子树
//在二叉排序树中插入关键字为k的新结点(递归实现)
int BST_Insert(BSTree &T, int k) {
if (T == NULL) {//原树为空,新插入的结点为根结点
T = (BSTree)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)//插入到T的左子树
return BST_Insert(T->lchild, k);
else//插入到T的左子树
return BST_Insert(T->rchild, k);
}
注意:新插入的结点一定是叶子结点
最坏空间复杂度O(h)
非递归插入
int BST_Insert(BSTree& T, int k) {
while (T!= NULL) { // 当找到空位置时停止循环
if (k < T->key) {
T = T->lchild; // 移动到左孩子
}
else if (k > T->key) {
T = T->rchild; // 移动到右孩子
}
else {
// 如果键值已存在,不插入,返回0
return 0;
}
}
// 创建新节点并插入到找到的位置
T = (BSTree)malloc(sizeof(BSTNode));
if (T== NULL) { // 内存分配失败
return 0;
}
T->key = k;
T->lchild = T->rchild = NULL;
return 1; // 插入成功
二叉排序树的构造
例题:
//按照str[]中的关键字序列建立二叉排序树
void Creat_BST(BSTree& T, int str[], int n) {
T = NULL;//初始T为空树
int i = 0;
while (i < n) {//依次将每个关键字插入到二叉排序树中
BST_Insert(T, str[i]);
i++;
}
}
二叉排序树的删除
先搜索找到目标结点:
1:若被删除结点z是叶结点,则直接删除,不会破坏二叉排序树的性质
2:若结点z只有一棵左子树或右子树,则让z的子树成为z父结点的子树,替代z的位置
3:若结点z有左、右两棵子树,则令z的直接后继(或直接前驱)替代z,然后从二叉排序树中删去这个直接后继(或直接前驱),这样就转换成了第一或第二种情况。
直接后继:
直接前驱:
查找效率分析
查找长度——在查找运算中,需要对比关键字的次数称为查找长度,反映了查找操作时间复杂度