底层实现set和map

本文详细介绍了红黑树的实现,并通过C++模板技术模拟实现了set和map的数据结构。内容包括红黑树节点结构、迭代器操作以及set和map的插入操作。同时,针对set和map的不同需求,定义了不同的键值提取函数以适应不同场景。通过封装,简化了红黑树在实际应用中的使用。
摘要由CSDN通过智能技术生成

  • 红黑树的实现blog链接link.

1. 改进红黑树

通过STL可以得到,对于set和map的实现底层所使用的的都是红黑树,所以这里比较难得是对模板的使用。

#pragma once

enum Color
{
	RED,
	BLACK
};

template<class T>
struct RBTreeNode
{
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	T _t;

	enum Color _col;

	RBTreeNode(const T& t)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _t(t)
		, _col(RED)
	{}
};

template<class T, class Ref, class Ptr>
struct RBTreeIterator
{
	typedef RBTreeIterator<T, Ref, Ptr> Self;
	typedef RBTreeNode<T> Node;
	Node* _node;
	RBTreeIterator(Node* node)
		:_node(node)
	{}

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

	//对于set来说,*it可以直接的取到Key值
	//但是对于map来说,it->first
	Ptr operator->()
	{
		return &(_node->_t);//如果是map那么这里返回的是一个pair<const K,V>*
	}

	// ++it 前置
	//对于这个迭代器的++来说,还是比较需要在重新好好的思考一下的
	Self& operator++()
	{
		//简单点说,当开始访问我这个结点的时候,说明这个结点的左树已经访问完了,此时分情况就要看右树是不是空
		// 找中序的下一个
		if (_node->_right)
		{
			// 右树的最左节点
			Node* cur = _node->_right;
			while (cur->_left)
			{
				cur = cur->_left;
			}

			_node = cur;
		}
		else
		{
			// 右为空,_node所在的子树已经访问完了,
			// 沿着路径往根走,找孩子不是父亲的右的那个祖先
			
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && parent->_right == cur)
			{
				cur = parent;
				parent = parent->_parent;
			}

			_node = parent;
		}

		return *this; //*this返回的是本身
	}

	//对于++来说,左子树 根 右子树
	//对于--来说,右子树 根 左子树,和++的逻辑刚好相反
	Self& operator--()
	{
		//也就是当走到那个结点的时候,右子树和根已经遍历完了,所以此时应该看左子树
		if (_node->_left)
		{
			//应该找左子树中的最右结点,也就是最大的结点
			Node* cur = _node->_left;
			while (cur->_right)
			{
				cur = cur->_right;
			}
			_node = cur;
		}
		else
		{
			Node* cur = _node;
			Node* parent = cur->_parent;
			while (parent && parent->_left == cur)
			{
				cur = parent;
				parent = parent->_parent;
			}
			_node = parent;
		}
		return *this;
	}

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


// set<K>    -> RBTree<K, K>
// map<K, V> -> RBTree<K,pair<const K, V>>
template<class K, class T, class KeyOfT>
struct RBTree
{
public:
	typedef RBTreeIterator<T, T&, T*> Iterator;
	typedef RBTreeIterator<T, const T&, const T*> Const_Iterator;
	typedef RBTreeNode<T> Node;
	//对于红黑树的Begin()迭代器来说,应该从中序遍历的第一个开始
	Iterator Begin()
	{
		Node* cur = _root;
		while (cur && cur->_left)
		{
			cur = cur->_left;
		}
		return Iterator(cur);
	}

	Iterator End()
	{
		return Iterator(nullptr);
	}


	//bool Find(const K& k);
	pair<Iterator, bool> Insert(const T& t)
	{
		KeyOfT kot;

		if (_root == nullptr)
		{
			_root = new Node(t);

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

		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (kot(cur->_t) < kot(t))
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (kot(cur->_t) > kot(t))
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return make_pair(Iterator(cur), false);
			}
		}

		cur = new Node(t); // RED
		if (kot(parent->_t) < kot(t))
		{
			parent->_right = cur;
			cur->_parent = parent;
		}
		else
		{
			parent->_left = cur;
			cur->_parent = parent;
		}

		Node* newnode = cur;

		// 
		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;
			if (grandfather->_left == parent)
			{
				Node* uncle = grandfather->_right;
				// 情况1:u存在且为红
				if (uncle && uncle->_col == RED)
				{
					// 变色
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					// 继续往上处理
					cur = grandfather;
					parent = cur->_parent;
				}
				else //  情况2+3:u不存在或存在且为黑
				{
					//        g
					//      p
					//   c
					//
					if (cur == parent->_left)  
					{
						RotateR(grandfather);
						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					else
					{
						//        g
						//      p
						//         c
						//
						RotateL(parent);
						RotateR(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}
			}
			else // grandfather->_right == parent
			{
				Node* uncle = grandfather->_left;
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;

					cur = grandfather;
					parent = cur->_parent;
				}
				else //  情况2+3:u不存在或存在且为黑
				{
					if (cur == parent->_right)
					{
						RotateL(grandfather);
						grandfather->_col = RED;
						parent->_col = BLACK;
					}
					else
					{
						RotateR(parent);
						RotateL(grandfather);
						cur->_col = BLACK;
						grandfather->_col = RED;
					}

					break;
				}
			}
		}


		_root->_col = BLACK;
		return make_pair(Iterator(newnode), true);
	}


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

			subL->_parent = parentParent;
		};
	}

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

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

		subR->_left = parent;

		Node* parentParent = parent->_parent;
		parent->_parent = subR;

		if (_root == parent)
		{
			_root = subR;
		}
		else
		{
			if (parentParent->_left == parent)
			{
				parentParent->_left = subR;
			}
			else
			{
				parentParent->_right = subR;
			}
		}

		subR->_parent = parentParent;
	}


private:
	Node* _root = nullptr;
};
  1. 红黑树的结点内存的不再是具体的类型Key值或者pair<const K,V>,而是一种更高维度的泛型,通过这个模板参数实现对同一颗树的复用。
  2. 对于模板所传了一个KeyOfT的仿函数的作用就是取出T模型中的K值,如果你是set那么T就是K,但是如果你是map的话,T就是pair<const K,V>,那么这里并不能拿来直接的比较大小,所以还需要将里面具体的Key值取出来,在进行比较大小才可以。
  3. 还有一个就是对于迭代器中的operator++()和operator–()需要好好的理解。对于迭代器的++操作来说,应该走的是中序遍历的过程,比如此时走到了7这个结点,下一个怎么找到,就是问题。

在这里插入图片描述

2. 对于set模拟封装

对于set和map来说,自己本身是没有什么内容的,他们就都是基于红黑树的基础上所实现的,底层所使用的也都是红黑树的结构和接口。

#pragma once
#include "RBTree.h"

namespace wzy
{
	template<class K>
	class set
	{
		struct SetKOfT
		{
			const K& operator()(const K& k)
			{
				return k;
			}
		};
	public:
		//对于set的迭代器其实就是对红黑树的迭代器进行了封装
		//这里typename还有一个作用:此时代码走到这里,模板还没有实例化,所以找不到
		//相当于告诉编译器,别急着报错,先放下,等待实例化之后再来找,如果还找不到,在报错也不急
		typedef typename RBTree<K, K, SetKOfT>::Iterator iterator;

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

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


		//pair<RBTreeNode<K>*, bool> insert(const K& k)
		pair<iterator, bool> insert(const K& k)
		{
			return _t.Insert(k);
		}

	private:
		RBTree<K, K, SetKOfT> _t;
	};

	void test_set()
	{
		set<int> s;
		s.insert(1);
		s.insert(20);
		s.insert(12);
		s.insert(2);
		s.insert(23);
		s.insert(21);
		s.insert(2);
		s.insert(30);

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

在这里插入图片描述

3. 对于map模拟封装

#pragma once
#include "RBTree.h"

namespace wzy
{
	template<class K, class V>
	class map
	{
		struct MapKOfT
		{
			const K& operator()(const pair<const K, V>& kv)
			{
				return kv.first;
			}
		};

	public:
		typedef typename RBTree<K, pair<const K, V>, MapKOfT>::Iterator iterator;
		iterator begin()
		{
			return _t.Begin();
		}

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

		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = insert(make_pair(key, V()));
			//ret.first拿到迭代器,->拿到了pair,然后返回第二个参数
			return ret.first->second;
		}

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

	void test_map()
	{
		//map<int, int> m;
		//m.insert(make_pair(1, 1));
		//m.insert(make_pair(2, 1));
		//m.insert(make_pair(3, 1));


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


		map<string, string> dict;
		dict["string"] = "字符串";
		dict["sort"] = "排序";

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

		支持迭代器就支持范围for
		//for (const auto& e : dict)
		//{
		//	cout << e.first << ":" << e.second << endl;
		//}
	}
}

在这里插入图片描述

  1. 对于map来说是重载了[]的,但是底层其实就是调用insert函数帮忙实现的,不管成功不成功,返回的都是Value的引用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值