C++·set与map容器(下)

news2024/11/13 6:44:22

        本节把红黑树封装到set与map容器中去主要就是迭代器的自增自减,封装的大部分内容都展示到最后代码中了

1. 红黑树的改造

        因为set容器只有关键码值,map容器中不仅要存关键码值,还要存关键码值对应的数据。但是红黑树只有一颗,我们如何让一颗树适配两种存储模式。

        答案就是给红黑树两个模板参数,无论是set还是map第一个模板参数都用来表示关键码值,第二个模板参数,如果是set就存关键码值,如果是map就存pair数据。红黑树节点就只给一个模板参数只用来存储数据,也就是树的第二个模板参数。

        如此修改就可以做到set和map同用一颗红黑树了。

        但是因为我们之前红黑树是按map的方案写的,也就是说,插入中对比key值大小从而判断向左还是向右走的逻辑我们都是用 ->_kv.first 的方式访问key值的,但是明显set没办法这么操作。

        因此我们再在set和map容器中添加一个仿函数,用来取节点的关键码值

                

        之后在树中比较关键码值就可以直接用这个KeyofT生成的仿函数来取关键码。

        那树的第一个模板参数的用途就是给搜索和删除,在查找节点时,我们只需要对比关键码值就可以了。

2. 红黑树的迭代器

        关于构建迭代器的思路,我们不在容器上构建迭代器,而是直接在容器的底层,也就是红黑树中构建底层的迭代器,容器的迭代器就封装底层就好了。

        我们将迭代器的框架构建好,并在红黑树中实现好begin和end。这个end可以直接给空指针,因为树结束的下一个节点就是空指针。begin就是中序的第一个,也就是最左节点。

        下一步,我们将begin和end再封装进set和map容器中去。

        然后我们该实现迭代器的自增和自减了

2.1 operator++()

        迭代器的下一位就是中序遍历的下一位,中序遍历的顺序是 左-中-右 那么此时给到中节点了,下面分为两种情况:右树存在或右树不存在。

        当右树存在时右子树的最左节点就是中序的下一位。

        当右树不存在时,说明以该节点为根的子树已经访问完了,然后回到父亲。那如何判断父节点是否也访问完了,就需要看父节点与该节点是不是在同侧,或者说如果该节点是父节点的右孩子,说明父节点也访问完了,只有该节点是父节点的左孩子时说明父节点还未访问。如果父节点为空,说明整棵树已经遍历完了。

                ​​​​​​​        ​​​​​​​        

2.2 operator--()

        自减的逻辑与自增完全相反,或者说自减的遍历顺序是 右-中-左。

        但是我们这里要给end()迭代器做一下特殊处理,因为end()迭代器的上一位在逻辑上是中序遍历的最后一位,但是我们的end()迭代器给的是个空指针,它无法像其他正常节点那样操作。我们的特殊操作就是判断当下的迭代器是否是end(),如果是就直接来到中序遍历的最后一位,也就是最右节点。

                                

        但是这么做特殊处理也有弊端,就是当_root被旋转改变了之后迭代器就失效了。因此在库中,root上面还有一个head节点用来维护树,其中存储了root节点,最左节点和最右节点的信息,这样就不会出现迭代器失效的问题了,同时end()迭代器可以直接给head节点而不用给空了,并且每次找最左节点和最右节点时也非常方便。

        

3. 完整代码

RBTree.h

//节点的颜色
enum color{RED,BLACK};
//红黑树节点的定义
template<class T>
struct RBTNode
{
	RBTNode(const T& data, color color = RED)
		: _data(data)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _col(color) 
	{}

	T _data;
	RBTNode<T>* _left;
	RBTNode<T>* _right;
	RBTNode<T>* _parent;	
	color _col;	//节点颜色
};


//红黑树的迭代器
template<class T, class Ref, class Ptr>
struct RBTIterator
{
	typedef RBTNode<T> Node;
	typedef RBTIterator<T, Ref, Ptr> Self;
	Node* _node;
	Node* _root;

	//构造
	RBTIterator(Node* node, Node* root)
		:_node(node)
		,_root(root)
	{}

	Self& operator++()
	{
		if (_node->_right)
		{
			//右不为空,右子树最左节点就是中序下一个
			Node* leftmost = _node->_right;
			while(leftmost->_left)
			{
				leftmost = leftmost->_left;
			}
			_node = leftmost;
		}
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent&& cur == parent->_right)
			{
				cur = parent;
				parent = parent->_parent;
			}
			_node = parent;
		}

		return *this;
	}

	Self& operator--()
	{
		if (_node == nullptr)//end()
		{
			Node* rightmost = _root;
			while (rightmost && rightmost->_right)
			{
				rightmost = rightmost->_right;
			}
			_node = rightmost;
		}
		else if (_node->_left)
		{
			//左不为空,左子树最后一个节点就是上一个
			Node* rightmost = _node->_left;
			while (rightmost->_right)
			{
				rightmost = rightmost->_right;
			}
			_node = rightmost;
		}
		else
		{
			//左树为空,同侧父节点遍历完了
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_left)
			{
				cur = parent;
				parent = parent->_parent;
			}
			_node = parent;
		}

		return *this;
	}

	Ref operator*()
	{
		return _node->_data;
	}
	Ptr operator->()
	{
		return &_node->_data;
	}

	bool operator!=(const Self& s)
	{
		return _node != s._node;
	}
	bool operator==(const Self& s)
	{
		return _node == s._node;
	}
};


template<class K, class T, class KeyOfT >
class RBTree
{
	typedef RBTNode<T> Node;

public:
	typedef RBTIterator<T,T&,T*> Iterator;
	typedef RBTIterator<T, const T&, const T*> Const_Iterator;
	Iterator Begin()
	{
		Node* leftmost = _root;
		while (leftmost && leftmost->_left)
		{
			leftmost = leftmost->_left;
		}
		return Iterator(leftmost, _root);
	}
	Iterator End()
	{
		return Iterator(nullptr, _root);
	}

	Const_Iterator Begin() const
	{
		Node* leftmost = _root;
		while (leftmost && leftmost->_left)
		{
			leftmost = leftmost->_left;
		}
		return Const_Iterator(leftmost, _root);
	}
	Const_Iterator End() const
	{
		return Const_Iterator(nullptr, _root);
	}


	//构造
	RBTree() = default;
	//拷贝构造
	RBTree(const RBTree<K, T, KeyOfT>& t)
	{
		_root = Copy(t._root);
	}

	//赋值运算符重载
	void operator=(const RBTree<K, T, KeyOfT>& t)
	{
		RBTree<K, T> new_t(t);
		std::swap(new_t._root, _root);
	}

	//析构
	~RBTree()
	{
		Destroy(_root);
		_root = nullptr;
	}

	void Destroy(Node* root)
	{
		if (root == nullptr)
			return;
		Destroy(root->_left);
		Destroy(root->_right);
		delete root;
	}
	Node* Copy(const Node* root)
	{
		if (root == nullptr)
			return nullptr;
		Node* newnode = new Node(root->kv);
		newnode->_left = Copy(root->_left);
		newnode->_right = Copy(root->_right);

		return newnode;
	}



	//插入
	pair<Iterator,bool> Insert(const T& data);

	//搜索
	Iterator Find(const K& key);

	//中序遍历
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

	//树的高度
	int Height()
	{
		return _Height(_root);
	}

	//统计节点总个数(插入时可能会有重复数据)
	int Size()
	{
		return _Size(_root);
	}

	//判断黑节点是否符合规则
	bool IsBalance()
	{
		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:

	bool Check(Node* root, int blackNum, const int refNum)
	{
		if (root == nullptr)
		{
			cout << blackNum << endl;
			if (refNum != blackNum)
			{
				cout << "存在黑色节点的数量不相等的路径" << endl;
				return false;
			}
			return true;
		}

		if (root->_col == RED && root->_parent->_col == RED)
		{
			cout << root->_kv.first << "存在连续的红色节点" << endl;
			return false;
		}
		if (root->_col == BLACK)
		{
			blackNum++;
		}
		return Check(root->_left, blackNum, refNum) && Check(root->_right, blackNum, refNum);
	}

	//左单旋
	void RotateL(Node* parent);
	//右单旋
	void RotateR(Node* parent);


	//中序遍历(子函数)
	void _InOrder(Node* root)
	{
		if (root == nullptr)
			return;

		_InOrder(root->_left);
		cout << root->_kv.first << ":" << root->_kv.second << endl;
		_InOrder(root->_right);
	}

	//树的高度
	int _Height(Node* root)
	{
		if (root == nullptr)
			return 0;
		int leftHeight = _Height(root->_left);
		int rightHeight = _Height(root->_right);
		return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
	}

	//统计节点总个数(插入时可能会有重复数据)
	int _Size(Node* root)
	{
		return root == nullptr ? 0 : _Size(root->_left) + _Size(root->_right) + 1;
	}

private:
	Node* _root = nullptr;
};





//插入
template<class K, class T, class KeyOfT>
pair<typename RBTree<K, T, KeyOfT>::Iterator,bool> RBTree<K, T, KeyOfT>::Insert(const T& data)
{
	//链表为空特殊处理
	if (_root == nullptr)
	{
		_root = new Node(data, BLACK);
		return make_pair(Iterator(_root, _root), true);
	}

	KeyOfT kot;
	Node* parent = nullptr;
	Node* cur = _root;
	while (cur)
	{
		if (kot(cur->_data) < kot(data))
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (kot(cur->_data) > kot(data))
		{
			parent = cur;
			cur = cur->_left;
		}
		else
			return make_pair(Iterator(cur, _root), false);
	}
	//需要插入一个新的红色节点
	cur = new Node(data);
	Node* newnode = cur;
	if (kot(cur->_data) < kot(parent->_data))
	{
		parent->_left = cur;
		cur->_parent = parent;
	}
	else
	{
		parent->_right = cur;
		cur->_parent = parent;
	}
	//判断是否需要对树进行调整
	while (parent && parent->_col==RED)//如果父节点颜色为红需要调整
	{
		Node* grandparent = parent->_parent;
		if (parent == grandparent->_left)	//叔叔在右
		{
			Node* uncle = grandparent->_right;
			
			if (uncle && uncle->_col == RED)	//当叔叔存在且为红时
			{
				parent->_col = uncle->_col = BLACK;
				grandparent->_col = RED;

				cur = grandparent;
				parent = grandparent->_parent;
			}
			else	//叔叔为黑或不存在
			{
				if (cur == parent->_left)//三节点同在左,右单旋
				{
					RotateR(grandparent);
					parent->_col = BLACK;
					grandparent->_col = RED;
				}
				else	//p节点在g左,cue节点在p右,左右双旋
				{
					RotateL(parent);
					RotateR(grandparent);
					cur->_col = BLACK;
					grandparent->_col = RED;	
				}
				break;
			}
		}
		else	//叔叔在左
		{
			Node* uncle = grandparent->_left;

			if (uncle && uncle->_col == RED)	//当叔叔存在且为红时
			{
				parent->_col = uncle->_col = BLACK;
				grandparent->_col = RED;

				cur = grandparent;
				parent = grandparent->_parent;
			}
			else	//叔叔为黑或不存在
			{
				if (cur == parent->_right)//三节点同在右,左单旋
				{
					RotateL(grandparent);
					parent->_col = BLACK;
					grandparent->_col = RED;
				}
				else	//p节点在g右,cue节点在p左,右左双旋
				{
					RotateR(parent);
					RotateL(grandparent);
					cur->_col = BLACK;
					grandparent->_col = RED;
				}
				break;
			}
		}
	}
	_root->_col = BLACK;
	return make_pair(Iterator(newnode, _root), true);
}


//搜索
template<class K, class T, class KeyOfT>
typename RBTree<K, T, KeyOfT>::Iterator RBTree<K, T, KeyOfT>::Find(const K& key)
{
	KeyOfT kot;
	Node* cur = _root;
	while (cur)
	{
		if (kot(cur->_data) < key)
		{
			cur = cur->_right;
		}
		else if (kot(cur->_data) > key)
		{
			cur = cur->_left;
		}
		else
		{
			return Iterator(cur,_root);
		}
	}
	return End();
}


//左单旋
template<class K, class T, class KeyOfT>
void RBTree<K, T, KeyOfT>::RotateL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = parent->_right->_left;

	//修改向下链接内容
	parent->_right = subRL;
	subR->_left = parent;
	//修改向上链接内容
	subR->_parent = parent->_parent;
	parent->_parent = subR;
	if (subRL)//防止该树点为空
	{
		subRL->_parent = parent;
	}

	//parent的parent向下链接
	Node* parentParent = subR->_parent;
	if (parentParent == nullptr)//整棵树的根
	{
		_root = subR;
	}
	else
	{
		if (parent == parentParent->_right)
		{
			parentParent->_right = subR;
		}
		else
		{
			parentParent->_left = subR;
		}
	}
}

//右单旋
template<class K, class V, class KeyOfT>
void RBTree<K, V, KeyOfT>::RotateR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;

	//修改向下链接内容
	parent->_left = subLR;
	subL->_right = parent;
	//修改向上链接属性
	subL->_parent = parent->_parent;
	parent->_parent = subL;
	if (subLR)
	{
		subLR->_parent = parent;
	}
	//修改parentParent
	Node* parentParent = subL->_parent;
	if (parentParent == nullptr)
	{
		_root = subL;
	}
	else
	{
		if (parent == parentParent->_right)
		{
			parentParent->_right = subL;
		}
		else
		{
			parentParent->_left = subL;

		}
	}
}

Myset.h

#include"RBTree.h"

namespace atl
{
	template <class K>
	class set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename RBTree<K, K, SetKeyOfT>::Iterator iterator;
		typedef typename RBTree<K, K, SetKeyOfT>::Const_Iterator cosnt_iterator;
		iterator begin()
		{
			return _t.Begin();
		}
		iterator end()
		{
			return _t.End();
		}
		cosnt_iterator begin()const
		{
			return _t.Begin();
		}
		cosnt_iterator end()const
		{
			return _t.End();
		}

		pair<iterator, bool> insert(const K& key)
		{
			return _t.Insert(key);
		}

		iterator find(const K& key)
		{
			return _t.Find(key);
		}

	private:
		RBTree<K, K, SetKeyOfT> _t;
	};

}

Mymap.h

#include"RBTree.h"

namespace atl
{
	template <class K,class V>
	class map
	{
		struct MapKeyOfT
		{
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;
		typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Const_Iterator const_iterator;
		iterator begin()
		{
			return _t.Begin();
		}
		iterator end()
		{
			return _t.End();
		}
		const_iterator begin()const
		{
			return _t.Begin();
		}
		const_iterator end()const
		{
			return _t.End();
		}

		pair<iterator,bool> insert(const pair<K, V>& kv)
		{
			return _t.Insert(kv);
		}

		iterator find(const K& key)
		{
			return _t.Find(key);
		}

		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = insert(make_pair(key, V()));
			return ret.first->second;
		}

	private:
		RBTree<K, pair<const K,V>, MapKeyOfT> _t;
	};

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1952889.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python操作PostgreSQL指南

文本介绍了使用Python中的psycopg2库来操作PostgreSQL数据库&#xff0c;包括安装必要的包、建立和关闭连接、执行增删改查操作以及处理可能的异常。这些操作将在Python应用程序中与PostgreSQL数据库进行有效的交互。 一. 简介和包的安装 PostgreSQL是一个强大、开源的对象关…

技术分享!国产ARM + FPGA的SDIO通信开发介绍!

SDIO总线介绍 SDIO(Secure Digital lnput and Output),即安全数字输入输出接口。SDIO总线协议是由SD协议演化而来,它主要是对SD协议进行了一些扩展。 SDIO总线主要是为SDIO卡提供一个高速的I/O能力,并伴随着较低的功耗。SDIO总线不但支持SDIO卡,而且还兼容SD内存卡。支持…

web前端开发一、VScode环境搭建

1、VScode安装live server插件&#xff0c;写完代码后&#xff0c;保存就会在浏览器自动更新&#xff0c;不需要再去浏览器点击刷新了 2、创建html文件 3、在文件中输入感叹号 &#xff01; 4、选择第一个&#xff0c;然后回车&#xff0c;就会自动输入html的标准程序 5、…

【Linux C | 网络编程】进程池零拷贝传输的实现详解(四)

上一篇解决了进程池中进行大文件传输的问题&#xff0c;通过循环接收和发送指定大小的内容实现大文件的可靠传输。 【Linux C | 网络编程】进程池大文件传输的实现详解&#xff08;三&#xff09; 但是其中不可避免的在循环中使用多次的send和recv&#xff0c;这就涉及到多次…

0725_驱动1 内核中并发和竟态解决方法

一、内核中并发和竟态相关概念 一、什么时候产生竟态 1.同一个驱动程序&#xff0c;同时被多个应用层程序进行访问 2.访问同一个临界资源&#xff0c;驱动产生竟态 二、竟态产生根本原因 1.在单核cpu中&#xff0c;如果内核支持抢占&#xff0c;就会产生竟态 2.在多核cpu中&…

Internxt:适用于Linux开源安全云存储平台

有无数的云存储平台为您的文件提供安全可靠的存储空间。可在 Linux 上安装的热门云存储应用程序包括Dropbox、Nextcloud和Google Drive&#xff0c;遗憾的是&#xff0c;后者迄今为止不提供 Linux 客户端。 其他自托管选项包括OwnCloud、Pydio Cells、Seafile、Resilio和Synct…

【C++深度探索】AVL树与红黑树的原理与特性

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;C从入门至进阶 这里将会不定期更新有关C/C的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 前言 前…

鱼哥好书分享活动第28期:看完这篇《终端安全运营》终端安全企业基石,为你的终端安全保驾护航!

鱼哥好书分享活动第28期&#xff1a;看完这篇《终端安全运营》终端安全企业基石&#xff0c;为你的终端安全保驾护航&#xff01; 读者对象&#xff1a;主要内容&#xff1a;本书目录&#xff1a;了解更多&#xff1a;赠书抽奖规则: 在当前网络威胁日益复杂化的背景下&#xff…

SGLang 大模型推理框架 qwen2部署使用案例;openai接口调用、requests调用

参考: https://github.com/sgl-project/sglang 纯python写,号称比vllm、tensorRT还快 暂时支持模型 安装 可以pip、源码、docker安装,这里用的pip 注意flashinfer安装最新版,不然会可能出错误ImportError: cannot import name ‘top_k_top_p_sampling_from_probs’ fr…

FreeSWITCH 1.10.10 简单图形化界面27-Auto-Answer功能

FreeSWITCH 1.10.10 简单图形化界面27-Auto-Answer功能 1、前言2、测试环境3、呼叫测试 1、前言 在某些支持 Auto-Answer 消息头的 SIP 设备上&#xff0c;我们可以通过使用 FreeSWITCH 的 sip_auto_answer 变量来实现 SIP 设备的自动接听功能。即使 SIP 设备本身没有明确地启…

【无为则无心SpringBoot】— 1.SpringBoot介绍

1、什么是SpringBoot SpringBoot是Spring家族中的一个全新的框架&#xff0c;它用来简化Spring应用程序的创建和开发过程&#xff0c;也可以说SpringBoot能简化我们之前采用SpringMVCSpringMybatis框架进行开发的过程。 我们在使用Spring Boot时只需要配置相应的Spring Boot配置…

开源数据结构存储系统Redis的内部数据结构详解(上)

目录 1、简单动态字符串 1.1、SDS的定义 1.2、SDS与C字符串的区别 2、链表 2.1、链表的定义 2.2、特性 3、字典 3.1、哈希表定义 3.2、哈希表节点定义 3.3、字典定义 3.4、Rehash 3.5、渐进式rehash 4、总结 C++软件异常排查从入门到精通系列教程(专栏文章列表,…

ReentrantReadWriteLock详解

目录 ReentrantReadWriteLock详解1、ReentrantReadWriteLock简介2、ReentrantReadWriteLock类继承结构和类属性3、ReentrantReadWriteLock的读写锁原理分析4、ReentrantReadWriteLock.WriteLock类的核心方法详解非公平写锁的获取非公平写锁的释放公平写锁的获取公平写锁的释放 …

FPGA开发——独立仿真和联合仿真

一、概述 我们在进行FPGA开发的过程之中&#xff0c;大部分情况下都是在进行仿真&#xff0c;从而验证代码实现结果的正确与否&#xff0c;这里我们引入了独立仿真和联合仿真进行一个简单介绍。 联合仿真&#xff1a;一般我们在进行仿真之前需要在相应的软件中建立相应的工程…

C语言强化-3.单链表的新建、查找

与408的关联&#xff1a;1. 链表出了很多大题。 2. 任何数据结构&#xff0c;主要进行的操作就是增删改查。 头插法新建链表的实战 流程图 代码 #include <stdio.h> #include <stdlib.h>typedef int ElemType; typedef struct LNode{ElemType data;//数据域struc…

Docker 搭建Elasticsearch详细步骤

本章教程使用Docker搭建Elasticsearch环境。 一、拉取镜像 docker pull docker.elastic.co/elasticsearch/elasticsearch:8.8.2二、运行容器 docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-n

分布式锁的三种实现方式:Redis、基于数据库和Zookeeper

分布式锁的实现 操作共享资源&#xff1a;例如操作数据库中的唯一用户数据、订单系统、优惠券系统、积分系统等&#xff0c;这些系统需要修改用户数据&#xff0c;而多个系统可能同时修改同一份数据&#xff0c;这时就需要使用分布式锁来控制访问&#xff0c;防止数据不一致。…

一步步教你学会如何安装VMare虚拟机(流程参考图)

前言&#xff1a;一步步教你安装VMare虚拟机&#xff08;此版本为17.5。2版本&#xff09;。 1、安装 2、确认协议 3、选择位置存放 4、选择第二个 5、都不选。 6、都选提供便捷操作 7、点击许可证&#xff0c;将密钥输入&#xff08;可以在网络寻找自己版本的密钥&#xff…

学好C++之——函数重载、缺省参数、内联函数

函数重载、缺省参数、内联函数都是C不同于C语言的知识点&#xff0c;简单轻松&#xff0c;这里就放到一篇来讲—— 目录 1.缺省参数 1.1什么是缺省参数&#xff1f; 1.2为什么需要缺省参数&#xff1f; 1.3缺省参数的使用规则 2.函数重载 参数类型不同&#xff1a; 参数个…

错误代码0x80070035是什么情况?针对错误代码0x80070035的解决方法

错误代码 0x80070035 通常与网络连接和文件共享有关&#xff0c;表示“找不到网络路径”。这个问题可能由多种原因引起&#xff0c;包括网络设置不当、服务未启动、注册表配置错误等。今天这篇文章就和大家分享几种针对错误代码0x80070035的解决方法。 针对错误代码0x80070035问…