news 2026/10/1 11:36:31

数据结构 ----- 二叉搜索树

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数据结构 ----- 二叉搜索树

BST,AVL,红黑树

共性:

  1. 本质都是二叉搜索树,都遵守BST规则,
  2. 中序遍历的结果都是升序有序序列,
  3. 节点结构都是二叉树节点:数据域+左指针+右指针
  4. 基础操作逻辑一致,查找,插入,删除的查找路径一致

区别:

主要在平衡约束强度。普通 BST 不保证平衡;AVL 严格平衡,查找快但增删旋转多;红黑树弱平衡,旋转少,增删性能更好。AVL 和红黑树是在 BST 基础上增加平衡约束,解决普通 BST 最坏退化成链表的缺陷。

二叉搜索树(BST)

核心规则:

  1. 左子树所有节点值 < 根节点值
  2. 右子树所有节点值 > 根节点值
  3. 左、右子树本身也都是 BST

三大基础操作

1.查找

从根开始比较:小于根去左子树,大于根去右子树,相等找到

平均:O()

最坏:O(n)(有序插入,树退化成一条链表)

TreeNode* search(TreeNode* root, int key) { if (root == nullptr || root->val == key)return root; if (key < root->val) { return search(root->left, key); } return search(root->right, key); }

2.插入

与查找的逻辑一致,新节点一定是叶子节点

TreeNode* insert(TreeNode* root, int val) { if (root == nullptr)return new TreeNode(val); if (val < root->val) { root->left = insert(root->left, val); } else if (val > root->val) { root->right = insert(root->right, val); } return root; }

3.删除

删除(难点,分 3 种情况)

  1. 叶子节点:直接删除
  2. 只有左孩子 / 只有右孩子:用子节点替换当前节点
  3. 左右孩子都存在:两种选择取右子树的最小值(右子树最左节点)替换当前节点,再删掉这个最小节点或者取左子树的最大值(左子树最右节点)替换当前节点,再删掉该节点
    TreeNode* remove(TreeNode* &root, int key) { if (root == nullptr)return nullptr; if (key < root->val) { root->left = remove(root->left, key); } else if (key > root->val) { root->right = remove(root->right, key); } else { if (!root->left) { TreeNode* tmp = root->right; delete root; return tmp; } if(!root->right) { TreeNode* tmp = root->left; delete root; return tmp; } TreeNode* minParent =nullptr; TreeNode* cur = getMinAndParent(root->right,minParent); if (minParent == nullptr) root->right = cur->right; else minParent->left = cur->right; cur->left = root->left; cur->right = root->right; delete root; return cur; } return root; }
    TreeNode* getMinAndParent(TreeNode* root, TreeNode*& parent) { parent = nullptr; while (root->left != nullptr) { parent = root; // 记录当前节点作为父 root = root->left; } return root; // root停在最左,就是最小值节点 }

    关于情况三,关键是要断掉cur与树的联系所以要提前保存cur的父节点,以免出现野指针

AVL(平衡二叉搜索树)

AVL 树 =BST + 平衡约束

平衡因子 BF = 左子树高度 − 右子树高度

AVL 强制要求:每个节点的平衡因子只能是 -1、0、1如果 (|BF|>1) → 树失衡,需要旋转修复

目的:限制树高,保证查找 / 插入 / 删除 时间复杂度 O (logn),不会退化成链表(普通 BST 最坏 O (n))

结点结构:

struct TreeNode { int val; TreeNode *left; TreeNode *right; int height; // AVL独有:记录以当前节点为根的子树高度 TreeNode(int v) : val(v), left(nullptr), right(nullptr), height(1){} };

四种失衡情况

LL左左(右旋)

在失衡节点的左子树的左孩子处插入,左子树过重

此时为AVL树,插入1

根节点平衡因子为2,失衡此时应该右旋

  1. 把失衡节点的左孩子提上来作为新根
  2. 左孩子原来的右子树,变成失衡节点的左子树
  3. 失衡节点变成其左孩子的右孩子

代码:

AVLNode* Right_Rotate(AVLNode* node) { AVLNode* child = node->leftchild; AVLNode* grandchild = child->rightchild; node->leftchild = grandchild; child->rightchild = node; //更新node和child的高度 Update_Height(node); Update_Height(child); return child;

RR右右(左旋)

  1. 失衡节点的右孩子 顶替失衡节点的位置:右孩子提升为当前子树根
  2. 失衡节点下沉,变成其右孩子的左孩子
  3. T2 搬家:右孩子原来的左子树 ,拿出来,作为失衡节点的右子树

AVLNode* Left_Rotate(AVLNode* node) { AVLNode* child = node->rightchild; AVLNode* grandchild = child->leftchild; node->rightchild = grandchild; child->leftchild = node; Update_Height(node); Update_Height(child); return child; }

LR(左-右)左子树的右子树过重

先左旋左孩子,再右旋失衡点

RL(右-左)右子树的左子树过重

先右旋右孩子,再左旋失衡点

AVLNode* Rotate(AVLNode* node) { int ba = Get_BalanceFactor(node); if (ba == 2) { int cba = Get_BalanceFactor(node->leftchild); if (cba == 1) { Right_Rotate(node); }//LL单右旋 if (cba ==-1) { //先左旋再右旋 node->leftchild = Left_Rotate(node->rightchild); } } int ba_right = Get_BalanceFactor(node); if(ba_right==- 2) { int cba_right = Get_BalanceFactor(node->rightchild); if (cba_right==-1){ return; }//RR单左旋 if (cba_right ==1) { //先右旋再左旋 } } } //判断先左旋还是先右旋关键是看失衡节点左右孩子的平衡因子

红黑树

红黑树的特点

红黑树是自平衡二叉搜索树 BST,不是靠高度差约束,靠 5 条颜色规则限制最长路径不超过最短路径 2 倍,保证查找、插入、删除都是 O(logn)

性质:

  1. 每个节点,要么红色,要么黑色。
  2. 根节点一定是黑色。
  3. 所有叶子节点(NIL 空哨兵节点,不是数据节点)是黑色。
  4. 红色节点的两个子节点一定都是黑色(不能有连续红节点,红不能连红)。
  5. 从任意一个节点,到它所有后代 NIL 叶子的所有路径,黑色节点数量相等→ 黑高相同。

核心思想:不强制左右高度差≤1,只限制红节点分布。牺牲一点点查找效率,大幅减少旋转次数。AVL 插入最多 2 次旋转;红黑树删除最多 3 次旋转,插入最多 2 次

红黑树的插入

插入新节点默认为红色,然后向上回溯,看是否违反了红连红规则

  1. 叔叔节点是红色:父、叔叔变黑,祖父变红,继续向上回溯。
  2. 叔叔黑色,LR / LL:旋转 + 变色。
  3. 叔叔黑色,RL / RR:旋转 + 变色
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 11:36:27

MySQL连接报错排查:Linux下socket文件路径问题全解析

刚在 Linux 上装完 MySQL&#xff0c;兴冲冲执行 mysql -uroot -p &#xff0c;结果屏幕弹出一句 Cant connect to local MySQL server through socket /var/lib/mysql/mysql.sock 。这个报错在 MySQL 安装阶段出现得极其高频&#xff0c;几乎每个新手都会撞一次。事实上它…

作者头像 李华
网站建设 2026/10/1 11:36:19

PPT打开乱码?一招“嵌入字体”从根上解决,告别字体替换

方案熬夜改到最后一版&#xff0c;U盘拔下来就冲进会议室。结果双击打开PPT&#xff0c;标题全变成方块&#xff0c;正文是一串看不懂的乱码——那一刻的心情&#xff0c;我相信做过PPT的人都懂。“制作好的PPT打开就乱码”这个问题常年排在办公类搜索榜前列&#xff0c;说明它…

作者头像 李华
网站建设 2026/10/1 11:36:17

基于YOLOv8的滑块验证码缺口检测:300张数据集训练与优化实战

简介&#xff1a;这份滑块数据集面向计算机视觉与深度学习方向的学习者和开发者&#xff0c;尤其适合正在练习目标检测、图像识别与定位任务的中级用户。数据集包含300张已标注图片&#xff0c;每张均配有边界框与类别标签&#xff0c;可用于训练模型识别滑块位置与状态&#x…

作者头像 李华
网站建设 2026/10/1 11:35:27

Excel波士顿矩阵图全流程:散点图、分割线与动态模板

市场复盘会前一天&#xff0c;产品总监丢过来一句"帮我把这几条产品线的家底用一张图讲清楚&#xff0c;谁该保、谁该砍、谁该投"&#xff0c;然后你就对着Excel里那堆销售额和增长率数据发呆了。这种时候&#xff0c;波士顿矩阵图&#xff08;BCG Matrix&#xff09…

作者头像 李华
网站建设 2026/10/1 11:35:09

UG NX圆柱面缠绕/展开曲线全解析:原理、参数与实操避坑指南

在UG NX里做圆柱面上的曲线&#xff0c;我敢说缠绕/展开这个命令是很多人绕不开的一道坎。做凸轮槽的、做螺旋送料管的、做圆柱凸轮机构的&#xff0c;甚至是做产品外观纹理雕刻的&#xff0c;只要你跟“圆柱面”和“曲线”这两个词沾边&#xff0c;迟早会碰到它。这个命令最早…

作者头像 李华
网站建设 2026/10/1 11:33:36

时间复杂度手推指南:从T(n)到O(log n)与双堆中位数

很多人第一次接触复杂度分析&#xff0c;都是在刷题或者准备面试的时候。看到题解上写着"本解法时间复杂度 O(n log n)&#xff0c;空间 O(log n)"&#xff0c;心里大概知道这是"衡量快慢"的东西&#xff0c;但真要自己推一遍&#xff0c;往往就卡在"…

作者头像 李华