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

目录

一、改造红黑树

二、红黑树的迭代器

1、operator++

 2、operator--

3、map-operator [ ]

4、const 迭代器

5、迭代器的begin()和end()

三、封装 map 和 set

1、提取 k 的值

​2、map 和set 的迭代器

四、key值不能修改的问题

1、set

2、map

​五、完整代码


一、改造红黑树

map 和 set 的底层都是红黑树,虽然不是同一棵树,但都是由同一个模板实例化而成。因此我们希望改造红黑树,让他适配不同类型的数据。关联式容器中存储的是的键值对,k为key的类型,ValueType: 如果是map,则为pair; 如果是set,则为k

我们可以定义一个模板T,通过传模板参数来决定树里存的是什么数据类型。

【存在问题】
当我们插入或者查找一个节点时,红黑树里的比较逻辑都是按照pair里面的K值进行比较的,这里的红黑树存储的数据是T类型,当插入一个T类型的数据时,我们不知道这个数据是 K 类型还是pair<K,V>类型,这就无法进行比较
【解决方法】
我们可以利用一个仿函数,这个仿函数的功能是可以将数据里的K类型数据取出来。那么我们可以给红黑树增加一个模板参数,给仿函数用。一旦遇到要比较的逻辑时,我们就可以将数据里的K值取出来进行比较。
仿函数实现的原理:当T类型是K类型数据时,直接返回K值即可,当T类型是pair<K,V>数据时,返回里面的 first 数据即可(就是K值)。


 

二、红黑树的迭代器

迭代器的好处是可以方便遍历,是数据结构的底层实现与用户透明。如果想要给红黑树增加迭代 器,需要考虑红黑树的迭代器和链表的迭代器类似,都是自定义类型,因为原生指针不能满足需要,所以需要自定义。

1、operator++

中序遍历是左、根、右。

所以begin的位置肯定是在最左边,也就是最小值。

++指向下一个位置,也就是右子树的最左边,此时我们需要考虑右子树是否存在。

当右边有结点时,那么就找右边的最小值,也就是右边的最左结点。
当右边没有结点时,我们就要往上找(父亲结点&&左结点)的节点。因为当右边没有结点时,说明右边已经访问完了,那么往上找凡是父亲结点是祖先右边时就直接跳过,当父亲结点是祖先左边时,那么这个祖先结点就是下一次要访问的结点。

 2、operator--

跟++倒着来就可以了。遍历顺序是右、根、左。
--就是到上一个比它小的位置。因此我们要讨论的是当前结点的左边是否有结点。
当左边有结点时,我们就找左边的最大值,也就是左边的最右结点。
当左边没有结点时,我们就找父亲结点为右结点的那个祖先。

3、map-operator [ ]

map的[ ]运算符重载,底层实现本质是调用了insert函数。然后通过insert函数返回的pair<iterator,bool>类型数据来找到Value值。所以在实现[ ]运算符重载时,我们需要对红黑树里的insert进行改造,因为原来的insert的返回值是布尔值,我们需要pair类型返回值。

 红黑树的insert改造后,那么set和map里的insert都需要修改,因为底层用的就是红黑树的insert。

4、const 迭代器

与链表的const迭代器实现原理一样,我们通过三个模板参数(template <class T,class Ref,class Ptr>)来控制函数的返回值,从而控制返回的是普通类型的迭代器还是const类型的迭代器。【链表迭代器

Ref控制解引用函数的返回值,当Ref为T&时,返回的就是普通迭代器,当Ref为const T&时,返回的就是const迭代器。
Ptr控制的->重载函数的返回值,当Ptr为T时,返回的就是普通迭代器,当Ptr为const T时,返回的就是const迭代器。

5、迭代器的begin()和end()

通过传不同的模板参数,来是实例化出我们想要的迭代器:普通迭代器和const迭代器。
红黑树的迭代器begin()是要求在最小结点那个位置的迭代器,即最左结点,找到最左结点后,我们就用该结点的指针构造迭代器即可。
红黑树的迭代器end()可以看作是nullptr的位置,因为end()是最后一个节点的下一个位置,当找不到父亲时,就说明到尽头了。 
const迭代器的begin()和end()与普通迭代器的begin()和end()是一样的,就是构造时用const迭代器构造,和返回const迭代器

三、封装 map 和 set

1、提取 k 的值

 set的底层结构就是红黑树,因此在set中直接封装一棵红黑树,储存的是pair<k,k>

  map的底层结构就是红黑树,因此在map中直接封装一棵红黑树,储存的是pair<k,v>

 2、map 和set 的迭代器

在重命名红黑树里的迭代器时,需要在类名前面加上 typename,因为这时类模板还没有实例化出对象出来,就算实例化了,也有部分类型没有实例,因为编译器也不知道这个是内置类型还是静态变量,typename 是告诉编译器这个是类型,这个类型在类模板里定义,等类模板实例化后再找。
定义好普通迭代和const迭代器后,就可以实现begin()和end()了。

 四、key值不能修改的问题

1、set

【存在问题】

迭代器的解引用是可以修改的,一旦修改可能不是二叉树:

set 的 key 值、使用迭代器修改:

为了保证二叉树的结构,我们希望:set里的key值不能被修改。map里的key值不能被修改,但value值可以被修改。 

【解决方法】
set 里存储的值就只有Key值,索性我们直接让这个存储的数据无法被修改,只能访问读取,无法修改。所以我们让普通迭代器变成const迭代器即可。所以在set里,我们将普通迭代器和const迭代器都设为const迭代器。
 但此时会遇到一个问题,begin() 和 end() 的返回类型是const 迭代器,但是_t.begin()是普通迭代器,这样就会类型不匹配。因此我们需要定义一个构造函数将普通迭代器和const迭代器相转换。

 

2、map

map的解决原理
在存储的时候就让K值无法修改。
因为我们知道map里存储的数据是pair<K,V>类型,我们不能想set那个让普通迭代器变成const迭代器,因为map要求Value的值还是可以修改的,所以不让pair<K,V>类型无法修改,而是单纯的让里面的K值无法修改,也就是在里面用const修饰K,那么这样K值就不能被修改,V值可以被修改。
pair是可以修改的,但是里面的K是无法被修改的!

 五、完整代码

RBTree.h
#pragma once

enum Colour
{
	RED,
	BLACK,
};

template<class T>//定义一个模板参数 T
struct RBTreeNode
{
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	//用T来取代关联时容器 pair<K, V>
	T _data;
	Colour _col;

	RBTreeNode(const T& data)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _data(data)
		, _col(RED)
	{}
};

template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef __RBTreeIterator<T, Ref, Ptr> Self;
	Node* _node;

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

	// 1、typedef __RBTreeIterator<T, T&, T*> itertaor;  拷贝构造
	// 2、 typedef __RBTreeIterator<T, const T&, const T*> const_itertaor;
	//  支持普通迭代器构造const迭代器的构造函数

	__RBTreeIterator(const __RBTreeIterator<T, T&, T*>& it)
		:_node(it._node)
	{}

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

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

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

	Self& operator++()
	{
		if (_node->_right)
		{
			// 1、右不为空,下一个就是右子树的最左节点
			Node* subLeft = _node->_right;
			while (subLeft->_left)
			{
				subLeft = subLeft->_left;
			}

			_node = subLeft;
		}
		else
		{
			// 2、右为空,沿着到根的路径,找孩子是父亲左的那个祖先
			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->_left)
		{
			// 1、左不为空,找左子树最右节点
			Node* subRight = _node->_left;
			while (subRight->_right)
			{
				subRight = subRight->_right;
			}

			_node = subRight;
		}
		else
		{
			// 2、左为空,孩子是父亲的右的那个祖先
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_left)
			{
				cur = parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this;
	}
};

// 仿函数
template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	~RBTree()
	{
		_Destroy(_root);
		_root = nullptr;
	}
public:
	typedef __RBTreeIterator<T, T&, T*> itertaor;
	typedef __RBTreeIterator<T, const T&, const T*> const_itertaor;

	itertaor begin()
	{
		Node* cur = _root;
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}
		//返回最小节点
		return itertaor(cur);
	}

	itertaor end()
	{
		return itertaor(nullptr);
	}

	const_itertaor begin() const
	{
		Node* cur = _root;
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}

		return const_itertaor(cur);
	}

	const_itertaor end() const
	{
		return const_itertaor(nullptr);
	}

	Node* Find(const K& key)
	{
		Node* cur = _root;
		KeyOfT kot;
		while (cur)
		{
			if (kot(cur->_data) < key)
			{
				cur = cur->_right;
			}
			else if (kot(cur->_data) > key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}

		return nullptr;
	}

	pair<itertaor, bool> Insert(const T& data)
	{
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;

			//插入成功则返回的是新结点指针构造的迭代器封装的pair类型,bool值为true
			return make_pair(itertaor(_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
			{
				//插入失败,返回的是已经存在结点的迭代器构造的pair类型,bool值是false
				return make_pair(itertaor(cur), false);
			}
		}

		cur = new Node(data);
		Node* newnode = cur;
		if (kot(parent->_data) > kot(data))
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;

		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;
			if (grandfather->_left == parent)
			{
				Node* uncle = grandfather->_right;
				// 情况1:u存在且为红,变色处理,并继续往上处理
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					// 继续往上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				else // 情况2+3:u不存在/u存在且为黑,旋转+变色
				{
					//     g
					//   p   u
					// c 
					if (cur == parent->_left)
					{
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						//     g
						//   p   u
						//     c
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						//parent->_col = RED;
						grandfather->_col = RED;
					}

					break;
				}
			}
			else // (grandfather->_right == parent)
			{
				//    g
				//  u   p
				//        c
				Node* uncle = grandfather->_left;
				// 情况1:u存在且为红,变色处理,并继续往上处理
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					// 继续往上调整
					cur = grandfather;
					parent = cur->_parent;
				}
				else // 情况2+3:u不存在/u存在且为黑,旋转+变色
				{
					//    g
					//  u   p
					//        c
					if (cur == parent->_right)
					{
						RotateL(grandfather);
						grandfather->_col = RED;
						parent->_col = BLACK;
					}
					else
					{
						//    g
						//  u   p
						//    c
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}
			}
		}

		_root->_col = BLACK;

		return make_pair(itertaor(newnode), true);;
	}

	bool IsBalance()
	{
		if (_root && _root->_col == RED)
		{
			cout << "根节点颜色是红色" << endl;
			return false;
		}

		int benchmark = 0;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
				++benchmark;
			cur = cur->_left;
		}

		// 连续红色节点
		return _Check(_root, 0, benchmark);
	}

	int Height()
	{
		return _Height(_root);
	}

private:
	void _Destroy(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}

		_Destroy(root->_left);
		_Destroy(root->_right);
		delete root;
	}

	int _Height(Node* root)
	{
		if (root == NULL)
			return 0;

		int leftH = _Height(root->_left);
		int rightH = _Height(root->_right);

		return leftH > rightH ? leftH + 1 : rightH + 1;
	}

	bool _Check(Node* root, int blackNum, int benchmark)
	{
		if (root == nullptr)
		{
			if (benchmark != blackNum)
			{
				cout << "某条路径黑色节点的数量不相等" << endl;
				return false;
			}

			return true;
		}

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

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

		return _Check(root->_left, blackNum, benchmark)
			&& _Check(root->_right, blackNum, benchmark);
	}

	void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		parent->_right = subRL;
		if (subRL)
			subRL->_parent = parent;

		Node* ppnode = parent->_parent;

		subR->_left = parent;
		parent->_parent = subR;

		if (ppnode == nullptr)
		{
			_root = subR;
			_root->_parent = nullptr;
		}
		else
		{
			if (ppnode->_left == parent)
			{
				ppnode->_left = subR;
			}
			else
			{
				ppnode->_right = subR;
			}

			subR->_parent = ppnode;
		}
	}

	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		if (subLR)
			subLR->_parent = parent;

		Node* ppnode = parent->_parent;

		subL->_right = parent;
		parent->_parent = subL;

		if (parent == _root)
		{
			_root = subL;
			_root->_parent = nullptr;
		}
		else
		{
			if (ppnode->_left == parent)
			{
				ppnode->_left = subL;
			}
			else
			{
				ppnode->_right = subL;
			}
			subL->_parent = ppnode;
		}
	}

private:
	Node* _root = nullptr;
};
Map.h
#define  _CRT_SECURE_NO_WARNINGS
#include"RBTree.h"
namespace zhou {
	template<class K, class V>
	class map
	{
		template<class K, class V>
		class map
		{
			struct MapKeyOfT
			{
				const K& operator()(const pair<const K, V>& kv)
				{
					return kv.first;
				}
			};
		public:
			typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::itertaor iterator;

			iterator begin()
			{
				return _t.begin();
			}

			iterator end()
			{
				return _t.end();
			}

			V& operator[](const K& key)
			{
				pair<iterator, bool> ret = _t.Insert(make_pair(key, V()));
				//已经存在就就不插入,不存在就插入,默认给V的缺省参数
			    //如果key在树里已经存在那么就返回已经存在结点的迭代器
			    //如果key不在树里,那么就将该结点插入进去,返回该结点的迭代器
				return ret.first->second;
				//first先访问里面的迭代器,迭代器的second才是Value值。
			}

			pair<iterator, bool> insert(const pair<const K, V>& kv)
			{
				return _t.Insert(kv);
			}
		private:
			RBTree<K, pair<const K, V>, MapKeyOfT> _t;
		};
	};
}
Set.h
#define  _CRT_SECURE_NO_WARNINGS
#include"RBTree.h"

namespace zhou
{	
		template<class K>
		class set
		{
			struct SetKeyOfT
			{
				const K& operator()(const K& key)
				{
					return key;
				}
			};
		public:
			typedef typename RBTree<K, K, SetKeyOfT>::const_itertaor iterator;
			typedef typename RBTree<K, K, SetKeyOfT>::const_itertaor const_iterator;


			iterator begin()
			{
				return _t.begin();
			}

			iterator end()
			{
				return _t.end();
			}

			pair<iterator, bool> insert(const K& key)
			{
				//这里insert返回的是树里的普通迭代器_treeIterator<T,T&,T*> iterator
				return _t.Insert(key);
				//用普通迭代器构造const迭代器
		        //所以我们需要写一个迭代器的构造函数,可以用迭代器构造迭代器
			}
		private:
			RBTree<K, K, SetKeyOfT> _t;
		};

	void test_set1()
	{
		int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
		set<int> s;
		for (auto e : a)
		{
			s.insert(e);
		}

		set<int>::iterator it = s.begin();
		while (it != s.end())
		{
			cout << *it << " ";
			//*it = 1;

			++it;
		}
		cout << endl;

		for (auto e : s)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值