👋 Hi, I’m @Beast Cheng
👀 I’m interested in photography, hiking, landscape…
🌱 I’m currently learning python, javascript, kotlin…
📫 How to reach me --> 458290771@qq.com
喜欢《数据结构》部分笔记的小伙伴可以订阅专栏,今后还会不断更新。🧑💻
感兴趣的小伙伴可以点一下订阅、收藏、关注!🚀
谢谢大家!🙏
定义
又称 二叉查找树(BST,Binary Search Tree)
一棵二叉树或是空二叉树,或者是具有如下性质的二叉树:
- 左子树上所有节点的关键字均小于根节点的关键字;
- 右子树上所有结点的关键字均大于根结点的关键字。
- 左子树和右子树又各是一棵二叉排序树
左子树结点值 < 根结点值 < 右子树结点值
根据中序遍历,可以得到一个递增的有序序列
查找
- 若树非空,目标值与根结点的值比较;
- 若相等,则查找成功;
- 若小于根结点,则在左子树上查找,否则在右子树上查找
- 查找成功,返回结点指针;查找失败,返回NULL
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 的结点(递归实现)
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); // 在右子树中查找
}
上面的最坏空间复杂度
O
(
1
)
O(1)
O(1)
下面的最坏空间复杂度
O
(
h
)
O(h)
O(h)
插入
若原二叉排序树为空,则直接插入结点;否则,若关键字 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);
}
构造
// 按照 str[] 中的关键字序列建立二叉排序树
void Create_BST(BSTree &T, int str[], int n){
T = NULL; // 初始时T为空树
int i = 0;
while(i < n){ // 依次将每个关键字插入到二叉排序树中
BST_Insert(T, str[i]);
i ++;
}
}
不同的关键字序列可能得到同款二叉排序树,也可能得到不同款
删除
先搜索找到目标节点:
- 若被删除节点 z 是叶子结点,则直接删除,不会破坏二叉排序树的性质
- 若结点 z 只有一棵左子树或右子树,则让 z 的子树称为 z 父结点的子树,替代 z 的位置
- 若结点 z 有左右两棵子树,则令 z 的直接后继(或直接前驱)替代 z,然后从二叉排序树中删去这个直接后继(或直接前驱),这样就成了第一或第二种情况
- z 的前驱:z 的左子树中最右下结点(该结点一定没有右子树)
- z 的后继:z 的右子树中最左下结点(该结点一定没有左子树)
查找效率分析
查找成功
查找长度:在查找运算中,需要对比关键字的次数。反映了查找操作时间复杂度
查找成功的平均查找长度ASL
查找操作时间复杂度:
- 最好情况:n 个结点的二叉树最小高度为 [ l o g 2 n ] + 1 [log_2n]+1 [log2n]+1 ,平均查找长度 = O ( l o g 2 n ) =O(log_2n) =O(log2n)
- 最坏情况:每个结点只有一个分支,树高 h = 结点数 n,平均查找长度 = O ( n ) =O(n) =O(n)
查找失败
看最尾端的叶子节点有几个(假设是 n ),那么就会出现 n 种情况是查找失败的,概率是 1/9