考点频率 :★★★★★(数据结构必考,选择题常考BST的性质与插入/删除操作)
难度 :⭐⭐⭐
建议:重点掌握BST的递归定义和中序遍历有序性,理解插入和删除操作的三种情况
1️⃣ 什么是二叉排序树?
二叉排序树(Binary Sort Tree,BST) 又称二叉查找树 ,是一种特殊的二叉树,它满足以下递归定义:
对于树中的任意一个节点:
- 若左子树非空,则左子树上所有节点 的值都小于该节点的值
- 若右子树非空,则右子树上所有节点 的值都大于该节点的值
- 左子树和右子树本身也都是二叉排序树
关键点 :不是"左子节点小于父节点"就够了,而是左子树上所有节点都小于父节点,右子树上所有节点都大于父节点。这是BST与普通二叉树最根本的区别。
打个比方 :二叉排序树就像一个有序的档案柜------每个抽屉里的所有文件都比左边的抽屉大,比右边的抽屉小。你要找一份文件,只需要从最上面的抽屉开始,根据文件编号决定往左走还是往右走,不需要翻遍所有抽屉。
2️⃣ BST的核心性质
| 性质 | 说明 |
|---|---|
| 中序遍历有序 | 对BST进行中序遍历,得到的序列是递增有序的 |
| 查找效率高 | 平均时间复杂度 O(logn)O(\log n)O(logn)(树平衡时) |
| 动态结构 | 支持插入和删除操作,且不需要移动大量数据 |
中序遍历有序 是BST最重要的性质,也是软考中最常考的点。例如,一棵BST的中序遍历结果为
1, 3, 4, 6, 7, 8, 9,则可以直接判断这棵树是否满足BST的定义。
3️⃣ BST的查找操作
查找思想:
- 从根节点开始,如果树为空,查找失败
- 如果当前节点的值等于目标值,查找成功
- 如果目标值小于当前节点的值,递归查找左子树
- 如果目标值大于当前节点的值,递归查找右子树
c
BSTNode* Search(BSTNode* root, int key) {
if (root == NULL || root->data == key) {
return root;
}
if (key < root->data) {
return Search(root->lchild, key);
} else {
return Search(root->rchild, key);
}
}
时间复杂度:
- 最好情况(完全平衡):O(logn)O(\log n)O(logn)
- 最坏情况(退化成链表):O(n)O(n)O(n)
4️⃣ BST的插入操作
插入思想:
- 如果树为空,创建新节点作为根节点
- 如果新节点的值小于当前节点,递归插入左子树
- 如果新节点的值大于当前节点,递归插入右子树
- 插入的新节点一定是叶子节点
c
BSTNode* Insert(BSTNode* root, int key) {
if (root == NULL) {
return CreateNode(key);
}
if (key < root->data) {
root->lchild = Insert(root->lchild, key);
} else if (key > root->data) {
root->rchild = Insert(root->rchild, key);
}
// 如果 key == root->data,通常不插入(BST中不允许重复值)
return root;
}
示例 :依次插入 5, 3, 7, 1, 4, 6, 8
5
/ \
3 7
/ \ / \
1 4 6 8
5️⃣ BST的删除操作(难点)
删除操作是BST中最复杂的操作,需要分三种情况讨论(软考必考):
情况一:删除叶子节点
直接删除该节点,将其父节点的对应指针置为 NULL。
删除前: 5 删除后: 5
/ \ / \
3 7 3 7
/ \ / \
1 4 1 4
删除节点 1(叶子):直接删掉。
情况二:删除只有左子树或只有右子树的节点
用该节点的唯一子节点替换它。
删除前: 5 删除后: 5
/ \ / \
3 7 4 7
/ \ / \
1 4 1
删除节点 3(只有右子树):用 4 替换 3 的位置。
情况三:删除同时有左子树和右子树的节点
方法 :用该节点的前驱节点 或后继节点来替换它。
- 前驱节点 :左子树中的最右节点(即左子树中值最大的节点)
- 后继节点 :右子树中的最左节点(即右子树中值最小的节点)
替换规则 :找到前驱或后继节点后,用它的值覆盖待删除节点的值,然后递归删除那个前驱或后继节点。这样可以保证替换后仍然保持BST的性质。通常选择前驱和后继中任意一个都可以,但软考中更常用前驱节点(左子树的最右节点)。
删除前: 5 删除后: 4
/ \ / \
3 7 3 7
/ \ / \
1 4 1
删除节点 5(根节点):
左子树 [3,1,4] 中的最右节点是 4
用 4 替换 5 的位置,然后删除原来的 4
6️⃣ BST查找、插入、删除的时间复杂度
| 操作 | 平均情况(树平衡) | 最坏情况(树退化为链表) |
|---|---|---|
| 查找 | O(logn)O(\log n)O(logn) | O(n)O(n)O(n) |
| 插入 | O(logn)O(\log n)O(logn) | O(n)O(n)O(n) |
| 删除 | O(logn)O(\log n)O(logn) | O(n)O(n)O(n) |
7️⃣ 经典例题
例题1:对一棵二叉排序树进行中序遍历,得到的序列一定是( )。
A. 递增有序的
B. 递减有序的
C. 无序的
D. 按插入顺序排列的
解析 :BST的中序遍历结果是递增有序 的序列。选 A。
例题2:在二叉排序树中,删除一个节点时,如果该节点同时有左子树和右子树,通常用( )来替换它。
A. 左子树的最左节点
B. 左子树的最右节点
C. 右子树的最右节点
D. 直接删除
解析 :删除同时有左右子树的节点时,用前驱节点 (左子树的最右节点)或后继节点 (右子树的最左节点)来替换。选 B(因为软考中通常选用前驱节点)。
例题3(判断):二叉排序树的插入操作一定是在叶子节点进行的。( )
解析 :正确。每次插入新节点时,都是从根节点开始比较,最终找到一个空位置(NULL),在该位置创建新节点,因此新插入的节点一定是叶子节点。
8️⃣ 记忆口诀
BST,左小右大中序排,查找插入效率高。
插入永远是叶子,删除分三种:
叶子直接删,单孩用孩替,双孩找前驱。
9️⃣ 小测验(评论区对答案)
依次插入
10, 5, 15, 3, 7, 12, 18构造一棵BST,然后删除节点10。删除后,根节点的值是( )。(提示:使用前驱节点替换)A. 7
B. 5
C. 12
D. 15
答案下期公布。
🔔 本专栏日更,点击头像 → 专栏《软考中级高频考点》订阅,第一时间接收新内容
📥 需要"数据结构与算法"完整思维导图?私信回复"软考数据结构"免费获取
#软考中级 #软件设计师 #二叉排序树 #BST #数据结构 #软考备考# 二叉排序树(BST)的定义与操作
考点频率 :★★★★★(数据结构必考,选择题常考BST的性质与插入/删除操作)
难度 :⭐⭐⭐
建议:重点掌握BST的递归定义和中序遍历有序性,理解插入和删除操作的三种情况
1️⃣ 什么是二叉排序树?
二叉排序树(Binary Sort Tree,BST) 又称二叉查找树 ,是一种特殊的二叉树,它满足以下递归定义:
对于树中的任意一个节点:
- 若左子树非空,则左子树上所有节点 的值都小于该节点的值
- 若右子树非空,则右子树上所有节点 的值都大于该节点的值
- 左子树和右子树本身也都是二叉排序树
关键点 :不是"左子节点小于父节点"就够了,而是左子树上所有节点都小于父节点,右子树上所有节点都大于父节点。这是BST与普通二叉树最根本的区别。
打个比方 :二叉排序树就像一个有序的档案柜------每个抽屉里的所有文件都比左边的抽屉大,比右边的抽屉小。你要找一份文件,只需要从最上面的抽屉开始,根据文件编号决定往左走还是往右走,不需要翻遍所有抽屉。
2️⃣ BST的核心性质
| 性质 | 说明 |
|---|---|
| 中序遍历有序 | 对BST进行中序遍历,得到的序列是递增有序的 |
| 查找效率高 | 平均时间复杂度 O(logn)O(\log n)O(logn)(树平衡时) |
| 动态结构 | 支持插入和删除操作,且不需要移动大量数据 |
中序遍历有序 是BST最重要的性质,也是软考中最常考的点。例如,一棵BST的中序遍历结果为
1, 3, 4, 6, 7, 8, 9,则可以直接判断这棵树是否满足BST的定义。
3️⃣ BST的查找操作
查找思想:
- 从根节点开始,如果树为空,查找失败
- 如果当前节点的值等于目标值,查找成功
- 如果目标值小于当前节点的值,递归查找左子树
- 如果目标值大于当前节点的值,递归查找右子树
c
BSTNode* Search(BSTNode* root, int key) {
if (root == NULL || root->data == key) {
return root;
}
if (key < root->data) {
return Search(root->lchild, key);
} else {
return Search(root->rchild, key);
}
}
时间复杂度:
- 最好情况(完全平衡):O(logn)O(\log n)O(logn)
- 最坏情况(退化成链表):O(n)O(n)O(n)
4️⃣ BST的插入操作
插入思想:
- 如果树为空,创建新节点作为根节点
- 如果新节点的值小于当前节点,递归插入左子树
- 如果新节点的值大于当前节点,递归插入右子树
- 插入的新节点一定是叶子节点
c
BSTNode* Insert(BSTNode* root, int key) {
if (root == NULL) {
return CreateNode(key);
}
if (key < root->data) {
root->lchild = Insert(root->lchild, key);
} else if (key > root->data) {
root->rchild = Insert(root->rchild, key);
}
// 如果 key == root->data,通常不插入(BST中不允许重复值)
return root;
}
示例 :依次插入 5, 3, 7, 1, 4, 6, 8
5
/ \
3 7
/ \ / \
1 4 6 8
5️⃣ BST的删除操作(难点)
删除操作是BST中最复杂的操作,需要分三种情况讨论(软考必考):
情况一:删除叶子节点
直接删除该节点,将其父节点的对应指针置为 NULL。
删除前: 5 删除后: 5
/ \ / \
3 7 3 7
/ \ / \
1 4 1 4
删除节点 1(叶子):直接删掉。
情况二:删除只有左子树或只有右子树的节点
用该节点的唯一子节点替换它。
删除前: 5 删除后: 5
/ \ / \
3 7 4 7
/ \ / \
1 4 1
删除节点 3(只有右子树):用 4 替换 3 的位置。
情况三:删除同时有左子树和右子树的节点
方法 :用该节点的前驱节点 或后继节点来替换它。
- 前驱节点 :左子树中的最右节点(即左子树中值最大的节点)
- 后继节点 :右子树中的最左节点(即右子树中值最小的节点)
替换规则 :找到前驱或后继节点后,用它的值覆盖待删除节点的值,然后递归删除那个前驱或后继节点。这样可以保证替换后仍然保持BST的性质。通常选择前驱和后继中任意一个都可以,但软考中更常用前驱节点(左子树的最右节点)。
删除前: 5 删除后: 4
/ \ / \
3 7 3 7
/ \ / \
1 4 1
删除节点 5(根节点):
左子树 [3,1,4] 中的最右节点是 4
用 4 替换 5 的位置,然后删除原来的 4
6️⃣ BST查找、插入、删除的时间复杂度
| 操作 | 平均情况(树平衡) | 最坏情况(树退化为链表) |
|---|---|---|
| 查找 | O(logn)O(\log n)O(logn) | O(n)O(n)O(n) |
| 插入 | O(logn)O(\log n)O(logn) | O(n)O(n)O(n) |
| 删除 | O(logn)O(\log n)O(logn) | O(n)O(n)O(n) |
7️⃣ 经典例题
例题1:对一棵二叉排序树进行中序遍历,得到的序列一定是( )。
A. 递增有序的
B. 递减有序的
C. 无序的
D. 按插入顺序排列的
解析 :BST的中序遍历结果是递增有序 的序列。选 A。
例题2:在二叉排序树中,删除一个节点时,如果该节点同时有左子树和右子树,通常用( )来替换它。
A. 左子树的最左节点
B. 左子树的最右节点
C. 右子树的最右节点
D. 直接删除
解析 :删除同时有左右子树的节点时,用前驱节点 (左子树的最右节点)或后继节点 (右子树的最左节点)来替换。选 B(因为软考中通常选用前驱节点)。
例题3(判断):二叉排序树的插入操作一定是在叶子节点进行的。( )
解析 :正确。每次插入新节点时,都是从根节点开始比较,最终找到一个空位置(NULL),在该位置创建新节点,因此新插入的节点一定是叶子节点。
8️⃣ 记忆口诀
BST,左小右大中序排,查找插入效率高。
插入永远是叶子,删除分三种:
叶子直接删,单孩用孩替,双孩找前驱。
9️⃣ 小测验(评论区对答案)
依次插入
10, 5, 15, 3, 7, 12, 18构造一棵BST,然后删除节点10。删除后,根节点的值是( )。(提示:使用前驱节点替换)A. 7
B. 5
C. 12
D. 15
🔔 本专栏日更,点击头像 → 专栏《软考中级高频考点》订阅,第一时间接收新内容
#软考中级 #软件设计师 #二叉排序树 #BST #数据结构 #软考备考