爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      红黑树精通指南:面试、实战与源码分析

      首页 知识中心 软件开发 文章详情页

      红黑树精通指南:面试、实战与源码分析

      2025-02-27 09:35:36 阅读次数:11

      删除,插入,操作,红黑树,节点,黑色

      红黑树作为一种自平衡的二叉搜索树,广泛应用于现代计算机科学的各个领域,尤其是在需要频繁执行查找、插入和删除操作的场景中。它的平衡性和高效性使其成为了许多标准库和开源项目的核心数据结构,例如 C++ 的 std::map 和 Java 的 TreeMap。尽管红黑树已经在多个编程语言中得到了实现,但其内部的平衡机制、旋转操作以及应用场景往往让很多开发者感到困惑。

      本文旨在通过对红黑树的全面总结,帮助读者从基础概念到实际应用深入理解这一数据结构的核心原理。首先,我们将介绍红黑树的基本性质、平衡特性以及它与其他自平衡树(如 AVL 树)的比较。然后,我们将分析红黑树在实际框架中的应用,探讨它在大规模数据处理中的优势。接着,文章会进一步深入红黑树的实现,详细解释插入、删除等操作的具体流程,并通过源码展示加深理解。

      无论你是刚接触红黑树的新手,还是希望优化已有代码的开发者,本文都将为你提供全面的知识点与实践经验,帮助你掌握这一经典的数据结构,并在实际项目中加以应用。

      一、对红黑树的理解

      (一)基本理解

      红黑树是一种自平衡的二叉搜索树,它在插入和删除操作时会通过一系列的旋转和颜色调整来保持树的平衡,从而保证了在最坏情况下的查找、插入和删除操作的时间复杂度都是 O(log n),其中 n 是树中节点的数量。

      红黑树精通指南:面试、实战与源码分析

      红黑树具有以下特性:

      1. 节点颜色: 每个节点要么是红色,要么是黑色。
      2. 根节点: 根节点是黑色的。
      3. 叶子节点(NIL节点): 叶子节点是黑色的,也被称为NIL节点。它们不存储任何数据,只是作为树结构的辅助。所有指向NIL节点的指针都被认为是黑色的。
      4. 颜色限制: 不能有两个相连的红色节点,即红色节点不能相邻,每个红色节点的子节点都是黑色的。
      5. 黑高度: 从任意节点出发,到达其每个叶子节点的路径上的黑色节点数量必须相同,这被称为黑高度。这个性质保证了树的平衡。

      红黑树通过旋转操作来维护平衡,主要有左旋和右旋两种操作,它们通过重新排列节点来保持或恢复树的性质。插入和删除操作可能会导致颜色违规或者黑高度违规,因此在执行这些操作后,红黑树需要通过颜色调整和旋转来恢复平衡。

      红黑树的平衡性质和性能保证使它在需要频繁进行插入、删除和查找操作的数据结构中表现出色,比如在各种编程语言的标准库中广泛使用,例如C++的std::map和std::set,以及Java的TreeMap和TreeSet。

      (二)红黑树与AVL树的比较

      红黑树(Red-Black Tree)和AVL树(Adelson-Velsky and Landis Tree)都是自平衡二叉搜索树,用于在动态数据集上进行高效的插入、删除和搜索操作。它们之间有一些相似之处,但也存在一些关键的区别。

      平衡性:

      • 红黑树:红黑树保证了一种弱平衡,即树的高度最多是2倍的对数级别。这使得红黑树在插入和删除操作时具有更高的灵活性,但可能导致一些操作稍微不如AVL树高效。
      • AVL树:AVL树是一种严格的平衡树,保证任何节点的左子树和右子树的高度差(平衡因子)不超过1。这确保了AVL树在平衡方面表现更好,但在插入和删除操作时可能需要更多的旋转来维持平衡。

      插入和删除操作的性能:

      • 红黑树:由于红黑树的平衡性要求相对较弱,插入和删除操作通常需要更少的旋转操作,因此在这些操作上性能可能比AVL树更好。
      • AVL树:AVL树的严格平衡性可能导致插入和删除操作需要更频繁的旋转操作,因此在这些操作上可能比红黑树略逊一筹。

      搜索性能:

      • 两者在搜索操作上都表现良好,因为它们都是二叉搜索树,保持了有序性。

      存储空间:

      • 红黑树:红黑树在维护平衡的同时,需要存储额外的颜色信息,因此通常比AVL树占用更少的存储空间。
      • AVL树:AVL树由于需要维护严格的平衡,可能需要更多的额外指针和信息,因此通常比红黑树占用更多的存储空间。

      适用场景:

      • 红黑树:适用于在插入和删除操作较频繁、搜索操作相对较少的场景,例如在数据库索引中。
      • AVL树:适用于搜索操作频繁、插入和删除操作相对较少的场景,以及对于对树的平衡性要求较高的场景。

      红黑树和AVL树都有各自的优势和适用场景。选择哪种树结构取决于应用的需求和对性能的具体要求。在实际使用中,还要考虑到具体的操作频率、数据量以及对内存占用的限制。

      二、在实际框架中的应用分析

      红黑树在实际的计算机科学和软件工程中有广泛的应用,特别是在需要高效地处理插入、删除和查找操作的情况下。

      1. C++标准库中的std::map和std::set: C++的STL(标准模板库)中提供了std::map和std::set这两个容器,它们分别基于红黑树实现。std::map是一个关联容器,它提供了键-值对的存储和查找功能,而std::set是一个集合容器,用于存储唯一的值。红黑树在这两个容器中保证了高效的插入、删除和查找操作。

      2. Java标准库中的TreeMap和TreeSet: Java的标准库中也提供了TreeMap和TreeSet,它们与C++中的std::map和std::set类似,同样基于红黑树实现。这些容器在Java编程中广泛用于需要有序数据存储和检索的场景。

      3. Linux内核中的进程调度: Linux内核中的进程调度器(例如CFS,Completely Fair Scheduler)使用了红黑树来维护进程的运行队列。红黑树的平衡性能保证了高效的进程切换和调度。

      4. 数据库索引: 数据库系统中的索引结构通常需要高效地支持范围查询、插入和删除操作。红黑树被广泛应用于数据库的索引结构,如B+树的实现中。

      5. 文件系统: 一些文件系统,特别是日志结构文件系统(Log-Structured File Systems,如LFS),可以使用红黑树来维护文件的元数据信息,如文件名和目录结构。

      6. 编译器优化: 在编译器优化中,使用红黑树来维护数据流分析的信息,如变量的定值分析和活跃变量分析。

      7. 网络路由表: 在网络路由器和交换机中,红黑树可以用于高效地管理路由表,以支持快速的路由查找和更新。

      8. 资源管理: 操作系统和服务器软件可能会使用红黑树来管理资源,如内存分配、文件描述符等。

      红黑树在各种领域中都有广泛的应用,主要是因为它能够在保持树的平衡的同时,提供高效的插入、删除和查找操作,从而满足了许多实际应用中对于数据结构的性能要求。

      三、开始深入红黑树

      引荐:检索算法和技术的本质回顾-CSDN博客,内含红黑树以及相关代码展示(高频思考)。

      (一)红黑树的基本概念和性质

      当谈到红黑树的基本概念和性质时,我们通常会涉及它的定义以及保持平衡的关键性质。下面是红黑树的基本概念和性质的详细解释:

      1、红黑树的基本定义

      红黑树是一种自平衡的二叉搜索树,它具有以下特性:

      1. 每个节点要么是红色,要么是黑色。
      2. 根节点是黑色的。
      3. 每个叶子节点(NIL节点)是黑色的,这些叶子节点不存储任何数据,只是作为树结构的辅助。
      4. 不能有两个相连的红色节点。这意味着红色节点不能相邻,每个红色节点的两个子节点都是黑色的。
      5. 从任意节点出发,到达其每个叶子节点的路径上的黑色节点数量必须相同。这个性质保证了树的平衡,确保了最长路径不会超过最短路径的两倍。

      2、红黑性质的五个要点

      1. 根节点是黑色的: 第一个性质要求根节点始终是黑色的,这确保了树的整体结构保持平衡。

      2. 红色子节点性质: 不能有两个相连的红色节点。这意味着从任意节点到其子节点的路径上不能出现连续的红色节点,以避免出现不平衡情况。

      3. 黑高度平衡性质: 从任意节点出发,到达其每个叶子节点的路径上的黑色节点数量必须相同。这确保了树的高度始终保持在一个合理的范围内,从而保证了高效的查找操作。

      4. 红黑性质的维护: 在执行插入和删除操作后,红黑树需要通过旋转和颜色调整来保持这些性质,从而恢复平衡。这些操作保证了在更新操作之后,树仍然是一颗满足红黑性质的树。

      5. 空节点的处理: 空节点(NIL节点)被认为是黑色的。这样可以确保每个路径上的黑色节点数量相等,即使是经过了空节点的路径。

      这五个性质共同保证了红黑树的平衡性和高效性能。红黑树在插入、删除和查找等操作时能够保持相对较低的时间复杂度,使其在很多应用中都得到广泛应用,如数据库索引、编程语言的标准库等。

      引理证明:一颗有n个内部结点的红黑树的高度至多为2lg(n+1)

      这个引理可以通过归纳法来证明。我们可以利用红黑树的性质,特别是黑高度平衡性质,来得出结论。下面是证明的大致步骤:

      基础情况: 当红黑树只有一个内部结点(根节点)时,树的高度为1,而2lg(1+1) = 2,因此基础情况成立。

      归纳假设: 假设对于任意的有k个内部结点的红黑树,其高度至多为2lg(k+1)。

      归纳步骤: 现在我们考虑有k+1个内部结点的红黑树。假设其中的一棵子树有i个内部结点,而另一棵子树有k+1-i个内部结点(这里0 <= i <= k+1)。

      根据归纳假设,i个结点的子树的高度至多为2lg(i+1),而k+1-i个结点的子树的高度至多为2lg((k+1-i)+1)。

      因此,整棵红黑树的高度不会超过这两个子树高度的较大值。即整棵树的高度至多为 max(2lg(i+1), 2lg((k+1-i)+1))。

      我们要找到使得这个值最大的i,这个值在i=k/2时达到最大。所以,整棵红黑树的高度至多为 max(2lg(k/2+1), 2lg((k/2+1)+1))。

      进一步简化这个表达式,我们可以得到整棵红黑树的高度至多为 2 + max(2lg(k/2+1), 2lg((k/2+1)+1))。

      通过化简可以得到 2 + 2lg(k+1),这就证明了有k+1个内部结点的红黑树的高度至多为2lg(k+2)。

      由归纳法的假设和步骤,我们可以得出结论,对于任意有n个内部结点的红黑树,其高度至多为2lg(n+1)。

      (二)对旋转的基本理解

      在数据结构中,旋转是一种常见的操作,用于调整树或其他数据结构的结构以保持平衡或满足某些性质。在红黑树、AVL树、二叉搜索树等数据结构中,旋转操作通常用于平衡树的结构,以确保高效的插入、删除和查找操作。旋转操作有两种基本类型:左旋和右旋。下面我将解释这两种旋转的基本理解:

      1、左旋(Left Rotation)

      左旋是一种将某个节点的右子节点旋转上来的操作。它会将当前节点下移,并且将其右子节点提升为新的父节点。这可以用于解决树向右倾斜的情况,以保持树的平衡。左旋的基本步骤:

      • 将当前节点的右子节点设为新的父节点。
      • 将新的父节点的左子节点设为当前节点的右子节点。
      • 如果当前节点有父节点,将新的父节点替代当前节点的位置。
      • 将当前节点设为新的父节点的左子节点。

      红黑树精通指南:面试、实战与源码分析

      2、右旋(Right Rotation)

      右旋是一种将某个节点的左子节点旋转上来的操作。它会将当前节点下移,并且将其左子节点提升为新的父节点。这可以用于解决树向左倾斜的情况,以保持树的平衡。右旋的基本步骤:

      • 将当前节点的左子节点设为新的父节点。
      • 将新的父节点的右子节点设为当前节点的左子节点。
      • 如果当前节点有父节点,将新的父节点替代当前节点的位置。
      • 将当前节点设为新的父节点的右子节点。

      红黑树精通指南:面试、实战与源码分析

      旋转操作可以使树保持平衡,确保最长路径和最短路径之间的差距不会过大,从而保证了树在查找、插入和删除等操作时的高效性能。在红黑树、AVL树等自平衡树结构中,旋转是实现平衡的关键步骤之一。

      3、代码展示

      package org.zyf.javabasic.rbtest;
      
      /**
       * @program: zyfboot-javabasic
       * @description:
       * @author: zhangyanfeng
       * @create: 2023-08-19 12:38
       **/
      public class RedBlackTree {
      
          private TreeNode root;
      
          public RedBlackTree() {
              root = null;
          }
      
          // 左旋操作
          private void leftRotate(TreeNode x) {
              TreeNode y = x.right; // y 为 x 的右子节点
              x.right = y.left; // 将 y 的左子节点设置为 x 的右子节点
              if (y.left != null) {
                  y.left.parent = x;
              }
              y.parent = x.parent; // 更新 y 的父节点
              if (x.parent == null) {
                  root = y;
              } else if (x == x.parent.left) {
                  x.parent.left = y;
              } else {
                  x.parent.right = y;
              }
              y.left = x; // 将 x 设为 y 的左子节点
              x.parent = y;
          }
      
          // 右旋操作
          private void rightRotate(TreeNode y) {
              TreeNode x = y.left; // x 为 y 的左子节点
              y.left = x.right; // 将 x 的右子节点设置为 y 的左子节点
              if (x.right != null) {
                  x.right.parent = y;
              }
              x.parent = y.parent; // 更新 x 的父节点
              if (y.parent == null) {
                  root = x;
              } else if (y == y.parent.left) {
                  y.parent.left = x;
              } else {
                  y.parent.right = x;
              }
              x.right = y; // 将 y 设为 x 的右子节点
              y.parent = x;
          }
      
      }
      

      (三)插入操作基本理解

      1、以图形方式进行初步理解

      红黑树规定,插入的节点必须是红色的。而且,二叉查找树中新插入的节点都是放在叶子节点上。

      关于插入操作的平衡调整,有这样两种特殊情况:

      • 如果插入节点的父节点是黑色的,那我们什么都不用做,它仍然满足红黑树的定义。
      • 如果插入的节点是根节点,那我们直接改变它的颜色,把它变成黑色就可以了。

      除此之外,其他情况都会违背红黑树的定义,需要进行调整,调整的过程包含两种基础的操作:左右旋转和改变颜色。

      红黑树的平衡调整过程是一个迭代的过程。把正在处理的节点叫作关注节点。关注节点会随着不停地迭代处理,而不断发生变化。最开始的关注节点就是新插入的节点。新节点插入之后,如果红黑树的平衡被打破,那一般会有下面三种情况:

      备注:我们只需要根据每种情况的特点,不停地调整,就可以让红黑树继续符合定义,也就是继续保持平衡。为了简化描述,把父节点的兄弟节点叫作叔叔节点,父节点的父节点叫作祖父节点。

      情况一:如果关注节点是 a,它的叔叔节点 d 是红色

      红黑树精通指南:面试、实战与源码分析

      具体操作为:将关注节点 a 的父节点 b、叔叔节点 d 的颜色都设置成黑色;将关注节点 a 的祖父节点 c 的颜色设置成红色;关注节点变成 a 的祖父节点 c;跳到情况二或者情况三。

      情况二:如果关注节点是 a,它的叔叔节点 d 是黑色,关注节点 a 是其父节点 b 的右子节点

      红黑树精通指南:面试、实战与源码分析

      具体操作为:关注节点变成节点 a 的父节点 b;围绕新的关注节点b 左旋;跳到情况三。

      情况三:如果关注节点是 a,它的叔叔节点 d 是黑色,关注节点 a 是其父节点 b 的左子节点

      红黑树精通指南:面试、实战与源码分析

      具体操作为:围绕关注节点 a 的祖父节点 c 右旋;将关注节点 a 的父节点 b、兄弟节点 c 的颜色互换,调整结束。

      2、详细步骤分析总结

      当在红黑树中执行插入操作时,需要考虑两个主要方面:保持二叉搜索树性质和保持红黑性质。以下是插入操作的详细步骤,包括可能的旋转操作和颜色调整。

      插入操作的基本步骤:

      • 将新节点插入到BST中: 首先,将新节点插入到红黑树中,就像在普通的二叉搜索树中一样。新节点会被标记为红色,因为它可能会破坏红黑性质的第一个性质(根节点必须是黑色)。

      • 检查红黑性质: 插入新节点后,可能会破坏红黑性质。需要通过一系列的操作来调整以确保所有的红黑性质得到满足。

      颜色调整: 在进行旋转操作之前,需要进行颜色调整以满足红黑性质。以下是颜色调整的可能情况:

      • 父节点为黑色: 如果插入的节点的父节点是黑色的,那么树的结构没有破坏,不需要进一步的调整。

      • 父节点为红色: 如果插入的节点的父节点是红色的,那么可能会破坏红黑性质的第二个性质(不能有两个相连的红色节点)。在这种情况下,需要考虑插入节点的叔叔节点(父节点的兄弟节点)的颜色。

        a. 叔叔节点是红色: 如果叔叔节点是红色的,可以通过改变父节点和叔叔节点的颜色,然后将问题向上移动到父节点。这样可以保持黑高度平衡性质。

        b. 叔叔节点是黑色或缺失: 如果叔叔节点是黑色的(包括叔叔节点为NIL节点),需要通过旋转来修复这种情况。

      旋转操作: 旋转操作用于调整树的结构,以保持红黑性质。以下是可能的旋转情况:

      • 左旋和右旋: 左旋和右旋操作已在之前的回答中进行了解释。当插入节点的父节点是红色,而叔叔节点是黑色或缺失时,需要进行旋转操作来保持红黑性质。

      总结: 插入操作的关键是保持红黑性质。颜色调整和旋转操作可以确保插入操作后的红黑树依然满足所有性质。需要注意的是,具体的情况会因树的结构而异,因此在编写插入操作的代码时,需要仔细考虑各种可能的情况,并根据实际情况进行相应的调整和处理。

      3、代码展示说明

      package org.zyf.javabasic.rbtest;
      
      /**
       * @program: zyfboot-javabasic
       * @description:
       * @author: zhangyanfeng
       * @create: 2023-08-19 12:58
       **/
      public class RedBlackTreeInsert {
      
          private TreeNode root;
      
          enum Color {
              RED, BLACK
          }
      
          class TreeNode {
              int key;
              Color color;
              TreeNode left;
              TreeNode right;
              TreeNode parent;
      
              public TreeNode(int key, Color color) {
                  this.key = key;
                  this.color = color;
                  this.left = null;
                  this.right = null;
                  this.parent = null;
              }
          }
      
          public void insert(int key) {
              TreeNode newNode = new TreeNode(key, Color.RED);
              if (root == null) {
                  root = newNode;
              } else {
                  TreeNode parent = findParentForInsert(root, key);
                  if (key < parent.key) {
                      parent.left = newNode;
                  } else {
                      parent.right = newNode;
                  }
                  newNode.parent = parent;
                  insertFixup(newNode);
              }
          }
      
          private TreeNode findParentForInsert(TreeNode node, int key) {
              TreeNode parent = null;
              while (node != null) {
                  parent = node;
                  if (key < node.key) {
                      node = node.left;
                  } else {
                      node = node.right;
                  }
              }
              return parent;
          }
      
          private void insertFixup(TreeNode node) {
              while (node.parent != null && node.parent.color == Color.RED) {
                  if (node.parent == node.parent.parent.left) {
                      TreeNode uncle = node.parent.parent.right;
                      if (uncle != null && uncle.color == Color.RED) {
                          node.parent.color = Color.BLACK;
                          uncle.color = Color.BLACK;
                          node.parent.parent.color = Color.RED;
                          node = node.parent.parent;
                      } else {
                          if (node == node.parent.right) {
                              node = node.parent;
                              leftRotate(node);
                          }
                          node.parent.color = Color.BLACK;
                          node.parent.parent.color = Color.RED;
                          rightRotate(node.parent.parent);
                      }
                  } else {
                      // 同上,但是左右对调
                  }
              }
              root.color = Color.BLACK;
          }
      
          private void leftRotate(TreeNode x) {
              // 左旋操作的代码
          }
      
          private void rightRotate(TreeNode y) {
              // 右旋操作的代码
          }
      
      }
      

      (四)删除操作基本理解

      1、以图形方式进行初步理解

      删除操作的平衡调整分为两步:

      • 第一步是针对删除节点初步调整。初步调整只是保证整棵红黑树在一个节点删除之后,仍然满足最后一条定义的要求,也就是说,每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点;
      • 第二步是针对关注节点进行二次调整,让它满足红黑树的第三条定义,即不存在相邻的两个红色节点。
      第一步:针对删除节点初步调整

      红黑树的定义中“只包含红色节点和黑色节点”,经过初步调整之后,为了保证满足红黑树定义的最后一条要求,有些节点会被标记成两种颜色,“红 - 黑”或者“黑 - 黑”。如果一个节点被标记为了“黑 - 黑”,那在计算黑色节点个数的时候,要算成两个黑色节点。

      备注:如果一个节点既可以是红色,也可以是黑色,图中用一半红色一半黑色来表示。如果一个节点是“红 - 黑”或者“黑 - 黑”,图中用左上角的一个小黑点来表示额外的黑色。

      情况一:如果要删除的节点是 a,它只有一个子节点 b

      红黑树精通指南:面试、实战与源码分析

      具体操作为:删除节点 a,并且把节点 b 替换到节点 a 的位置,这一部分操作跟普通的二叉查找树的删除操作一样;节点 a 只能是黑色,节点 b 也只能是红色,其他情况均不符合红黑树的定义。这种情况下,我们把节点 b 改为黑色;调整结束,不需要进行二次调整。

      情况二:如果要删除的节点 a 有两个非空子节点,并且它的后继节点就是节点 a 的右子节点 c

      红黑树精通指南:面试、实战与源码分析

      具体操作为:如果节点 a 的后继节点就是右子节点 c,那右子节点 c 肯定没有左子树。我们把节点 a 删除,并且将节点 c 替换到节点 a 的位置。这一部分操作跟普通的二叉查找树的删除操作无异;然后把节点 c 的颜色设置为跟节点 a 相同的颜色;如果节点 c 是黑色,为了不违反红黑树的最后一条定义,我们给节点 c 的右子节点 d 多加一个黑色,这个时候节点 d 就成了“红 - 黑”或者“黑 - 黑”;这个时候,关注节点变成了节点 d,第二步的调整操作就会针对关注节点来做。

      情况三:如果要删除的是节点 a,它有两个非空子节点,并且节点 a 的后继节点不是右子节点

      红黑树精通指南:面试、实战与源码分析

      具体操作为:找到后继节点 d,并将它删除,删除后继节点 d 的过程参照 CASE 1;将节点 a 替换成后继节点 d;把节点 d 的颜色设置为跟节点 a 相同的颜色;如果节点 d 是黑色,为了不违反红黑树的最后一条定义,我们给节点 d 的右子节点 c 多加一个黑色,这个时候节点 c 就成了“红 - 黑”或者“黑 - 黑”;这个时候,关注节点变成了节点 c,第二步的调整操作就会针对关注节点来做。

      第二步:针对关注节点进行二次调整

      初步调整之后,关注节点变成了“红 - 黑”或者“黑 - 黑”节点。针对这个关注节点,再分四种情况来进行二次调整。

      备注:二次调整是为了让红黑树中不存在相邻的红色节点。

      情况一:如果关注节点是 a,它的兄弟节点 c 是红色的

      红黑树精通指南:面试、实战与源码分析

      具体操作:围绕关注节点 a 的父节点 b 左旋;关注节点 a 的父节点 b 和祖父节点 c 交换颜色;关注节点不变;继续从四种情况中选择适合的规则来调整。

      情况二:如果关注节点是 a,它的兄弟节点 c 是黑色的,并且节点 c 的左右子节点 d、e 都是黑色的

      红黑树精通指南:面试、实战与源码分析

      具体操作:将关注节点 a 的兄弟节点 c 的颜色变成红色;从关注节点 a 中去掉一个黑色,这个时候节点 a 就是单纯的红色或者黑色;给关注节点 a 的父节点 b 添加一个黑色,这个时候节点 b 就变成了“红 - 黑”或者“黑 - 黑”;关注节点从 a 变成其父节点 b;继续从四种情况中选择符合的规则来调整。

      情况三:如果关注节点是 a,它的兄弟节点 c 是黑色,c 的左子节点 d 是红色,c 的右子节点 e 是黑色

      红黑树精通指南:面试、实战与源码分析

      具体操作:围绕关注节点 a 的兄弟节点 c 右旋;节点 c 和节点 d 交换颜色;关注节点不变;跳转到 CASE 4,继续调整。

      情况四:如果关注节点 a 的兄弟节点 c 是黑色的,并且 c 的右子节点是红色的

      红黑树精通指南:面试、实战与源码分析

      具体操作:围绕关注节点 a 的父节点 b 左旋;将关注节点 a 的兄弟节点 c 的颜色,跟关注节点 a 的父节点 b 设置成相同的颜色;将关注节点 a 的父节点 b 的颜色设置为黑色;从关注节点 a 中去掉一个黑色,节点 a 就变成了单纯的红色或者黑色;将关注节点 a 的叔叔节点 e 设置为黑色;调整结束。

      2、详细步骤分析总结

      红黑树的删除操作相对比较复杂,因为删除一个节点可能会引发多种情况,需要仔细考虑旋转和颜色调整来维持红黑性质。以下是红黑树中执行删除操作的详细步骤,包括可能涉及的旋转和颜色调整。

      删除操作的基本步骤:

      • 找到要删除的节点: 首先,找到需要删除的目标节点。如果目标节点有两个子节点,可以选择它的后继节点(即右子树中最小的节点)来替代删除。

      • 删除节点并用子节点替代: 删除目标节点,并用它的子节点(或者后继节点)来替代它的位置。

      颜色调整和旋转: 在删除操作中,可能会导致红黑性质被破坏。以下是删除操作中可能需要考虑的情况:

      • 删除节点为红色节点: 如果删除的节点是红色的,它不会破坏红黑性质。只需将它从树中移除即可。

      • 删除节点为黑色节点: 删除的黑色节点可能会引发性质的破坏,需要进行颜色调整和旋转操作。

        a. 删除节点有一个红色子节点: 如果删除的节点有一个红色子节点,用红色子节点替代删除节点,然后将子节点染成黑色,以保持黑高度性质。

        b. 删除节点没有红色子节点: 如果删除的节点没有红色子节点,那么需要通过颜色调整和旋转来修复。

        i. 删除节点是根节点:如果删除的节点是根节点,直接删除并返回。

        ii.删除节点的兄弟节点是红色:如果删除节点的兄弟节点是红色的,可以通过旋转和颜色调整将情况转化为其他情况处理。

        iii. 删除节点的兄弟节点是黑色:如果删除节点的兄弟节点是黑色的,可能需要进行旋转和颜色调整来恢复平衡。

        - 双重黑色节点向兄弟节点的借:如果删除的节点是黑色的,兄弟节点是黑色的,而兄弟节点有至少一个红色子节点,可以通过旋转和颜色调整来消除双重黑色。

        - 双重黑色节点没有向兄弟节点的借:如果删除的节点是黑色的,兄弟节点是黑色的,而兄弟节点没有红色子节点,需要将双重黑色节点向上传递。

      总结: 删除操作在红黑树中是相对复杂的,因为涉及到多种情况的处理。颜色调整和旋转操作的目标是保持红黑性质,并确保树的结构平衡。确保你的删除操作代码能够正确处理所有可能的情况,以保证红黑树的正确性。在实际开发中,逐步编写代码并进行测试是验证删除操作的有效方法。

      3、具体代码展示

      package org.zyf.javabasic.rbtest;
      
      /**
       * @program: zyfboot-javabasic
       * @description:
       * @author: zhangyanfeng
       * @create: 2023-08-19 13:10
       **/
      public class RedBlackTreeDelete {
      
          private TreeNode root;
      
          enum Color {
              RED, BLACK
          }
      
          class TreeNode {
              int key;
              Color color;
              TreeNode left;
              TreeNode right;
              TreeNode parent;
      
              public TreeNode(int key, Color color) {
                  this.key = key;
                  this.color = color;
                  this.left = null;
                  this.right = null;
                  this.parent = null;
              }
          }
      
          // 省略其他方法...
      
          public void delete(int key) {
              TreeNode nodeToDelete = findNodeToDelete(root, key);
              if (nodeToDelete != null) {
                  deleteNode(nodeToDelete);
              }
          }
      
          private void deleteNode(TreeNode nodeToDelete) {
              TreeNode replacementNode = (nodeToDelete.left != null && nodeToDelete.right != null)
                      ? findSuccessor(nodeToDelete.right)
                      : nodeToDelete;
      
              TreeNode childNode = (replacementNode.left != null) ? replacementNode.left : replacementNode.right;
      
              if (childNode != null) {
                  childNode.parent = replacementNode.parent;
              }
      
              if (replacementNode.parent == null) {
                  root = childNode;
              } else if (replacementNode == replacementNode.parent.left) {
                  replacementNode.parent.left = childNode;
              } else {
                  replacementNode.parent.right = childNode;
              }
      
              if (replacementNode != nodeToDelete) {
                  nodeToDelete.key = replacementNode.key; // 将替代节点的值赋给被删除节点
              }
      
              if (replacementNode.color == Color.BLACK) {
                  deleteFixup(childNode, replacementNode.parent); // 进行颜色调整和可能的旋转操作
              }
          }
      
          // 寻找要删除的节点
          private TreeNode findNodeToDelete(TreeNode current, int key) {
              if (current == null || current.key == key) {
                  return current;
              }
              if (key < current.key) {
                  return findNodeToDelete(current.left, key);
              }
              return findNodeToDelete(current.right, key);
          }
      
          // 寻找后继节点
          private TreeNode findSuccessor(TreeNode node) {
              TreeNode current = node;
              while (current.left != null) {
                  current = current.left;
              }
              return current;
          }
      
          private void deleteFixup(TreeNode x, TreeNode xParent) {
              while (x != root && (x == null || x.color == Color.BLACK)) {
                  if (x == xParent.left) {
                      TreeNode sibling = xParent.right;
      
                      if (sibling.color == Color.RED) {
                          // 情况 1:兄弟节点为红色
                          sibling.color = Color.BLACK;
                          xParent.color = Color.RED;
                          leftRotate(xParent);
                          sibling = xParent.right;
                      }
      
                      if ((sibling.left == null || sibling.left.color == Color.BLACK) &&
                              (sibling.right == null || sibling.right.color == Color.BLACK)) {
                          // 情况 2:兄弟节点和其子节点都为黑色
                          sibling.color = Color.RED;
                          x = xParent;
                          xParent = xParent.parent;
                      } else {
                          if (sibling.right == null || sibling.right.color == Color.BLACK) {
                              // 情况 3:兄弟节点是黑色,且兄弟节点的左子节点是红色
                              if (sibling.left != null) {
                                  sibling.left.color = Color.BLACK;
                              }
                              sibling.color = Color.RED;
                              rightRotate(sibling);
                              sibling = xParent.right;
                          }
      
                          // 情况 4:兄弟节点是黑色,且兄弟节点的右子节点是红色
                          sibling.color = xParent.color;
                          xParent.color = Color.BLACK;
                          if (sibling.right != null) {
                              sibling.right.color = Color.BLACK;
                          }
                          leftRotate(xParent);
                          x = root; // 完成调整,退出循环
                      }
                  } else {
                      // 同上,但是左右对调
                  }
              }
      
              if (x != null) {
                  x.color = Color.BLACK; // 将 x 染黑
              }
          }
      
          private void leftRotate(TreeNode x) {
              TreeNode y = x.right;
              x.right = y.left;
              if (y.left != null) {
                  y.left.parent = x;
              }
              y.parent = x.parent;
              if (x.parent == null) {
                  root = y;
              } else if (x == x.parent.left) {
                  x.parent.left = y;
              } else {
                  x.parent.right = y;
              }
              y.left = x;
              x.parent = y;
          }
      
          private void rightRotate(TreeNode y) {
              TreeNode x = y.left;
              y.left = x.right;
              if (x.right != null) {
                  x.right.parent = y;
              }
              x.parent = y.parent;
              if (y.parent == null) {
                  root = x;
              } else if (y == y.parent.left) {
                  y.parent.left = x;
              } else {
                  y.parent.right = x;
              }
              x.right = y;
              y.parent = x;
          }
      }
      

      四、源码上的分析

      红黑树在很多编程语言和算法库中都有相应的实现:

      1. C++ STL 源码分析: C++ 的标准模板库(STL)中包含了红黑树的实现,你可以阅读 STL 的源码,特别是 std::map 和 std::set 的实现。

      2. Java TreeMap 和 TreeSet 源码分析: Java 中的 TreeMap 和 TreeSet 类是基于红黑树实现的。

      3. Linux 内核红黑树: Linux 内核中有红黑树的实现,用于高效地管理各种数据结构。

      (一)TreeMap源码简单总结

      红黑树操作的主要源码部分

      1. 插入操作 (put 方法): 在插入新的键值对时,TreeMap 会调用 put 方法来处理插入操作。在插入的过程中,会调用红黑树的旋转和颜色调整操作来保持红黑树的性质。

      2. 删除操作 (remove 方法): 删除操作也会涉及到红黑树的旋转和颜色调整。当删除一个节点后,TreeMap 会通过调用红黑树的 fixAfterDeletion 方法来修复性质。

      3. 旋转操作 (rotateLeft 和 rotateRight 方法): 旋转操作用于调整红黑树的平衡,包括左旋和右旋。在 TreeMap 中,rotateLeft 方法和 rotateRight 方法用于进行旋转操作。

      4. 颜色调整操作: 在插入和删除操作中,通过改变节点的颜色来调整红黑树的性质。TreeMap 会根据情况调用红黑树节点的 fixAfterInsertion 和 fixAfterDeletion 方法来进行颜色调整。

      注意事项

      1. 性质维护: 红黑树是一种自平衡二叉搜索树,需要保持五个红黑性质。在所有操作(插入、删除等)后,必须确保红黑性质得到满足。

      2. 平衡操作: 旋转操作是红黑树的关键部分,用于保持树的平衡性。TreeMap 的 rotateLeft 和 rotateRight 方法用于执行左旋和右旋。

      3. 颜色调整: 插入和删除操作可能会导致性质被破坏,通过改变节点的颜色来恢复性质。注意在进行颜色调整时,要确保叶子节点(即 null 节点)的颜色为黑色。

      4. 迭代器和遍历: TreeMap 提供了迭代器用于遍历键值对。在遍历过程中,应该按照中序遍历来访问节点,以保持有序性。

      5. 自定义比较器: TreeMap 可以使用默认的键比较器(如果键类型实现了 Comparable 接口),或者使用自定义的比较器。在插入和删除时,要根据比较结果来确定节点的位置。

      6. 性能: 尽管红黑树保持了一定的平衡性,但在极端情况下,可能会导致树高较高,影响性能。在某些情况下,考虑使用其他数据结构(如哈希表)来获得更好的性能。

      (二)Linux 内核红黑树

      Linux 内核中的红黑树实现位于头文件 include/linux/rbtree.h 中。这个头文件定义了红黑树的数据结构和相关的操作函数。以下是 Linux 内核中红黑树的一些关键部分:

      // 内核红黑树节点结构
      struct rb_node {
          unsigned long  __rb_parent_color;
          struct rb_node *rb_right;
          struct rb_node *rb_left;
      } __attribute__((aligned(sizeof(long))));
      
      // 红黑树根节点
      struct rb_root {
          struct rb_node *rb_node;
      };
      
      // 初始化红黑树根节点
      static inline void rb_init_node(struct rb_node *rb)
      {
          rb->__rb_parent_color = 0;
          rb->rb_right = NULL;
          rb->rb_left = NULL;
          RB_CLEAR_NODE(rb);
      }
      
      // 插入节点到红黑树
      void rb_insert_color(struct rb_node *, struct rb_root *);
      
      // 从红黑树中删除节点
      void rb_erase(struct rb_node *, struct rb_root *);
      
      // 红黑树的旋转操作
      static inline void rb_rotate_left(struct rb_node *node, struct rb_root *root)
      {
          // 左旋操作实现
      }
      
      static inline void rb_rotate_right(struct rb_node *node, struct rb_root *root)
      {
          // 右旋操作实现
      }

      上面的示例是非常简化的,实际内核中的红黑树实现更加复杂和全面。在 Linux 内核中,红黑树被广泛用于管理各种数据结构,如文件系统中的目录项、网络协议栈中的路由表等。可以通过查看实际的内核源码文件来了解更多细节。

      五、总结

      红黑树是一种非常高效且广泛应用的自平衡二叉搜索树,它通过一系列简单的颜色标记和旋转操作,确保了在最坏情况下查找、插入和删除操作的时间复杂度始终保持在 O(log n) 级别。其平衡性保证了即使在频繁的动态操作下,树的高度也不会过大,避免了类似普通二叉搜索树在极端情况下退化为链表的性能问题。

      本文首先介绍了红黑树的基本性质,包括节点颜色、平衡性要求和黑高度等。接着,我们分析了红黑树与 AVL 树的区别,强调了红黑树在插入和删除操作时的优势,以及在内存和空间上的高效性。通过对红黑树在实际框架中的应用分析,展示了它在如数据库索引、内存管理等领域的广泛应用。

      在深入红黑树的实现部分,我们详细探讨了插入和删除操作中的平衡调整机制,介绍了旋转操作和颜色调整的实际应用,帮助读者了解如何在代码中实现这些操作,并保证树的平衡性。特别是针对红黑树中的插入和删除,处理方式具有一定的复杂性,需要考虑多种不同的情况和调整策略,因此理解每一步操作的细节对于实现正确的红黑树至关重要。

      通过源码分析,我们进一步探讨了红黑树的实现细节,结合 Java 和 Linux 内核中的具体代码,展示了如何在实际开发中使用红黑树。这些源码不仅加深了我们对红黑树的理解,也为在开发中实际应用红黑树提供了宝贵的经验。

      总之,红黑树作为一种经典的数据结构,凭借其高效的性能和广泛的适用性,已经成为了很多编程语言和应用框架的核心组件。掌握红黑树的原理和实现,不仅能帮助我们在实际项目中解决各种复杂的数据管理问题,也能为提升我们对数据结构和算法的理解打下坚实的基础。希望本文能够帮助大家更深入地理解红黑树,并在今后的工作中充分应用这一强大的工具。

      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://zyfcodes.blog.csdn.net/article/details/106080394,作者:张彦峰ZYF,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:National _C_C++_A\\3.埃及分数

      下一篇:【数据库】时序数据库InfluxDB 性能测试和为什么时序数据库更快、时序数据库应用场景

      相关文章

      2025-05-19 09:04:44

      spark控制台没显示其他机器

      spark控制台没显示其他机器

      2025-05-19 09:04:44
      Spark , 节点 , 集群
      2025-05-19 09:04:38

      js本地上传图片后实现预览与删除功能

      js本地上传图片后实现预览与删除功能

      2025-05-19 09:04:38
      js , 上传 , 删除 , 文件
      2025-05-19 09:04:14

      二叉树经典OJ练习

      二叉树经典OJ练习

      2025-05-19 09:04:14
      root , 二叉树 , 子树 , 节点 , 遍历
      2025-05-14 10:33:31

      计算机初级选手的成长历程——操作符详解(2)

      计算机初级选手的成长历程——操作符详解(2)

      2025-05-14 10:33:31
      对象 , 操作 , 操作符 , 表达式 , 运算 , 逗号 , 逻辑
      2025-05-14 10:03:13

      【MySQL】-数据库优化(索引)

      索引(index)是帮助数据库高效获取数据的数据结构

      2025-05-14 10:03:13
      index , Tree , 二叉 , 搜索 , 数据 , 索引 , 节点
      2025-05-14 10:02:48

      MongoDB常用管理命令(1)

      MongoDB常用管理命令(1)

      2025-05-14 10:02:48
      会话 , 命令 , 操作 , 节点
      2025-05-14 09:51:15

      java实现管线拓扑关系连通性分析

      管线拓扑关系的连通性分析通常涉及图论(Graph Theory)中的概念,特别是无向图(Undirected Graph)的遍历算法,如深度优先搜索(DFS, Depth-First Search)或广度优先搜索(BFS, Breadth-First Search)。

      2025-05-14 09:51:15
      BFS , DFS , 复杂度 , 搜索 , 节点 , 访问 , 遍历
      2025-05-13 09:51:17

      rac dg节点2在修改完alert_oracle_sid.log文件名,主库切换日志后备库节点2不产生新的日志文件

      rac dg节点2在修改完alert_oracle_sid.log文件名,主库切换日志后备库节点2不产生新的日志文件

      2025-05-13 09:51:17
      dg , rac , 日志 , 节点
      2025-05-13 09:51:17

      rac环境节点1修改参数后,节点2启动出现ORA-01105、ORA-01677告警

      rac环境节点1修改参数后,节点2启动出现ORA-01105、ORA-01677告警

      2025-05-13 09:51:17
      ORA , rac , 节点
      2025-05-13 09:50:48

      oracle数据库中删除表后创建同名表,如何闪回删除后的表?

      oracle数据库中删除表后创建同名表,如何闪回删除后的表?

      2025-05-13 09:50:48
      oracle , 删除
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5243066

      查看更多

      最新文章

      二叉搜索树中第K小的元素

      2025-05-13 09:50:17

      用go语言,现有一棵无向、无根的树,树中有 n 个节点,按从 0 到 n - 1 编号 给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges

      2025-05-13 09:49:12

      代码 测试用例 测试结果 测试结果 两两交换链表中的节点

      2025-05-09 09:30:19

      DS进阶:并查集

      2025-05-09 08:50:35

      基于springboot图书借阅管理系统【源码+数据库】

      2025-05-08 09:03:21

      数据结构知识点

      2025-05-08 09:03:07

      查看更多

      热门文章

      走读源码探究HashMap的树化时机以及红黑树的操作机制

      2023-03-02 10:21:34

      jquery-节点操作

      2023-06-13 08:29:18

      【C++】RBTree——红黑树

      2023-07-26 08:09:37

      Stream流式编程详解

      2023-07-17 08:10:17

      app自动化测试——XPATH高级用法

      2024-11-15 06:46:25

      Java数据结构与算法:AVL树

      2024-12-06 06:23:53

      查看更多

      热门标签

      java Java python 编程开发 代码 开发语言 算法 线程 Python html 数组 C++ 元素 javascript c++
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      表与索引分布在不同表空间,删除其中一个表空间的测试

      算法题:25. K 个一组翻转链表 (困难)一次AC(题目+思路+代码+注释)

      关联式数据结构_红黑树剖析 #C++

      【C++BFS】802. 找到最终的安全状态

      【软件工程】进程资源图理解与化简

      【C++贪心】2366. 将数组排序的最少替换次数|2060

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号