【数据结构】二叉排序树(BST)的定义与操作

考点频率 :★★★★★(数据结构必考,选择题常考BST的性质与插入/删除操作)

难度 :⭐⭐⭐

建议:重点掌握BST的递归定义和中序遍历有序性,理解插入和删除操作的三种情况

1️⃣ 什么是二叉排序树?

二叉排序树(Binary Sort Tree,BST) 又称二叉查找树 ,是一种特殊的二叉树,它满足以下递归定义

对于树中的任意一个节点:

  1. 若左子树非空,则左子树上所有节点 的值都小于该节点的值
  2. 若右子树非空,则右子树上所有节点 的值都大于该节点的值
  3. 左子树和右子树本身也都是二叉排序树
    关键点 :不是"左子节点小于父节点"就够了,而是左子树上所有节点都小于父节点,右子树上所有节点都大于父节点。这是BST与普通二叉树最根本的区别。

打个比方 :二叉排序树就像一个有序的档案柜------每个抽屉里的所有文件都比左边的抽屉大,比右边的抽屉小。你要找一份文件,只需要从最上面的抽屉开始,根据文件编号决定往左走还是往右走,不需要翻遍所有抽屉。

2️⃣ BST的核心性质

性质 说明
中序遍历有序 对BST进行中序遍历,得到的序列是递增有序
查找效率高 平均时间复杂度 O(log⁡n)O(\log n)O(logn)(树平衡时)
动态结构 支持插入和删除操作,且不需要移动大量数据

中序遍历有序 是BST最重要的性质,也是软考中最常考的点。例如,一棵BST的中序遍历结果为 1, 3, 4, 6, 7, 8, 9,则可以直接判断这棵树是否满足BST的定义。

3️⃣ BST的查找操作

查找思想

  1. 从根节点开始,如果树为空,查找失败
  2. 如果当前节点的值等于目标值,查找成功
  3. 如果目标值小于当前节点的值,递归查找左子树
  4. 如果目标值大于当前节点的值,递归查找右子树
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(log⁡n)O(\log n)O(logn)
  • 最坏情况(退化成链表):O(n)O(n)O(n)

4️⃣ BST的插入操作

插入思想

  1. 如果树为空,创建新节点作为根节点
  2. 如果新节点的值小于当前节点,递归插入左子树
  3. 如果新节点的值大于当前节点,递归插入右子树
  4. 插入的新节点一定是叶子节点
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(log⁡n)O(\log n)O(logn) O(n)O(n)O(n)
插入 O(log⁡n)O(\log n)O(logn) O(n)O(n)O(n)
删除 O(log⁡n)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) 又称二叉查找树 ,是一种特殊的二叉树,它满足以下递归定义

对于树中的任意一个节点:

  1. 若左子树非空,则左子树上所有节点 的值都小于该节点的值
  2. 若右子树非空,则右子树上所有节点 的值都大于该节点的值
  3. 左子树和右子树本身也都是二叉排序树
    关键点 :不是"左子节点小于父节点"就够了,而是左子树上所有节点都小于父节点,右子树上所有节点都大于父节点。这是BST与普通二叉树最根本的区别。

打个比方 :二叉排序树就像一个有序的档案柜------每个抽屉里的所有文件都比左边的抽屉大,比右边的抽屉小。你要找一份文件,只需要从最上面的抽屉开始,根据文件编号决定往左走还是往右走,不需要翻遍所有抽屉。

2️⃣ BST的核心性质

性质 说明
中序遍历有序 对BST进行中序遍历,得到的序列是递增有序
查找效率高 平均时间复杂度 O(log⁡n)O(\log n)O(logn)(树平衡时)
动态结构 支持插入和删除操作,且不需要移动大量数据

中序遍历有序 是BST最重要的性质,也是软考中最常考的点。例如,一棵BST的中序遍历结果为 1, 3, 4, 6, 7, 8, 9,则可以直接判断这棵树是否满足BST的定义。

3️⃣ BST的查找操作

查找思想

  1. 从根节点开始,如果树为空,查找失败
  2. 如果当前节点的值等于目标值,查找成功
  3. 如果目标值小于当前节点的值,递归查找左子树
  4. 如果目标值大于当前节点的值,递归查找右子树
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(log⁡n)O(\log n)O(logn)
  • 最坏情况(退化成链表):O(n)O(n)O(n)

4️⃣ BST的插入操作

插入思想

  1. 如果树为空,创建新节点作为根节点
  2. 如果新节点的值小于当前节点,递归插入左子树
  3. 如果新节点的值大于当前节点,递归插入右子树
  4. 插入的新节点一定是叶子节点
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(log⁡n)O(\log n)O(logn) O(n)O(n)O(n)
插入 O(log⁡n)O(\log n)O(logn) O(n)O(n)O(n)
删除 O(log⁡n)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 #数据结构 #软考备考

相关推荐
lally.1 小时前
整数等差数列超图中的三个非微扰现象
算法
wabs6661 小时前
关于字符串【力扣541.反转字符串II的思考】
数据结构·算法·leetcode·字符串
土司大王1 小时前
LeetCode hot100——移动零
java·算法·leetcode
简简单单lym1 小时前
mediasou c++分析--流分析
笔记·webrtc
糖炒栗子03262 小时前
learn-claude-code 简要记录
笔记·python
Tyler_TXZ3 小时前
C++C语言之——树
c语言·c++·算法·
旖旎夜光3 小时前
LeetCode 30:串联所有单词的子串(滑动窗口) —— 题解
数据结构·c++·算法·leetcode·滑动窗口
白狐_7983 小时前
408 数据结构|完全二叉树两道典型题:第 6 层叶结点数与叶结点总数
数据结构·算法
lucas_AI3 小时前
喂张白纸也能吐出证件号?文档 MLLM 的"关系级泄露"被测出来了
人工智能·算法·掘金技术征文