【C++关联式容器】map

目录

map

1. pair类型

2. 关联式容器额外的类型别名

3. Member functions

3.1 constructor、destructor、operator=

3.1.1 constructor

3.1.2 destructor

3.1.3 operator= 

3.2 Iterators

3.3 Capacity

​3.3.1 empty

3.3.2 size

3.3.3 max_size

3.4 Element access

3.4.1 operator[]

3.4.2 at

3.5 Modifiers

3.5.1 insert

3.5.2 erase

3.5.3 swap

3.5.4 clear

3.5.5 emplace

3.5.6 emplace_hint

3.6 Observers

3.6.1 key_comp

3.6.2 value_comp

3.7 Operations

3.7.1 find

3.7.2 count

3.7.3 lower_bound

3.7.4 upper_bound

3.7.5 equal_range

3.8 Allocator

​3.8.1 get_allocator

4. map对象的插入方法

5. map对象的遍历方法

5.1 迭代器

5.2 范围for


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;

map是关联式容器,它按照特定的顺序存储由关键字值和映射值的组合形成的元素。

在map中,关键字值通常用于排序和唯一识别元素,而映射值则存储与此键相关的内容。关键字值和映射值的类型可能不同,在成员类型value_type中被组合在一起,它是一个结合了两者的pair类型:

typedef pair<const Key, T> value_type;

在内部,map中的元素总是按照它的关键字进行排序,遵循一个特定的严格的弱排序标准,由其内部的比较对象(类型为Compare)指示。

map容器通常比unordered_map容器按关键字访问单个元素的速度要慢,但是它们允许根据顺序直接迭代子集。

map中的映射值可以使用括号操作符(operator[])直接通过其相应的关键字来访问。

map通常以二叉搜索树(准确地说,是红黑树)的形式实现。

map定义在头文件map和命名空间std中。

1. pair类型

pair定义在头文件utility和命名空间std中。

一个pair保存两个数据成员。类似容器,pair是一个用来生成特定类型的模板。当创建一个pair时,我们必须提供两个类型名,pair的数据成员将具有对应的类型。两个类型不要求一样:

pair<string, string> anon;       // 保存两个string
pair<string, size_t> word_count; // 保存一个string和一个size_t
pair<string, vector<int>> line;  // 保存string和vector<int>

pair的默认构造函数对数据成员进行值初始化。因此,anon是一个包含两个空string的pair,line保存一个空string和一个空vector。word_count中的size_t成员值为0,而string成员被初始化为空。

我们也可以为每个成员提供初始化器:

pair<string, string> author{ "James","Joyce" };

这条语句创建一个名为author的pair,两个成员被初始化为"James"和"Joyce"。

与其他标准库类型不同,pair的数据成员是public的。两个成员分别命名为first和second。我们用普通的成员访问符号来访问它们。

pair上的操作
pair<T1, T2> p;p是一个pair,两个类型分别为T1和T2的成员都进行了值初始化
pair<T1, T2> p(v1, v2);

p是一个成员类型为T1和T2的pair

first和second成员分别用v1和v2进行初始化

pair<T1, T2> p = { v1,v2 };等价于pair<T1, T2> p(v1, v2);
make_pair(v1, v2)

返回一个用v1和v2初始化的pair

pair的类型从v1和v2的类型推断出来

p.first返回p的名为first的(公有)数据成员
p.second返回p的名为second的(公有)数据成员
p1 relop p2

关系运算符(<、>、<=、>=)按字典序定义

p1 == p2

p1 != p2

当first和second成员分别相等时,两个pair相等

相等性判断利用元素的==运算符实现

创建pair对象的函数:

想象有一个函数需要返回一个pair。在新标准下,我们可以对返回值进行列表初始化:

pair<string, int> process(vector<string>& v)
{
	// 处理v
	if (!v.empty())
		return { v.back(), v.back().size() }; // 列表初始化
	else
		return pair<string, int>(); // 隐式构造返回值
}

若v不为空,我们返回一个由v中最后一个string及其大小组成的pair。否则,隐式构造一个空pair,并返回它。

在较早的C++版本中,不允许用花括号包围的初始化器来返回pair这种类型的对象,必须显式构造返回值:

if (!v.empty())
	return pair<string, int>(v.back(), v.back().size());

我们还可以用make_pair来生成pair对象,pair的两个类型来自于make_pair的参数:

if (!v.empty())
	return make_pair(v.back(), v.back().size());

2. 关联式容器额外的类型别名

key_type此容器类型的关键字类型
mapped_type每个关键字关联的类型;只适用于map
value_type对于set,与key_type相同
对于map,为pair<const key_type, mapped_type>

对于set类型,key_type和value_type是一样的:set中保存的值就是关键字。在一个map中,元素是键值对。即,每个元素是一个pair对象,包含一个关键字和一个关联的值。由于我们不能改变一个元素的关键字,因此这些pair的关键字部分是const的:

set<string>::value_type vl;       // v1是一个string
set<string>::key_type v2;         // v2是一个string
map<string, int>::value_type v3;  // v3是一个pair<const string, int>
map<string, int>::key_type v4;    // v4是一个string
map<string, int>::mapped_type v5; // v5是一个int

与序列式容器一样,我们使用作用域运算符来提取一个类型的成员——例如,map<string, int>::key_type。

只有map类型(unordered_map、unordered_multimap、multimap和map)才定义了mapped_type。

3. Member functions

3.1 constructor、destructor、operator=

3.1.1 constructor

// empty (1)
explicit map(const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type());
explicit map(const allocator_type& alloc);
// range (2)
template <class InputIterator> map(InputIterator first, InputIterator last, const key_compare& comp = key_compare(), const allocator_type& = allocator_type());
// copy (3)
map(const map& x);
map(const map& x, const allocator_type& alloc);
// move (4)
map(map&& x);
map(map&& x, const allocator_type& alloc);
// initializer list (5)
map(initializer_list<value_type> il, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type());

创建降序排序的空map:

#include <map>
#include <iostream>
using namespace std;

struct cmp
{
	bool operator()(const int e1, const int e2) const
	{
		return e1 > e2;
	}
};

int main()
{
	map<char, int, cmp> mp;

	// 插入
	mp.insert({ 'g',30 });
	mp.insert(make_pair('a', 10));
	mp.insert(pair<char, int>('f', 50));
	mp.insert(map<char, int>::value_type('h', 70));
	mp['b'];
	mp['d'] = 20;

	for (auto& [x, y] : mp) // C++17 结构化绑定
	{
		cout << x << " " << y << endl;
	}
	// h 70
	// g 30
	// f 50
	// d 20
	// b 0
	// a 10

	return 0;
}

3.1.2 destructor

~map();

3.1.3 operator= 

// copy (1)
map& operator=(const map& x);
// move (2)
map& operator=(map&& x);
// initializer list (3)
map& operator=(initializer_list<value_type> il);

3.2 Iterators

// begin
iterator begin() noexcept;
const_iterator begin() const noexcept;
// end
iterator end() noexcept;
const_iterator end() const noexcept;
// rbegin
reverse_iterator rbegin() noexcept;
const_reverse_iterator rbegin() const noexcept;
// rend
reverse_iterator rend() noexcept;
const_reverse_iterator rend() const noexcept;
// cbegin
const_iterator cbegin() const noexcept;
// cend
const_iterator cend() const noexcept;
// crbegin
const_reverse_iterator crbegin() const noexcept;
// crend
const_reverse_iterator crend() const noexcept;
函数功能

begin

&

end

begin返回一个迭代器,指向map中第一个元素

end返回一个迭代器,指向map中最后一个元素的下一个位置

rbegin

&

rend

rbegin返回一个反向迭代器,指向map中最后一个元素

rend返回一个反向迭代器,指向map中第一个元素的上一个位置

cbegin

&

cend

cbegin返回一个const迭代器,指向map中第一个元素

cend返回一个const迭代器,指向map中最后一个元素的下一个位置

crbegin

&

crend

crbegin返回一个const反向迭代器,指向map中最后一个元素

crend返回一个const反向迭代器,指向map中第一个元素的上一个位置

begin&end和rbegin&rend返回的迭代器指向:

const_iterator是一个指向const内容的迭代器。迭代器本身可以修改,但是它不能被用来修改它所指向的内容。

begin&end/rbegin&rend和cbegin&cend/crbegin&crend的不同:

  • begin&end/rbegin&rend的返回类型由对象是否是常量来决定。如果不是常量,返回iterator;如果是常量,返回const_iterator。
  • cbegin&cend/crbegin&crend的返回类型是const_iterator,不管对象本身是否是常量。

当解引用一个关联式容器迭代器时,我们会得到一个类型为容器的value_type的值的引用。对map而言,value_type是一个pair类型,其first成员保存const的关键字,second成员保存值。

必须记住,一个map的value_type是一个pair,我们可以改变pair的值,但不能改变关键字成员的值。

#include <iostream>
#include <map>
using namespace std;

int main()
{
	map<string, string> mp{ {"iterator", "迭代器"},{"begin","开始"},{"end", "结束"} };

	map<string, string>::iterator it = mp.begin();
	while (it != mp.end())
	{
		cout << it->first << " " << it->second << endl;
		// 等价于cout << (*it).first << " " << (*it).second << endl;
		++it;
	}
	// begin 开始
	// end 结束
	// iterator 迭代器

	auto rit = mp.rbegin();
	// map<string, string>::reverse_iterator rit = mp.rbegin();
	while (rit != mp.rend())
	{
		cout << rit->first << " " << rit->second << endl;
		// 等价于cout << (*rit).first << " " << (*rit).second << endl;
		++rit;
	}
	// iterator 迭代器
	// end 结束
	// begin 开始

	return 0;
}

3.3 Capacity

​3.3.1 empty

bool empty() const noexcept;
// 检测map是否为空,是返回true,否则返回false

3.3.2 size

size_type size() const noexcept;
// 返回map中元素的个数

3.3.3 max_size

size_type max_size() const noexcept;
// 返回map能够容纳的最大元素个数

3.4 Element access

3.4.1 operator[]

mapped_type& operator[](const key_type& k);
mapped_type& operator[](key_type&& k);
// 如果k与某个元素的关键字相匹配,返回对其映射值的引用
// 如果k与任何元素的关键字不匹配,插入一个关键字为k的新元素,并返回对其映射值的引用

3.4.2 at

mapped_type& at(const key_type& k);
const mapped_type& at(const key_type& k) const;
// 如果k与某个元素的关键字相匹配,返回对其映射值的引用
// 如果k与任何元素的关键字不匹配,抛异常

Element access系列函数使用示例:​

#include <map>
#include <iostream>
using namespace std;

int main()
{
	map<char, int> mp;

	mp['b'];      // 插入一个关键字为'b'的元素,但没有对映射值进行初始化
	mp['d'] = 20; // 插入一个关键字为'd'的元素,并将映射值初始化为20	
	cout << "mp['b'] = " << mp['b'] << endl; // mp['b'] = 0
	cout << "mp['d'] = " << mp['d'] << endl; // mp['d'] = 20

	mp['b'] = 50; // 修改关键字为'b'的元素的映射值为50
	cout << "mp['b'] = " << mp.at('b') << endl; // mp['b'] = 50
	cout << "mp['d'] = " << mp.at('d') << endl; // mp['d'] = 20

	return 0;
}

3.5 Modifiers

3.5.1 insert

// single element (1) 成功返回pair<插入位置, true>,失败返回pair<插入位置, false>
pair<iterator, bool> insert(const value_type& val);
template <class P> pair<iterator, bool> insert(P&& val);
// with hint (2)
iterator insert(const_iterator position, const value_type& val);
template <class P> iterator insert(const_iterator position, P&& val);
// range (3)
template <class InputIterator> void insert(InputIterator first, InputIterator last);
// initializer list (4)
void insert(initializer_list<value_type> il);

// 插入

3.5.2 erase

// (1)
iterator erase(const_iterator position);
// (2)
size_type erase(const key_type& k);
// (3)
iterator erase(const_iterator first, const_iterator last);

// 删除

3.5.3 swap

void swap(map& x);
// 交换

3.5.4 clear

void clear() noexcept;
// 清空

3.5.5 emplace

template <class... Args> pair<iterator, bool> emplace(Args&&... args);
// 对应insert,区别是:
// 当调用insert时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中
// 当调用emplace时,则是将参数传递给元素类型的构造函数,然后使用这些参数在容器管理的内存空间中直接构造元素

3.5.6 emplace_hint

template <class... Args> iterator emplace_hint(const_iterator position, Args&&... args);
// 对应insert的with hint(2),区别是:
// 当调用insert时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中
// 当调用emplace时,则是将参数传递给元素类型的构造函数,然后使用这些参数在容器管理的内存空间中直接构造元素

3.6 Observers

3.6.1 key_comp

key_compare key_comp() const;
// 返回关键字比较对象(决定容器中元素的顺序)

3.6.2 value_comp

value_compare value_comp() const;
// 返回值比较对象(决定容器中元素的顺序)

3.7 Operations

3.7.1 find

iterator find(const key_type& k);
const_iterator find(const key_type& k) const;
// 返回一个迭代器,指向第一个关键字为k的元素,若k不在容器中,则返回end迭代器

3.7.2 count

size_type count(const key_type& k) const;
// 返回关键字等于k的元素的数量
// 对于不允许重复关键字的容器,返回值永远是0或1
#include <map>
#include <iostream>
using namespace std;

int main()
{
	map<char, int> mp;
	mp.insert({ 'g',30 });
	mp.insert(make_pair('a', 10));
	mp.insert(pair<char, int>('f', 50));
	mp['b'];
	mp['d'] = 20;

	auto it = mp.find('f');
	if (it != mp.end())
	{
		cout << "f在map中" << endl;
	}
	else
	{
		cout << "f不在map中" << endl;
	}
	// f在map中

	it = mp.find('h');
	if (it != mp.end())
	{
		cout << "h在map中" << endl;
	}
	else
	{
		cout << "h不在map中" << endl;
	}
	// h不在map中

	if (mp.count('a'))
	{
		cout << "a在map中" << endl;
	}
	else
	{
		cout << "a不在map中" << endl;
	}
	// a在map中

	if (mp.count('c'))
	{
		cout << "c在map中" << endl;
	}
	else
	{
		cout << "c不在map中" << endl;
	}
	// c不在map中

	return 0;
}

3.7.3 lower_bound

iterator lower_bound(const key_type& k);
const_iterator lower_bound(const key_type& k) const;
// 返回一个迭代器,指向第一个关键字不小于k的元素

3.7.4 upper_bound

iterator upper_bound(const key_type& k);
const_iterator upper_bound(const key_type& k) const;
// 返回一个迭代器,指向第一个关键字大于k的元素

3.7.5 equal_range

pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
pair<iterator, iterator> equal_range(const key_type& k);
// 返回一个迭代器pair,表示关键字等于k的元素的范围(左闭右开的区间)
// 若k不存在,pair的两个成员均为end迭代器
// 对于不允许重复关键字的容器,返回的范围最多只包含一个元素

3.8 Allocator

​3.8.1 get_allocator

allocator_type get_allocator() const noexcept;
// 返回空间配置器

4. map对象的插入方法

#include <map>
#include <iostream>
using namespace std;

int main()
{
	map<char, int> mp;

	// 插入
	mp.insert({ 'g',30 });
	mp.insert(make_pair('a', 10));
	mp.insert(pair<char, int>('f', 50));
	mp.insert(map<char, int>::value_type('h', 70));
	mp['b'];
	mp['d'] = 20;

	for (auto& e : mp)
	{
		cout << e.first << " " << e.second << endl;
	}
	// a 10
	// b 0
	// d 20
	// f 50
	// g 30
	// h 70

	return 0;
}

5. map对象的遍历方法

5.1 迭代器

#include <map>
#include <iostream>
using namespace std;

int main()
{
	map<char, int> mp;

	// 插入
	mp.insert({ 'g',30 });
	mp.insert(make_pair('a', 10));
	mp.insert(pair<char, int>('f', 50));
	mp.insert(map<char, int>::value_type('h', 70));
	mp['b'];
	mp['d'] = 20;

	map<char, int>::iterator it = mp.begin();
	while (it != mp.end())
	{
		cout << it->first << " " << it->second << endl;
		++it;
	}
	// a 10
	// b 0
	// d 20
	// f 50
	// g 30
	// h 70

	return 0;
}

5.2 范围for

#include <map>
#include <iostream>
using namespace std;

int main()
{
	map<char, int> mp;

	// 插入
	mp.insert({ 'g',30 });
	mp.insert(make_pair('a', 10));
	mp.insert(pair<char, int>('f', 50));
	mp.insert(map<char, int>::value_type('h', 70));
	mp['b'];
	mp['d'] = 20;

	for (auto& e : mp)
	{
		cout << e.first << " " << e.second << endl;
	}
	// a 10
	// b 0
	// d 20
	// f 50
	// g 30
	// h 70

	return 0;
}
#include <map>
#include <iostream>
using namespace std;

int main()
{
	map<char, int> mp;

	// 插入
	mp.insert({ 'g',30 });
	mp.insert(make_pair('a', 10));
	mp.insert(pair<char, int>('f', 50));
	mp.insert(map<char, int>::value_type('h', 70));
	mp['b'];
	mp['d'] = 20;

	for (auto& [x, y] : mp) // C++17 结构化绑定
	{
		cout << x << " " << y << endl;
	}
	// a 10
	// b 0
	// d 20
	// f 50
	// g 30
	// h 70

	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值