基于红黑树对map和set的封装

前言

前面我们已经对红黑树做了介绍和实现,本期我们来对红黑树进一步改造,然后基于改造后的红黑树封装出map和set!

本期内容介绍

• 红黑树的改造

• 红黑树的迭代器实现

• map的封装

• set的封装

• 全部源码

● 红黑树的改造

我们目前的实现的红黑树,里面存的是一个pair<K,V>的键值对,但是我们知道set是只有key没有val的,map是<key,val>的!而他两都是基于红黑树实现的,难道是弄两棵红黑树分别封装?这是不是太cuo了呀!显然不是的,库里面他两底层用的是一颗红黑树:

这里人家是将底层存的数据没有写死,给了一个Value的类型!你上层如果封装成map就给pair<K,V>,如果是封装成set就给K即可!(后面的比较器和空间配置器暂时就不看了)

• 问题一:set使用时是一个key为什么底层也要传给红黑树两个key?

由于map和set的底层都用的是同一棵红黑树,而map存的是K,V类型的键值对,所以这里可以认为是set对map的迁就!所以set即使用的时候只是一个key,但底层还是给红黑树一样的V和K,目的是使得红黑树的模板参数的一致性!

• 问题二:红黑树的是在左插入等操作时,如何知道你是pair还是key呢?

的确红黑树那一层是不知道的,但是我们map和set层是知道的!如何让红黑树那一层知道呢?就是第三个参数,是一个获取存储值key的类;当map和set传过去之后,红黑树层可以创建对象获取!

OK,我们也改造一下自己的红黑树出来吧:(我们就把存储的数据类型改成T避免与V混淆)

节点类要就不在是K,V了,而是T了:

insert也是不再是插入(inert后面介绍到[]还会改造

OK,我们先把红黑树的构造和拷贝构造以及赋值拷贝给整出来,在上层例如set进行赋值,拷贝等操作,就会到红黑树这一层,如果红黑树没有就成了浅拷贝了!

• 默认构造

这里本来可以不用写的,但是后面如果实现了赋值拷贝后就自动生不成了,所以得写!

RBTree()
	:_root(nullptr)
{}

还有一种就是即使有了拷贝构造可以强制让编译器生成:

RBTree() = default;//强制让编译器生成默认构造

• 拷贝构造

这里采用二叉树的前序逐一拷贝即可:

RBTree(const RBTree<K, T, KofT>& t)
{
	_root = Copy(t._root);
}
Node* Copy(Node* root)
{
	if (root == nullptr)
		return nullptr;
    
    //复制节点和颜色
	Node* newnode = new Node(root->_data);
	newnode->_col = root->_col;
    
    //复制左孩子
	newnode->_left = Copy(root->_left);
	if (newnode->_left)//连接
		newnode->_left->_parent = newnode;
        
    //复制右孩子
	newnode->_right = Copy(root->_right);
	if (newnode->_right)//连接
		newnode->_right->_parent = newnode;

	return newnode;
}

• 赋值拷贝

直接采用以前的那种现在写法:将形参用值接受,然后与当前交换

RBTree<K, T, KofT>& operator=(RBTree<K, T, KofT> t)
{
	swap(_root, t._root);
}

• 析构函数

采用二叉树的后序先删除做孩子,再删除右孩子,最后删除根节点

~RBTree()
{
	Destory(_root);
	_root = nullptr;
}
void Destory(Node* root)
{
	if (root == nullptr)
		return;

	Destory(root->_left);
	Destory(root->_right);
	delete root;
	root = nullptr;
}

● 红黑树的迭代器实现

红黑树的迭代器和链表的一样,空间不是连续的无法用原生指针来实现,得改一个类来达到“连续”的行为!我们使用的迭代器无非就begin、end、!=, *,->,++等但是begin和end只有红黑树知道,所以我们在迭代器里面只需要实现!=, *, ->,++等即可:

迭代器本质就是也即是一个节点的指针,所以这里的迭代器类和链表的一模一样:

template<class T, class Ref, class Ptr>
struct _RBTree_Iterator
{
	typedef RBTreeNode<T> Node;
	typedef _RBTree_Iterator<T, Ref, Ptr> Self;

	Node* _node;

	_RBTree_Iterator(Node* node)
		:_node(node)
	{}
}

operator*

直接返回该节点的数据的引用即可!

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

operator->

直接返回当前节点的数据的地址(指针)即可!

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

operator !=

直接比较两个节点的地址是否不相等即可!

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

operator==

直接比较两个节点的地址是否相同即可!

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

operator++

实现思路:因为红黑树迭代器走的是中序,即 左->根->右!而*的时候已经访问了该节点的左和他本身++是去找当前节点的下一个节点!所以此时只需要考虑,当前节点的有节点是是否为空!

1、如果当前节点的右节点不为空,下一个要访问的节点就是,右子树的最左节点!

2、如果当前节点的右节点为空,说当树全部都访问完了,此时就得向上找当前节点是父节点的左的父节点!下一个访问的就是这个父节点!

Self& operator++()
{
	if (_node->_right)
	{
		Node* leftMin = _node->_right;
		while (leftMin->_left)
		{
			leftMin = leftMin->_left;
		}

		_node = leftMin;
	}
	else
	{
		Node* cur = _node;
		Node* parent = cur->_parent;
		while (parent && cur == parent->_right)
		{
			cur = parent;
			parent = parent->_parent;
		}

		_node = parent;
	}

	return *this;
}

operator++(int)

有了前置的++后置直接复用即可!后置++的特点是返回+1前的值,这里同理!我们先拷贝一份当前的迭代器,然后当前迭代器复用前置++到下一个要访问的节点,然后返回拷贝即可!

//后置++
Self operator++(int)
{
	Self tmp = *this;
	++(*this);
	return tmp;
}

operator--

前置++的思路是更具中序的:左->根->右!这里的--就和前置++相反:右->根->左!

1、当前节点的左不为空,下一个访问的节点就是当前节点左子树的最右节点!

2、当前节点的左为空,找当前节点是父节点的有孩子的父节点,下一个访问的是该父节点

// 前置--
Self& operator--()
{
	if (_node->_left)
	{
		Node* cur = _node->_left;
		while (cur->_right)
		{
			cur = cur->_right;
		}
		_node = cur;
	}
	else
	{
		Node* cur = _node, * parent = cur->_parent;
		while (parent && parent->_left == cur)
		{
			cur = parent;
			parent = parent->_parent;
		}
		_node = parent;
	}
	return *this;
}

operator--(int)

后置--同理直接先拷贝一份当前节点,然后调用前置--带下一个访问的节点,最后返回该拷贝即可!

//后置--
Self operator--(int)
{
	Self tmp = *this;
	--(*this);
	return tmp;
}

begin

因为迭代器是按照中序走的,所以begin是整棵树的最左节点!

Iterator Begin()
{
	Node* leftMin = _root;
	while (leftMin && leftMin->_left)
	{
		leftMin = leftMin->_left;
	}

	return Iterator(leftMin);
}

end

这里的end应该是最右节点的下一个节点,这里简单处理为nullptr;

Iterator End()
{
	return Iterator(nullptr);
}

const_begin

ConstIterator Begin() const
{
	Node* leftMin = _root;
	while (leftMin && leftMin->_left)
	{
		leftMin = leftMin->_left;
	}

	return ConstIterator(leftMin);
}

const_end

ConstIterator End() const
{
	return ConstIterator(nullptr);
}

 ● map的封装

OK,先搞一个框架出来:

#pragma once

namespace cp
{
	template<class K, class V>
	class map
	{
		struct MapKeyOfT
		{
			const K& operator()(const prai<K,V>& kv)
			{
				return kv.first;
			}
		};
	public:

	private:
		RBTree<K, pair<const K, V>, MapKeyOfT> _m;//map的key不允许修改
	};
}

• 注意:map的key是不允许修改的所以用const修饰

OK,先来整迭代器出来,直接调用干红黑树的即可:

iterator

typedef typename RBTree<K, pair<const K,V>, MapKeyofT>::Iterator iterator;
typedef typename RBTree<K, pair<const K,V>, MapKeyofT>::ConstIterator const_iterator;
		
		
iterator begin()
{
	return _m.Begin();
}

iterator end()
{
	return _m.End();
}

const_iterator begin() const 
{
	return _m.Begin();
}

const_iterator end() const
{
	return _m.End();
}

注意:

typedef typename RBTree<K, const K, SetKofT>::Iterator iterator;
typedef typename RBTree<K, const K, SetKofT>::ConstIterator const_iterator;

这里的RBTree<K, const K, SetKofT>只是类型不是实体,所以编译器不认识,得加上typename告诉编译器这是类型;

find


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

insert

这里的insert,当前的红黑树是不要满足的,因为我们以前介绍使用的时候介绍过它的返回值是一个pair<iterator, bool>,如果插入成功返回当前插入节点的迭代器,bool设置为true;如果插入的元素失败,返回当前存在元素的迭代器,bool是false;

所以,我么先得改造红黑树的insert:挂在燥起来也不难,就是将返回值换成pair<iterator, bool>即可,唯一注意的一个点就是最后返回的那个节点的迭代器;一定要在前面提前记录变色前的那个新节点的指针,方便后面构造迭代器;如果不记录后面直接返回cur这个cur就不一定是前面的cur了因为会旋转 + 变色改变!!!

pair<Iterator, bool> Insert(const T& data)
{
	//第一次插入
	if (_root == nullptr)
	{
		_root = new Node(data);
		_root->_col = BLACK;//根节点是黑色
		return make_pair(Iterator(_root), true);
	}

	Node* cur = _root;//当前节点
	Node* parent = nullptr;//当前节点的父节点
	KofT kot;
	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), false);//插入的值已经存在
		}
	}

	//找到了插入位置
	cur = new Node(data);
	Node* newnode = cur;//提前保存返回的元素的位置,方便构造迭代器
	//链接
	if (kot(cur->_data) > kot(parent->_data))
	{
		parent->_right = cur;
	}
	else
	{
		parent->_left = cur;
	}
	cur->_parent = parent;

	//调节颜色平衡
	while (parent && parent->_col == RED)
	{
		Node* grandfather = parent->_parent;
		if (parent == grandfather->_left)//父亲在爷爷的左
		{
			Node* uncle = grandfather->_right;//叔叔在爷爷的右
			//叔叔存在且为红 -> 变色
			if (uncle && uncle->_col == RED)
			{
				grandfather->_col = RED;
				parent->_col = uncle->_col = BLACK;
				//继续更新
				cur = grandfather;
				parent = cur->_parent;
			}
			else//叔叔不存在或存在在且为黑 --> 旋转 + 变色
			{
				if (cur == parent->_left)
				{
					//     g
					//   p   u
					// c
					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
		{
			Node* uncle = grandfather->_left;//叔叔在爷爷的左
			//叔叔存在且为红 -> 变色
			if (uncle && uncle->_col == RED)
			{
				grandfather->_col = RED;
				parent->_col = uncle->_col = BLACK;
				//继续更新
				cur = grandfather;
				parent = cur->_parent;
			}
			else//叔叔不存在或为黑 --> 旋转+变色
			{
				if (cur == parent->_left)
				{
					//     g
					//   u   p
					//     c
					RotateR(parent);
					RotateL(grandfather);
					cur->_col = BLACK;
					grandfather->_col = RED;
				}
				else
				{
					//     g
					//   u   p
					//         c
					RotateL(grandfather);
					parent->_col = BLACK;//变色
					grandfather->_col = RED;
				}

				break;//旋转+变色完了就结束掉
			}
		}
	}

	_root->_col = BLACK;//保证根节点永远是黑色
	return make_pair(Iterator(newnode), true);
}

成功改造完红黑的的insert之后map和set的就直接可以调用了!

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

operator[]

[]是基于insert实现的,在介绍使用的时候介绍过,[]按照K值插入,不管插入成功与否,都返回V的引用~!

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

OK,测试一下:

void Print_map(const cp::map<string, int> m)
{
	for (auto& e : m)
	{
		cout << e.first << " : " << e.second << endl;
	}
}

void TestMap()
{
	cp::map<int, int> m1;
	m1.insert({ 1,1 });
	m1.insert({ 2,2 });
	m1.insert({ 3,3 });
	m1.insert({ 4,4 });
	m1.insert({ 5,5 });
	cp::map<int, int>::iterator it = m1.begin();
	while (it != m1.end())
	{
		cout << it->first << ":" << it->second << endl;
		it++;
	}
	cout << "--------------------" << endl;


	cp::map<string, int> m2;
	string s[] = { "aaa", "bbb", "ccc", "bbb", "cpdd", "000", "苹果", "西瓜", "aaa" };
	for (auto& e : s)
		m2[e]++;
	Print_map(m2);
}

● set的封装

同理,我们可以搭建出一个set的基本框架出来:

#pragma once

namespace cp
{
	template<class K>
	class set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:

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

OK,先来整迭代器出来,直接调用干红黑树的即可:

inerator

typedef typename RBTree<K, const K, SetKofT>::Iterator iterator;
typedef typename RBTree<K, const K, SetKofT>::ConstIterator const_iterator;

iterator begin()
{
	return _s.Begin();
}

iterator end()
{
	return _s.End();
}

const_iterator begin() const
{
	return _s.Begin();
}

const_iterator end() const
{
	return _s.End();
}

find

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

insert

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

OK,测试一下:

void Print_set(const cp::set<int>& s)
{
	for (auto& e : s)
	{
		cout << e << endl;
	}
}

void TestSet()
{
	vector<int> v = { 8, 3, 1, 10, 6, 4, 7, 14, 13, 8, 6 };
	cp::set<int> s;
	for (auto& e : v)
	{
		s.insert(e);
	}

	Print_set(s);
}

OK,到这里map和set的封装就已经实现完了!一些接口例如size、clear等前面实现过很多次这里就不在实现了!这里想说的是map和set就是套了一层红黑树的壳,真正的核心还是红黑!

● 全部源码

RBTree.h

#pragma once

#pragma once

enum Col
{
	RED = 0,
	BLACK
};

template <class T>
struct RBTreeNode
{
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	T _data;
	Col _col;

	RBTreeNode(const T& data)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _data(data)
		, _col(RED)//默认新的节点是红色
	{}
};

template<class T, class Ref, class Ptr>
struct _RBTree_Iterator
{
	typedef RBTreeNode<T> Node;
	typedef _RBTree_Iterator<T, Ref, Ptr> Self;

	Node* _node;

	_RBTree_Iterator(Node* node)
		:_node(node)
	{}

	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;
	}

	//前置++
	Self& operator++()
	{
		if (_node->_right)
		{
			Node* leftMin = _node->_right;
			while (leftMin->_left)
			{
				leftMin = leftMin->_left;
			}

			_node = leftMin;
		}
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_right)
			{
				cur = parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this;
	}

	//后置++
	Self operator++(int)
	{
		Self tmp = *this;
		++(*this);
		return tmp;
	}

	// 前置--
	Self& operator--()
	{
		if (_node->_left)
		{
			Node* cur = _node->_left;
			while (cur->_right)
			{
				cur = cur->_right;
			}
			_node = cur;
		}
		else
		{
			Node* cur = _node, * parent = cur->_parent;
			while (parent && parent->_right != cur)
			{
				cur = parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		return *this;
	}

	//后置--
	Self operator--(int)
	{
		Self tmp = *this;
		--(*this);
		return tmp;
	}
};

template <class K, class T, class KofT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	typedef _RBTree_Iterator<T, T&, T*> Iterator;
	typedef _RBTree_Iterator<T, const T&, const T*> ConstIterator;

	RBTree() = default;//强制让编译器生成默认构造

	//RBTree()
	//	:_root(nullptr)
	//{}

	RBTree(const RBTree<K, T, KofT>& t)
	{
		_root = Copy(t._root);
	}

	RBTree<K, T, KofT>& operator=(RBTree<K, T, KofT> t)
	{
		swap(_root, t._root);
	}

	~RBTree()
	{
		Destory(_root);
		_root = nullptr;
	}

	Iterator Begin()
	{
		Node* leftMin = _root;
		while (leftMin && leftMin->_left)
		{
			leftMin = leftMin->_left;
		}

		return Iterator(leftMin);
	}

	Iterator End()
	{
		return Iterator(nullptr);
	}

	ConstIterator Begin() const
	{
		Node* leftMin = _root;
		while (leftMin && leftMin->_left)
		{
			leftMin = leftMin->_left;
		}

		return ConstIterator(leftMin);
	}

	ConstIterator End() const
	{
		return ConstIterator(nullptr);
	}

	Iterator Find(const K& key)
	{
		KofT 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);
			}
		}

		return End();
	}

	pair<Iterator, bool> Insert(const T& data)
	{
		//第一次插入
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;//根节点是黑色
			return make_pair(Iterator(_root), true);
		}

		Node* cur = _root;//当前节点
		Node* parent = nullptr;//当前节点的父节点
		KofT kot;
		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), false);//插入的值已经存在
			}
		}

		//找到了插入位置
		cur = new Node(data);
		Node* newnode = cur;//提前保存返回的元素的位置,方便构造迭代器
		//链接
		if (kot(cur->_data) > kot(parent->_data))
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		cur->_parent = parent;

		//调节颜色平衡
		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;
			if (parent == grandfather->_left)//父亲在爷爷的左
			{
				Node* uncle = grandfather->_right;//叔叔在爷爷的右
				//叔叔存在且为红 -> 变色
				if (uncle && uncle->_col == RED)
				{
					grandfather->_col = RED;
					parent->_col = uncle->_col = BLACK;
					//继续更新
					cur = grandfather;
					parent = cur->_parent;
				}
				else//叔叔不存在或存在在且为黑 --> 旋转 + 变色
				{
					if (cur == parent->_left)
					{
						//     g
						//   p   u
						// c
						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
			{
				Node* uncle = grandfather->_left;//叔叔在爷爷的左
				//叔叔存在且为红 -> 变色
				if (uncle && uncle->_col == RED)
				{
					grandfather->_col = RED;
					parent->_col = uncle->_col = BLACK;
					//继续更新
					cur = grandfather;
					parent = cur->_parent;
				}
				else//叔叔不存在或为黑 --> 旋转+变色
				{
					if (cur == parent->_left)
					{
						//     g
						//   u   p
						//     c
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						//     g
						//   u   p
						//         c
						RotateL(grandfather);
						parent->_col = BLACK;//变色
						grandfather->_col = RED;
					}

					break;//旋转+变色完了就结束掉
				}
			}
		}

		_root->_col = BLACK;//保证根节点永远是黑色
		return make_pair(Iterator(newnode), true);
	}

	void InOrder()
	{
		return _InOrder(_root);
	}

	bool IsBalance()
	{
		if (_root && _root->_col == RED)
			return false;//根节点不可能为红

		int black = 0;//根节点到任意一条从根节点到叶子节点的黑色节点的数目
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
				black++;

			cur = cur->_left;
		}

		return Check(_root, black, 0);
	}

private:

	Node* Copy(Node* root)
	{
		if (root == nullptr)
			return nullptr;

		Node* newnode = new Node(root->_data);
		newnode->_col = root->_col;

		newnode->_left = Copy(root->_left);
		if (newnode->_left)
			newnode->_left->_parent = newnode;

		newnode->_right = Copy(root->_right);
		if (newnode->_right)
			newnode->_right->_parent = newnode;

		return newnode;
	}

	void Destory(Node* root)
	{
		if (root == nullptr)
			return;

		Destory(root->_left);
		Destory(root->_right);
		delete root;
		root = nullptr;
	}

	void _InOrder(Node* root)
	{
		if (root == nullptr)
			return;

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

	bool Check(Node* root, const int black, int num)
	{
		if (root == nullptr)
		{
			if (num != black)
				return false;

			return true;
		}

		if (root->_col == RED && root->_parent && root->_parent->_col == RED)
		{
			cout << "存在连续的红色节点:" << endl;
			return false;
		}

		if (root->_col == BLACK)
		{
			++num;
		}

		return Check(root->_left, black, num) && Check(root->_right, black, num);
	}

	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;//父亲的左
		Node* subLR = subL->_right;//左子树的右
		Node* ppNode = parent->_parent;//parent的父节点,方便旋转后的链接

		parent->_left = subLR;//将左子树的右给父亲的做
		if (subLR)
			subLR->_parent = parent;

		subL->_right = parent;//parent做左子树的右
		parent->_parent = subL;

		if (parent == _root)//parent是根
		{
			_root = subL;//此时的新根就是subL
			_root->_parent = ppNode;
		}
		else//parent不是根
		{
			//将新的根连接到ppNode
			if (ppNode->_left == parent)
			{
				ppNode->_left = subL;
			}
			else
			{
				ppNode->_right = subL;
			}
			subL->_parent = ppNode;
		}
	}

	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;//父亲的右
		Node* subRL = subR->_left;//右子树的左
		Node* ppNode = parent->_parent;//parent的父节点,方便旋转后的链接

		parent->_right = subRL;//将右子树的左连接到parent的右
		if (subRL)
			subRL->_parent = parent;

		subR->_left = parent;//parent连接到subR的左
		parent->_parent = subR;

		if (parent == _root)//parent是根
		{
			_root = subR;//此时的新根就是subR
			_root->_parent = ppNode;
		}
		else//parent不是根
		{
			//将新的根连接到ppNode
			if (ppNode->_left == parent)
			{
				ppNode->_left = subR;
			}
			else
			{
				ppNode->_right = subR;
			}
			subR->_parent = ppNode;
		}
	}

private:
	Node* _root = nullptr;
};

Mymap.h

#pragma once

namespace cp
{
	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>::ConstIterator const_iterator;


		iterator begin()
		{
			return _m.Begin();
		}

		iterator end()
		{
			return _m.End();
		}

		const_iterator begin() const
		{
			return _m.Begin();
		}

		const_iterator end() const
		{
			return _m.End();
		}

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

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

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

	private:
		RBTree<K, pair<const K, V>, MapKeyofT> _m;
	};
}

Myset.h

#pragma once

namespace cp
{
	template<class K>
	class set
	{
		struct SetKofT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename RBTree<K, const K, SetKofT>::Iterator iterator;
		typedef typename RBTree<K, const K, SetKofT>::ConstIterator const_iterator;

		iterator begin()
		{
			return _s.Begin();
		}

		iterator end()
		{
			return _s.End();
		}

		const_iterator begin() const
		{
			return _s.Begin();
		}

		const_iterator end() const
		{
			return _s.End();
		}

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

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

	private:
		RBTree<K, const K, SetKofT> _s;
	};
}

OK,本期分享就到这里,好兄弟我们下期再见~!

结束语:我们的目标是星辰大海!

  • 26
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
在C++ STL中,树的实现被封装在`std::map`和`std::set`这两个容器类中。这两个容器类都是基于树实现的,它们提供了高效的查找、插入和删除操作,保证了元素的有序性。 STL中的树实现与你提供的C++代码略有不同。STL中的树使用节点颜色(色或色)和节点指针(parent、left、right)来表示树的结构,而你提供的代码使用了模板和节点对象来实现。 在STL中,树的插入和删除操作已经被封装在`std::map`和`std::set`中,使用起来非常简单。你只需要包含相应的头文件`<map>`或`<set>`,并使用`std::map`或`std::set`类来定义变量,就可以直接使用树的功能了。 以下是使用STL中树的简单示例: ```cpp #include <map> int main() { std::map<int, std::string> myMap; // 插入元素 myMap.insert(std::make_pair(1, "one")); myMap = "two"; // 查找元素 auto it = myMap.find(1); if (it != myMap.end()) { std::cout << it->second << std::endl; // 输出 "one" } // 删除元素 myMap.erase(2); return 0; } ``` 在上面的示例中,我们使用`std::map`来创建一个键-值对的树。我们使用`insert`函数插入元素,使用`find`函数查找元素,使用`erase`函数删除元素。 总结一下,C++ STL中的树实现被封装在`std::map`和`std::set`中,使用起来非常方便。你可以直接包含相应的头文件,并使用这些类来实现树的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值