stl map底层之红黑树插入步骤详解与代码实现

5分钟搞懂MSDNet:用Transformer实现小样本语义分割的保姆级教程 本文详细介绍了MSDNet(Multi-Scale Decoder Network)如何利用Transformer架构实现小样本语义分割。通过多尺度解码器和空间Transformer解码器,MSDNet能够在仅有1-5张标注图像的情况下完成精确分割任务。文章提供了PyTorch代码实例和优化技巧,帮助开发者快速掌握这一前沿技术。 阅读详情

转载请注明出处:http://blog.youkuaiyun.com/mxway/article/details/29216199

本篇文章并没有详细的讲解红黑树各方面的知识,只是以图形的方式对红黑树插入节点需要进行调整的过程进行的解释。

最近在看stl源码剖析,看到map底层红黑树的实现。为了加深对于红黑树的理解就自己动手写了红黑树插入的实现。关于红黑树插入节点后破坏红黑树性质的几种情况,可以在网上搜到很多相关的信息。下面用图说明插入新节点时红黑树所做的调整。插入的序列分别是30,40,50,20,35,10,11。

首先是插入30,由于现在红黑树是一棵空,所以直接将30作为根节点,并将根节点颜色染成黑色即可。

一、插入40,如下图所示。由于此时并没有破坏红黑树的性质,所以此时插入成功。

图1:插入40

二、插入50,插入节点50后,50及其父节点都为红色,由于此时40没有兄弟节点。此时将父节点变黑,祖父节点变红,以祖父节点为根进行左旋。调整后如图2-2所示

                           图2-1:插入节点50                                                                  图2-2:插入节点50调整后

三、插入20,插入节点20后,其父节点30及叔节点50都是红色节点。解决方法是将父节点及叔节点变黑,祖父节点变红。祖父节点变成新的当前节点重新进行算法。由于40是根节点,所以将根节点变黑。调整后如图3-2所示,此时满足红黑树的全部性质。

                                       图3-1:插入节点20                                                                 图3-2:插入节点20调整后

四、插入节点35,如图4所示,由于此时并未破坏红黑树的任何性质。不需要进行调整算法。

                                图4:插入节点35

五、插入节点10,此时10的父节点20及其叔节点35都是红色。将20及35节点变黑,祖父节点30变红。30作为新的当前节点。由于30的父节点40是黑色。所以调整算法结束。调整后如图5-2所示


                                                                                                                      图5-1:插入节点10 

  图5-2:插入节点10调整后

六、插入节点11,如图6-1所示,由于11的父节点10是红色节点,并且11是10的右子节点。所以首先以10节点为根节点进行左旋,旋转后其的红黑树如图6-2所示。此时节点10的父节点11为红色,并且10是11节点的左子节点;此时将父节点11变黑,祖父节点20变红,以祖父节点20为根节点进行右旋。旋转后如图6-3所示。

                                                                                                                   图6-1:插入节点11 

                         

                                                                                            图6-2:10为根节点进行左旋后


图6-3:插入节点调整后的红黑树


下面附上只实现了插入功能的红黑树源码

rbtree.h

#include <iostream>
#include <queue>
using namespace std;
static int _rb_black_node = 0;
static int _rb_red_node   = 1;
template<typename T>
struct RBNode
{
	RBNode():left(NULL),right(NULL),parent(NULL),val(T()),color(_rb_red_node){}
	RBNode(const T &v1):left(NULL),right(NULL),parent(NULL),val(v1),color(_rb_red_node){}
	RBNode	*left;
	RBNode	*right;
	RBNode	*parent;
	int		color;
	T		val;
};

template<typename T>
class RBTree
{
public:
	RBTree():root(NULL){}
	~RBTree()
	{
		if(root)
		{
			Destroy(root);
		}
	}
	void	print();
	void	Search(const T &v1, RBNode<T> *&node);
	bool	InsertUnique(const T &v1);
	void	DeleteValue(const T &v1);
	void	Destroy(RBNode<T> *p);
	void	InsertReBalance(RBNode<T> *node);
	RBNode<T>*	_rbtree_rotate_left(RBNode<T> *node);
	RBNode<T>*  _rbtree_rotate_right(RBNode<T> *node);
private:
	RBNode<T>	*root;
};

/*
*
* 打印红黑树的节点信息
*
*/
template<typename T>
void RBTree<T>::print()
{
	RBNode<T> *p;
	queue<RBNode<T> *> Q;
	Q.push(root);
	while(!Q.empty())
	{
		p = Q.front();
		Q.pop();
		cout<<"节点: "<<p->val<<" ";
		if(p->left)
		{
			cout<<"left:"<<p->left->val<<"->color:"<<p->left->color<<" ";
			Q.push(p->left);
		}
		if(p->right)
		{
			cout<<"right:"<<p->right->val<<"->color:"<<p->right->color<<" ";
			Q.push(p->right);
		}
		cout<<endl<<endl;
	}
}

/*
*
* 搜索v1在红黑树中出现的位置,如果v1在红黑树中则node节点为
* 值为v1所在红黑树中的节点。
* 否则node节点为如果将v1插入到红黑树中的父节点
*
*/
template<typename T>
void RBTree<T>::Search(const T &v1,RBNode<T> *&node)
{
	RBNode<T> *p = root;
	node = NULL;
	while(p)
	{
		if(p->val == v1)
		{
			node = p;
			break;
		}
		else if(p->val < v1)
		{
			node = p;
			p = p->right;
		}
		else
		{
			node = p;
			p = p->left;
		}
	}
}

template<typename T>
bool RBTree<T>::InsertUnique(const T &v1)
{
	RBNode<T> *parent = NULL;
	RBNode<T> *newNode = new RBNode<T>(v1);
	Search(v1, parent);
	if(parent == NULL)
	{//红黑树为空,当前插入的节点为根节点。插入后将根颜色变为黑
		root = newNode;
		root->color = _rb_black_node;
		return true;
	}
	if(parent->val == v1)//v1已经存在红黑树中。不再插入
		return false;
	
	if(v1 < parent->val)
	{
		parent->left = newNode;
	}
	else
	{
		parent->right = newNode;
	}
	newNode->parent = parent;
	InsertReBalance(newNode);
	return true;
}

/*
*
* 插入节点后进行调整,
* 使所有节点满足红黑树的性质
*
*/
template<typename T>
void RBTree<T>::InsertReBalance(RBNode<T> *node)
{
	RBNode<T> *parent = node->parent;
	RBNode<T> *grandParent = NULL;
	while(parent && parent->color==_rb_red_node)
	{
		grandParent = parent->parent;
		if(parent == grandParent->left)
		{//父节点为祖父节点的左儿子
			RBNode<T> *uncle = grandParent->right;
			if(uncle && uncle->color == _rb_red_node)
			{//情形1 父节点与叔节点都为红
				//解决方法父与叔变黑,祖父变黑。祖父变为新的当前节点重新进入算法
				parent->color = _rb_black_node;
				uncle->color  = _rb_black_node;
				grandParent->color = _rb_red_node;
				node = grandParent;
				parent = grandParent->parent;
			}
			else
			{
				if(node == parent->right)
				{//情形2,叔为黑,当前节点为其父节点的右子节点
					//解决方法:以父节点为根进行左旋
					//操作后将转换为情形3
					node = _rbtree_rotate_left(parent);
					parent = node->parent;
					grandParent = parent->parent;
				}
				//情形3父为红,当前节点为父节点的左子节点
				//解决方法:父节点变黑,祖父节点变红,以
				//祖父节点为根节点进行右旋
				parent->color = _rb_black_node;
				grandParent->color = _rb_red_node;
				_rbtree_rotate_right(grandParent);
			}
		}
		else
		{//父节点为祖父节点的右子节点,情况与上面相同
			RBNode<T> *uncle = grandParent->left;
			if(uncle && uncle->color == _rb_red_node)
			{
				uncle->color = _rb_black_node;
				parent->color = _rb_black_node;
				grandParent->color = _rb_red_node;
				node = grandParent;
				parent = node->parent;
			}
			else
			{
				if(node == parent->left)
				{
					node = _rbtree_rotate_right(parent);
					parent = node->parent;
					grandParent = parent->parent;
				}
				parent->color = _rb_black_node;
				grandParent->color = _rb_red_node;
				_rbtree_rotate_left(grandParent);
			}
		}
	}
	root->color = _rb_black_node;
}

/*
*
* 左旋
*
*/
template<typename T>
RBNode<T> *RBTree<T>::_rbtree_rotate_left(RBNode<T> *x)
{
	RBNode<T> *y = x->right;
	if(y == NULL)
	{
		return x;
	}
	//x的右节点为y的左节点
	x->right = y->left;
	if(y->left)//如果y的左节点存在,其父节点为y
		y->left->parent = x;
	if(root == x)
	{//x为root,旋转后y为新的root根节点
		root = y;
	}
	else
	{
		if(x == x->parent->left)
		{//如果x为其父节点的左子节点。
			//x的父节点的新左子节点为y
			x->parent->left = y;
		}
		else
		{
			x->parent->right = y;
		}
		//y的父节点为x的父节点
		y->parent = x->parent;
	}
	//y的左子节点为x
	y->left = x;
	//x的父节点为y
	x->parent = y;
	return x;
}

/*
*
* 右旋
* 分析其逻辑与左旋代码类似
*
*/
template<typename T>
RBNode<T>* RBTree<T>::_rbtree_rotate_right(RBNode<T> *x)
{
	RBNode<T> *y = x->left;
	if(y == NULL)
	{
		return x;
	}
	x->left = y->right;
	if(y->right)
		y->right->parent = x;
	if(root == x)
	{
		root = y;
	}
	else
	{
		if(x == x->parent->left)
		{
			x->parent->left = y;
		}
		else
		{
			x->parent->right = y;
		}
		y->parent = x->parent;
	}
	y->right = x;
	x->parent = y;
	return x;
}

/*
*
* 销毁整棵红黑树
*
*/
template<typename T>
void RBTree<T>::Destroy(RBNode<T> *p)
{
	if(p->left)
	{
		Destroy(p->left);
	}
	if(p->right)
	{
		Destroy(p->right);
	}
	delete p;
}

插入节点的程序:

#include "rbtree.h"
#include <iostream>
using namespace std;

int main()
{
	RBTree<int> obj;
	obj.InsertUnique(30);
	obj.InsertUnique(40);
	obj.InsertUnique(50);
	obj.InsertUnique(20);
	obj.InsertUnique(35);
	obj.InsertUnique(10);
	obj.InsertUnique(11);
	obj.print();
	return 0;
}


Python+ArcGIS实战:5步搞定土壤类型预测(附随机森林模型配置技巧) 本文详细介绍了如何结合Python与ArcGIS,利用随机森林模型进行土壤类型预测。通过5个核心步骤——数据预处理、样本创建、模型构建、空间预测与精度验证,构建了一套自动化、高精度的空间预测工作流,并提供了关键的模型配置与调参技巧,助力GIS开发者高效完成土壤制图任务。 阅读详情

相关推荐

Xilinx Vivado vitis IDE launch Failed \ Web installer client Obsolete 怎么办

Xilinx vitis_IDE failed Web installer client Obsolete

weixin_44820962的博客 8644

红黑树知识全面详解之节点插入

将一个节点插入到红黑树中,需要执行哪些步骤呢?首先,将红黑树当作一颗二叉查找树,将节点插入;然后,将节点着色为红色;最后,通过旋转和重新着色等方法来修正该树,使之重新成为一颗红黑树。详细描述如下: 第一步: 将红黑树当作一颗二叉查找树,将节点插入。       红黑树本身就是一颗二叉查找树,将节点插入后,该树仍然是一颗二叉查找树。也就意味着,树的键值仍然是有序的。此外,无论是左旋还是右旋,若旋转...

小小城御园的博客 1754

从零开始!在 Windows 上安装与配置 Dify

这篇博客将详细介绍如何在 Windows 系统上部署 Dify,适合零基础用户。从 Docker 和 WSL 的安装配置开始,逐步指导用户设置 Git、Docker 环境以及 Dify 配置文件,解决可能遇到的端口冲突等问题,最终完成 Dify 的启动和测试。通过简明易懂的步骤,帮助用户在本地成功运行 Dify,实现模型供应商配置,让 Dify 项目在 Windows 平台上顺利上线。

qq_49035156的博客 5万+

2020-08-16

完整简单的红黑树算法 一、红黑树性质 1.每个结点要么是红的要么是黑的 2.根结点是黑的 3.每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的 4.如果一个结点是红的,那么它的两个儿子都是黑的 5.对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点 总结:平衡状态下红黑树要么单支黑-红,要么有两个子节 二、复杂度 O(lgn) 三、结点插入 将一个节点插入到红黑树中,需要执行哪些步骤呢?首先,将红黑树当作一颗二叉查找树,将节点插入;然后,将.

qq_40510469的博客 235

大数据应用技术实验报告一 Hadoop三种模式安装配置

JDK+Hadoop安装配置、单机模式配置 以下操作在SecureCRT里面完成 1.关闭防火墙 firewall-cmd --state 显示防火墙状态running/not running systemctl stop firewalld 临时关闭防火墙,每次开机重新开启防火墙 systemctl disable firewalld 禁止防火墙服务。 2.传输JDK和HADOOP压缩包 Sec...

Ruthless_Childe的博客 3090

泛微ecology9 利用字段值动态控制明细表显示与隐藏

本文详细介绍了在泛微ecology9中,如何利用WfForm.bindFieldChangeEvent监听字段变化,结合jQuery动态控制明细表显示与隐藏的实战方法。通过五步操作,可实现根据字段值(如报销类型)智能切换明细表,提升表单交互体验与开发效率,并确保PC与移动端完美兼容。

7z8x2c4v6b9的博客 585

SGISTL源码探究-STL中的红黑树(上)

前言本小节将进入到SGISTL的红黑树部分。关于红黑树,是一种比较复杂的数据结构,但是并不是特别难。如果对红黑树不太了解,可以去网上查阅相关的资料,因为本文的主要目的是分析STL中的红黑树的源码,和普通的红黑树略有不同,还要复杂一些,需要有一定的基础。基本概念首先什么是二叉搜索树,二叉搜索树即符合任何一个节点的值一定大于其左子树的任何一个节点的值并且小于其右子树的任何一个节点的值(节点的值不允许重复

Move_now的博客 1806

kettle连接达梦资源库数据库插件

kettle自定义插件plugin database plugin 达梦插件 dm插件

weixin_42122126的博客 2169

map异常崩溃分析汇总

节点树,父节点删除,子节点成了野指针,节点的属性在map的value中,使用map的find导致崩溃。

yantuguiguziPGJ的博客 1429

Supreme小程序自动化抢购终端——源码架构与执行流程全解析

本系统是一套基于开发的桌面端小程序自动化抢购终端。把只有开发者能跑的脚本,包装成普通用户也能操作的桌面工具。参数自动捕获 → 商品多关键词检索 → sku/尺码/库存映射 → 多商品任务队列 → 定时/立即抢购 → 订单创建 → 支付参数拉取 → 本地服务生成支付链接 → 手机微信扫码付款这套 Supreme 抢购终端,表面上看是一个"下单工具"。但从工程角度审视,它已经具备了一个小型桌面自动化系统GUI 层:CustomTkinter 现代化界面,线程安全业务层:多商品队列、定时调度、任务编排。

猫敷雪 202

手把手教你学simulink(8.2)--simulink的实战案例:信号分析

通过以上步骤,你已经成功使用 Simulink 对信号进行了频谱分析和时域分析,提取了信号的有用信息。这个案例展示了如何创建 Simulink 模型、添加和连接模块、设置仿真参数、运行仿真以及分析结果。希望这个案例能帮助你更好地理解和使用 Simulink 进行信号分析。

MHD0815的博客 1123

【数据结构】认识红黑树 --map/set的底层原理

**红黑树**也叫RB树(Red-Black Tree),实际就是一种二叉搜索树,只是它的节点不是通过平衡因子来控制树的形状,而是为节点设置了两种颜色来控制,使得树中**最长路径中节点个数不会超过最短路径节点个数的两倍**,这样就能保证树触发旋转的几率大大减小。因此红黑树在每个节点上增加了一个一个的存储位表示节点的颜色,可以是Red或Black。

ly_6699的博客 2608

华为OD机试真题 新系统【进制转换后自定义排序】

华为OD机试 新系统真题【进制转换后自定义排序】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题【进制转换后自定义排序】多语言题解。

qq_45776114的博客 594

底层实现红黑树_stl map底层之红黑树插入步骤详解与代码实现 | 学步园

本篇文章并没有详细的讲解红黑树各方面的知识,只是以图形的方式对红黑树插入节点需要进行调整的过程进行的解释。最近在看stl源码剖析,看到map底层红黑树的实现。为了加深对于红黑树的理解就自己动手写了红黑树插入的实现。关于红黑树插入节点后破坏红黑树性质的几种情况,可以在网上搜到很多相关的信息。下面用图说明插入新节点时红黑树所做的调整。插入的序列分别是30,40,50,20,35,10,11。首先是插入...

weixin_35843410的博客 256

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

STL中关于map和set的四个问题?

STL中关于map和set的四个问题?  STL map和set的使用虽不复杂,但也有一些不易理解的地方,如: # 为何map和set的插入删除效率比用其他序列容器高? # 为何每次insert之后,以前保存的iterator不会失效? # 为何map和set不能像vector一样有个reserve函数来预分配数据? # 当数据元素增多时(10000到20

刘日新的博客 411

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

C++手撕红黑树:从0到200行,拿下STL map底层核心

红黑树作为一种自平衡的二叉搜索树,凭借其红黑相间的结点颜色和四条核心规则,在计算机科学领域占据着举足轻重的地位。本文从红黑树的基本概念出发,深入剖析了其如何通过颜色约束实现“最长路径不超过最短路径2倍”的近似平衡特性,并对比分析了与AVL树的效率差异。

凤年徐的博客 1766

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

【C++红黑树应用】模拟实现STL中的map与set

详细讲解了c++stl中map和set的模拟实现

You build it, you run it 2326

STL map / set 底层机制: 红黑树完全剖析

前言: 在 STL 的容器中两大阵营 (vector deque list forward_list) 顺序容器 与 关联容器 (map set unorder_map unorder_set) 。 关联容器指的是以关键字匹配指定数据的一种关联数据结构的集合, 在关联容器中通过关键字去查找对应的数据是非常块的, 下面我们会彻底地去剖析其底层实现机制 : 红黑树。 由基础树 到 二叉搜索树 介绍红黑树之前,容许我介绍树的概念。 1. 树(tree), 在计算机科学中,是十分基础的数据结构: .

专注游戏研发 3365

【c++】STL容器——使用红黑树模拟实现map和set(由浅入深逐步完善3w字详解)

一、了解STL库中的map/set的底层 二、红黑树的迭代器 三、红黑树的插入 四、map/set的封装 set的封装 map的封装 五、测试 测试一 测试二 六、学习STL库中的实现 set如何保证key不被修改 map如何保证key不被修改 八、set的改进 红黑树的const迭代器 改进set 测试一 测试二 测试三 九、map的改进 测试一 测试二 operator[] Insert 继续完善operaotr[] 测试一 十、完善set的Insert 十一、源代码 MyMap.h Myset.h R

重铸自身根基的博客 1784

C++【STL】改造红黑树简单模拟实现set map(带你了解set map的底层实现结构)

C++【STL】改造红黑树简单模拟实现set map(带你了解set map的底层实现结构)

foodsx的博客 1505

STL详解(十一)—— 用一棵红黑树同时封装出map和set

文章目录 用一棵红黑树同时封装出map和set

2021dragon的博客 5306

如何使用 c++ stl 中的 map 以及红黑树 (一)

 Two Sum Given an array of integers, find two numbers such thatthey add up to a specific target number. The function twoSum should return indices of the twonumbers such that they add up

博客 8162

封装map和set(红黑树作为底层结构如何实现map和set插入遍历)

摘要: 红黑树作为map和set的底层结构,通过泛型设计同时支持两种容器。关键点在于引入仿函数KeyOfT,用于提取键:set直接返回键本身,map从键值对中提取键。迭代器按中序遍历实现,插入操作返回pair<iterator, bool>,既定位元素又反馈插入结果。map的operator[]通过插入缺省值实现查找或修改,简化用法。红黑树迭代器需显式构造函数,维护节点与根的关系以支持遍历。设计巧妙融合泛型与仿函数,兼顾通用性与效率。 (149字)

asciiletters的博客 1680

【C++】—— 实现底层为红黑树的Map和Set

STL关联式容器map/set介绍: https://blog.youkuaiyun.com/chenxiyuehh/article/details/89361160 红黑树的模拟实现 https://blog.youkuaiyun.com/chenxiyuehh/article/details/89437298 这两篇博客介绍了map/set的相关接口使用和红黑树的模拟实现,现在我们来用一个红黑树封装实现MyMap和M...

chenxiyuehh的博客 3056

【C++】map与set容器——红黑树底层封装

map和set的介绍,以及如何用红黑树封装map和set,细节拉满!

Pursue quality, not quantity. 1387
上一篇: 从百万关键字中提取前K个关键字
下一篇: 一种新的删除红黑树节点的算法
mxway
博客等级 码龄17年 370粉丝 66原创
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值