rbtree封装map和set

1.理论分析

先看stl源码中rbtree对set和map的封装

在模拟实现的时候结合map和set的具体需求及stl源码进行分析问题和解决问题

分析KeyOfT存在的原因

对于迭代器本身而言,*,->用于找内容, ++用于向前遍历,--用于回退,==和!=用于迭代;而在用迭代器的具体数据结构比如rbtree需要begin作为开始,end作为结尾,根据需要支持find, insert从而支持[]等操作,同时结合实际使用情况,综合rbtree要封装set和Map,因为set的iterator就是rbtree的const_iterator封装,而insert返回的是普通迭代器,因为如果是const对象不能插入,这时候不支持普通迭代器构造const迭代器,那么迭代器本身就要支持这个构造

每次旋转L,R,LR,RL中间结点也就是新的父结点都是黑色,那即使是成为根节点,也不需要担心染色

blacknum是值传参的好处在于每次递归返回到上层,不会受影响

__TreeIterator的实现和stl中并不完全一样,在迭代的时候nullptr作为end,

但是stl引入了虚拟节点header,header左指针指向最左节点,右指针指向最右节点,parent指针指向root节点,root的parent指针指向header节点,那么可以通过header快速找到最左和最右,但是增删改都要付出代价来维护这一性质,并且在迭代器--的时候,如果左为空,就要向上找最近一个cur是父亲的左孩子,因为是右根左,左结束,根也结束,但如果出现root就是最右节点,这时候root和parent的右指针指向彼此,如果cur是parent的右孩子就一直向上迭代,cur=root,parent=header,此时cur= =parent- >right,则cur=parent=header,parent=cur- >parent=root,依然满足cur==parent- >right,死循环,所以单独做了处理,如果到header就停止

2.代码实现

2.1 测试代码

cpp 复制代码
#include <utility>
#include <iostream>
#include <string>
using namespace std;
#include "My_Map.h"
#include "My_Set.h"
#include <map>
int main() {
	//map测试
	diy::map<string, string> mp;
	
	mp.Insert(make_pair("sort", "排序"));
	mp.Insert({ "chocolate", "巧克力" });//插入

	mp["left"];//插入
	mp["right"] = "右边";//插入+赋值

	mp["right"] = "测试";//修改

	//迭代器
	diy::map<string, string>::iterator it = mp.begin();
	//auto it = mp.begin();
	while (it != mp.end()) {
		cout << it->first << ": " << it->second << " ";
		++it;
	}
	cout << endl;

	//范围for
	for (auto& kv : mp)
		cout << kv.first << ": " << kv.second << " ";
	cout << endl;

	diy::set<int> s;
	s.insert(3);
	s.insert(5);//插入
	s.insert(5);
	s.insert(7);
	s.insert(4);
	
	diy::set<int>::iterator it = s.begin();
	//auto it = s.begin();
	while (it != s.end()) {
		cout << *it << " ";
		++it;
	}
	cout << endl;
	
	//范围for
	for (auto& e : s)
		cout << e << " ";
	cout << endl;

	return 0;
}

2.2 封装set

My_set.h

cpp 复制代码
#pragma once
#include "BRTree.h"
namespace diy {
	template<class K>
	class set {
		struct SetKeyOfT {
			const K& operator()(const K& data) const{
				return data;
			}
		};
		typedef BRTree<K, K, SetKeyOfT> rbtree;
	public:
		typedef typename rbtree::const_iterator iterator;
		typedef typename rbtree::const_iterator const_iterator;//set是rbtree封装的,可以使用rbtree的一切组件,如果直接调用__TreeIterator进行实例化就散了
		//做了rbtree普通迭代器到const迭代器的转换
		/*iterator begin() {
			return _t.begin();
		}
		iterator end() {
			return _t.end();
		}*/ //可以不写,因为普通对象和const对象都可以调用const,而且只会返回const_iterator
		const_iterator begin() const{
			return _t.begin();
		}
		const_iterator end() const{
			return _t.end();
		}
		pair<iterator, bool> insert(const K& key) {
			pair<rbtree::iterator,bool> p = _t.Insert(key);
			return pair<rbtree::const_iterator, bool>(p.first, p.second);
		}
		pair<iterator, bool> insert1(const K& key) {
			pair<rbtree::iterator, bool> p = _t.Insert(key);
			return { p.first, p.second };
		}
		pair<iterator, bool> insert2(const K& key) {
			pair<rbtree::iterator, bool> p = _t.Insert(key);
			return make_pair(iterator(p.first), p.second);
		}
		const_iterator Find(const K& key) const{
			return _t.Find(key);
		}
	private:
		rbtree _t;
	};
}

2.3 封装map

My_map.h

cpp 复制代码
#pragma once
#include "BRTree.h"
namespace diy {
	template<class K,class V>
	class map {
	public:
		struct MapKeyOfT {
			const K& operator()(const pair<const K, V>& data) const{
				return data.first;
			}
		};
		typedef BRTree<K, pair<const K,V>, MapKeyOfT> rbtree;
		typedef typename BRTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;
		typedef typename rbtree::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();
		}
		iterator Find(const K& key) {
			return _t.Find(key);
		}
		const_iterator Find(const K& key) const{
			return _t.Find(key);
		}
		pair<iterator, bool> Insert(const pair<const K, V>& data) {
			return _t.Insert(data);
		}
		V& operator[](const K& key) {
			pair<iterator, bool> ret = _t.Insert(make_pair(key, V()));
			return ret.first->second;
		}
	private:
		rbtree _t;
	};
}

2.4 封装rbtree

rbtree.h

cpp 复制代码
#pragma once
enum color {
	RED,
	BLACK
};
namespace diy {
	template<class T>
	struct BRTreeNode {
		BRTreeNode<T>* _left;//类名是不等同于类型名的,因为引入模版之后类名+具体参数类型=>类型名
		BRTreeNode<T>* _right;
		BRTreeNode<T>* _parent;
		T _data;
		color _col;
		BRTreeNode(const T& data)
			:_data(data),
			_left(nullptr),
			_right(nullptr),
			_parent(nullptr),
			_col(RED)
		{}
	};

	template<class T,class Ptr,class Ref>
	struct __TreeIterator {

		typedef BRTreeNode<T> Node;
		Node* _node;
		typedef __TreeIterator<T, T*, T&> iterator;//因为const_iterator可能用到iterator
		typedef __TreeIterator<T, Ptr, Ref> Self;

		__TreeIterator(Node* node) :_node(node) {};
		__TreeIterator(const iterator& it) :_node(it._node) {};//如果是const_iterator就是iterator构造const迭代器,如果是普通迭代器就是拷贝构造
		Ref operator*() const{
			return _node->_data;
		}
		Ptr operator->() const{
			return &_node->_data;
		}
		Self& operator++() {//it++ 等价于函数调用it.operator++(),前置++
			//左 根 右
			//这个地方it一定非空,因为如果是nullptr就和end相等,不会进入
			if (_node->_right) {//右子树的最左节点
				Node* subleft = _node->_right;
				while (subleft->_left)//因为刚开始subleft一定不为空
					subleft = subleft->_left;
				_node = subleft;
			}
			else {
				Node* cur = _node;//至少cur不为空
				Node* parent = cur->_parent;
				while (parent && parent->_right == cur) {
					cur = parent;
					parent = cur->_parent;
				}
				_node = parent;//要么parent为空,整棵树都遍历完了;要么cur是parent的左子树,该遍历parent了
			}
			return *this;
		}
		Self operator++(int) {
			Self tmp(_node);
			++(*this);
			return tmp;
		}
		Self& operator--() {
			if (_node->_left) {
				Node* subright = _node->_left;
				while (subright->_right)
					subright = subright->_right;
				_node = subright;
			}
			else {
				Node* cur = _node;
				Node* parent = _node->_parent;
				while (parent && parent->_left == cur) {
					cur = parent;
					parent = 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;
		}
	};

	template<class K,class T,class KeyOfT>
	class BRTree {
		typedef BRTreeNode<T> Node;
		Node* _root=nullptr;
	public:
		typedef __TreeIterator<T, T*, T&> iterator;
		typedef __TreeIterator<T, const T*, const T&> const_iterator;
		iterator begin() {
			Node* cur = _root;
			while (cur && cur->_left)
				cur = cur->_left;
			return iterator(cur);
		}
		iterator end() {
			return iterator(nullptr);
		}
		const_iterator begin() const{
			Node* cur = _root;
			while (cur && cur->_left)
				cur = cur->_left;
			return const_iterator(cur);
		}
		const_iterator end() const{
			return const_iterator(nullptr);
		}
		iterator Find(const K& k) {
			Node* cur = _root;
			while (cur) {
				if (k > kot(cur->_data))
					cur = cur->_right;
				else if (k < kot(cur->_data))
					cur = cur->_left;
				else
					return iterator(cur);
			}
			return iterator(nullptr);
		}
		const_iterator Find(const K& k) const{
			Node* cur = _root;
			while (cur) {
				if (k > kot(cur->_data))
					cur = cur->_right;
				else if (k < kot(cur->_data))
					cur = cur->_left;
				else
					return const_iterator(cur);
			}
			return const_iterator(nullptr);
		}
		/*BRTree()
			:_root(nullptr)
		{}*/
		KeyOfT kot;
		pair<iterator,bool> Insert(const T& data) {
			if (_root == nullptr) {
				_root = new Node(data);
				_root->_col = BLACK;
				return make_pair(iterator(_root),true);//make_pair自动推到类型
			}
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur) {
				if (kot(data) > kot(cur->_data)) {
					parent = cur;
					cur = cur->_right;
				}
				else if (kot(data) < kot(cur->_data)) {
					parent = cur;
					cur = cur->_left;
				}
				else
					return make_pair(iterator(cur),false);
			}
			//Node* add = Node(data);
			/*if (cur == parent->_left)
				parent->_left = add;
			else if (cur == parent->_right)
				parent->_right = add;*/ //其实不太合适,因为有可能左右均为空
			//链接父与子
			cur = new Node(data);
			if (kot(data) > kot(parent->_data)) 
				parent->_right = cur;
			else if (kot(data) < kot(parent->_data)) 
				parent->_left = cur;
			cur->_parent = parent;
			//调整过程中cur可能会改变
			Node* newnode = cur;
			//调整颜色
			while (parent && parent->_col == RED) {
				//如果uncle是红色
				Node* grandfather = parent->_parent;//用于继续向上迭代
				if (parent == grandfather->_left) {
					Node* uncle = grandfather->_right;
					if (uncle && uncle->_col == RED) {
						uncle->_col = parent->_col = BLACK;
						grandfather->_col = RED;
						cur = grandfather;
						parent = cur->_parent;
					}
					else {//uncle不存在或者为黑
						//本质是将一侧的两个红节点通过旋转+染色分散到两端,达到不影响黑色节点数量和不违反红黑树规则的目的
						if (cur == parent->_left) {
							RotateR(grandfather);
							parent->_col = BLACK;//根节点grandfather->parent
							grandfather->_col = RED;
						}
						else{
							RotateLR(grandfather);
							cur->_col = BLACK;//根节点grandfather->cur
							grandfather->_col = RED;
						}
						break;//不会向上影响
					}
				}
				else if (parent == grandfather->_right) {
					Node* uncle = grandfather->_left;
					if (uncle && uncle->_col == RED) {
						uncle->_col = parent->_col = BLACK;
						grandfather->_col = RED;//由黑变红,可能继续向上影响
						cur = grandfather;
						parent = cur->_parent;
					}
					else {
						if (cur == parent->_right) {
							RotateL(grandfather);
							parent->_col = BLACK;
							grandfather->_col = RED;
						}
						else if (cur == parent->_left) {
							RotateRL(grandfather);
							cur->_col = BLACK;
							grandfather->_col = RED;
						}
						break;
					}
				}
			}
			_root->_col = BLACK;
			return make_pair(iterator(newnode),true);
			//每次旋转L,R,LR,RL中间结点也就是新的父结点染色后都是黑色,即使是成为根节点,也不需要担心染色
		}
		bool RotateR(Node* parent) {
			rotateCount++;
			Node* cur = parent->_left;
			Node* curright = cur->_right;
			parent->_left = curright;
			if (curright)
				curright->_parent = parent;

			Node* ppnode = parent->_parent;
			parent->_parent = cur;
			cur->_right = parent;

			if (ppnode == nullptr) {
				_root = cur;
				//_root->_col = BLACK;
			}
			else {
				if (ppnode->_left == parent)
					ppnode->_left = cur;
				else
					ppnode->_right = cur;
			}
			cur->_parent = ppnode;
			return true;
		}
		bool RotateL(Node* parent) {
			rotateCount++;
			Node* cur = parent->_right;
			Node* curleft = cur->_left;
			parent->_right = curleft;
			if(curleft)//注意空指针
				curleft->_parent = parent;
			Node* ppnode = parent->_parent;
			cur->_left = parent;
			parent->_parent = cur;
			if (ppnode == nullptr)
				_root = cur;
			else {
				if (ppnode->_left == parent)
					ppnode->_left = cur;
				else
					ppnode->_right = cur;
			}
			cur->_parent = ppnode;
			return true;
		}
		bool RotateLR(Node* parent) {
			//       g
			//	p
			//	   c
			RotateL(parent->_left);
			RotateR(parent);
			return true;
		}
		bool RotateRL(Node* parent) {
			//  g
			//	     p
			//	  c
			RotateR(parent->_right);
			RotateL(parent);
			return true;
		}
		void InOrder() {
			_InOrder(_root);
		}
		void _InOrder(Node* root) {//或者是重载
			if (root == nullptr)//涉及到传参,递归终止条件,但是如果在类外调用InOrder要么通过GetRoot类成员函数获取或设置为静态成员函数,但一般采用子函数的形式
				return;
			_InOrder(root->_left);
			//cout << root->_data << " ";//封装map时_data是pair<K,V>,封装set时_data是K
			_InOrder(root->_right);
		}
		bool CheckColor(Node* root, int blacknum, int benchmark) {//blacknum是值传参的好处在于每次递归返回到上层,不会受影响
			if (root == nullptr)
				return blacknum == benchmark;
			if (root->_col == BLACK)
				blacknum++;
			if (root->_col == RED && root->_parent && root->_parent->_col == RED) {
				cout << kot(root->_data) << ": 出现连续红色节点" << endl;
				return false;
			}
			return CheckColor(root->_left, blacknum, benchmark) && CheckColor(root->_right, blacknum, benchmark);
		}
		bool IsBalance() {
			return _IsBalance(_root);
		}
		bool _IsBalance(Node* root) {
			if (root == nullptr)
				return true;
			if (root->_col == RED)
				return false;
			int benchmark = 0;
			Node* cur = root;
			while (cur) {
				if (cur->_col == BLACK)
					benchmark++;
				cur = cur->_left;
			}
			return CheckColor(root, 0, benchmark);
		}
		int _Height(Node* root) {
			if (root == nullptr)
				return 0;
			int leftHeight = _Height(root->_left);
			int rightHeight = _Height(root->_right);
			return max(leftHeight, rightHeight) + 1;
		}
		int Height() {
			return _Height(_root);
		}
	public:
		int rotateCount = 0;

	};
};
相关推荐
汉克老师2 小时前
GESP2025年6月认证C++三级( 第一部分选择题(1-8))
c++·二进制·原码·补码·gesp三级·gesp3级·八进制、
不想写代码的星星2 小时前
C++ 折叠表达式:“我写递归你写折叠,咱俩代码差十年”
c++
Titan20243 小时前
map和set的封装学习笔记
数据结构·c++
懒惰的bit3 小时前
MFC常见消息映射(简洁版)
c++·mfc
Yupureki3 小时前
《算法竞赛从入门到国奖》算法基础:动态规划-路径dp
数据结构·c++·算法·动态规划
321.。4 小时前
Linux 进程控制深度解析:从创建到替换的完整指南
linux·开发语言·c++·学习
小Tomkk4 小时前
怎么配置 Visual Studio Code 配置 C/C++
c语言·c++·vscode
CheerWWW4 小时前
C++学习笔记——枚举、继承、虚函数、可见性
c++·笔记·学习
比昨天多敲两行4 小时前
C++ AVL树
开发语言·c++