【C++】STL中map的详细使用说明

说明

std::map是一个有序关联容器包含具有唯一键的键值对key-value键使用比较函数Compare比较来进行排序
搜索,删除和插入操作具有对数复杂性。map通常实现为红黑树。
定义于头文件 <map>
特别注意,map中同一个键值只能存在一个实体
map的特点是增加和删除节点对迭代器的影响很小,除了那个被操作的节点,对其他的节点都没有什么影响(只是内部的一些指针指向的改变)。对于map的迭代器来说,可以修改实value,而不能修改key

内部构造(基本操作函数和成员)

1、成员类型

成员类型Definition
key_typeKey
mapped_typeT
value_typestd::pair<const Key, T>
size_type无符号整数类型(通常是 std::size_t
difference_type有符号整数类型(通常是 std::ptrdiff_t
key_compareCompare
allocator_typeAllocator
referenceAllocator::reference(C++11 前)value_type& (C++11 起)
const_referenceAllocator::const_reference (C++11 前) const value_type& (C++11 起)
pointerAllocator::pointer (C++11 前)std::allocator_traits<Allocator>::pointer (C++11 起)
const_pointer Allocator::const_pointer (C++11 前)std::allocator_traits<Allocator>::const_pointer (C++11 起)
iterator双向迭代器(BidirectionalIterator)
const_iterator常双向迭代器
reverse_iteratorstd::reverse_iterator<iterator>
const_reverse_iteratorstd::reverse_iterator<const_iterator>

2、成员函数


元素的访问

名称说明
at (C++11)访问指定的元素,同时进行越界检查 (公开成员函数)
operator[]访问指定的元素 (公开成员函数)

迭代器

名称说明
begin cbegin返回指向容器第一个元素的迭代器 (公开成员函数)
end cend返回指向容器尾端的迭代器 (公开成员函数)
rbegin crbegin返回一个指向容器最后一个元素的反向迭代器 (公开成员函数)
rend crend返回一个指向容器前端的反向迭代器 (公开成员函数)

容量

名称说明
empty检查容器是否为空 (公开成员函数)
size返回容纳的元素数 (公开成员函数)
max_size返回可容纳的最大元素数 (公开成员函数)

修饰符

名称说明
clear删除全部内容 (公开成员函数)
insert插入元素 (公开成员函数)
emplace (C++11)就地构造元素 (公开成员函数)
emplace_hint (C++11)使用hint就地构造元素 (公开成员函数)
erase删除元素 (公开成员函数)
swap交换内容 (公开成员函数) 查找
count返回匹配特定键的元素数量 (公开成员函数)
find寻找带有特定键的元素 (公开成员函数)
equal_range返回匹配特定键的元素范围 (公开成员函数)
lower_bound返回一个迭代器,指向第一个“不小于”给定值的元素 (公开成员函数)
upper_bound返回一个迭代器,指向第一个“大于”给定值的元素 (公开成员函数) 观察器
key_comp返回用于比较键key的函数 (公开成员函数)
value_comp返回用于在value_type类型的对象中比较键的函数。 (公开成员函数)

3、非成员函数

名称说明
std::swap(std::map)特化 std::swap 算法 (函数模板)
operator==operator!=operator<operator<=operator>operator>=根据字典顺序比较 map 中的值 (函数模板)

常用函数用法

构造函数

一般通过以下形式定义map:

map<T1,T2>name

T1为键值key的类型,T2为value键值类型

一个实例如下:

map<string , int >mapstring; 

添加函数(insert)

我们首先要了解,一个map<T1,T2>中存储的元素并不是一个个的keyvalue,而是一个个pair<T1,T2>,所以我们进行添加元素的时候就是要添加一个个的pair进去。
pair(定义于头文件 <utility>),同时这个头文件包含在<map>

pair定义如下:

template<
    class T1,
    class T2
> struct pair;

其成员对象

成员类型
firstT1
secondT2

我们有多种方式可以对一个pair进行初始化:

pair<string, int>person1("name", 16);
pair<string, int>person2 = { "name",15 };
pair<string, int>person3 = make_pair("name", 17);

map和其他诸如vectorlist的插入是不同的,它的插入不仅涉及到其内部的红黑树的遍历,还涉及到很多的比较以及红黑树枝干的调整,所以虽然插入之后的元素都已经根据键值大小被排好了序,但是每一次插入的开销也是很大的。
所以,我们用map和其同类的关联容器setmultmap去取代排序算法用来排序元素的想法是很错误的。
insert函数的系统定义如下(可看可不看):

std::pair<iterator,bool> insert( const value_type& value );

template <class P>
std::pair<iterator,bool> insert( P&& value );//(C++11 起)

iterator insert( iterator hint, const value_type& value );//(C++11 前) 
iterator insert( const_iterator hint, const value_type& value );//(C++11 起)

template <class P>
iterator insert( const_iterator hint, P&& value );//(C++11 起)

template< class InputIt >
void insert( InputIt first, InputIt last );

void insert( std::initializer_list<value_type> ilist );
/*
参数
hint    -   迭代器,用于插入内容,作为一个建议

value   -   元素的值插入

first, last -   范围插入的元素

ilist   -   初始化列表中插入的值
*/

我们就只说说最基本的一种。插入一个pair。其他的就不多讲了,自己用一下就知道。
通过介绍pair的多种初始化形式,map也同样有很多种的方式(可能有更多的方式)进行pair元素的添加:

map<string, int> persons;//定义

persons.insert(pair<string, int>("xiaohong", 3));//传入pair元素添加
persons["xiaoming"] = 6;//通过[]操作符添加(有相同键值的话就会改变这个键值的value)
persons.insert(map<string, int>::value_type("xiaogang", 7));//通过内置的typedef value_type 传入
persons.insert({ "xiaogang", 7 });//通过pair的多种定义方式自动转换成pair插入
persons.insert(make_pair("xiaobai", 17));//make_pair方式返回pair实体,再进行插入

查找函数(find)

被插入的元素都是根据其键值进行了排序,所以我们的查找顺序也大致如此。但是由于map的实现是通过红黑树实现的,所以其也是一个二叉查找树,对一个二叉查找树中的元素进行查找,效率是非常高的,查找的复杂度平均是Log(N),比如如果有1000个元素,最多查找10次,1,000,000个记录,最多查找20次。
下面是其查找函数的定义:

iterator find( const Key& key );
//key为要搜索的元素的键值
const_iterator find( const Key& key ) const;
//如果没有为key的元素,则返回end()的迭代器

以下为一个查找示例:

auto it = persons.find("xiaohong");
if (it!=persons.end())
{
    cout << "find it the key is: " << it->first << " value is : " << it->second << endl;
}

删除函数(erase)

删除函数,其实不用过多的介绍其内部构造了,我们需要知道的就是,在关联容器中,插入和删除一个元素的开销都是很高的,至于为什么就不多提,主要讲这个函数的原理和使用方法.

以下为map::erase()函数的定义:

void erase( iterator position );//(C++11 前)     //(1)

iterator erase( const_iterator position );//(C++11 起)

void erase( iterator first, iterator last );//(C++11 前) (2)

iterator erase( const_iterator first, const_iterator last );//(C++11 起)

size_type erase( const key_type& key );//   (3)

/*
1) 删除的元素pos.

2) 在范围[first; last)内移出元素pos.

3) 在所有元素中移出键值为key的元素

*/
-------------------------
/*

参数

pos -   要移除的元素的迭代器

first, last -   要移除的元素范围

key -   要移除的元素的键值

*/

在每次删除和添加元素的时候,map内部的红黑树都会进行一定的重新构建。不过不管是erase()还是insert()的时候,受影响的只是这一个节点,其他节点的内存位置并不会发生改变,因为其实现是节点型的红黑树。
以下为简单erase()的示例:

for (auto it = persons.begin(); it != persons.end();)
{
    if (it->first == "xiaohong")it = persons.erase(it);
    else 
    {

        cout << it->first << " " << it->second << endl;
        it++;
    }
}

注意,erase(it)之后,it指向的节点就已经被删除了,所以这个迭代器就不能进行使用了,erase()函数会返回一个指向it后一个节点的迭代器,我们让it = persons.erase(it)就可以保证没有错误了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值