c++:map和set的底层实现

一、对源码的分析

我们知道对map和set的基本实现,一定离不开红黑树的实现,在我实现的红黑树中,只适用于map的pair结构的使用,并不适合set单参数key的使用,故此我们要 解决使map和set使用同一个红黑树去实现他们不同的功能,所以我们需要把红黑树泛型化,也就是利用模板来操作,所以我们目前没有大佬思维那就去看大佬的代码,去借鉴然后实现功能差不多的就可以了,因为看源码还是有难度的所以我就截取重要的核心部分来理解。
这是树的核心模板参数

cpp 复制代码
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc 
= alloc>
class rb_tree {
protected:
typedef void* void_pointer;
typedef __rb_tree_node_base* base_ptr;
typedef __rb_tree_node<Value> rb_tree_node;
typedef rb_tree_node* link_type;
typedef Key key_type;
typedef Value value_type;

下面是map和set的核心部分

cpp 复制代码
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set {
public:
// typedefs:
typedef Key key_type;
typedef Key value_type;
private:
typedef rb_tree<key_type, value_type, 
identity<value_type>, key_compare, Alloc> rep_type;
rep_type t;  // red-black tree representing set
}

template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class map {
public:
// typedefs:
typedef Key key_type;
typedef T mapped_type;

typedef pair<const Key, T> value_type;
private:
typedef rb_tree<key_type, value_type, 
select1st<value_type>, key_compare, Alloc> rep_type;
rep_type t;  // red-black tree representing map
}

直接说结论,红黑树RBTree中它这里的Value对应的就是如果传的是Key,那就是set,如果传的是pair<K,V>,那就是map的实例化,我知道它这里的Value命名有点会不知道,让人以为是pair中的Value也就是第二个值,所以下面我对以前实现的红黑树的模板会改为T,map第二个值T也会改为Value的简称V,

二、对map和set的底层实现

2.1对红黑树的改造

先讲讲初步的改变

这样使得我们的红黑树就是个泛型模板可以同时适用于map和set

模板参数的讲解

第一个K:其实它的作用不大,因为第二个参数T已经可以实例化出map和set,这个就是红黑树里的find函数里需要,它是只要第一个参数K,所以第一个模板参数的作用就是这个
第二个T:上面也说到了,判断是存入Key,还是pair<K,V>,也就是set和map的底层储存方式
第三个keyofT,顾名思义从T中取出Key,这个在红黑树的插入和查找都会用,因为比如查找中,因为写的是泛型你不知道是set的实例化还是map的实例化,插入的数据比当前结点的小往左走,大就往右走,因为是map传入的数据是pair键值我们比较的是键值的第一个参数,如果是set那就直接是Key,可以直接比较,但就是如果是map的实例化,那就要加.first,就不符合set的比较,并且pair的重载的比较函数不符合我们的比较方式,它是第二个参数second也用了,所以我们需要在set和map中写仿函数传不同的仿函数就能自己控制比较方式

下面是改动的地方的代码

cpp 复制代码
template <class K, class T,class KeyofT>
class RBTree
{
bool insert(const T& data)
{
	if (!_root)
	{
		_root = new node(data);
		_root->_Col = BLACK;
	}
	node* cur = _root;
	node* parent = nullptr;
	KeyofT kot;
	while (cur)
	{
		if (kot(data)< kot(cur->_data))
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (kot(data)> kot(cur->_data))
		{
			parent = cur;
			cur = cur->_right;
		}
		else {
			return false;
		}
	}
	cur = new node(data);
	node* newnode = cur;
	if (kot(data) < kot(parent->_data))
		parent->_left = cur;
	else
		parent->_right = cur;
	cur->_parent = parent;
	cur->_Col = RED;
	};

2.2map和set的实现操作

cpp 复制代码
namespace TAO
{
	template <class K>
	class set
	{
	public:
		struct setofT
		{
			const K& operator()(const K& key)const
			{
				return key;
			}
				bool insert(const K& key)
	{
		return _t.insert(key);
	}
	

private:
	RBTree<K, K, setofT> _t;
};
namespace TAO
{
	template <class K,class V>
	class map
	{
	public:
		struct mapofT
		{
			 const K& operator()(const pair<const K,V>& kv)
			{
				return kv.first;
			}
		};
		bool insert(const pair<const K,V>& kv)
{
	return _t.insert(kv);
}
private:
	RBTree<K, pair<const K, V>, mapofT> _t;

由上面也可以看出就是set和map的底层实际就是靠封装的红黑树实现,插入就是调用红黑树的插入函数,然后在这里的传的参数都是各种map和set的实际存的数值,外层只需要给出要存的值的类型就行当然还没完还要给它们适配迭代器

2.3迭代器的实现

cpp 复制代码
template <class T,class Ref,class Ptr>
struct RBTree_Iterator
{
	typedef RBNode<T> node;
	typedef RBTree_Iterator<T,Ref,Ptr> self;
	node* _node;
	RBTree_Iterator(node* node)
		:_node(node)
	{
	}
	Ref operator* ()
	{
		return _node->_data;
	}
	self& operator++()
	{
		if (_node->_right) {
			_node = _node->_right;
			while (_node->_left)
			{
				_node = _node->_left;
			}
		}
		else {
			node* cur = _node;
			node* parent = _node->_parent;
			while (parent && parent->_right == cur)
			{
				cur = parent;
				parent = cur->_parent;
			}
			_node = parent;
		}
		return *this;
	}
	Ptr operator->()
	{
		return &_node->_data;
	}
	bool operator!=(const self& s)const
	{
		return _node != s._node;
	}

};

也是一样,想要实现迭代器那就要先实现红黑树的迭代器,然后再在map和set直接套用,这里的跟list的类似,主要讲一下++的操作,因为是中序遍历,所以返回的值的排序是有序的。

第一步: 先找到最左结点,到外层也就是传的begin()

二步: 因为是左子树->根 ->右子树,那当右子树为空时那就证明当前子树遍历完了,要想上找祖先,比如如上图的15的右为空证明以15为父结点的子树遍历完了,想上找祖先,10的右边是15,证明10的右边找完了,也就是以10为子树的结点都遍历完了,那再向上找祖先,18的左边是10,那证明18的左子树已经遍历完了,现在到根,然后再遍历18的右子树,然后再循环往复,知道到18的祖先为空那就介素,所以end()返回的就是nullptr

然后map和set都是套一层壳子,下面是关于迭代器的相关的代码

cpp 复制代码
class RBTree
{
public:
	typedef RBNode<T> node;
	typedef RBTree_Iterator<T,T&,T*> Iterator;
	typedef RBTree_Iterator<T,const T& ,T*> ConstIterator;
	Iterator Begin()
	{
		node* cur = _root;
		while (cur && cur->_left)
			cur = cur->_left;
		return Iterator(cur);
	}
	Iterator End()
	{
		return Iterator(nullptr);
	}
	ConstIterator cBegin()const
	{
		const node* cur = _root;
		while (cur && cur->_left)
			cur = cur->_left;
		return ConstIterator(cur);
	}
	ConstIterator cEnd()const
	{
		return ConstIterator(nullptr);
	}
template <class K>
class set
{
typedef typename RBTree<K, K, setofT>::Iterator iterator;
typedef typename RBTree<K, K, setofT>::ConstIterator const_iterator;
iterator begin()
{
	return _t.Begin();
}
iterator end()
{
	return _t.End();
}
const_iterator cbegin()const
{
	return _t.cBegin();
}
const_iterator cend()const
{
	return _t.cEnd();
}

template <class K,class V>
class map
{
	typedef typename RBTree<K, pair<const K,V>, mapofT>::Iterator iterator;
	typedef typename RBTree<K, pair<const K,V>, mapofT>::ConstIterator const_iterator;
	iterator begin()
	{
		return _t.Begin();
	}
	iterator end()
	{
		return _t.End();
	}
	const_iterator cbegin()const
	{
		return _t.cBegin();
	}
	const_iterator cend()const
	{
		return _t.cEnd();
	}
		

注意,这里的map和set中的对红黑树的迭代器的重命名一定要加typename,因为红黑树的迭代器还是未实例化的,不加的话可能也是静态成员变量也是这样的写法,编译器就无法分辨,所以加typename就是告诉编译器这是类型不是静态成员变量

2.4对map重载\[\]

mKey,这个的意思就是Key在m中那就返回它的Value值也就是第二个参数second,不在就插入Key然后也返回second的值,
所以源码中,对insert的返回值不是bool,而是pair<iterator,bool>
下面代码中,ret,first就是pair中的返回key的迭代器,->就是重载的->返回的是存key的pair然后实际会省略一个->,引用返回就能达到改second

cpp 复制代码
 pair<Iterator,bool> insert(const T& data)
 V& operator[](const K& key)
{
	pair<iterator, bool> ret = insert({ key,V() });
	return ret.first->second;//进行了->重载的函数
}

三、完整代码

cpp 复制代码
#pragma once
#include <iostream>
#include <assert.h>
#include <vector>
using namespace std;


enum Color
{
	RED,
	BLACK
};
//需要同时满足map和set的红黑树
template < class T> //
struct RBNode
{
	T _data;
	RBNode<T>* _left;
	RBNode<T>* _right;
	RBNode<T>* _parent;
	Color _Col;
	RBNode(const T& data)
		:_data(data)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _Col(RED)
	{
	}

};
template <class T,class Ref,class Ptr>
struct RBTree_Iterator
{
	typedef RBNode<T> node;
	typedef RBTree_Iterator<T,Ref,Ptr> self;
	node* _node;
	RBTree_Iterator(node* node)
		:_node(node)
	{
	}
	Ref operator* ()
	{
		return _node->_data;
	}
	self& operator++()
	{
		if (_node->_right) {
			_node = _node->_right;
			while (_node->_left)
			{
				_node = _node->_left;
			}
		}
		else {
			node* cur = _node;
			node* parent = _node->_parent;
			while (parent && parent->_right == cur)
			{
				cur = parent;
				parent = cur->_parent;
			}
			_node = parent;
		}
		return *this;
	}
	Ptr operator->()
	{
		return &_node->_data;
	}
	bool operator!=(const self& s)const
	{
		return _node != s._node;
	}

};

//红黑树的实现
template <class K, class T,class KeyofT>
class RBTree
{
public:
	typedef RBNode<T> node;
	typedef RBTree_Iterator<T,T&,T*> Iterator;
	typedef RBTree_Iterator<T,const T& ,T*> ConstIterator;
	Iterator Begin()
	{
		node* cur = _root;
		while (cur && cur->_left)
			cur = cur->_left;
		return Iterator(cur);
	}
	Iterator End()
	{
		return Iterator(nullptr);
	}
	ConstIterator cBegin()const
	{
		const node* cur = _root;
		while (cur && cur->_left)
			cur = cur->_left;
		return ConstIterator(cur);
	}
	ConstIterator cEnd()const
	{
		return ConstIterator(nullptr);
	}
	 pair<Iterator,bool> insert(const T& data)
	{
		if (!_root)
		{
			_root = new node(data);
			_root->_Col = BLACK;
			return { Iterator(_root),true};
		}
		node* cur = _root;
		node* parent = nullptr;
		KeyofT kot;
		while (cur)
		{
			if (kot(data)< kot(cur->_data))
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (kot(data)> kot(cur->_data))
			{
				parent = cur;
				cur = cur->_right;
			}
			else {
				return { Iterator(cur),false};
			}
		}
		cur = new node(data);
		node* newnode = cur;
		if (kot(data) < kot(parent->_data))
			parent->_left = cur;
		else
			parent->_right = cur;
		cur->_parent = parent;
		cur->_Col = RED;
		//如果parent的颜色为红色就要变色
		while (parent && parent->_Col == RED)
		{
			node* grandfather = parent->_parent;
			if (parent == grandfather->_left)
			{
				node* uncle = grandfather->_right;
				//cur是新增结点
				//叔叔存在且为红色
				if (uncle && uncle->_Col == RED)
				{
					parent->_Col = BLACK;
					uncle->_Col = BLACK;
					grandfather->_Col = RED;
					cur = grandfather;
					parent = cur->_parent;
				}
				//cur不是新增结点
				//叔叔为空或为黑色
				else {
					//  g
					// p
					//c  u
					// 右旋加变色
					if (cur == parent->_left)
					{
						RotateR(grandfather);
						parent->_Col = BLACK;
						grandfather->_Col = RED;
					}
					else {
						//  g
						// p  u
						//  c
						// 左右双旋加变色
						RotateL(parent);
						RotateR(grandfather);
						cur->_Col = BLACK;
						grandfather->_Col = RED;
					}
					break;
				}
			}
			else {//parent== grandfather-> _right;
				node* uncle = grandfather->_left;
				//cur是新增结点
				//叔叔存在且为红色
				if (uncle && uncle->_Col == RED)
				{
					parent->_Col = BLACK;
					uncle->_Col = BLACK;
					grandfather->_Col = RED;
					cur = grandfather;
					parent = cur->_parent;
				}
				//cur不是新增结点
				//叔叔为空或为黑色
				else {
					//  g
					// u  p
					//     c
					// 左单旋+变色
					if (cur == parent->_right)
					{
						RotateL(grandfather);
						parent->_Col = BLACK;
						grandfather->_Col = RED;
					}
					else {
						//  g
						// u  p
						//   c
						//右左双旋+变色
						RotateR(parent);
						RotateL(grandfather);
						cur->_Col = BLACK;
						grandfather->_Col = RED;
					}
					break;
				}
			}
		}
		_root->_Col = BLACK;
		return { Iterator(newnode),true};
	}
	void Inorder()
	{
		_Inorder(_root);
	}
	bool RBblance()
	{
		if (!_root)
			return true;
		if (_root && _root->_Col == RED)
			return false;
		int mostleftB = 0;
		node* cur = _root;
		while (cur)
		{
			if (cur->_Col == BLACK) {
				++mostleftB;
			}
			cur = cur->_left;
		}
		return check(_root, 0, mostleftB);
	}
	bool find(const K& key)
	{
		KeyofT kot;
		node* cur = _root;
		while (cur)
		{
			if (kot(data) < kot(cur->_data))
			{
			
				cur = cur->_left;
			}
			else if (kot(data) > kot(cur->_data))
			{
				
				cur = cur->_right;
			}
			else {
				return true;
			}
		}
		return false;
	}
private:
	bool check(node* root, int blacknum, const int mostleftB)
	{
		if (!root)
		{
			if (mostleftB != blacknum)
			{
				cout << "存在黑色结点的数量不相等的路径" << endl;
			}
			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, mostleftB)
			&& check(root->_right, blacknum, mostleftB);
	}
	void _Inorder(node* root)
	{
		if (!root)
			return;
		_Inorder(root->_left);
		cout << root->_kv.first << ' ';
		_Inorder(root->_right);
	}
	void RotateR(node* parent)
	{
		node* subL = parent->_left;
		node* subLR = subL->_right;
		node* parent_parent = parent->_parent;
		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;
		subL->_right = parent;
		parent->_parent = subL;
		if (parent_parent)
		{
			if (parent_parent->_left == parent)
			{
				parent_parent->_left = subL;
			}
			else {
				parent_parent->_right = subL;
			}
			subL->_parent = parent_parent;
		}
		else {
			_root = subL;
			_root->_parent = nullptr;
		}

	}
	void RotateL(node* parent)
	{
		node* subR = parent->_right;
		node* subRL = subR->_left;
		node* parent_parent = parent->_parent;
		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;
		subR->_left = parent;
		parent->_parent = subR;
		if (parent_parent)
		{
			if (parent_parent->_left == parent)
			{
				parent_parent->_left = subR;
			}
			else {
				parent_parent->_right = subR;
			}
			subR->_parent = parent_parent;
		}
		else {
			_root = subR;
			_root->_parent = nullptr;
		}

	}
private:
	node* _root = nullptr;
};
#pragma once
#include "RBTree.h"

namespace TAO
{
	template <class K>
	class set
	{
	public:
		struct setofT
		{
			const K& operator()(const K& key)const
			{
				return key;
			}
		};
		////未实例化需要用typename来告诉编译器不是静态成员变量 
		typedef typename RBTree<K, K, setofT>::Iterator iterator;
		typedef typename RBTree<K, K, setofT>::ConstIterator const_iterator;
		iterator begin()
		{
			return _t.Begin();
		}
		iterator end()
		{
			return _t.End();
		}
		const_iterator cbegin()const
		{
			return _t.cBegin();
		}
		const_iterator cend()const
		{
			return _t.cEnd();
		}
		
		pair<iterator,bool> insert(const K& key)
		{
			return _t.insert(key);
		}
		

	private:
		RBTree<K, K, setofT> _t;
	};
	#pragma once
#include "RBTree.h"

namespace TAO
{
	template <class K>
	class set
	{
	public:
		struct setofT
		{
			const K& operator()(const K& key)const
			{
				return key;
			}
		};
		////未实例化需要用typename来告诉编译器不是静态成员变量 
		typedef typename RBTree<K, K, setofT>::Iterator iterator;
		typedef typename RBTree<K, K, setofT>::ConstIterator const_iterator;
		iterator begin()
		{
			return _t.Begin();
		}
		iterator end()
		{
			return _t.End();
		}
		const_iterator cbegin()const
		{
			return _t.cBegin();
		}
		const_iterator cend()const
		{
			return _t.cEnd();
		}
		
		pair<iterator,bool> insert(const K& key)
		{
			return _t.insert(key);
		}
		

	private:
		RBTree<K, K, setofT> _t;
	};
}
相关推荐
恋猫de小郭1 小时前
Flutter 开发怎么做 Agent ?从工程实战详细给你解读下
android·前端·flutter
汉克老师1 小时前
GESP2026年6月认证C++一级( 第一部分选择题(1-7))精讲
c++·运算符·表达式·赋值·gesp1级·输入与输出·单循环
ALex_zry1 小时前
C++26 Freestanding 库扩展详解:无操作系统也能用标准库
java·jvm·c++
Tian_Hang1 小时前
Eclipse Mosquitto 安装及介绍
java·运维·服务器·ide·sql·mysql·eclipse
weelinking1 小时前
weytoken微元算力企业级大模型治理平台深度评测
java·大数据·人工智能
安卓修改大师1 小时前
安卓修改大师实战:Activity生命周期全解析与Smali插桩教程
android
卓怡学长1 小时前
w273基于springboot的智能笔记的开发与应用
java·spring boot·spring·intellij-idea
峥嵘life2 小时前
Android GMS 开机向导横竖屏切换配置总结
android·学习
apihz2 小时前
PING 接口 PLUS 全球版 —— 免费全球多节点 Ping 检测 API教程
android