【C++】STL----封装红黑树实现map和set

目录

前言

今天继续来学习【C++】封装红黑树实现map和set,本文是基于红黑树实现的,【C++】红黑树详情请点击查看

一、map/set源码及框架分析

  • map和set是通过红黑树封装实现的,我们首先学习一下STL库中是如何通过封装红黑树实现的map/set,截取核心部分做讲解(stl_map.h/stl_set.h/stl_tree.h)
cpp 复制代码
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class map {
public:
    // typedefs:
    typedef Key key_type;
    typedef pair<const Key, T> value_type;
private:
    typedef rb_tree<key_type, value_type,
        select1st<value_type>, key_compare, Alloc> rep_type;
    rep_type t;  // red-black tree representing map
};

template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set {
public:
    // typedefs:
    typedef Key key_type;
    typedef Key value_type;
private:
    typedef rb_tree<key_type, value_type,
        identity<value_type>, key_compare, Alloc> rep_type;
    rep_type t;  // red-black tree representing set
};
  • 从源码中我们可以看到,map和set使用是一个红黑树,map中的value是pair结构(存储的key,value),set的value是key,那为什么还要key结构呢?
  • 分析map和set的整体,rb_tree是实现key的搜索场景,还是key/value的搜索场景不是直接写死的,而是由第二个模板参数Value决定_rb_tree_node中存储的数据类型
  • set实例化rb_tree时第二个模板参数给的是key,map实例化rb_tree时第二个模板参数给的是pair<const key, T>,这样⼀颗红黑树既可以实现key搜索场景的set,也可以实现key/value搜索场景的map

  • rb_tree第二个模板参数Value已经控制了红黑树结点中存储的数据类型,为什么还要传第一个模板参数Key呢?尤其是set,两个模板参数是⼀样的。要注意的是对于map和set,find/erase时的函数参数都是Key,所以第一个模板参数是传给find/erase等函数做形参的类型的。对于set而言两个参数是一样的,但是对于map而言就完全不⼀样了,map insert的是pair对象,但是find和ease的是Key对象

二、红黑树框架修改

  • 前面我们实现了红黑树,通过上面源码的分析,我们对红黑树代码,进行修改,红黑树节点实现泛型编程
  • 节点我们传入T类型,T根据传入的数据类型来确定(set是key,map是pair<K, V>)
cpp 复制代码
template<class T>
struct RBTreeNode
{
	T _data;
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	Colour _col;

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

};
cpp 复制代码
template<class K, class T>
class RBTree
{
	typedef RBTreeNode<T> Node;
private:
	Node* _root = nullptr;
};

三、map/set的封装实现

  • 首先根据源码我们将map/set结构搭建
cpp 复制代码
//set
namespace gy
{
	template<class K>
	class set
	{
	public:
		bool insert(const K& key)
		{
			return _t.Insert(key);
		}
	private:
		RBTree<K, K> _t;

	};
}

//map
namespace gy
{
	template<class K, class V>
	class map
	{
	public:
		bool insert(const pair<K, V>& kv)
		{
			return _t.Insert(kv);
		}
	private:
		RBTree<K, pair<K, V>> _t;
	};
}

insert

  • 下面是原来我们实现的红黑树插入代码,传入的是pair类型数据
cpp 复制代码
bool Insert(const pair<K, V>& kv)
{
	if (_root == nullptr)
	{
		_root = new Node(kv);
		_root->_col = BLACK;
		return true;
	}
	Node* cur = _root;
	Node* parent = nullptr;

	while (cur)
	{
		if (cur->_kv.first < kv.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_kv.first > kv.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else
		{
			return false;
		}
	}
	cur = new Node(kv);
	cur->_col = RED;
	if (parent->_kv.first < kv.first)
	{
		parent->_right = cur;
	}
	else
	{
		parent->_left = cur;
	}
	cur->_parent = parent;

	while (parent && parent->_col == RED)
	{
		Node* grandparent = parent->_parent;
		if (parent == grandparent->_left)
		{
			Node* uncle = grandparent->_right;
			if (uncle && uncle->_col == RED)
			{
				parent->_col = BLACK;
				uncle->_col = BLACK;
				grandparent->_col = RED;
				//继续往上处理
				cur = grandparent;
				parent = cur->_parent;
			}
			else
			{
				//uncle不存在,或者存在且为黑色
				//  g
				//p   u
			   //c
				//单旋 
				if (cur == parent->_left)
				{
					RotateR(grandparent);
					//将parent->Col :BLACK
					//将grandparent->Col:RED
					parent->_col = BLACK;
					grandparent->_col = RED;
				}
				else
				{
					//  g
				   //p    u
			       //  c
				   //双旋
					RotateL(parent);
					RotateR(grandparent);

					cur->_col = BLACK;
					grandparent->_col = RED;
				}
				break;
			}
		}
		else
		{

			Node* uncle = grandparent->_left;
			if (uncle && uncle->_col == RED)
			{
				parent->_col = BLACK;
				uncle->_col = BLACK;
				grandparent->_col = RED;
				//继续往上处理
				cur = grandparent;
				parent = cur->_parent;
			}
			else
			{
				//存在且为黑或者不存在
				 //  g
				//u    p
			   //         c
			    //单旋 
				if (cur == parent->_right)
				{
					RotateL(grandparent);
					//将parent->Col :BLACK
					//将grandparent->Col:RED
					parent->_col = BLACK;
					grandparent->_col = RED;
				}
				else
				{
					//  g
				   //u    p
				   //  c
				   //双旋
					RotateR(parent);
					RotateL(grandparent);

					cur->_col = BLACK;
					grandparent->_col = RED;
				}
				break;
			}
		}
	}
	_root->_col = BLACK;
	return true;
}
  • 现在我们将其修改为泛型编程逻辑,data不确定类型(set是key,map是pair),那么里面的比较逻辑我们就不能只是单纯的使用cur->_data < data来比较了,set的key支持比较大小,但是pair支持吗?
  • 查看文档我们发现pair支持比较大小,但是其比较逻辑是first小就小,first等于再去比较second,second小就小,但是我们需要的比较逻辑是比较first
    >
  • 我们在map和set层分别实现一个MapKeyOfT和SetKeyOfT的仿函数传给RBTree的KeyOfT,然后RBTree中通过KeyOfT仿函数取出T类型对象中的key,再进行比较
cpp 复制代码
//myset.h
namespace gy
{
	template<class K>
	class set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		bool insert(const K& key)
		{
			return _t.Insert(key);
		}
	private:
		RBTree<K, K, SetKeyOfT> _t;

	};
}
//mymap.h
namespace gy
{
	template<class K, class V>
	class map
	{
		struct MapKeyOfT
		{
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		bool insert(const pair<K, V>& key)
		{
			return _t.Insert(key);
		}
	private:
		RBTree<K, pair<K, V>, MapKeyOfT> _t;
	};
}
cpp 复制代码
//RBTree.h
template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;
private:
	Node* _root = nullptr;
};
cpp 复制代码
//泛型编程Insert代码
	bool Insert(const T& data)
	{
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;
			return 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 false;
			}
		}
		cur = new Node(data);
		cur->_col = RED;
		if (kot(parent->_data) < kot(data))
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		cur->_parent = parent;

		while (parent && parent->_col == RED)
		{
			Node* grandparent = parent->_parent;
			if (parent == grandparent->_left)
			{
				Node* uncle = grandparent->_right;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandparent->_col = RED;
					//继续往上处理
					cur = grandparent;
					parent = cur->_parent;
				}
				else
				{
					//uncle不存在,或者存在且为黑色
					//  g
					//p   u
				   //c
					//单旋 
					if (cur == parent->_left)
					{
						RotateR(grandparent);
						//将parent->Col :BLACK
						//将grandparent->Col:RED
						parent->_col = BLACK;
						grandparent->_col = RED;
					}
					else
					{
						//  g
					   //p    u
					   //  c
					   //双旋
						RotateL(parent);
						RotateR(grandparent);

						cur->_col = BLACK;
						grandparent->_col = RED;
					}
					break;
				}
			}
			else
			{

				Node* uncle = grandparent->_left;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandparent->_col = RED;
					//继续往上处理
					cur = grandparent;
					parent = cur->_parent;
				}
				else
				{
					//存在且为黑或者不存在
					 //  g
					//u    p
				   //         c
					//单旋 
					if (cur == parent->_right)
					{
						RotateL(grandparent);
						//将parent->Col :BLACK
						//将grandparent->Col:RED
						parent->_col = BLACK;
						grandparent->_col = RED;
					}
					else
					{
						//  g
					   //u    p
					   //  c
					   //双旋
						RotateR(parent);
						RotateL(grandparent);

						cur->_col = BLACK;
						grandparent->_col = RED;
					}
					break;
				}
			}
		}
		_root->_col = BLACK;
		return true;
	}

find

  • 同理,红黑树的查找也要使用仿函数来解决泛型编程导致底层不知道类型的问题
cpp 复制代码
Node* Find(const K& key)
{
	KeyOfT kot;
	Node* cur = _root;
	while (cur)
	{
		if (kot(cur->_data) < key)
		{
			cur = cur->_right;
		}
		else if (kot(cur->_data) > key)
		{
			cur = cur->_left;
		}
		else
		{
			return cur;
		}
	}
	return nullptr;
}

iterator

iterator源码逻辑:

cpp 复制代码
//iterator++
void increment()
{
  if (node->right != 0) {
    node = node->right;
    while (node->left != 0)
      node = node->left;
  }
  else {
    base_ptr y = node->parent;
    while (node == y->right) {
      node = y;
      y = y->parent;
    }
    if (node->right != y)
      node = y;
  }
}
//iterator--
void decrement()
{
  if (node->color == __rb_tree_red &&
      node->parent->parent == node)
    node = node->right;
  else if (node->left != 0) {
    base_ptr y = node->left;
    while (y->right != 0)
      y = y->right;
    node = y;
  }
  else {
    base_ptr y = node->parent;
    while (node == y->left) {
      node = y;
      y = y->parent;
    }
    node = y;
  }
}

iterator++

  • iterator实现的大框架跟list的iterator思路是一致的,用一个类型封装结点的指针,再通过重载运算符实现,迭代器像指针一样访问的行为
  • map和set的迭代器走的是中序遍历,左子树->根结点->右子树,那么begin()会返回中序第一个结点的iterator
  • 迭代器++时,如果it指向的结点的右子树不为空 ,代表当前结点已经访问完了,要访问下一个结点是右子树的中序第一个,一棵树中序第一个是最左结点,所以直接找右子树的最左结点即可
  • 迭代器++时,如果it指向的结点的右子树空,代表当前结点已经访问完了且当前结点所在的子树也访问完了,要访问的下一个结点在当前结点的祖先里面,所以要沿着当前结点到根的祖先路径向上找(下面15节点iterator++之后是18,25节点iterator++之后是30)
  • 当前结点是父亲的左,下一个访问的结点(iterator++)就是当前结点的父亲(如25节点);如果当前结点是父亲的右,当前结点所在的子树访问完了,当前结点所在父亲的子树也访问完了,那么下一个访问的需要继续往根的祖先中去找,直到找到孩子是父亲左的那个祖先就是中序要问题的下一个结点(15节点)
  • end()如何表示呢?当it指向50时,++it,50是40的右,40是30的右,30是18的右,18到根没有父亲,没有找到孩子是父亲左的那个祖先,父亲为空了,那我们就把it中的结点指针置为nullptr,我们用nullptr去充当end。
  • iterator实现的大框架跟list的iterator思路是一致的,详情搭建过程在这里不做过多赘述详情请点击查看
cpp 复制代码
//RBTree.h
template<class T>
struct _TreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef _TreeIterator<T> Self;
	Node* _node;
	_TreeIterator(Node* node)
		:_node(node)
	{ }
	T& operator*()
	{
		return _node->_data;
	}
	T* operator->()
	{
		return &_node->_data;
	}

	Self& operator++()
	{
		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 = parent->_parent;
			}
			_node = parent;
		}
		return *this;
	}
	bool operator!=(const Self& s)
	{
		return _node != s._node;
	}
};

class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	typedef _TreeIterator<T> Iterator;
	Iterator Begin()
	{
		Node* minLeft = _root;
		while (minLeft && minLeft->_left)
		{
			minLeft = minLeft->_left;
		}
		return Iterator(minLeft);
	}
	Iterator Begin()
	{
		return Iterator(nullptr);
	}
	//.....
};
  • 上层map和set的iterator的实现,注意,当需要使用一个模板里面的某一个函数或者变量时,typedef必须要加上typename
cpp 复制代码
//set.h
typedef typename RBTree<K, K, MapKeyOfT>::Iterator iterator;
iterator begin()
{
	return _t.Begin();
}
iterator end()
{
	return _t.End();
}
//map.h
typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::Iterator iterator;
iterator begin()
{
	return _t.Begin();
}
iterator end()
{
	return _t.End();
}

测试

cpp 复制代码
void test_set()
{
	gy::set<int> s;
	s.insert(1);
	s.insert(4);
	s.insert(3);
	s.insert(6);
	gy::set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it <<" ";
		++it;
	}
	cout << endl;

}

void test_map()
{
	gy::map<string, string> dict;
	dict.insert({"left", "左边"});
	dict.insert({ "right", "右边" });
	dict.insert({"sort", "排序"});
	dict.insert({"string", "字符串"});
	gy::map<string, string>::iterator it = dict.begin();
	while (it != dict.end())
	{
		cout << it->first << ":" << it->second << endl;
		++it;
	}
}
int main()
{
	test_set();
	test_map();
	return 0;
}

iterator--

  • 迭代器--的实现跟++的思路完全类似,逻辑正好反过来即可,因为他访问顺序是右子树->根结点->左子树
  • iterator--有一个需要注意的是:当节点为空时即为end()节点 ,所以我们需要从根节点遍历,遍历到最右边节点,所以还需要一个根节点
cpp 复制代码
Self& operator--()
{
	if (_node == nullptr) // end()
	{
		// --end(),特殊处理,⾛到中序最后⼀个结点,整棵树的最右结点 
		Node* rightMost = _root;
		while (rightMost && rightMost->_right)
		{
			rightMost = rightMost->_right;
		}
		_node = rightMost;
	}
	else if(_node->_left)
	{
		_node = _node->_left;
		while (_node->_right)
		{
			_node = _node->_right;
		}
	}
	else
	{
		Node* cur = _node;
		Node* parent = cur->_parent;
		while (parent && cur == parent->_left)
		{
			cur = parent;
			parent = parent->_parent;
		}
		_node = parent;
	}
	return *this;
}
  • 最终代码
cpp 复制代码
template<class T>
struct _TreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef _TreeIterator<T> Self;
	Node* _node;
	Node* _root;
	_TreeIterator(Node* node, Node* root)
		:_node(node)
		,_root(root)
	{ }
	T& operator*()
	{
		return _node->_data;
	}
	T* operator->()
	{
		return &_node->_data;
	}

	Self& operator++()
	{
		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 = parent->_parent;
			}
			_node = parent;
		}
		return *this;
	}

	Self& operator--()
	{
		if (_node == nullptr) // end()
		{
			// --end(),特殊处理,⾛到中序最后⼀个结点,整棵树的最右结点 
			Node* rightMost = _root;
			while (rightMost && rightMost->_right)
			{
				rightMost = rightMost->_right;
			}

			_node = rightMost;
		}
		else if(_node->_left)
		{
			_node = _node->_left;
			while (_node->_right)
			{
				_node = _node->_right;
			}
		}
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && cur == parent->_left)
			{
				cur = parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		return *this;
	}
	//后置++
	Self operator++(int)
	{
		Self tmp = *this;
		++(*this);
		return tmp;
	}

	//后置--
	Self operator--(int)
	{
		Self tmp = *this;
		--(*this);
		return tmp;
	}

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

template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;

public:
	typedef _TreeIterator<T> Iterator;
	Iterator Begin()
	{
		Node* minLeft = _root;
		while (minLeft && minLeft->_left)
		{
			minLeft = minLeft->_left;
		}
		return Iterator(minLeft, _root);
	}
	Iterator End()
	{
		return Iterator(nullptr, _root);
	}
	//.....
}

测试

cpp 复制代码
void test_set()
{
	gy::set<int> s;
	s.insert(1);
	s.insert(4);
	s.insert(3);
	s.insert(6);
	gy::set<int>::iterator it = s.end();
	while (it != s.begin())
	{
		--it;
		cout << *it <<" ";
		
	}
	cout << endl;

}

void test_map()
{
	gy::map<string, string> dict;
	dict.insert({"left", "左边"});
	dict.insert({ "right", "右边" });
	dict.insert({"sort", "排序"});
	dict.insert({"string", "字符串"});
	gy::map<string, string>::iterator it = dict.end();

	while (it != dict.begin())
	{
		--it;
		cout << it->first << ":" << it->second << endl;
		
	}
}
int main()
{
	test_set();
	test_map();
	return 0;
}

const_iterator

const_iterator和list的iterator也是类似的,const迭代器不是本身不能修改,而是指向的内容不能修改,因此我们可以和list的实现一样,多传入两个参数来控制内容不可改变和可变

cpp 复制代码
typedef _TreeIterator<T, T&, T*> Iterator;
typedef _TreeIterator<T, const T&, const T*> ConstIterator;
cpp 复制代码
//RBTree.h
template<class T, class Ref, class Ptr>
struct _TreeIterator
{
	typedef RBTreeNode<T> Node;
	typedef _TreeIterator<T, Ref, Ptr> Self;
	Node* _node;
	Node* _root;
	_TreeIterator(Node* node, Node* root)
		:_node(node)
		,_root(root)
	{ }
	Ref operator*()
	{
		return _node->_data;
	}
	Ptr operator->()
	{
		return &_node->_data;
	}
	//......
}

template<class K, class T, class KeyOfT>
class RBTree
{
	typedef RBTreeNode<T> Node;

public:
	typedef _TreeIterator<T, T&, T*> Iterator;
	typedef _TreeIterator<T, const T&, const T*> ConstIterator;
	Iterator Begin()
	{
		Node* minLeft = _root;
		while (minLeft && minLeft->_left)
		{
			minLeft = minLeft->_left;
		}
		return Iterator(minLeft, _root);
	}
	Iterator End()
	{
		return Iterator(nullptr, _root);
	}

	ConstIterator Begin() const
	{
		Node* minLeft = _root;
		while (minLeft && minLeft->_left)
		{
			minLeft = minLeft->_left;
		}
		return ConstIterator (minLeft, _root);
	}
	ConstIterator End() const
	{
		return ConstIterator (nullptr, _root);
	}
	//.....
}
cpp 复制代码
//set.h
namespace gy
{
	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 typename RBTree<K, 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();
		}
		bool insert(const K& key)
		{
			return _t.Insert(key);
		}
	private:
		RBTree<K, K, SetKeyOfT> _t;

	};
}

//map.h
namespace gy
{
	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;
		typedef typename RBTree<K, pair<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();
		}
		bool insert(const pair<K, V>& key)
		{
			return _t.Insert(key);
		}
	private:
		RBTree<K, pair<K, V>, MapKeyOfT> _t;
	};
}

测试

cpp 复制代码
void Print(const gy::set<int>& s)
{
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
}
void test_set()
{
	gy::set<int> s;
	s.insert(1);
	s.insert(4);
	s.insert(3);
	s.insert(6);
	gy::set<int>::iterator it = s.end();
	Print(s);

}

int main()
{
	test_set();

	return 0;
}

key不支持修改问题

  • 上面实现的代码,普通迭代器的key是能够修改的,这不符合map/set的规则
  • 对于set而言,key不能修改,因此在RBTree<K, K, SetKeyOfT> _t加入const修饰RBTree<K, const K, SetKeyOfT> _t
cpp 复制代码
namespace gy
{
	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();
		}
		bool insert(const K& key)
		{
			return _t.Insert(key);
		}
	private:
		//const修饰key,不可改变
		RBTree<K, const K, SetKeyOfT> _t;

	};
}
  • 对于map而言,不能修改pair结构中的key,因此将RBTree<K, pair<K, V>, MapKeyOfT> _t修改为RBTree<K, pair<const K, V>, MapKeyOfT> _t
cpp 复制代码
namespace gy
{
	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();
		}
		bool insert(const pair<K, V>& key)
		{
			return _t.Insert(key);
		}
	private:
		RBTree<K, pair<const K, V>, MapKeyOfT> _t;
	};
}

测试

cpp 复制代码
void Print(gy::set<int>& s)
{
	for (auto& e : s)
	{
		e++;
		cout << e << " ";
	}
	cout << endl;
}

void test_set()
{
	gy::set<int> s;
	s.insert(1);
	s.insert(4);
	s.insert(3);
	s.insert(6);
	gy::set<int>::iterator it = s.end();
	Print(s);

}

void test_map()
{
	gy::map<int, int> dict;
	dict.insert({ 1, 1 });
	dict.insert({ -1, -1 });
	dict.insert({6, 6});
	dict.insert({3, 3});
	gy::map<int, int>::iterator it = dict.begin();

	while (it != dict.end())
	{
		it->first++;
		it->second++;
		cout << it->first << ":" << it->second << endl;
	}
}
int main()
{
	test_set();
	test_map();
	return 0;
}

从结果可以看出,无论是map还是set,普通迭代器也无法修改key,map的value值可以修改

insert/find返回值完善代码

  • 根据库里面insert,返回值是一个pair类型,当插入成功,返回新节点的{iterator,true},插入失败(已经存在),返回旧的节点的{iterator,false}
cpp 复制代码
pair<Iterator, bool> Insert(const T& data)
{
	if (_root == nullptr)
	{
		_root = new Node(data);
		_root->_col = BLACK;
		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;
	cur->_col = RED;
	if (kot(parent->_data) < kot(data))
	{
		parent->_right = cur;
	}
	else
	{
		parent->_left = cur;
	}
	cur->_parent = parent;

	while (parent && parent->_col == RED)
	{
		Node* grandparent = parent->_parent;
		if (parent == grandparent->_left)
		{
			Node* uncle = grandparent->_right;
			if (uncle && uncle->_col == RED)
			{
				parent->_col = BLACK;
				uncle->_col = BLACK;
				grandparent->_col = RED;
				//继续往上处理
				cur = grandparent;
				parent = cur->_parent;
			}
			else
			{
				//uncle不存在,或者存在且为黑色
				//  g
				//p   u
			   //c
				//单旋 
				if (cur == parent->_left)
				{
					RotateR(grandparent);
					//将parent->Col :BLACK
					//将grandparent->Col:RED
					parent->_col = BLACK;
					grandparent->_col = RED;
				}
				else
				{
					//  g
				   //p    u
				   //  c
				   //双旋
					RotateL(parent);
					RotateR(grandparent);

					cur->_col = BLACK;
					grandparent->_col = RED;
				}
				break;
			}
		}
		else
		{

			Node* uncle = grandparent->_left;
			if (uncle && uncle->_col == RED)
			{
				parent->_col = BLACK;
				uncle->_col = BLACK;
				grandparent->_col = RED;
				//继续往上处理
				cur = grandparent;
				parent = cur->_parent;
			}
			else
			{
				//存在且为黑或者不存在
				 //  g
				//u    p
			   //         c
				//单旋 
				if (cur == parent->_right)
				{
					RotateL(grandparent);
					//将parent->Col :BLACK
					//将grandparent->Col:RED
					parent->_col = BLACK;
					grandparent->_col = RED;
				}
				else
				{
					//  g
				   //u    p
				   //  c
				   //双旋
					RotateR(parent);
					RotateL(grandparent);

					cur->_col = BLACK;
					grandparent->_col = RED;
				}
				break;
			}
		}
	}
	_root->_col = BLACK;
	return { Iterator(newnode, _root), true};
}
  • find的返回值也是迭代器,找到了返回当前节点,没有找到,则返回End()节点
cpp 复制代码
Iterator Find(const K& key)
{
	KeyOfT kot;
	Node* cur = _root;
	while (cur)
	{
		if (kot(cur->_data) < key)
		{
			cur = cur->_right;
		}
		else if (kot(cur->_data) > key)
		{
			cur = cur->_left;
		}
		else
		{
			return Iterator(cur, _root);
		}
	}
	return End();
}

operator[]

  • map的operator[]的实现,当传入的key已经存在,则插入失败,我们可以获得key的iterator,根据iterator,返回value的值;如果key不存在,则会将{ key, V() }插入到map中,再通过迭代器返回value值
cpp 复制代码
//map.h
V& operator[](const K& key)
{
	pair<iterator, bool> ret = _t.Insert({ key, V() });
	return ret.first->second;
}

测试

cpp 复制代码
void test_map()
{
	gy::map<string, string> dict;
	dict.insert({"left", "左边"});
	dict.insert({ "right", "右边" });
	dict.insert({"sort", "排序"});
	dict.insert({"string", "字符串"});
	gy::map<string, string>::iterator it = dict.begin();
	while (it != dict.end())
	{
		cout << it->first << ":" << it->second << endl;
		++it;
	}
	cout << endl;

	dict["insert"];
	dict["left"] = "剩余";
	for (auto& e : dict)
	{
		cout << e.first << ":" << e.second << endl;
	}
}
int main()
{
	
	test_map();
	return 0;
}

operator[]从下面运行结果可以看到成功实现

相关推荐
loosenivy2 小时前
IP风险画像识别和IP风险预警接口
java·ip查询·ip风险画像识别·ip预警查询·ip画像
violet-lz2 小时前
C++ 内存分区详解
开发语言·jvm·c++
汤姆yu2 小时前
基于springboot的林业资源管理系统
java·spring boot·后端
软件管理系统2 小时前
基于Spring Boot的医疗服务系统的设计与实现
java·spring boot·后端
软件管理系统2 小时前
基于微信小程序的健身房管理系统
java·tomcat·maven
小张成长计划..2 小时前
【C++】20:set和map的理解和使用
c++
大志哥1232 小时前
IntelliJ IDEA父子工程中导入公网远程备份项目到新目录
java·ide·intellij-idea
renke33642 小时前
Flutter 2025 跨平台工程体系:从 iOS/Android 到 Web/Desktop,构建真正“一次编写,全端运行”的产品
android·flutter·ios