C++——set,map的模拟实现

文章目录

前言

set,map底层使用红黑树这种平衡二叉搜索树来组织元素 ,这使得set, map能够提供对数时间复杂度的查找、插入和删除操作。

下面都是基于红黑树实现的set和map。

红黑树的改变

由于set和map是公用一棵树,set是K 、map是KV的结构,为了适应set与map的结构,红黑树要做出一定的改变.

  • 仿函数是为了取到set内所存储的数据
  • 在set的map中 set所存储的是key而map是pair
cpp 复制代码
#pragma once
#include <iostream>
#include <assert.h>
using namespace std;

enum Color
{
	RED,
	BLACK
};

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

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

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

	Node* _node;
	Node* _root;

	RBTreeIterator(Node* node,Node* root)
		:_node(node),
		_root(root)
	{}

	//左 -> 根 -> 右
	Self operator++()
	{
		//右不为空,右的最左(小)结点
		if (_node->_right)
		{
			Node* min = _node->_right;
			while (min && min->_left)
			{
				min = min->_left;
			}
			_node = min;
		}
		//右为空,找孩子是父亲左的结点
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && parent->_right == cur)
			{
				cur = parent;
				parent = cur->_parent;
			}
			_node = parent;
		}
		return *this;
	}

	Self operator--()
	{
		// --end(),特殊处理,走到中序最后一个结点,整棵树的最右结点
		if (_node == nullptr)
		{
			Node* rightMost = _root;
			while (rightMost && rightMost->_right)
			{
				rightMost = rightMost->_right;
			}
			_node = rightMost;
		}
		// 左不为空,中序左的最右(大)结点
		else if (_node->_left)
		{
			Node* rightMost = _node->_left;
			while (rightMost && rightMost->_right)
			{
				rightMost = rightMost->_right;
			}
			_node = rightMost;
		}
		// 左为空,孩子是父亲右的那个祖先
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_left)
			{
				cur = parent;
				parent = cur->_parent;
			}
			_node = parent;
		}
		return *this;
	}

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

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

	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 RBTree
{
	typedef RBTreeNode<T> Node;

public:
	typedef RBTreeIterator<T, T&, T*> Iterator;
	typedef RBTreeIterator<T, const T&, const T*> ConstIterator;

	Iterator begin()
	{
		Node* cur = _root;
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}
		return Iterator(cur, _root);
	}

	Iterator end()
	{
		return Iterator(nullptr, _root);
	}

	ConstIterator begin() const
	{
		Node* cur = _root;
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}
		return Iterator(cur, _root);
	}

	ConstIterator end() const
	{
		return Iterator(nullptr, _root);
	}

	pair<Iterator,bool> Insert(const T& data)
	{
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;
			//return pair<Iterator, bool>(Iterator(_root, _root), true);
			return { Iterator(_root, _root), true };
		}
		Node* cur = _root;
		Node* parent = nullptr;
		KeyOfT 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 { Iterator(cur, _root), false };

			}
		}

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

		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;
			//  g
			//p   u
			if (parent == grandfather->_left)
			{
				Node* uncle = grandfather->_right;
				//存在为红,变色向上调整
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					cur = grandfather;
					parent = cur->_parent;
				}
				//不存在或者为黑,旋转+变色
				else
				{
					//    g
					//  p     
					//c
					if (cur == parent->_left)
					{
						RotateR(grandfather);

						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					//      g
					//  p
					//    c
					else
					{
						RotateL(parent);
						RotateR(grandfather);

						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}
			}
			//  g
			//u   p
			else
			{
				Node* uncle = grandfather->_left;
				//存在为红,变色向上调整
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					cur = grandfather;
					parent = cur->_parent;
				}
				//不存在或者为黑,旋转+变色
				else
				{
					//   g
					//      p
					//         c
					if (cur == parent->_right)
					{
						RotateL(grandfather);

						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					//   g
					//       p
					//     c
					else
					{
						RotateR(parent);
						RotateL(grandfather);

						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					break;
				}
				
			}
		}
		
		_root->_col = BLACK;

		return { Iterator(newnode, _root), true };
	}

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

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

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

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

		if (subLR)
		{
			subLR->_parent = parent;
		}
		parent->_left = subLR;
		parent->_parent = subL;
		subL->_right = parent;

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

	}

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

	int Size()
	{
		return _Size(_root);
	}

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

	Node* Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_kv.first < key)
			{
				cur = cur->_right;
			}
			else if(cur->_kv.first > key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
		return nullptr;
	}

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

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

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

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

private:

	void Destroy(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		Destroy(root->_left);
		Destroy(root->_right);
		delete root;
	}

	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_InOrder(root->_left);
		cout << root->_kv.first << ":" << root->_kv.second << "->" << root->_col << endl;
		_InOrder(root->_right);
	}

	int _Size(Node* root)
	{
		if (root == nullptr)
		{
			return 0;
		}
		return _Size(root->_left) + _Size(root->_right) + 1;
	}

	int _Height(Node* root)
	{
		if (root == nullptr)
		{
			return 0;
		}
		int leftHeight = _Height(root->_left);
		int rightHeight = _Height(root->_right);

		return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
	}

	bool Check(Node* root, int blackNum, const int refNum)
	{
		if (root == nullptr)
		{
			//cout << blackNum << endl;
			//说明一条路径已经走完了
			if (blackNum != refNum)
			{
				cout << "存在黑色结点数量不相等的路径" << endl;
				return false;
			}
			return true;
		}

		if (root->_col == RED && root->_parent->_col == RED)
		{
			cout << root->_kv.first << "出现连续的红色结点" << endl;
			return false;
		}

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

		return Check(root->_left, blackNum, refNum) && Check(root->_right, blackNum, refNum);
	}
private:
	Node* _root = nullptr;
};

set的模拟实现

当前的红黑树需要这三个类型参数(键值、数据,通过数据求key的仿函数),这是为了map也能够复用,但是set只传入一个数据,所以采用这样的方式:<K, const K,SetKeyOfT< K >>,因为set中的数据是不能被修改的所以在第二个类型中加上const.

基本框架

cpp 复制代码
template<class K>
class set
{
	struct SetKeyOfT
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};
private:
	RBTree<K, const K,SetKeyOfT> _t;
};

迭代器

这里的迭代器直接复用红黑树的迭代器.

cpp 复制代码
typedef typename RBTree<K,const K,SetKeyOfT>::Iterator iterator;
typedef typename RBTree<K, const K, SetKeyOfT>::ConstIterator 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();
}

插入

直接复用红黑树接口,其他的接口也是同样的道理

cpp 复制代码
pair<iterator,bool> insert(const K& key)
{
	return _t.Insert(key);
}

源码

cpp 复制代码
#pragma once

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

		typedef typename RBTree<K,const K,SetKeyOfT>::Iterator iterator;
		typedef typename RBTree<K, const K, SetKeyOfT>::ConstIterator 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();
		}

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

		~set()
		{

		}

	private:
		RBTree<K, const K,SetKeyOfT> _t;
	};
}

map模拟实现

map给红黑树传的类型为:<K, pair<const K, V>, MapKeyOfT> ,K类型用于删除、查找等,pair<const K, V>作为数据插入,MapKeyOfT取pair<const K, V,>中的K类型,又因为键值不能修改所以pair<const K, V,>中的K加上const修饰.

基础框架

cpp 复制代码
template<class K,class V>
class map
{
	struct MapKeyOfT
	{
		const K& operator()(const pair<K, V>& kv)
		{
			return kv.first;
		}
	};
private:
	RBTree<K, pair<const K,V>,MapKeyOfT> _t;
};

迭代器

cpp 复制代码
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 _t.begin();
}

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

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

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

插入

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

赋值重载

在map里面,当key不存在时,重载[ ]就会用key进行插入操作并返回插入后key对应数据的引用(此时key对应数据是用其默认构造进行初始化的),当key存在时,返回key对应数据的引用。

cpp 复制代码
V& operator[](const K& key)
{
	pair<iterator, bool> it = insert({ key,V()});
	return it.first->second;
}

源码

cpp 复制代码
#pragma once

namespace mihayou
{
	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 _t.begin();
		}

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

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

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

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

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

		~map()
		{

		}

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

测试代码

cpp 复制代码
#include "RBTree.h"
#include "Myset.h"
#include "Mymap.h"
#include <string>

void Print(const mihayou::set<int>& s)
{
	mihayou::set<int>::const_iterator it = s.end();
	while (it != s.begin())
	{
		--it;
		cout << *it << " ";
	}
	cout << endl;
}

void test01()
{
	mihayou::set<int> s;
	s.insert(1);
	s.insert(5);
	s.insert(3);
	s.insert(7);
	s.insert(6);

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

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

	Print(s);
	s.~set();

	mihayou::map<string, string> dict;
	dict.insert({ "sort", "排序" });
	dict.insert({ "left", "左边" });
	dict.insert({ "right", "右边" });

	dict["left"] = "左边,剩余";
	dict["insert"] = "插入";
	dict["string"];

	mihayou::map<string, string>::iterator it = dict.begin();
	while (it != dict.end())
	{
		// 不能修改first,可以修改second
		//it->first += 'x';
		it->second += 'x';

		cout << it->first << ":" << it->second << endl;
		++it;
	}
	cout << endl;

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

	dict.~map();
}


int main()
{
	test01();
	return 0;
}