news 2026/9/27 6:05:37

C++进阶——红黑树

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++进阶——红黑树

一、红黑树的概念

红黑树是一棵二叉搜索树,他的每个节点增加一个数据来存储颜色,可以是红色或者黑色。通过对任何一条从根到叶子的路径上各个结点的颜色进行约束,红黑树确保没有一条路径会超出其他路径2倍的长度

1.1 红黑树的规则

  • 每个节点不是红色就是黑色
  • 根节点是黑色的
  • 如果一个节点是红的,他的孩子节点就是黑色的,这意味着任意一条路径不能出现连续的红色节点
  • 对任意一个节点,从该节点到其所有NULL节点的简单路径上,均包含相同数量的黑色节点

当我们能时刻满足这四条规则时,我们就能确保树上没有一条路径会超出其他路径2倍的长度。

1.2 红黑树的效率

假设N是红黑树树中结点数量,h是最短路径长度,则2^h-1<=N<2^(2*h)-1,由此推出:h大约为logN,也就意味着红黑树增删查改最坏也就是走最长路径2*logN,那么时间复杂度还是O(logN)

红黑树的表达相对AVL树要抽象一些,AVL树通过控制高度差直观地控制了平衡。红黑树通过4条规则的约束,实现了近似平衡,它们的效率都是同一档次,但红黑树插入节点时旋转次数更少

二、红黑树的实现

2.1 红黑树的结构

enum Color { RED, BLACK }; template<class K,class V> struct RBTreeNode { pair<K, V> _kv; Color _col; RBTreeNode<K, V>* _parent; RBTreeNode<K, V>* _left; RBTreeNode<K, V>* _right; RBTreeNode(const pair<K,V> kv) :_kv(kv) ,_parent(nullptr) ,_left(nullptr) ,_right(nullptr) { } }; template<class K,class V> class RBTree { typedef RBTreeNode<K, V> Node; public: RBTree(Node* root=nullptr) :_root(root) { } private: Node* _root; };

2.2 红黑树的插入

2.2.1 节点插入的大概过程
  1. 插入一个值按二叉搜索树规则插入,插入后只需观察是否符合红黑树的四条规则
  2. 如果是空树插入,新增节点是黑色节点。如果不是空树,选中节点必须是红色节点,若插入黑色节点,会破坏规则4
  3. 非空树插入后,新增节点的父节点如果是黑色,就未破坏规则,插入结束
  4. 若父节点是红色的,则违反规则3。据下图:c是红色,p是红色,g必为黑色

2.2.2 情况1:变色

若c、p、u均为红色节点,g为黑色节点,就将p、u变黑,g变红;再将g变为新的c,向上更新

2.2.3 情况2:单旋+变色

c、p为红,g为黑,u不存在或u为黑:

  • u不存在,c必为新增节点,因为若c为原来的g节点,那么它因为孩子节点变色而变红,原来是黑色节点,但u的分支后面没有黑色节点了,不满足每条分支黑色节点数量相等
  • u存在且为黑,c一定不是新增节点

2.2.4 情况3:双旋+变色

c、p为红,g为黑,u不存在或存在为黑:

2.3 红黑树的验证

  1. 规则1枚举颜色类型,天然保证了颜色只有黑色和红色
  2. 规则2可直接验证
  3. 规则3前序遍历检查,遇到红色节点就查孩子不太方便,可反过来检查父节点颜色
  4. 前序遍历,遍历时用形参记录当前节点到根黑色节点数量,直到空节点,再选任意一条路径黑色节点作为参考值,依次比较

三、全部实现代码

#pragma once #include<iostream> #include<cassert> using namespace std; enum Color { RED, BLACK }; template<class K,class V> struct RBTreeNode { pair<K, V> _kv; Color _col; RBTreeNode<K, V>* _parent; RBTreeNode<K, V>* _left; RBTreeNode<K, V>* _right; RBTreeNode(const pair<K,V> kv) :_kv(kv) ,_parent(nullptr) ,_left(nullptr) ,_right(nullptr) { } }; template<class K,class V> class RBTree { typedef RBTreeNode<K, V> Node; public: RBTree(Node* root=nullptr) :_root(root) { } bool Insert(const pair<K, V>& kv) { Node* newnode = new Node(kv); newnode->_col = RED; if (_root == nullptr) { newnode->_col = BLACK; _root = newnode; return true; } Node* pcur = _root; Node* parent = pcur; while (pcur) { parent = pcur; if (pcur->_kv.first < kv.first) pcur = pcur->_right; else if (pcur->_kv.first > kv.first) pcur = pcur->_left; else { delete newnode; return false; } } //开始插入 pcur = newnode; pcur->_parent = parent; if (parent->_kv.first > kv.first) parent->_left = pcur; else parent->_right = pcur; while (parent && parent->_col != BLACK) { Node* g = parent->_parent; Node* u = nullptr; if (g) { if (parent == g->_left)u = g->_right; else u = g->_left; if (u && u->_col == RED && g->_col == BLACK)//情况1:p、c、u、都是红色,g为黑色 { parent->_col = BLACK; u->_col = BLACK; g->_col = RED; pcur = g; parent = g->_parent; } else if (parent==g->_left&&pcur==parent->_left)//情况2:单旋+变色 { RotateR(parent); parent->_col = BLACK; g->_col = RED; break; } else if (parent->_right == pcur && g->_right == parent) { RotateL(parent); parent->_col = BLACK; g->_col = RED; break; } else if (parent->_right==pcur&&g->_left==parent)//情况三:双旋+变色 { RotateL(pcur); RotateR(pcur); pcur->_col = BLACK; g->_col = RED; break; } else if (parent->_left == pcur && g->_right == parent) { RotateR(pcur); RotateL(pcur); pcur->_col = BLACK; g->_col = RED; break; } } } _root->_col = BLACK; return true; } void Print(Node* root) { if (root == nullptr) return; Print(root->_left); cout << root->_kv.first << ":" << root->_kv.second << " "; Print(root->_right); } Node* root() { return _root; } Node* Find(const K& key) { Node* pcur = _root; while (pcur) { if (pcur->_kv.first > key) pcur = pcur->_left; else if (pcur->_kv.first < key) pcur = pcur->_right; else return pcur; } return nullptr; } bool Isrbtree(Node* root) { if (_root == nullptr)return true; if (root->_col != BLACK)return false; int refnum = 0; Node* cur = root; while (cur != nullptr) { if (cur->_col == BLACK)refnum++; cur = cur->_left; } return Preorder(root,0,refnum); } private: bool Preorder(Node* root, int num, const int ref) { if (root == nullptr) { return num == ref; } if (root->_col == RED && root->_parent->_col != BLACK) { cout << "出现连续红色节点!" << endl; return false; } if (root->_col == BLACK) return Preorder(root->_left, num + 1, ref) && Preorder(root->_right, num + 1, ref); if (root->_col == RED) return Preorder(root->_left, num, ref) && Preorder(root->_right, num, ref); } void RotateR(Node* cur) { Node* parent = cur->_parent; Node* grandpa = parent->_parent; parent->_left = cur->_right; parent->_parent = cur; if (cur->_right) cur->_right->_parent = parent; if (grandpa) { if (grandpa->_right == parent) grandpa->_right = cur; else grandpa->_left = cur; } else _root = cur; cur->_parent = grandpa; cur->_right = parent; } void RotateL(Node* cur) { Node* parent = cur->_parent; Node* grandpa = parent->_parent; parent->_right = cur->_left; parent->_parent = cur; if (cur->_left) { cur->_left->_parent = parent; } if (grandpa) { if (grandpa->_right == parent) grandpa->_right = cur; else grandpa->_left = cur; } else _root = cur; cur->_parent = grandpa; cur->_left = parent; } Node* _root; };
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/27 6:04:57

嵌入式排障三阶法:换机排除、录屏取证、批次对照

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 5:58:07

嵌入式烧录下载仿真调试:原理、工具选型与实战排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 5:55:08

圆极化波产生与检测:栅网组件实验全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 5:54:04

5.2 备考复习

备考是学习场景里压力最集中的阶段&#xff0c;例如知识点太多、时间有限、不知道重点在哪里、零散的笔记不知道怎么整合成能背的内容。大模型在备考阶段最实用用途可以是&#xff0c;根据大纲生成复习重点、针对薄弱章节出练习题、把零散笔记整理成结构化的要点、帮难记的知识…

作者头像 李华
网站建设 2026/9/27 5:44:11

Python 3.13 安装教程:环境变量配置+自定义路径

Python3.13是一种面向对象、直译式计算机程序设计语言&#xff0c;具有简单、易学、免费开源、可移植性、可扩展性等特点&#xff0c;已经具有十多年的发展历史&#xff0c;成熟且稳定。随着版本的不断更新和语言新功能的添加&#xff0c;越多被用于独立的、大型项目的开发。 …

作者头像 李华