当前位置: 首页 > ds >正文

红黑树insert笔记

贴的代码还是有点“小问题”,比如insert里的比较是直接和kv比较,用pair的内置比较,即用到了key,也用到了value,这是不合“红黑树key,value逻辑”的,总之就这样了,能用就行。

ps:博主在写insert的时候,vs2022也是狂出毛病,然后博主调试分析不出错误,问豆包也是一本正经的胡说八道。。。。。。

贴个代码水一下

R_B_T.hpp


#pragma once
#include <iostream>
#include <set>// 枚举值表示颜色
enum Colour
{RED,BLACK
};
// 这里我们默认按key/value结构实现
template<class K, class V>
struct RBTreeNode
{// 这里更新控制平衡也要加入parent指针std::pair<K, V> _kv;RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;Colour _col;RBTreeNode(const std::pair<K, V>& kv):_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr){}
};template<class K, class V>
class RBTree
{typedef RBTreeNode<K, V> Node;
public:bool Insert(const std::pair<K, V>& kv) {if (!_root) {_root = new Node(kv);_root->_col = BLACK;return true;}// 先找到要插入的位置Node* pcur = _root, * pPrev = nullptr;while (pcur) {pPrev = pcur;if (kv < pcur->_kv) {pcur = pcur->_left;}else if (kv > pcur->_kv) {pcur = pcur->_right;}else {return false;}}// 插入pcur = new Node(kv);pcur->_col = RED;if (kv < pPrev->_kv) {pPrev->_left = pcur;}else {pPrev->_right = pcur;}pcur->_parent = pPrev;// 向上检查更新,pcur仍是新插入结点,而pPrev是pcur的父结点while (pPrev != nullptr) {//直接合格if (pPrev->_col == BLACK) {break;}else {// 分1,2,3,4种情况,每种情况又有uncle结点为红/空与黑的区别// cur(son), pPrev(father), grandfatherNode* pGF = pPrev->_parent; // grandfatherif (pPrev == pGF->_left) {// uncle为红if (pGF->_right != nullptr && pGF->_right->_col == RED) {pGF->_col = RED;pGF->_right->_col = pPrev->_col = BLACK;// 更新, pGF不改变pcur = pGF;pPrev = pcur->_parent;}// uncle为黑或空的旋转else {// 两种情况,cur(son), pPrev(father), grandfather为左右左/左左左if (pcur == pPrev->_left) {RotateR(pGF);// pGF改变pcur = pPrev;pPrev = pcur->_parent;}else {RotateLR(pGF);pcur = pcur;pcur = pcur->_parent;}}}else {if (pGF->_left != nullptr && pGF->_left->_col == RED) {pGF->_col = RED;pGF->_left->_col = pPrev->_col = BLACK;// 更新, pGF不改变pcur = pGF;pPrev = pcur->_parent;}else {if (pcur == pPrev->_left) {RotateRL(pGF);// 旋转里考虑了pGF为_root的情况并进行了处理pcur = pcur;pPrev = pcur->_parent;}else {RotateL(pGF);pcur = pPrev;pPrev = pcur->_parent;}}}}// 无脑一点,uncle为红的时候pGF可能为_root,uncle为黑或null的时候左旋右旋处理了// 就顺便的放这里了,放uncle为红那里可能会更好_root->_col = BLACK;}return true;}void InOrder() {_InOrder(_root);}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);std::cout << root->_kv.first << " ";_InOrder(root->_right);}// 前序递归遍历bool Check(Node* root, int blackNum, const int refNum){if (root == nullptr){// 前序遍历走到空时,意味着一条路径走完了//cout << blackNum << endl;if (refNum != blackNum){std::cout << "存在黑色结点的数量不相等的路径" << std::endl;return false;}return true;}// 检查孩子不太方便,因为孩子有两个,且不一定存在,反过来检查父亲就方便多了if (root->_col == RED && root->_parent && root->_parent->_col == RED){std::cout << root->_kv.first << "存在连续的红色结点" << std::endl;return false;}if (root->_col == BLACK){blackNum++;}return Check(root->_left, blackNum, refNum)&& Check(root->_right, blackNum, refNum);}bool IsBalanceTree(){if (_root == nullptr)return true;if (_root->_col == RED)return false;// 参考值int refNum = 0;Node* cur = _root;while (cur){if (cur->_col == BLACK){++refNum;}cur = cur->_left;}return Check(_root, 0, refNum);}private:void RotateR(Node* pcur) { //复用,这里是连续两个红结点的父结点if (!pcur) return;Node* pPL = pcur->_left;if (pcur->_parent) {if (pcur->_parent->_right == pcur) {pcur->_parent->_right = pPL;}else if (pcur->_parent->_left == pcur) {pcur->_parent->_left = pPL;}}// 利用根节点的父节点是nullptr判断了pcur是否是根节点else {_root = pPL;}pPL->_parent = pcur->_parent;pcur->_left = pPL->_right;if (pPL->_right)pPL->_right->_parent = pcur;pPL->_right = pcur;pcur->_parent = pPL;// bf// pcur->_bf = pPL->_bf = 0;// _colpPL->_col = BLACK;pcur->_col = RED;}// 左单旋void RotateL(Node* pcur) { //pParent  if (!pcur) return;Node* pPR = pcur->_right;if (pcur->_parent) {if (pcur->_parent->_right == pcur) {pcur->_parent->_right = pPR;}else if (pcur->_parent->_left == pcur) {pcur->_parent->_left = pPR;}}else {_root = pPR;}pPR->_parent = pcur->_parent;pcur->_right = pPR->_left;if (pPR->_left)pPR->_left->_parent = pcur;pPR->_left = pcur;pcur->_parent = pPR;// bf// pcur->_bf = pPR->_bf = 0;pPR->_col = BLACK;pcur->_col = RED;}// 右左双旋, 先右再左void RotateRL(Node* pParent) {Node* pPR = pParent->_right;Node* pPRL = pPR->_left;RotateR(pParent->_right);RotateL(pParent);}// 左右双旋void RotateLR(Node* pParent) {Node* pPL = pParent->_left;Node* pPLR = pPL->_right;RotateL(pParent->_left);RotateR(pParent);}
private:Node* _root = nullptr;
};

main.cpp(简单的测试代码)

#include "Red_Black_Tree.hpp"void test() {RBTree<int, int> rbt;// 插入一些键值对rbt.Insert(std::make_pair(10, 10));rbt.Insert(std::make_pair(20, 20));rbt.Insert(std::make_pair(30, 30));rbt.Insert(std::make_pair(15, 15));rbt.Insert(std::make_pair(25, 25));// 中序遍历std::cout << "中序遍历结果: ";rbt.InOrder();std::cout << std::endl;// 检查红黑树的平衡性if (rbt.IsBalanceTree()) {std::cout << "红黑树是平衡的。" << std::endl;}else {std::cout << "红黑树不是平衡的。" << std::endl;}
}
int main() {test();return 0;
}

http://www.xdnf.cn/news/270.html

相关文章:

  • 2025年03月中国电子学会青少年软件编程(Python)等级考试试卷(六级)真题
  • 使用Service发布应用程序
  • std::set (C++)
  • #手动控制windows更新时间(非常安全,可随时恢复)
  • C++ 网络层接口设计与实现:基于 Socket 编程
  • L2-018 多项式A除以B
  • SQL-exists和in核心区别​、 性能对比​、适用场景​
  • 2.1 数据处理
  • 【 解决Cline插件无法激活及DeepSeek模型请求卡顿或者无法加载问题】
  • CMake使用教程
  • IO流(二)
  • 从 Transformer 到文本生成 (From Transformer to Text Generation)
  • STM32---GPIO
  • Linux——进程通信
  • Spring MVC 初体验~~
  • 自定义 el-menu
  • 【jenkins】首次配置jenkins
  • 合成数据中的对抗样本生成与应用:让AI模型更强、更稳、更安全
  • 代码学习总结(五)
  • cmake 语法大纲
  • 研究生面试常见问题
  • 1.Linux基础指令
  • 卷积神经网络(CNN)与VGG16在图像识别中的实验设计与思路
  • docker镜像被覆盖了怎么办?通过sha256重新上传镜像
  • VueRouter笔记
  • 6. 实战(二):用Spring AI+OpenAI构建企业级智能客服
  • LeetCode19.删除链表的倒数第N个节点
  • OpenCV图像加密和解密
  • PGSql常用操作命令
  • OBS 日期时间.毫秒时间脚本 date-and-time.lua