_cpp利用红黑树封装实现map和set

0. 前言

链接:_cpp 红黑树快速了解底层结构
上面那篇文章,我们了解了红黑树的底层结构并模拟实现红黑树数据插入;最后我们又验证我们红黑树的准确性。

这篇文章我们利用红黑树封装实现map和set。

1. 改造红黑树

1.1 红黑树节点的定义

  • 因为我们要利用一颗树封装实现map和set,所以我们不能写死。

  • 怎么作那看下面代码。

enum Colour
{
	RED,
	BLACK
};

template<class T>	//k or pair<K, V>
struct RBTreeNode
{
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;

	//pair<K, V> _kv;
	T _date;	//   数据
	Colour _col;

	RBTreeNode(const T& date)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _date(date)
	{}
};

  • 我们把模板template<class K, class V>改为template; 而T代表k or pair<K, V>。这样就实现了泛型。

  • 看到这里uu们就很疑惑,那怎么区别那?我们就要借助仿函数(KeyOfT )-> 支持取出T对象中key的值。

1.2 红黑树中的迭代器

  • 迭代器大致框架跟list模拟实现不变,变的是++和- -怎么操作。我们知道红黑树的中序遍历可以得到一个有序序列;而我们的加加和减减就是查找中序遍历中某一个节点前后的节点是那个。

1.2.1 模拟实现前置加加的方法

在这里插入图片描述

  • 通过上图和根据中序遍历的规则,我们很快就发现两条规律。
    1. 右子树不为空,++就是找右子树中序第一个(最左节点);

      • 例如:11的下一个节点就是12,根据中序遍历的规则。
    2. 右子树为空,++找孩子不是父亲右的那个祖先。

      • 例如:12的下一个节点就是13,根据中序遍历的规则;而7的下一个节点是8,不是6。

在这里插入图片描述

1.2.2 模拟实现前置减减的方法

在这里插入图片描述

  • 通过上图和根据中序遍历的规则,我们很快就发现两条规律。
    1. 左子树不为空,–就是找右子树中序最后一个(最右节点);

      • 例如:8的上一个节点就是7,根据中序遍历的规则。
    2. 左子树为空,–找孩子不是父亲左的那个祖先。

      • 例如:15的上一个节点就是13,根据中序遍历的规则;而12的上一个节点是11,而不是13。

到了这里我们发现–和++恰好相反;后置++与- -我们复用一下前置的就可以实现了。

1.2.3 红黑树迭代器代码

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

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

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

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


	Self& operator++()
	{
		//思路:左子树的父亲,右子树的父亲的父亲直到找到另一个子树的左节点(模拟中序遍历)

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

			_node = left;
		}
		else         // 找祖先里面孩子不是祖先的右的那个
		{
			Node* parent = _node->_parent;
			Node* cur = _node;
			while (parent && cur == parent->_right)
			{
				parent = parent->_parent;
				cur = cur->_parent;
			}
			
			_node = parent;
		}

		return *this;
	}
	Self operator++(int)
	{
		Self tmp(*this);
		++(*this);

		return tmp;
	}

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

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

			_node = parent;
		}

		return *this;
	}
	Self operator--(int)
	{
		Self tmp(*this);
		--(*this);

		return tmp;
	}

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

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

private:
	Node* _node;

};

1.3 仿函数

  • 因为map是pair<K,V>; kv型原来的直接比较并插入就失效了,我们就需要借助仿函数来提取map中pair的first值;来进行比较。

	template<class K, class V>
	class map
	{
		struct MapKeyOfT
		{
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};
	template<class k>
	class set
	{
		struct SetKeyOfT
		{
			const k& operator()(const k& key) 
			{
				return key;
			}
		};

实现过程就在上图代码里了。

1.4 红黑树整体改造完成后的代码

#pragma once
#include<iostream>
#include<assert.h>

using namespace std;
enum Colour
{
	RED,
	BLACK
};

template<class T>	//k or pair<K, V>
struct RBTreeNode
{
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;

	//pair<K, V> _kv;
	T _date;	//   数据
	Colour _col;

	RBTreeNode(const T& date)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _date(date)
	{}
};

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

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

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

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


	Self& operator++()
	{
		//思路:左子树的父亲,右子树的父亲的父亲直到找到另一个子树的左节点(模拟中序遍历)

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

			_node = left;
		}
		else         // 找祖先里面孩子不是祖先的右的那个
		{
			Node* parent = _node->_parent;
			Node* cur = _node;
			while (parent && cur == parent->_right)
			{
				parent = parent->_parent;
				cur = cur->_parent;
			}
			
			_node = parent;
		}

		return *this;
	}
	Self operator++(int)
	{
		Self tmp(*this);
		++(*this);

		return tmp;
	}

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

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

			_node = parent;
		}

		return *this;
	}
	Self operator--(int)
	{
		Self tmp(*this);
		--(*this);

		return tmp;
	}

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

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

private:
	Node* _node;

};

// T决定红黑树存什么数据
// set  RBTree<K, K>
// map  RBTree<K, pair<K, V>>
// KeyOfT -> 支持取出T对象中key的仿函数
template<class K, class T, class keyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	typedef __RBTreeIterator<T, T&, T*> iterator;
	iterator begin()
	{
		Node* left = _root;
		while (left && left->_left)
		{
			left = left->_left;
		}
		//找到最左,也就是最小值

		return iterator(left);
	}
	iterator end()
	{
		return iterator(nullptr);
	}


	RBTree()
	{}

	pair<iterator, bool> Insert(const T& date)
	{

		keyOfT kot;
		if (_root == nullptr)
		{
			_root = new Node(date);
			_root->_col = BLACK;
			return make_pair(iterator(_root), true);
		}

		//找find
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (kot(cur->_date) < kot(date))
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (kot(cur->_date) > kot(date))
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				//重复的
				return make_pair(iterator(cur), false);
			}
		}


		//插入
		cur = new Node(date);
		Node* newNode = cur;	//记录一下,最后返回的时候要用。
		cur->_col = RED;

		if (kot(parent->_date) < kot(date))
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		cur->_parent = parent;

		//调整颜色
		while (parent && parent->_col == RED)	//父母为红,违法规则;才调整
		{
			Node* grandfather = parent->_parent;
			assert(grandfather);
			assert(grandfather->_col == BLACK);
			//关键看叔叔
			//     g
			//   p or p
			// 
			if (parent == grandfather->_left)
			{
				Node* uncle = grandfather->_right;
				//情况一: uncle存在且为红,变色+继续往上调整
				//     g
				//   p   u
				//   c
				if (uncle && uncle->_col==RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					cur = grandfather;
					parent = cur->_parent;
				}
				else  //uncle || uncle->_col == BLACK
				{
					//情况二、三: uncle存在且为黑或者不存在,变色+旋转
					if (cur == parent->_left)
					{
						//     g				p
						//   p   u			  c	  g
						//  c						u
						//(g)右单旋+变色
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						//     g             g				c
						//   p   u		   c   u		  p	   g
						//		c		 p	                     u
						//(p)左单旋+(g)右单旋+ 变色
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}
			}
			else    //parent == grandfather->_right
			{
				Node* uncle = grandfather->_left;

				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					cur = grandfather;
					parent = cur->_parent;
				}
				else  //uncle || uncle->_col == BLACK
				{
					//情况二、三: uncle存在且为黑或者不存在,变色+旋转
					if (cur == parent->_right)
					{
						//(g)左单旋+变色
						RotateL(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						//(p)右单旋+(g)左单旋+ 变色
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}
			}
		}

		_root->_col = BLACK;
		return make_pair(iterator(newNode), true);
	}

	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

	bool IsBalance()
	{
		if (_root == nullptr)
		{
			return true;
		}

		if (_root->_col == RED)
		{
			return false;
		}

		//黑色节点数量的基准
		int benchmark = 0;

		return PrecCheck(_root, 0, benchmark);
	}
private:
	bool PrecCheck(Node* root, int blackNum, int& benchmark)
	{
		if (root == nullptr)
		{
			if (benchmark == 0)
			{
				benchmark = blackNum;
				return true;
			}

			if (benchmark != blackNum)
			{
				cout << "某条黑色结点数量不对" << endl;
				return false;
			}
			else
			{
				return true;
			}
		}

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

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

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

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

		_InOrder(root->_left);
		cout << kot(root->_date) << " ";
		_InOrder(root->_right);
	}

	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 (_root == parent)
		{
			_root = subL;
			_root->_parent = nullptr;
		}
		else
		{
			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;

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

		Node* ppNode = parent->_parent;
		subR->_left = parent;
		parent->_parent = subR;
		if (parent == _root)
		{
			_root = subR;
			_root->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = subR;
			}
			else  //ppNode->_right == parent
			{
				ppNode->_right = subR;
			}
			subR->_parent = ppNode;
		}

	}

	Node* _root = nullptr;
};

2. 封装实现map

  • 注意:typename的使用–我们要取取类里面的类型而不是变量(例如:类的静态变量)需要说明。
#pragma once
#include "BR_TREE.h"

namespace Ding
{
	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<K, V>, MapKeyOfT>::iterator iterator;

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

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

		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = insert(make_pair(key, V()));

			return ret.first->second;
		}

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

3. 封装实现set

  • 注意:typename的使用–我们要取取类里面的类型而不是变量(例如:类的静态变量)需要说明。
#pragma once
#include "BR_TREE.h"

namespace Ding
{
	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--告诉编译器我们这里取得是类里面的类型而不是变量

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

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

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

4. 测试案例

/map.h///

	void test_set()
	{
		set<int> s;

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

		s.insert(3);
		s.insert(2);
		s.insert(1);
		s.insert(5);
		s.insert(3);
		s.insert(6);
		s.insert(4);
		s.insert(9);
		s.insert(7);


		it = s.begin();
		while (it != s.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

/set.h///

	void test_map()
	{
		string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };

		map<string, int> countMap;
		for (auto& str : arr)
		{
			// 1、str不在countMap中,插入pair(str, int()),然后在对返回次数++
			// 2、str在countMap中,返回value(次数)的引用,次数++;
			countMap[str]++;
		}

		map<string, int>::iterator it = countMap.begin();
		while (it != countMap.end())
		{
			cout << it->first << ":" << it->second << endl;
			++it;
		}

		for (auto& kv : countMap)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
	}

5. 测试结果

在这里插入图片描述

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昨天;明天。今天。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值