【STL】map

m a p map map C C C++ 标准模板库( S T L STL STL)中的一部分,它是一个关联式容器,用于存储键值对。每个元素都有一个唯一的键,并且可以通过键快速检索对应的值 m a p map map 中的元素是按照键的特定顺序排列的,默认情况下是按照键的升序排列的,但这可以通过提供自定义的比较函数(仿函数)来改变。


前言 —— pair 类型介绍

p a i r pair pair 类型的本质就是一个结构体,这个结构体将一对值耦合在一起。这些值可能具有不同的类型(模板类型),且可以通过其 p u b l i c public public 成员 f i r s t first first s e c o n d second second 来访问各个值。更多细节可以 C C C++ 官网查看 p a i r pair pair 类型的基本介绍 : p a i r pair pair 类型

在这里插入图片描述

template <class T1, class T2>
struct pair
{
	typedef T1 first_type;
	typedef T2 second_type;
	
	T1 first;
	T2 second;
	
	// 1.无参构造函数
	pair()
		: first(T1())
		, second(T2())
	{}
	
	// 2.构造函数
	pair(const T1& a, const T2& b)
		: first(a)
		, second(b)
	{}
	
	// 3.拷贝构造函数
	template<class U, class V>
	pair (const pair<U,V>& pr)
		: first(pr.first)
		, second(pr.second)
	{}
};

m a p map map 底层的红黑树节点中的数据,就使用 pair<Key, T> 存储键值对数据。

typedef pair<const Key, T> value_type;	// Key值不可修改,只能修改value值

此外,为了方便传 p a i r pair pair 类型的参数,还提供了一个专门构造 p a i r pair pair 类型的函数 m a k e _ p a i r make\_pair make_pair):

template <class T1,class T2>
inline pair<T1,T2> make_pair (T1 x, T2 y)
{
	return ( pair<T1,T2>(x,y) );
}

那么 p a i r pair pair 类型有什么用呢?为什么要使用 p a i r pair pair 类型?

C C C++ 中,函数返回值一次只能返回一个值,如果想传两个或多个值就可以传 p a i r pair pair 类型的变量,通过 f i r s t first first s e c o n d second second 来指向这两个不同的值(多个值可以通过嵌套 p a i r pair pair 来实现)。


一、map 的介绍

m a p map map 系列根据容器是否支持插入相同元素(通过 K e y Key Key 值判断)而分为了 m a p map map(映射)和 m u l t i m a p multimap multimap(多重映射)。

m a p map map 其实就是用于存储由键值和映射值组合而成的元素,并按特定顺序进行存储的容器

在这里插入图片描述

m u l t i m a p multimap multimap 其实就是用于存储由键值和映射值组合形成的元素,并遵循特定顺序进行存储的容器,其中多个元素可以具有等效的键值

在这里插入图片描述

由于最常用的还是 m a p map map 容器,因此这里主要介绍的是 m a p map map,而 m u l t i m a p multimap multimap m a p map map 只有在一些地方有略微的不同,稍注意一下即可。

m a p map map 的声明如下:

template < class Key, 									// map::key_type
		   class T, 									// map::mapped_type
		   class Compare = less<Key>, 					// map::key_compare
		   class Alloc = allocator<pair<const Key,T> > 	// map::allocator_type
		 > class map;
  1. K e y Key Key 就是 m a p map map 底层关键字的类型。

  2. T T T m a p map map 底层 v a l u e value value 的类型。

  3. m a p map map 默认要求 K e y Key Key 支持小于比较(less<T>升序排序),如果不支持或者需要的话可以自行实现仿函数传给第二个模板参数。

  4. m a p map map 底层存储数据的内存是从空间配置器申请的,如果需要可以自己实现内存池,传给第三个模板参数。

注意:一般情况下,我们都不需要传后两个模板参数。

m a p map map 底层是用红黑树实现的,增删查改效率是 O ( l o g N ) O(logN) O(logN)只支持 v a l u e value value 修改),迭代器遍历是走的中序,所以是按 k e y key key 有序顺序遍历的。


二、map 的使用(常用接口)

m a p map map成员类型 v a l u e _ t y p e value\_type value_type)为 p a i r pair pair 键值对。其中, p a i r pair pair 的第一个参数为 k e y key key 关键字 k e y _ t y p e key\_type key_type); p a i r pair pair 的第二个参数为 v a l u e value value 映射值 m a p p e d _ t y p e mapped\_type mapped_type)。

Member types
key_type 	->	The first template parameter (Key)
mapped_type	->	The second template parameter (T)
value_type 	->	pair<const key_type, mapped_type>	// key不可修改

1. 常见构造

构造 ( c o n s t r u c t o r ) (constructor) (constructor) 函数声明接口说明
m a p ( ) map() map()无参默认构造
m a p ( c o n s t   m a p &   x ) map(const\ map\&\ x) map(const map& x)拷贝构造
m a p ( I n p u t I t e r a t o r   f i r s t , I n p u t I t e r a t o r   l a s t ) map(InputIterator\ first, InputIterator\ last) map(InputIterator first,InputIterator last)使用迭代器区间构造
m a p ( i n i t i a l i z e r _ l i s t < v a l u e _ t y p e > i l ) map (initializer\_list<value\_type> il) map(initializer_list<value_type>il)使用 i n i t i a l i z e r initializer initializer 列表构造
  1. 无参默认构造:
map<char, int> mp							// 升序
map<char, int, greater<char>>				// 降序
  1. 拷贝构造:
map<char, int, greater<char>> mp = { {'a',1},{'b',2},{'c',3} };

map<char, int> mp1(mp);						// 升序
map<char, int, greater<char>> mp2(mp);		// 降序
  1. 迭代器区间构造:
vector<pair<char,int>> v = { {'a',1},{'b',2},{'c',3} };

map<char, int> mp1(v.begin(),v.end());								// 升序
map<char, int, greater<int>> mp2(v.begin(),v.end());				// 降序
  1. i n i t i a l i z e r initializer initializer 列表构造:
map<char, int> mp1 = { {'a',1},{'b',2},{'c',3}};					// 升序
map<char, int, greater<char>> mp2 = { {'a',1},{'b',2},{'c',3}};		// 降序

2. iterator 的使用

i t e r a t o r iterator iterator 的使用接口说明
b e g i n ( ) begin() begin() + + + e n d ( ) end() end()正向迭代器( i t e r a t o r iterator iterator
r b e g i n ( ) rbegin() rbegin() + + + r e n d ( ) rend() rend()反向迭代器( r e v e r s e _ i t e r a t o r reverse\_iterator reverse_iterator
  1. m a p map map 的支持正向和反向迭代遍历,遍历默认按 k e y key key 的升序顺序,因为底层是二叉搜索树迭代器遍历走的是中序遍历

  2. 支持迭代器就意味着支持范围 f o r for for

  3. m a p map map 支持修改 v a l u e value value 数据,不支持修改 k e y key key 数据,修改关键字数据,就破坏了底层搜索树的结构。

  4. m a p map map 的迭代器是一个双向迭代器iterator -> a bidirectional iterator to const value_type
    在这里插入图片描述

map<char, int> mp = { {'a',1},{'b',2},{'c',3},{'d',4},{'e',5}};

// 1.正向迭代器
auto it = mp.begin();
while (it != mp.end())
{
	cout << it->first << ":" << it->second << " ";
	++it;
}
cout << endl;

// 2.反向迭代器
auto rit = mp.rbegin();
while (rit != mp.rend())
{
	cout << rit->first << ":" << rit->second << " ";
	++rit;
}
cout << endl;

// 3.范围for
for (const auto& e : mp)
{
	cout << e.first << ":" << e.second << " ";
}
cout << endl;

输出:

a:1 b:2 c:3 d:4 e:5
e:5 d:4 c:3 b:2 a:1
a:1 b:2 c:3 d:4 e:5

3. 增删查

m a p map map 增删查接口说明
i n s e r t insert insert插入 v a l val val 数据
e r a s e erase erase删除 v a l val val 数据
f i n d find find查找 v a l val val,返回 v a l val val 位置的迭代器(没找到返回 e n d ( ) end() end()
c o u n t count count查找 v a l val val,返回 v a l val val 的个数
l o w e r _ b o u n d lower\_bound lower_bound返回大于等于 v a l val val 位置的迭代器
u p p e r _ b o u n d upper\_bound upper_bound返回大于 v a l val val 位置的迭代器

其中,增加数据的接口跟 s e t set set 所有不同, m a p map map 插入的是 p a i r pair pair 键值对数据,但是查找数据和删除数据的接口只和关键字 k e y key key 有关,因此跟 s e t set set 是完全类似的。

不过 f i n d find find 返回 i t e r a t o r iterator iterator,不仅可以确认 k e y key key 在不在,还能找到 k e y key key 映射的 v a l u e value value,同时通过迭代器还可以修改 v a l u e value value

  1. 插入数据(insert):
vector<pair<char, int>> v = { {'a',1},{'e',5},{'b',2} };
map<char, int> mp;

// 1.直接插入(pair)
mp.insert(make_pair('c', 3));
// 2.指定位置插入(pair)
mp.insert(mp.begin(), pair<char,int>('d',4));
// 3.迭代器区间插入
mp.insert(v.begin(), v.end());
// 4.initializer插入
mp.insert({ { 'f',6 }, { 'g',7 }, { 'h',8 } });
// 5.operator[]插入(最常用)
mp['i'] = 9;

for (const auto& e : mp) cout << e.first << ":" << e.second << " "; cout << endl;

输出:

a:1 b:2 c:3 d:4 e:5 f:6 g:7 h:8 i:9
  1. 查找 + 删除数据(find + erase):
map<char, int> mp = { {'a',1},{'b',2},{'c',3},{'d',4},{'e',5} };

// 1.指定位置删除
mp.erase(mp.begin());
// 2.指定数据删除
mp.erase('d');
// 3.迭代器区间删除
auto it = mp.find('c');		// 返回值对应的迭代器(没找到就返回mp.end())
if (it != mp.end())
	mp.erase(mp.begin(), it);	// 前闭后开[mp.begin(),it)

for (const auto& e : mp) cout << e.first << ":" << e.second << " "; cout << endl;

输出:

c:30 e:5
  1. lower_bound / upper_bound
map<char, int> mp = { {'a',1},{'b',2},{'c',3},{'d',4},{'e',5} };

auto it1 = mp.lower_bound('b');	// 返回第一个key值 >= b的迭代器
auto it2 = mp.upper_bound('d');	// 返回第一个key值 > d的迭代器

// 删除[b,d]区间的数据
mp.erase(it1,it2);

for (const auto& e : mp) cout << e.first << ":" << e.second << " "; cout << endl;

输出:

a:1 e:5

4. 数据修改

m a p map map 只支持修改 m a p p e d _ t y p e mapped\_type mapped_type v a l u e value value)数据,不支持修改 k e y key key 数据,修改关键字数据,就破坏了底层搜索树的结构

  1. m a p map map 第一个支持修改的方式是通过迭代器,迭代器遍历时或者 f i n d find find 返回 k e y key key 所在的 i t e r a t o r iterator iterator 修改:
map<char, int> mp = { {'a',1},{'b',2},{'c',3},{'d',4},{'e',5} };

// 通过find找到迭代器可以修改其value值
auto fv = mp.find('c');
fv->second *= 10;

for (const auto& e : mp) cout << e.first << ":" << e.second << " "; cout << endl;

输出:

a:1 b:2 c:30 d:4 e:5
m a p map map 数据修改接口说明
o p e r a t o r [   ] operator[\ ] operator[ ]修改 k e y key key 位置所对应的 v a l u e value value 数据
  1. m a p map map 还有一个非常重要的修改接口 o p e r a t o r [   ] operator[\ ] operator[ ],但是 o p e r a t o r [   ] operator[\ ] operator[ ] 不仅支持修改数据,还支持插入数据查找数据,所以他是一个多功能复合接口:
map<char, int> mp = { {'a',1},{'b',2},{'c',3},{'d',4},{'e',5} };

// 最常用的方式:
// 1.修改数据
mp['c'] *= 10;
// 2.插入数据
mp['f'] = 6;
// 3.查找数据
cout << mp['b'] << endl;

for (const auto& e : mp) cout << e.first << ":" << e.second << " "; cout << endl;

输出:

2
a:1 b:2 c:30 d:4 e:5 f:6

需要注意从内部实现角度, m a p map map 这里把我们传统说的 v a l u e value value 值,给的是 T T T 类型, t y p e d e f typedef typedef m a p p e d _ t y p e mapped\_type mapped_type。而 v a l u e _ t y p e value\_type value_type红黑树结点中存储的 p a i r pair pair 键值对值。日常使用我们还是习惯将这里的 T T T 映射值叫做 v a l u e value value

  1. 如果 k k k 不在 m a p map map 中, i n s e r t insert insert 会插入 k k k m a p p e d _ t y p e mapped\_type mapped_type 默认值,同时 [   ] [\ ] [ ] 返回结点中存储 m a p p e d _ t y p e mapped\_type mapped_type 值的引用,那么我们可以通过引用修改返回映射值。所以 [   ] [\ ] [ ] 具备了插入 + + + 修改功能。

  2. 如果 k k k m a p map map 中, i n s e r t insert insert 会插入失败,但是 i n s e r t insert insert返回 p a i r pair pair 对象的 f i r s t first first 是指向 k e y key key 结点的迭代器,返回值同时 [   ] [\ ] [ ] 返回结点中存储 m a p p e d _ t y p e mapped\_type mapped_type 值的引用,所以 [   ] [\ ] [ ] 具备了查找 + + + 修改的功能。

pair<iterator,bool> insert (const value_type& val);

// operator的内部实现
mapped_type& operator[] (const key_type& k)
{
	pair<iterator, bool> ret = insert({ k, mapped_type() });
	iterator it = ret.first;
	return it->second;
}

5. multimap 和 map 的差异

m u l t i m a p multimap multimap m a p map map 的使用基本完全类似,主要区别点在于 m u l t i m a p multimap multimap 支持关键值 k e y key key 冗余

  1. 那么 i n s e r t / f i n d / c o u n t / e r a s e insert/find/count/erase insert/find/count/erase 都围绕着支持关键值 k e y key key 冗余有所差异,比如 f i n d find find 时,有多个 k e y key key,返回中序第一个。

这里跟 s e t set set m u l t i s e t multiset multiset 完全一样,在此不再重复介绍,有兴趣可以参考这篇博客:【STL】 s e t set set

  1. 其次就是 m u l t i m a p multimap multimap 不支持 [   ] [\ ] [ ],因为支持 k e y key key 冗余, [   ] [\ ] [ ] 就只能支持插入了,不能支持修改。

三、map 的模拟实现

1. STL 中的 map 源码

S G I − S T L   30 SGI-STL\ 30 SGISTL 30 版本源代码, m a p map map 容器的实现需要用到红黑树,对于红黑树这个数据结构的详细介绍,可以参考我的这篇博客:【数据结构】红黑树

  1. 因此库里 m a p map map 容器的头文件包含了 s t l _ t r e e . h stl\_tree.h stl_tree.h s t l _ m a p . h stl\_map.h stl_map.h s t l _ m u l t i m a p . h stl\_multimap.h stl_multimap.h
// map
#ifndef __SGI_STL_INTERNAL_TREE_H
#include <stl_tree.h>
#endif
#include <stl_map.h>
#include <stl_multimap.h>
  1. s t l _ m a p . h stl\_map.h stl_map.h
// stl_map.h
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class map 
{
public:
	// typedefs:
	typedef Key key_type;
	typedef T mapped_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
};

2. map 的迭代器

m a p map map i t e r a t o r iterator iterator 不支持修改 k e y key key 但是可以修改 v a l u e value value,我们把 m a p map map 的第二个模板参数 p a i r pair pair 的第一个参数改成 c o n s t   K const\ K const K 即可。

typedef typename RBTree<K, pair<const K, V>, mapKeyOfT>::iterator iterator;
typedef typename RBTree<K, pair<const K, V>, mapKeyOfT>::const_iterator const_iterator;

RBTree<K, pair<const K, V>, mapKeyOfT> _t;

3. map 支持 operator[]

m a p map map 要支持 o p e r a t o r [   ] operator[\ ] operator[ ] 主要需要修改 i n s e r t insert insert 返回值支持,修改 R B t r e e RBtree RBtree 中的 i n s e r t insert insert 返回值为 pair<iterator, bool> insert(const T& data) 即可。

有了 i n s e r t insert insert 支持 o p e r a t o r [   ] operator[\ ] operator[ ] 实现就很简单了:

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

4. 模拟实现 map

由于 m a p map map 属于 C C C++ S T L STL STL 容器模板类),因此, m a p map map 声明和定义都要写到一个文件中。又因为 m a p map map 的底层结构是红黑树,因此迭代器直接使用红黑树的迭代器即可。

总共分为三个文件:红黑树类直接使用我们之前泛型封装好的 r b _ t r e e . h rb\_tree.h rb_tree.h(底层数据结构); m a p . h map.h map.h 用来存放 m a p map map 的定义和实现; t e s t . c p p test.cpp test.cpp 用来测试。

注意:这里两个文件中的 m a p map map 都是自己定义的,为了和 s t d : : m a p std::map std::map 作区分,我们要单独创建一个命名空间,这里我用的是 n a m e s p a c e   y b c namespace\ ybc namespace ybc

  1. r b _ t r e e . h rb\_tree.h rb_tree.h
#pragma once
#include<iostream>

using namespace std;

namespace ybc
{
	// 枚举值表示颜色
	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)
			, _col(red)
		{}
	};

	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* lm = _node->_right;
				while (lm->_left)
				{
					lm = lm->_left;
				}
				_node = lm;
			}
			else
			{
				// 右为空,孩子是父亲的左的那个祖先就是下一个结点
				Node* cur = _node;
				Node* parent = cur->_parent;
				while (parent && cur != parent->_left)
				{
					cur = parent;
					parent = cur->_parent;
				}
				_node = parent;
			}
			return *this;
		}

		self& operator -- ()
		{
			if (_node == nullptr) // end()
			{
				// 整棵树的最右结点就是end()的上一个结点
				Node* rm = _root;
				while (rm && rm->_right)
				{
					rm = rm->_right;
				}
				_node = rm;
			}
			else if (_node->_left)
			{
				// 左不为空,左子树的最右结点就是上一个结点
				Node* rm = _node->_left;
				while (rm->_right)
				{
					rm = rm->_right;
				}
				_node = rm;
			}
			else
			{
				// 左为空,孩子是父亲右的那个祖先就是上一个结点
				Node* cur = _node;
				Node* parent = cur->_parent;
				while (parent && cur != parent->_right)
				{
					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;
		KeyOfT kot;
	public:
		typedef RBTreeIterator<T, T&, T*> iterator;
		typedef RBTreeIterator<T, const T&, const T*> const_iterator;

		iterator begin()
		{
			node* lm = _root;
			while (lm && lm->_left)
			{
				lm = lm->_left;
			}
			return iterator(lm, _root);
		}

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

		const_iterator cbegin() const
		{
			node* lm = _root;
			while (lm && lm->_left)
			{
				lm = lm->_left;
			}
			return const_iterator(lm, _root);
		}

		const_iterator cend() const
		{
			return const_iterator(nullptr, _root);
		}

		RBTree() = default;

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

		pair<iterator, bool> insert(const T& data)
		{
			if (_root == nullptr)
			{
				_root = new node(data);
				_root->_col = black;
				return make_pair(iterator(nullptr, _root), true);
			}

			node* parent = nullptr;
			node* cur = _root;
			while (cur)
			{
				if (kot(data) < kot(cur->_data))
				{
					parent = cur;
					cur = cur->_left;
				}
				else if (kot(data) > kot(cur->_data))
				{
					parent = cur;
					cur = cur->_right;
				}
				else
				{
					return make_pair(iterator(cur, _root), false);
				}
			}

			cur = new node(data);
			node* newnode = cur;

			if (kot(data) < kot(parent->_data))
			{
				parent->_left = cur;
			}
			else
			{
				parent->_right = cur;
			}
			cur->_parent = parent;

			// 维持平衡操作
			while (parent && parent->_col == red)	// 如果父亲是红,说明出现了连续的红色结点
			{
				node* grandparent = parent->_parent;

				if (parent == grandparent->_left)
				{
					node* uncle = grandparent->_right;
					/*
						  g
						 / \
						p   u
					*/
					if (uncle && uncle->_col == red)	// 情况一:u 存在且为红色
					{
						// 变色
						grandparent->_col = red;
						parent->_col = uncle->_col = black;

						// 继续向上更新
						cur = grandparent;
						parent = cur->_parent;
					}
					else								// 情况二:u 存在且为黑色 或者 u 不存在
					{
						// 旋转 + 变色
						if (cur == parent->_left)
						{
							/*	1. 单旋
									g          p
								   / \        / \
								  p   u  ->  c   g
								 /                \
								c                  u
							*/
							rotateR(grandparent);
							// 变色
							parent->_col = black;
							grandparent->_col = red;
						}
						else
						{
							/*	2. 双旋
									g          c
								   / \        / \
								  p   u  ->  p   g
								   \              \
									c              u
							*/
							rotateL(parent);
							rotateR(grandparent);
							// 变色
							cur->_col = black;
							grandparent->_col = red;
						}
						break;
					}
				}
				else
				{
					node* uncle = grandparent->_left;
					/*
						  g
						 / \
						u   p
					*/
					if (uncle && uncle->_col == red)	// 情况一:u 存在且为红色
					{
						// 只变色
						grandparent->_col = red;
						uncle->_col = parent->_col = black;

						// 继续向上更新
						cur = grandparent;
						parent = cur->_parent;
					}
					else								// 情况二:u 存在且为黑色 或者 u 不存在
					{
						// 旋转 + 变色
						if (cur == parent->_right)
						{
							/*	1. 单旋
									g          p
								   / \        / \
								  u   p  ->  g   c
									   \    /
										c  u
							*/
							rotateL(grandparent);
							// 变色
							parent->_col = black;
							grandparent->_col = red;
						}
						else
						{
							/*	2. 双旋
									g          c
								   / \        / \
								  u   p  ->  g   p
									 /      /
									c      u
							*/
							rotateR(parent);
							rotateL(grandparent);
							// 变色
							cur->_col = black;
							grandparent->_col = red;
						}
						break;
					}
				}
			}

			_root->_col = black;
			return make_pair(iterator(newnode, _root), true);
		}

		iterator find(const K& key)
		{
			node* cur = _root;
			while (cur)
			{
				if (key < kot(cur->_data))
				{
					cur = cur->_left;
				}
				else if (key > kot(cur->_data))
				{
					cur = cur->_right;
				}
				else
				{
					return iterator(cur, _root);
				}
			}
			return iterator(nullptr, _root);
		}
	private:
		void rotateL(node* parent)
		{
			node* subR = parent->_right;
			node* subRL = subR->_left;
			node* pParent = parent->_parent;

			// 旋转核心逻辑
			subR->_left = parent;
			parent->_right = subRL;
			if (pParent == nullptr)	// parent == _root
				_root = subR;
			else if (pParent->_left == parent)
				pParent->_left = subR;
			else
				pParent->_right = subR;

			// 处理_parent
			if (subRL)
				subRL->_parent = parent;
			parent->_parent = subR;
			subR->_parent = pParent;
		}

		void rotateR(node* parent)
		{
			node* subL = parent->_left;
			node* subLR = subL->_right;
			node* pParent = parent->_parent;

			// 旋转核心逻辑
			subL->_right = parent;
			parent->_left = subLR;
			if (pParent == nullptr)	// parent == _root
				_root = subL;
			else if (pParent->_left = parent)
				pParent->_left = subL;
			else
				pParent->_right = subL;

			// 处理_parent
			if (subLR)
				subLR->_parent = parent;
			parent->_parent = subL;
			subL->_parent = pParent;
		}

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

		node* _root = nullptr;
	};
}
  1. m a p . h map.h map.h
#pragma once
#include"rb_tree.h"

using namespace std;

namespace ybc
{
	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>::const_iterator const_iterator;

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

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

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

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

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

		iterator find(const K& key)
		{
			return _t.find(key);
		}

		V& operator [] (const K& key)
		{
			pair<iterator, bool> ret = insert(make_pair(key, V()));
			return ret.first->second;
		}
	private:
		RBTree<K, pair<const K, V>, mapKeyOfT> _t;
	};
}
  1. t e s t . c p p test.cpp test.cpp
#include"set.h"

namespace ybc
{
	void test1()
	{
		set<int> s;
		s.insert(5);
		s.insert(1);
		s.insert(3);
		s.insert(4);
		s.insert(2);

		auto it = s.begin();
		while (it != s.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

	template<class T>
	void print(set<T>& s)
	{
		auto it = s.begin();
		while (it != s.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

	void test2()
	{
		set<int> s;
		int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
		for (auto e : a)
		{
			s.insert(e);
		}
		for (auto e : s)
		{
			cout << e << " ";
		}
		cout << endl;
		print(s);
	}
}

int main()
{
	//ybc::test1();

	ybc::test2();

	return 0;
}

总结

m a p map map 是一个关联式容器,其特性是,所有元素都会根据元素的键值自动排序,并且其所有元素都是 p a i r pair pair,同时拥有键值( k e y key key)和实值( v a l u e value value)。

m a p map map 的底层数据结构采用的是红黑树,并根据键值是否冗余分为了 m a p map map m u l t i m a p multimap multimap,但 m a p map map 重载了 [   ] [\ ] [ ],使其非常方便好用,其不仅可以通过迭代器进行访问和修改元素(只能修改 v a l u e value value,不能修改 k e y key key),还能直接使用 [   ] [\ ] [ ] 进行访问和修改。

红黑树的本质是一棵自平衡二叉搜索树,增删查的时间复杂度都是 O ( log ⁡ N ) O(\log N) O(logN),因此 m a p map map 的效率很高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值