map和set的模拟实现

前言

map和set的底层是红黑树,现在我们就用红黑树来封装map和set,前提是我们用一个模板来封装map和set

代码实现

RBTree代码

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

enum Col
{
	RED
	, BLACK
};

template<class v>
class RBTreeNode
{
public:
	RBTreeNode(const v& data = v(), Col col = RED)
		:_val(data)
		, _col(col)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)

	{

	}
	v _val;
	Col _col;
	RBTreeNode<v>* _left;
	RBTreeNode<v>* _right;
	RBTreeNode<v>* _parent;

};



template<class v,class ref,class ptr >
struct RBTreeIterator
{

	typedef RBTreeNode<v> Node;
	typedef RBTreeIterator<v,ref,ptr> Self;
	Node* _node;

	RBTreeIterator(const RBTreeIterator&other)
		:_node(other._node)
	{
		
	}

	RBTreeIterator(Node* node=nullptr)
		:_node(node)
	{

	}

	template<class OtherRef, class OtherPtr>
	RBTreeIterator(const RBTreeIterator<v, OtherRef, OtherPtr>& other)
		: _node(other._node)
	{
		// 允许从 iterator (v&, v*) 转换为 const_iterator (const v&, const v*)
	}

	ref operator*()
	{
		return _node->_val;
	}

	ptr operator->()
	{
		return &_node->_val;
	}

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

		}
		return *this;
	}

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

};

template<class k, class v,class keyofv>
class RBTree
{

	typedef RBTreeNode<v> Node;
public:
	typedef  typename RBTreeIterator<v,v&,v*> iterator;
	typedef  typename RBTreeIterator<v,const v&,const v*> constiterator;
	
public:

	constiterator begin()const
	{
		if (_root == nullptr) return constiterator(nullptr);
		Node* LeftMost = _root;
		while (LeftMost->_left)
		{
			LeftMost = LeftMost->_left;
		}
		return constiterator(LeftMost);
	}





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

	iterator begin()
	{
		if (_root == nullptr) return iterator(nullptr);
		Node* LeftMost = _root;
		while (LeftMost->_left)
		{
			LeftMost = LeftMost->_left;
		}
		return iterator(LeftMost);
	}

	

	

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

	iterator find(const v& val)
	{
		keyofv kot;
		if (_root == nullptr) return iterator(nullptr);
		Node* cur = _root;
		while (cur)
		{
			if (kot(val) >kot(cur->_val))
			{
				cur = cur->_right;
			}
			else if (kot(val) <kot(cur->_val))
			{
				cur = cur->_left;
			}
			else
			{
				return iterator(cur);
			}
		}
		return end();
	}


	RBTree() = default;

	RBTree& operator=(const RBTree<k, v,keyofv>& a)
	{
		swap(_root, a._root);
		return *this;
	}

	RBTree(const RBTree<k, v,keyofv>& t)
	{
		_root = Copy(t._root);
	}

	bool insert(const v& val)
	{
		if (_root == nullptr)
		{
			_root = new Node(val);
			_root->_col = BLACK;
			return true;
		}
		Node* cur = _root;
		Node* parent = _root;
		keyofv kot;
		while (cur)
		{
			if (kot(cur->_val) <kot(val))
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (kot(cur->_val) >kot(val))
			{
				parent = cur;
				cur = cur->_left;
			}
			else return false;
		}
		cur = new Node(val);
		cur->_col = RED;              //新节点定义为红色节点,给黑色违反黑路同

		if (kot(val) >kot(parent->_val))
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		cur->_parent = parent;

		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;
			if (parent == grandfather->_left)
			{
				//      g
				//   p     u
				//cur
				Node* uncle = grandfather->_right;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
					cur = grandfather;
					parent = cur->_parent;
				}
				else
				{
					//uncle不存在或者为黑色
					if (cur == parent->_left)
					{
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}

			}
			else
			{
				//parent为grandfather的右边

				//uncle在左边
				Node* uncle = grandfather->_left;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
					cur = grandfather;
					parent = cur->_parent;
				}
				else
				{
					//uncle的颜色为黑色或者不存在
					//    g
					// u      p
					//           cur
					if (cur == parent->_right)
					{
						RotateL(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;

				}


			}
		}


		_root->_col = BLACK;
		return true;
	}

	

	void inordered()
	{
		_MidOrdered(_root);                 //中序遍历,判断是否是二叉搜索树
	}



	bool IsValidRBTree()                     //红黑树的检测
	{
		Node* pRoot = GetRoot();
		// 空树也是红黑树
		if (nullptr == pRoot)
			return true;
		// 检测根节点是否满足情况
		if (BLACK != pRoot->_col)
		{
			cout << "违反红黑树性质二:根节点必须为黑色" << endl;
			return false;
		}
		// 获取任意一条路径中黑色节点的个数
		size_t blackCount = 0;
		Node* pCur = pRoot;
		while (pCur)
		{
			if (BLACK == pCur->_col)
				blackCount++;
			pCur = pCur->_left;
		}
		// 检测是否满足红黑树的性质,k用来记录路径中黑色节点的个数
		size_t k = 0;
		return _IsValidRBTree(pRoot, k, blackCount);
	}
	bool _IsValidRBTree(Node* pRoot, size_t k, const size_t blackCount)
	{
		//走到null之后,判断k和black是否相等
		if (nullptr == pRoot)
		{
			if (k != blackCount)
			{
				cout << "违反性质四:每条路径中黑色节点的个数必须相同" << endl;
				return false;
			}
			return true;
		}
		// 统计黑色节点的个数
		if (BLACK == pRoot->_col)
			k++;
		// 检测当前节点与其双亲是否都为红色
		Node* pParent = pRoot->_parent;
		if (pParent && RED == pParent->_col && RED == pRoot->_col)
		{
			cout << "违反性质三:没有连在一起的红色节点" << endl;
			return false;
		}
		return _IsValidRBTree(pRoot->_left, k, blackCount) &&
			_IsValidRBTree(pRoot->_right, k, blackCount);
	}
private:


	Node* Copy(Node *t)
	{
		if (t == nullptr) return nullptr;
		_root = new Node(t->_val);
		_root->_left = Copy(t->_left);
		_root->_right = Copy(t->_right);
		return _root;
		

	}

	Node* GetRoot()
	{
		return _root;
		}


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

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


	}

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

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


	}

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



	}

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



	}

	void _MidOrdered(Node* root)
	{
		if (root == nullptr) return;
		_MidOrdered(root->_left);
		cout << root->_val << " ";
		_MidOrdered(root->_right);
	}



private:
	Node* _root = nullptr;

};

set代码

cpp 复制代码
#include"RBTree.h"


namespace LiHao
{



	template<class k>
	class set
	{
		struct SetKofV
		{
			const k& operator()(const k&key)
			{
				return key;
			}
		};
	public:
		typedef  typename RBTree<k,k,SetKofV>::iterator iterator;
		typedef  typename RBTree<k,k,SetKofV>::constiterator const_iterator;
		
	public:

		const_iterator begin() const
		{
			return _t.begin();
		}

		const_iterator end()const
		{
			return _t.end();
		}

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

		iterator find(const k&val)
		{
			return _t.find(val);
		}

		bool insert(const k& val)
		{
			return _t.insert(val);
		}


		
	private:
		RBTree<k,k,SetKofV> _t;

	};

}

map代码

cpp 复制代码
#include"RBTree.h"

namespace LiHao
{
	template<class k,class v>
	class map
	{
		struct MapofV
		{
			const k& operator()(const pair<k, v>& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename RBTree<k,pair<k,v>,MapofV>::iterator iterator;
	public:

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

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



		bool insert(const pair<k, v>& kv)
		{
			return _t.insert(kv);
		}

		


	private:
		RBTree<k,pair<k,v>,MapofV> _t;

	};
}

测试代码

cpp 复制代码
#include"MyMap.h"
#include"MySet.h"
#include<time.h>

void test_set1()
{
	LiHao::set<int> s1;
	srand(time(0));

	for (int i = 0; i < 10; i++)
	{
		s1.insert(i);
	}
	for (auto e : s1)
		cout << e << " ";
	cout << endl;

	LiHao::set<int>::const_iterator it = s1.begin();
	


	
}


//void print(const LiHao::set<int>& s1)
//{
//	LiHao::set<int>::const_iterator it = s1.begin();
//	*it += 10;
//}


void test_map()
{
	LiHao::map<string, string> m1;
	m1.insert({ "left","左边" });
	m1.insert({ "right","右边" });
	m1.insert({ "insert","插入" });
	for (auto e : m1)
		cout << e.first << " " << e.second << endl;
}

int main()
{
	

	test_set1();
    test_map();
	return 0;
}

测试结果

代码解释

RBTree基本框架

cpp 复制代码
template<class k, class v,class keyofv>
class RBTree
{

private:
	Node* _root = nullptr;

};

解释模板参数为什么要设置这三个:

先解释前两个,我们需要兼顾set和map两个,set有一个模板参数,map有两个模板参数,要用一个模板来实现两个类,那只能要这两个模板参数来实现,那么,我们定义map和set的成员时,需要向下面的两个定义

cpp 复制代码
template<class k>
class set
{
	
private:
	RBTree<k,k,SetKofV> _t;

};
cpp 复制代码
template<class k,class v>
class map
{
private:
	RBTree<k,pair<k,v>,MapofV> _t;

};

这样就很好的兼顾了两者

解释第三个模板参数:这个参数的实现是为了实现两个的插入和查找功能,因为插入需要对比插入值和红黑树节点的值然后决定向左还是向右边走,set当然是对比k就可以了,但是map需要对比的是

RBTree<k,pair<k,v>,MapofV> _t;对比的是pair<k,v>中的k

这样看来对比的不都是k吗,那搞这个不就是多余的吗,但是我们仔细看一看insert()函数

bool insert(const v& val)

发现插入的是v,也就是第二个参数,map对应的红黑树的第二个参数是pair<k,v>,我们对比的是第v的第一个参数,实现这个也是兼顾map,如果所以我们可以实现一个仿函数来实现,set里面的仿函数实现和map里面的实现不同

cpp 复制代码
struct SetKofV
{
	const k& operator()(const k&key)
	{
		return key;
	}
};                          //set里面的
cpp 复制代码
struct MapofV
{
	const k& operator()(const pair<k, v>& kv)
	{
		return kv.first;
	}
};                //map里面的,返回pair<k,v>里面的k

typename

cpp 复制代码
typedef   RBTreeIterator<v,v&,v*> iterator;

typedef   RBTreeIterator<v,const v&,const v*> constiterator;

typedef typename RBTree<k,pair<k,v>,MapofV>::iterator iterator;

typedef typename RBTree<k,pair<const k,v>,MapofV>::constiterator const_iterator;

typedef  typename RBTree<k,k,SetKofV>::iterator iterator;

typedef  typename RBTree<k,k,SetKofV>::constiterator const_iterator;

typename的作用是为了告诉编译器这是一个类型,比如上面的后面四个都用了typename,拿第三个来说


typedef typename RBTree<k,pair<k,v>,MapofV>::iterator iterator;

因为 RBTree<k,pair<k,v>,MapofV>里面有成员变量,也有类型,编译器无法知道它是一个类型还是一个变量,typename的作用就是告诉编译器这是一个类型

小细节

cpp 复制代码
void test_set1()
{
	LiHao::set<int> s1;
	srand(time(0));

	for (int i = 0; i < 10; i++)
	{
		s1.insert(i);
	}
	for (auto e : s1)
		cout << e << " ";
	cout << endl;

	LiHao::set<int>::const_iterator it = s1.begin();	
}

void print(const LiHao::set<int>& s1)
{
	LiHao::set<int>::const_iterator it = s1.begin();
	*it += 10;
}

首先看第二个print()函数,里面传的参数是const类型的,所以它调用的是const类型的begin()函数,但是如果里面的是非const的set变量,调用的便是非const的变量,也就是说,编译器看见const的变量的时候,使用迭代器的时候,默认使用的便是const的函数,比如这里的,非const的时候道理类似

再如下面的这句代码

LiHao::set<int>::const_iterator it = s1.begin();

s1是非const的对象,s1.begin()调用的便是非const类型的,但是这里又是非给const_iterator,如果不实现将iterator类型的转化为const_iterator的函数,也就是下面的函数

cpp 复制代码
template<class OtherRef, class OtherPtr>
RBTreeIterator(const RBTreeIterator<v, OtherRef, OtherPtr>& other)
	: _node(other._node)
{
	// 允许从 iterator (v&, v*) 转换为 const_iterator (const v&, const v*)
}

迭代器设计

cpp 复制代码
template<class v,class ref,class ptr >
struct RBTreeIterator
{

};

设置三个参数的目的是为了实现const迭代器的需要,如果不需要const迭代器,一个参数v就可以了

cpp 复制代码
typedef   RBTreeIterator<v,v&,v*> iterator;
typedef   RBTreeIterator<v,const v&,const v*> constiterator;

因为const迭代器是里面的参数不可以改变,只需要再传递模板参数的时候限定参数的类型是const就可以了

iterator operator++()

这个函数是实现迭代器加1,也就是中序遍历的下一个,直接按照中序遍历的逻辑来实现就可以了

1.如果当前节点有右子树,那么右子树的最左边的元素便是下一个

2.如果没有右子树(这里自己找一颗树来看一下就知道了)

相关推荐
六义义5 小时前
java基础十二
java·数据结构·算法
四维碎片5 小时前
QSettings + INI 笔记
笔记·qt·算法
Tansmjs5 小时前
C++与GPU计算(CUDA)
开发语言·c++·算法
独自破碎E5 小时前
【优先级队列】主持人调度(二)
算法
weixin_445476686 小时前
leetCode每日一题——边反转的最小成本
算法·leetcode·职场和发展
打工的小王6 小时前
LeetCode Hot100(一)二分查找
算法·leetcode·职场和发展
Swift社区6 小时前
LeetCode 385 迷你语法分析器
算法·leetcode·职场和发展
sonadorje6 小时前
svd在图像处理中的应用
算法
挖矿大亨6 小时前
c++中的函数模版
java·c++·算法
海天一色y6 小时前
普利姆算法(Prim)和克鲁斯卡尔算法(Kruskal)
windows·算法