C++笔记---unordered_set和unordered_map(两万字史诗巨著,虽然全是代码堆起来的)

1. 简单介绍

我们知道set和map的底层为红黑树,使用迭代器进行遍历时(中序),所得到的数据是有序的。

而unordered_set和unordered_map的底层为哈希表,顾名思义,二者存储的数据是无序的。

虽然数据无序,但unordered_set和unordered_map的查找效率可达O(1),在一些只要求能快速查找而不要求有序场景下有很高的价值,因此也在C++11中被纳入了标准。

unordered_set/unordered_map与set/map的使用如出一辙,只是一个数据有序,一个数据无序。

所以在这里我们就不多介绍其用法了,大家可以参考set/map的使用方法:

C++笔记---set和map-CSDN博客

或者直接参考文档:

unordered_set - C++ Reference

unordered_map - C++ Reference

2. 模拟实现

unordered太难写了,接下来都直接简称set/map。

2.1 set/map专用哈希表

仅用于学习原理的哈希表我们已经实现过了:

C++笔记---哈希表-CSDN博客

要用来适配出unordered_set和unoerdered_map还需要对其进行一些修改,我们使用链地址法的那一版来进行修改。

首先我们要明确,set/map的最主要的区别只在于存储的是key还是pair,底层的哈希表逻辑基本相同,所以我们修改出来的哈希表最好能同时适配出二者。

所以如何区别存储的数据是key还是pair呢?因为在查找删除时用到的都是key,如果存储的是pair,我们还需要访问pair的first才能得到key。

2.1.1 仿函数KeyOfT

参照STL源码,我们可以看到其解决上面问题的方式是:

在哈希表的参数列表中传入仿函数KeyOfT,用于获取数据(T)的key,该仿函数在set和map的中分别实现并传给自身内部的哈希表。

对于set来说,SetKeyOfT直接返回数据本身;对于map来说,MapKeyOfT返回pair的first。

cpp 复制代码
struct SetKeyOfT
{
	const K& operator()(const K& key)
	{
		return key;
	}
};

struct MapKeyOfT
{
	const K& operator()(const pair<K, V>& kv)
	{
		return kv.first;
	}
};

这样,在哈希表内部需要用到key时,统一使用仿函数KeyOfT取得,就不需要对二者进行区分了。

相应地,我们要对数据结点进行修改:

cpp 复制代码
template<class T>
struct HashNode
{
	T _data;
	HashNode* _next;
	HashNode(const T& data)
		:_data(data)
		, _next(nullptr)
	{}
};

在哈希表地参数列表中,也不以传入K,V的方式传入数据类型了,而是传入K,T:

cpp 复制代码
template<class K, class T, class KeyOfT, class Hash, class Compare>
class HashTable

另外,Hash和Compare也由外层的set/map指定,所以也不需要缺省值了。

注意,这样修改之后,各个函数都需要相应地发生变化,注意修改。

2.1.2 迭代器

unordered_set/unordered_map的迭代器是单向迭代器,底层就是对结点指针的包装。

迭代器实现中唯一的难点就是,当一个桶中没有任何数据或访问到桶的最后一个数据时,需要跳转到下一个有数据的桶中,也就是operator++的逻辑。

如果能访问到哈希表内部的数组,这一点自然很好解决。

而为了降低耦合提高代码的可维护性,迭代器与哈希表是分开实现的,且哈希表内部的数组是private成员。

参考STL源代码,其解决方式是给迭代器增加一个指向对应哈希表的指针成员,并声明为哈希表的友元类,以便其访问哈希表底层的数组。

cpp 复制代码
// 前置声明
template<class K, class T, class KeyOfT, class Hash, class Compare>
class HashTable;

template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash, class Compare>
class HTIterator
{
	typedef HashNode<T> Node;
	typedef HTIterator<K, T, Ref, Ptr, KeyOfT, Hash, Compare> Self;
	typedef HashTable<K, T, KeyOfT, Hash, Compare> Table;
public:
	HTIterator(Node* node, Table* pHT)
		:_node(node)
		, _pHT(pHT)
	{}

	template<class reference, class pointer>
	HTIterator(const HTIterator<K, T, reference, pointer, KeyOfT, Hash, Compare>& it)
		:_node(it._node)
		, _pHT(it._pHT)
	{}

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

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

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

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

	Self& operator++()
	{
		assert(_node);
		if (_node->_next)
			_node = _node->_next;
		else
		{
			size_t pos = _hash(_keyOf(_node->_data)) % _pHT->_tables.size();
			++pos;
			while (pos < _pHT->_tables.size() && _pHT->_tables[pos] == nullptr)
			{
				++pos;
			}

			if (pos < _pHT->_tables.size())
				_node = _pHT->_tables[pos];
			else
				_node = nullptr;
		}

		return *this;
	}

	Self operator++(int)
	{
		Self it = *this;
		++(*this);
		return it;
	}

private:
	Node* _node;
	Table* _pHT;
	Hash _hash;
	KeyOfT _keyOf;
};

注意,模板声明为友元类需要带上参数列表:

cpp 复制代码
template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash, class Compare>
friend class HTIterator;
2.1.3 插入函数

由于map需要实现operator[],所以插入函数的返回值需要改为:

cpp 复制代码
pair<iterator, bool>

相应的逻辑也要发生变化:

cpp 复制代码
pair<iterator, bool> Insert(const T& data)
{
	iterator it = Find(_keyof(data));
	if (it != end())
		return {it, false};
	// 负载因子等于1,扩容
	if (_n == _tables.size())
	{
		vector<Node*> newTables(__stl_next_prime(_n + 1));
		// 原结点依次插入新表
		for (size_t i = 0; i < _n; i++)
		{
			Node* cur = _tables[i];
			while (cur)
			{
				Node* next = cur->_next;
				size_t pos = _hash(_keyof(cur->_data)) % _tables.size();
				cur->_next = newTables[pos];
				newTables[pos] = cur;
				cur = next;
			}
			_tables[i] = nullptr;
		}
		_tables.swap(newTables);
	}

	size_t pos = _hash(_keyof(data)) % _tables.size();
	Node* newnode = new Node(data);
	newnode->_next = _tables[pos];
	_tables[pos] = newnode;
	++_n;
	return { iterator(newnode, this) , true};
}
2.1.4 代码参考示例
cpp 复制代码
#pragma once
#include<string>
#include<vector>
#include<assert.h>
using namespace std;

static const int __stl_num_primes = 28;
static const unsigned long __stl_prime_list[__stl_num_primes] =
{
  53,         97,         193,       389,       769,
  1543,       3079,       6151,      12289,     24593,
  49157,      98317,      196613,    393241,    786433,
  1572869,    3145739,    6291469,   12582917,  25165843,
  50331653,   100663319,  201326611, 402653189, 805306457,
  1610612741, 3221225473, 4294967291
};

inline unsigned long __stl_next_prime(unsigned long n)
{
	const unsigned long* first = __stl_prime_list;
	const unsigned long* last = __stl_prime_list + __stl_num_primes;
	const unsigned long* pos = lower_bound(first, last, n);
	return pos == last ? *(last - 1) : *pos;
}

// 哈希函数采用除留余数法
template<class K>
struct HashFunc
{
	size_t operator()(const K& key)
	{
		return (size_t)key;
	}
};

// 哈希表中支持字符串的操作
template<>
struct HashFunc<string>
{
	size_t operator()(const string& key)
	{
		size_t hash = 0;
		for (auto e : key)
		{
			hash *= 131;
			hash += e;
		}

		return hash;
	}
};

template<class K>
struct Equal
{
	bool operator()(const K& key1, const K& key2)
	{
		return key1 == key2;
	}
};

// 给unorder_set和unordered_map使用的HashTable
namespace lbz
{
	template<class T>
	struct HashNode
	{
		T _data;
		HashNode* _next;
		HashNode(const T& data)
			:_data(data)
			, _next(nullptr)
		{}
	};

	// 前置声明
	template<class K, class T, class KeyOfT, class Hash, class Compare>
	class HashTable;

	template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash, class Compare>
	class HTIterator
	{
		typedef HashNode<T> Node;
		typedef HTIterator<K, T, Ref, Ptr, KeyOfT, Hash, Compare> Self;
		typedef HashTable<K, T, KeyOfT, Hash, Compare> Table;
	public:
		HTIterator(Node* node, Table* pHT)
			:_node(node)
			, _pHT(pHT)
		{}

		template<class reference, class pointer>
		HTIterator(const HTIterator<K, T, reference, pointer, KeyOfT, Hash, Compare>& it)
			:_node(it._node)
			, _pHT(it._pHT)
		{}

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

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

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

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

		Self& operator++()
		{
			assert(_node);
			if (_node->_next)
				_node = _node->_next;
			else
			{
				size_t pos = _hash(_keyOf(_node->_data)) % _pHT->_tables.size();
				++pos;
				while (pos < _pHT->_tables.size() && _pHT->_tables[pos] == nullptr)
				{
					++pos;
				}

				if (pos < _pHT->_tables.size())
					_node = _pHT->_tables[pos];
				else
					_node = nullptr;
			}

			return *this;
		}

		Self operator++(int)
		{
			Self it = *this;
			++(*this);
			return it;
		}

	private:
		Node* _node;
		Table* _pHT;
		Hash _hash;
		KeyOfT _keyOf;
	};

	template<class K, class T, class KeyOfT, class Hash, class Compare>
	class HashTable
	{
		template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash, class Compare>
		friend class HTIterator;

		typedef HashNode<T> Node;
		typedef HashTable<K, T, KeyOfT, Hash, Compare> Self;
	public:
		typedef HTIterator<K, T, T&, T*, KeyOfT, Hash, Compare> iterator;
		typedef HTIterator<K, T, const T&, const T*, KeyOfT, Hash, Compare> const_iterator;
		HashTable()
			:_tables(__stl_next_prime(0))
			, _n(0)
		{}

		HashTable(const Self& hashtable)
			:HashTable()
		{
			for (auto cur : hashtable._tables)
			{
				while (cur)
				{
					Insert(cur->_kv);
					cur = cur->_next;
				}
			}
		}

		Self& operator=(Self hashtable)
		{
			swap(_tables, hashtable._tables);
			swap(_n, hashtable._n);
			return *this;
		}

		~HashTable()
		{
			for (auto cur : _tables)
			{
				while (cur)
				{
					Node* next = cur->_next;
					delete cur;
					cur = next;
				}
			}
		}

		iterator begin()
		{
			if (_n == 0)
				return end();

			size_t i = 0;
			for (i = 0; i < _tables.size(); i++)
			{
				if (_tables[i] != nullptr)
					break;
			}

			return iterator(_tables[i], this);
		}

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

		const_iterator begin() const
		{
			if (_n == 0)
				return end();

			size_t i = 0;
			for (i = 0; i < _tables.size(); i++)
			{
				if (_tables[i] != nullptr)
					break;
			}

			return const_iterator(_tables[i], this);
		}

		const_iterator end() const
		{
			return const_iterator(nullptr, this);
		}

		pair<iterator, bool> Insert(const T& data)
		{
			iterator it = Find(_keyof(data));
			if (it != end())
				return {it, false};
			// 负载因子等于1,扩容
			if (_n == _tables.size())
			{
				vector<Node*> newTables(__stl_next_prime(_n + 1));
				// 原结点依次插入新表
				for (size_t i = 0; i < _n; i++)
				{
					Node* cur = _tables[i];
					while (cur)
					{
						Node* next = cur->_next;
						size_t pos = _hash(_keyof(cur->_data)) % _tables.size();
						cur->_next = newTables[pos];
						newTables[pos] = cur;
						cur = next;
					}
					_tables[i] = nullptr;
				}
				_tables.swap(newTables);
			}

			size_t pos = _hash(_keyof(data)) % _tables.size();
			Node* newnode = new Node(data);
			newnode->_next = _tables[pos];
			_tables[pos] = newnode;
			++_n;
			return { iterator(newnode, this) , true};
		}

		iterator Find(const K& key)
		{
			size_t pos = _hash(key) % _tables.size();
			Node* cur = _tables[pos];
			while (cur && !_com(_keyof(cur->_data), key)) { cur = cur->_next; }
			return iterator(cur, this);
		}

		bool Erase(const K& key)
		{
			size_t pos = _hash(key) % _tables.size();
			if (_tables[pos] == nullptr)
				return false;
			Node* del = nullptr;
			if (_com(_keyof(_tables[pos]->_data), key))
			{
				del = _tables[pos];
				_tables[pos] = _tables[pos]->_next;
			}
			else
			{
				Node* parent = _tables[pos];
				while (parent->_next && !_com(_keyof(parent->_next->_data), key))
				{
					parent = parent->_next;
				}

				if (parent->_next == nullptr)
					return false;

				del = parent->_next;
				parent->_next = parent->_next->_next;
			}
			delete del;
			--_n;
			return true;
		}

	private:
		vector<Node*> _tables;
		size_t _n = 0;  // 表中存储数据个数
		Hash _hash;
		Compare _com;
		KeyOfT _keyof;
	};
}

2.2 unordered_set

没什么好说的,注意set中的key是不可修改的,所以在传入参数T时直接传入const K。

cpp 复制代码
#pragma once
#include"hashTable.h"

namespace lbz
{
	template<class K, class Hash = HashFunc<K>, class Compare = Equal<K>>
	class unordered_set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename HashTable<K, const K, SetKeyOfT, Hash, Compare>::iterator iterator;
		typedef typename HashTable<K, const K, SetKeyOfT, Hash, Compare>::const_iterator const_iterator;

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

		bool Erase(const K& key)
		{
			return _hashtable.Erase(key);
		}

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

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

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

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

	private:
		HashTable<K, const K, SetKeyOfT, Hash, Compare> _hashtable;
	};
}

2.3 unordered_map

也没什么好说的,就是还需要实现一个operator[],具体实现方式参考下面的代码(当然下面的代码也是参考STL源码实现的)。

cpp 复制代码
#pragma once
#include"hashTable.h"

namespace lbz
{
	template<class K, class V, class Hash = HashFunc<K>, class Compare = Equal<K>>
	class unordered_map
	{
		struct MapKeyOfT
		{
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename HashTable<K, pair<const K, V>, MapKeyOfT, Hash, Compare>::iterator iterator;
		typedef typename HashTable<K, pair<const K, V>, MapKeyOfT, Hash, Compare>::const_iterator const_iterator;

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

		bool Erase(const K& key)
		{
			return _hashtable.Erase(key);
		}

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

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

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

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

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

	private:
		HashTable<K, pair<const K, V>, MapKeyOfT, Hash, Compare> _hashtable;
	};
}

3. 总结

unordered_set/unordered_map底层为哈希表,相比于底层为红黑树的set/map来说,数据无序但查找插入都更高效。

要自己实现unordered_set/unordered_map,重点在于底层哈希表的实现,难点在于各个结构之间的相互嵌套,参数类型的传值,在自己实现的过程中一定会出现很多问题的。而且报出来的错误会让你觉得牛头不对马嘴,例如:

这是由于end()后面加上了const而发生的报错,但感觉怎么想二者之间都没关系,真给我搞红温了。

4. set/map的模拟实现

红黑树的实现可以参考:C++笔记---红黑树的插入删除_红黑树 删除-CSDN博客

这里我就不再多说了,基本实现思路与上面相似,但红黑树结构更复杂,在改的过程中会更加困难,有多难呢?难得我都不想再水一篇文章了,直接贴到下面大家参考一下吧。

4.1 SM_RBTree

就是set/map专用红黑树的意思,没什么含义哈。

cpp 复制代码
#pragma once
#include"reverse_iterator.h"
namespace lbz
{
	// 枚举值表示颜色
	enum Colour
	{
		RED,
		BLACK
	};

	// 这里我们默认按key/value结构实现
	template<class T>
	struct RBTreeNode
	{
		// 这里更新控制平衡也要加入parent指针
		T _data;
		RBTreeNode<T>* _left;
		RBTreeNode<T>* _right;
		RBTreeNode<T>* _parent;
		Colour _col;
		RBTreeNode(const T& data, Colour col = RED)
			:_data(data)
			, _left(nullptr)
			, _right(nullptr)
			, _parent(nullptr)
			, _col(col)
		{}
	};

	template<class T, class Ref, class Ptr>
	struct RBTreeIterator
	{
		typedef RBTreeIterator<T, Ref, Ptr> Self;
		typedef RBTreeNode<T> Node;
		typedef T value_type;
		typedef Ref reference;
		typedef Ptr pointer;
	public:
		RBTreeIterator(Node* node = nullptr, Node* root = nullptr)
			:_node(node)
			,_root(root)
		{}

		RBTreeIterator(const Self& it)
			:_node(it._node)
			,_root(it._root)
		{}

		template<class T, class reference, class pointer>
		RBTreeIterator(const RBTreeIterator<T, reference, pointer>& it)
			:_node(it._node)
			,_root(it._root)
		{}

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

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

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

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

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

		Self operator++(int)
		{
			Self tmp = *this;
			++(*this);
			return tmp;
		}

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

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

		Node* _node;
		Node* _root;
	};

	template<class K, class T, class KeyOfT>
	class RBTree
	{
		typedef RBTreeNode<T> Node;
		typedef RBTree<K, T, KeyOfT> Self;
	public:
		typedef RBTreeIterator<T, T&, T*> iterator;
		typedef RBTreeIterator<T, const T&, const T*> const_iterator;
		typedef Reverse_iterator<iterator> reverse_iterator;
		typedef Reverse_iterator<const_iterator> const_reverse_iterator;
	public:
		RBTree() = default;

		RBTree(const RBTree& tree)
		{
			_root = Construct(tree._root);
		}

		RBTree(const initializer_list<const T>& li)
		{
			for (auto& e : li)
			{
				Insert(e);
			}
		}

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

		RBTree& operator=(RBTree tree)
		{
			std::swap(_root, tree._root);
			return *this;
		}

		iterator begin()
		{
			Node* first = _root;
			while (first->_left) { first = first->_left; }
			return iterator(first, _root);
		}

		const_iterator begin() const
		{
			return (Self)(*this).begin();
		}

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

		const_iterator end() const
		{
			return (Self)(*this).end();
		}

		reverse_iterator rbegin()
		{
			return end();
		}

		const_reverse_iterator rbegin() const
		{
			return end();
		}

		reverse_iterator rend()
		{
			return begin();
		}

		const_reverse_iterator rend() const
		{
			return begin();
		}

		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, * parent = nullptr;
			while (cur)
			{
				parent = cur;
				if (keyOf(data) < keyOf(cur->_data))
					cur = cur->_left;
				else if (keyOf(data) > keyOf(cur->_data))
					cur = cur->_right;
				else
					return {iterator(cur, _root), false};
			}

			cur = new Node(data);
			Node* ret = cur;
			cur->_col = RED;
			if (keyOf(data) < keyOf(cur->_data))
				parent->_left = cur;
			else
				parent->_right = cur;
			cur->_parent = parent;

			while (parent && parent->_col == RED)
			{
				// 因为_root为黑色,所以parent为红色,grandfather一定存在且为黑色
				Node* grandfather = parent->_parent;
				// 不进行双旋时需变色
				parent->_col = BLACK;
				grandfather->_col = RED;
				if (parent == grandfather->_left)// uncle在右子树
				{
					Node* uncle = grandfather->_right;
					if (uncle && uncle->_col == RED)// uncle存在且为红,直接变色
					{
						uncle->_col = BLACK;
						cur = grandfather;
						parent = cur->_parent;
					}
					else// uncle不存在或为黑,变色加旋转
					{
						if (cur == parent->_right)
						{
							RotateL(parent);
							if (uncle)
								uncle->_col = RED;
							parent->_col = RED;
							cur->_col = BLACK;
						}
						RotateR(grandfather);

						break;// 转后parent为子树根(黑),无需继续向上更新
					}
				}
				else
				{
					Node* uncle = grandfather->_left;
					if (uncle && uncle->_col == RED)
					{
						uncle->_col = BLACK;
						cur = grandfather;
						parent = cur->_parent;
					}
					else
					{
						if (cur == parent->_left)
						{
							RotateR(parent);
							if (uncle)
								uncle->_col = RED;
							parent->_col = RED;
							cur->_col = BLACK;
						}
						RotateL(grandfather);

						break;
					}
				}
			}

			_root->_col = BLACK;
			return {iterator(ret, _root), true};
		}

		bool Erase(const K& k)
		{
			Node* del = Find(k);
			if (del == nullptr)
				return false;

			// 两个孩子都有,更新要删除的结点
			if (del->_left && del->_right)
			{
				Node* replace = del->_right;
				while (replace->_left) { replace = replace->_left; }
				std::swap(del->_data, replace->_data);
				del = replace;
			}

			// 接下来处理至少一个孩子为空
			if (del == _root)
				_root = nullptr;
			else if (del->_left || del->_right || del->_col == RED)// 有一个孩子或为红色
			{
				Node* child = del->_left ? del->_left : del->_right;
				if (child)
					child->_parent = del->_parent;

				if (del->_parent->_left == del)
					del->_parent->_left = child;
				else
					del->_parent->_right = child;

				if (del->_col == BLACK)
					child->_col = BLACK;
			}
			else// 没有孩子且为黑色
			{
				Node* cur = del;// 可能会向上调整,用cur代替del,始终认为cur无孩子
				while (1)
				{
					if (cur->_parent->_col == RED)// 父结点为红色,一定有黑色兄弟,直接删除+变色
					{
						cur->_parent->_col = BLACK;
						if (cur->_parent->_left == cur)
						{
							cur->_parent->_left = nullptr;
							cur->_parent->_right->_col = RED;
						}
						else
						{
							cur->_parent->_right = nullptr;
							cur->_parent->_left->_col = RED;
						}
					}
					else// 父结点为黑色,看情况单双旋或调整
					{
						Node* parent = cur->_parent;
						if (parent->_left == cur)// 在左,右边是兄弟
						{
							Node* brother = parent->_right;
							parent->_left = nullptr;
							if (brother->_col == RED)// 红色兄弟,一定有两个黑孩子
							{
								brother->_col = BLACK;
								brother->_left->_col = RED;
								RotateL(parent);
							}
							else// 黑色兄弟,要么没孩子,要么有红孩子
							{
								if (brother->_left == nullptr && brother->_right == nullptr)// 兄弟没孩子,差一个调不了,向上调整
								{
									brother->_col = RED;
									cur = parent;
									continue;
								}
								else if (brother->_right)
								{
									brother->_right->_col = BLACK;
									RotateL(parent);
								}
								else
								{
									brother->_left->_col = BLACK;
									RotateR(brother);
									RotateL(parent);
								}
							}
						}
						else// 在右,左边是兄弟
						{
							Node* brother = parent->_left;
							parent->_right = nullptr;
							if (brother->_col == RED)// 红色兄弟,一定有两个黑孩子
							{
								brother->_col = BLACK;
								brother->_right->_col = RED;
								RotateR(parent);
							}
							else// 黑色兄弟,要么没孩子,要么有红孩子
							{
								if (brother->_left == nullptr && brother->_right == nullptr)// 兄弟没孩子,差一个调不了,向上调整
								{
									brother->_col = RED;
									cur = parent;
									continue;
								}
								else if (brother->_left)
								{
									brother->_left->_col = BLACK;
									RotateR(parent);
								}
								else
								{
									brother->_right->_col = BLACK;
									RotateL(brother);
									RotateR(parent);
								}
							}
						}
					}

					break;
				}
			}

			delete del;
			return true;
		}

		void RotateR(Node* parent)
		{
			Node* cur = parent->_left;
			Node* subR = cur->_right;

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


			if (parent == _root)
				_root = cur;
		}

		void RotateL(Node* parent)
		{
			Node* cur = parent->_right;
			Node* subL = cur->_left;

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

			if (parent == _root)
				_root = cur;
		}

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

			return nullptr;
		}

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

		bool isRBTree()
		{
			if (_isRBTree(_root) == -1)
				return false;
			else
				return true;
		}

	private:
		Node* Construct(Node* root)
		{
			if (root == nullptr)
				return nullptr;

			Node* copy = new Node(root->_data, root->_col);
			copy->_left = Construct(root->_left);
			copy->_left->_parent = copy;
			copy->_right = Construct(root->_right);
			copy->_right->_parent = copy;
			return copy;
		}

		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 << keyOf(_root->_data) << " ";
			_InOrder(root->_right);
		}

		int _isRBTree(Node* root)
		{
			int flag = 0;
			if (root == nullptr)
				return 0;
			if (root->_col == RED && root->_parent->_col == RED)
				return -1;
			if (root->_col == BLACK)
				flag = 1;

			int left = _isRBTree(root->_left);
			int right = _isRBTree(root->_right);

			if (left == right)
				return left + flag;
			else
				return -1;
		}

		KeyOfT keyOf;
	private:
		Node* _root = nullptr;
	};
}

4.2 mySet

cpp 复制代码
#pragma once
#include"SM_RBTree.h"

namespace lbz
{
	template<class K>
	class set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef RBTreeNode<K> Node;
		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
		typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
		typedef typename RBTree<K, K, SetKeyOfT>::const_reverse_iterator reverse_iterator;
		typedef typename RBTree<K, K, SetKeyOfT>::const_reverse_iterator const_reverse_iterator;

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

		bool Erase(const K& key)
		{
			return _tree.Erase(key);
		}

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

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

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

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

		reverse_iterator rbegin()
		{
			return _tree.rbegin();
		}

		const_reverse_iterator rbegin() const
		{
			return _tree.rbegin();
		}

		reverse_iterator rend()
		{
			return _tree.rend();
		}

		const_reverse_iterator rend() const
		{
			return _tree.rend();
		}
	private:
		RBTree<K, K, SetKeyOfT> _tree;
	};
}

4.3 myMap

cpp 复制代码
#pragma once
#include"SM_RBTree.h"

namespace lbz
{
	template<class K, class V>
	class map
	{
		struct MapKeyOfT
		{
			const K& operator()(const pair<const K, V>& p)
			{
				return p.first;
			}
		};
	public:
		typedef pair<const K, V> T;
		typedef RBTreeNode<T> Node;
		typedef typename RBTree<K, T, MapKeyOfT>::iterator iterator;
		typedef typename RBTree<K, T, MapKeyOfT>::const_iterator const_iterator;
		typedef typename RBTree<K, T, MapKeyOfT>::reverse_iterator reverse_iterator;
		typedef typename RBTree<K, T, MapKeyOfT>::const_reverse_iterator const_reverse_iterator;

		pair<iterator, bool> Insert(const T& data)
		{
			return _tree.Insert(data);
		}

		bool Erase(const T& data)
		{
			return _tree.Erase(data);
		}

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

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

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

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

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

		reverse_iterator rbegin()
		{
			return _tree.rbegin();
		}

		const_reverse_iterator rbegin() const
		{
			return _tree.rbegin();
		}

		reverse_iterator rend()
		{
			return _tree.rend();
		}

		const_reverse_iterator rend() const
		{
			return _tree.rend();
		}
	private:
		RBTree<K, pair<const K, V>, MapKeyOfT> _tree;
	};
}
相关推荐
红色的山茶花2 分钟前
YOLOv8-ultralytics-8.2.103部分代码阅读笔记-block.py
笔记·深度学习·yolo
召木4 分钟前
C++小白实习日记——Day 2 TSCNS怎么读取当前时间
c++·职场和发展
yngsqq5 分钟前
037集——JoinEntities连接多段线polyline和圆弧arc(CAD—C#二次开发入门)
开发语言·c#·swift
Zԅ(¯ㅂ¯ԅ)7 分钟前
C#桌面应用制作计算器进阶版01
开发语言·c#
过期的H2O28 分钟前
【H2O2|全栈】JS进阶知识(七)ES6(3)
开发语言·javascript·es6
坚硬果壳_10 分钟前
《硬件架构的艺术》笔记(六):流水线的艺术
笔记·硬件架构
一路冰雨19 分钟前
Qt打开文件对话框选择文件之后弹出两次
开发语言·qt
St_Ludwig22 分钟前
C语言 蓝桥杯某例题解决方案(查找完数)
c语言·c++·后端·算法·游戏·蓝桥杯
松树戈28 分钟前
JS推荐实践
开发语言·javascript·ecmascript
瑞雨溪30 分钟前
java中的this关键字
java·开发语言