[C++] 关联容器

文章详细介绍了C++标准库中的有序关联容器,包括map、multimap、set和multiset,强调了它们的元素排序规则、关键字类型要求以及pair的使用。此外,还提到了关联容器的操作,如插入、删除、查找和下标操作。最后,预告了无序关联容器的内容。
摘要由CSDN通过智能技术生成

目录

1. 有序关联容器

1.1 有序关联容器要点

1.2 分类:

1.3 关键字类型要求

1.4 pair类型

1.5 关联容器操作

1.5.1 类型别名

1.5.2 迭代器

1.5.3 添加

1.5.4 删除

1.5.5 下标操作(非const的map、multimap)

1.5.6 访问

2. 无序关联容器

2.1 有序关联容器要点

2.2 分类:

2.3 关键字类型要求:

3. 有序容器和无序容器的比较


1. 有序关联容器

1.1 有序关联容器要点

        1.容器里的元素对都是有序的,并且是按关键字来排序的。

        2.容器里元素的排序,是按"<"运算符来算的,所以容器的关键字的类型必须支持"<"运算符

1.2 分类:

容器头文件含义底层实现
map  <key_type,mapped_type> #include<map>关联数组,保存关键字-值对,关键字唯一红黑树
multimap  <key_type,mapped_type> #include<map>关键字可重复的map,关键字对应多个值红黑树
set  <key_type> #include<set>关键字即值,即只保存关键字的容器,关键字唯一红黑树
multiset  <key_type> #include<set>关键字可重复的set红黑树
pair  <key_type,mapped_type> #include<utility>是一个用来生成特定类型的模板,map中每一个元素对,都是pair类型。

1.3 关键字类型要求

        1.有序容器的关键字必须遵循严格弱序C++ 严格弱序)的要求,即必须有'<'运算符的定义

        2.有序容器set可以指定操作类型,使用关键字类型的比较函数,其函数传入的是一个函数指针,形式:set<key_type, 函数指针>  /  set<key_type,decltype(函数) * >,并且函数指针指向的自定义比较函数,也必须遵循严格弱序的要求。

1.4 pair类型

头文件:#include<utility>

形式:pair  <key_type,mapped_type>

含义:是一个用来生成特定类型的模板,并且pair的数据成员都是公有的,map中每一个元素对,都是pair类型。 

操作含义
pair<T1,T2> p;创建一个名为p的pair类型,并对T1,T2类型进行值初始化

pair<T1,T2> p(v1,v2);

pair<T1,T2> p={v1,v2};

创建一个名为p的pair类型,并对T1,T2类型分别用v1,v2进行初始化
make_pair(v1,v2);返回一个v1,v2初始化的pair。pair的对应类型由v1,v2推断而出。
p.first;返回p的名为first的公有数据成员
p.second;返回p的名为second的公有数据成员
p1 relop p2relop是关系运算,关系运算用运算符'<'来实现

p1==p2

p1!=p2

当first和seconde都相等时,才相等,否则不等

1.5 关联容器操作

1.5.1 类型别名

关联容器额外的类型别名含义操作(map为例)
key_type此容器的关键字类型map<string,int>::key_type
mapped_typemap容器的值类型,只有map才有map<string,int>::mapped_type
value_type

map:pair<const key_type,mapped_type>

set:与key_type相同

map<string,int>::value_type

1.5.2 迭代器

操作注意
解引用符:*mapiterator,*setiterator

1.对map迭代器使用解引用符,会得到一个value_type类型的值,即pair<const key_type,mapped_type>,注意这里的关键字是const类型

2.对set迭代器使用解引用符,会得到一个const key_type类型,这个关键字也是const类型。

遍历关联容器关联容器支持begin()和end()操作,可以用来遍历容器,但是迭代器在遍历容器时是按关键字的升序来遍历的。
关联容器和算法一般来说关联容器很少使用算法,因为关联容器的迭代器取到的是const类型,所以像修改、排序等算法就不能使用,但是关联容器可以用作目的位置和源序列,比如:copy(map.begin(),map.end(),back_inserter(vector));

1.5.3 添加

对于map和set来说,只有当要插入的关键字不存在容器里时,才进行插入。

添加元素含义

c.insert(v);

c.emplace(args);

v是value_type类型,args是构造生成的单个元素。

函数返回一个pair,pair的first是一个迭代器指向插入的元素的位置second是一个bool类型。second为true意味着插入成功,false意味着容器里已经存在要插入的这个关键字了,并且first迭代器指向这个已存在的关键字的位置

对于multimap和multiset来说,元素的插入总是成功的,函数返回一个指向新元素的迭代器

c.insert(b,e);

c.insert(il);

b和e是一对迭代器,表示一个c::value_type(pair<......>)类型值的范围,il是c::value_type的花括号列表。

函数返回void。

c.insert(p,v);

c.emplace(p,args);

类似insert(v),p是一个迭代器,指出应该从p所指向的元素位置开始搜索新元素应该存储的位置。

返回一个迭代器,指向具有给定关键字的元素。

1.5.4 删除

删除元素含义
c.erase(k);

k是一个关键字类型的元素,从c中删除每个关键字为k的元素。

返回一个size_type值,指出删除元素的数量

c.erase(p);

p是一个迭代器,p必须指向c中容器的某个元素,且不能为c.end(),从c中删除迭代器p指向的元素。

返回一个指向p之后的元素的迭代器。

c.erase(b,e);b,e是一对迭代器,删除b和e所指范围内的元素,返回e

1.5.5 下标操作(非const的map、multimap)

set不支持此操作:因为set只有关键字没有关联的值。

map的下标操作——map[key_type]=value流程:

        Step1:在map里查找关键字为key_type的值

        Step2:如果找到,则将其值赋为value

        Step3:如果没找到,则将关键字key_type插入到map容器里

        Step4:新插入的关键字的值进行值初始化

        Step5:将value赋值给关键字key_type

因为map的下标操作会对新关键字进行插入,所以const类型的map不能使用下标操作。

map[]与*(map<...>::iterator)——map下标操作与map迭代器解引用操作的区别:

map下标操作返回的是mapped_type对象。

 map迭代器解引用操作返回的是value_type对象。

1.5.6 访问

查找元素含义

lower_bound、upper_bound不使用于无序容器

下标和at操作只适用用于非const的map和unordered_map
c.find(k);返回一个迭代器,指向第一个关键字为k的元素,如果k不在迭代器中,则返回end();
c.count(k);

返回关键字为k的元素的数量。不重复容器要么0要么1

c.lower_bound(k);(左闭合[)返回一个迭代器,指向第一个关键字不小于k的元素,如果没有找到,则返回一个指向给定关键字的插入点,能保持容器中元素顺序的插入位置(意思是在这个位置插入关键字k,整个容器的顺序依然是按照关键字升序的)
c.upper_bound(k);(左开合()返回一个迭代器,指向第一个关键字大于k的元素,如果没有找到,则返回一个指向给定关键字的插入点,能保持容器中元素顺序的插入位置
c.equal_range(k);返回一个pair,pair表示一个关键字等于k范围,first——beg,second——end,若k不存在,则pair的两个成员都为end(),可以用以遍历multimap和multiset,这种存有多种相同key值的关联容器。
c.at(k);返回关键字为k的元素相关联的值,如果没有这个关键字,则抛出异常out_of_range,注意:set是没有此操作的。

在multimap或multiset中,相同关键字会相邻存储

lower_boud、upper_bound的使用:

multimap<int,string> mulmap;

for(auto beg=mulmap.lower_bound(k),end=mulmap.upper_bound(k);    
         beg!=end;
         ++beg)
{
        ......
}
//如果,k在mulmap中已存在
//那么,beg=mulmap.lower_bound(k),得到的是第一个k存储的位置的迭代器
//      end=mulmap.upper_bound(k),得到的是第一个大于k存储的位置的迭代器
//则,beg和end的范围就是一个[beg,end)的范围,这范围里都是关键字为k的元素

equal_range的使用:

multimap<int,string> mulmap;
pair<multimap<int,string>::iterator,multimap<int,string>::iterator> pairit=mulmap.equal_range(k);

auto pairit=mulmap.equal_range(k);

auto beg=pairit.first;
auto end=pairit.second;
for(;beg!=end;++beg)
{...}

2. 无序关联容器

2.1 有序关联容器要点

        1.容器里的元素对都是无序、不可重复的

2.2 分类:

容器头文件含义底层实现
unordered_map  <key_type,mapped_type> #include<unordered_map>无序关联数组,保存关键字-值对,不会对Key进行排序关键字唯一哈希表
unordered_set  <value_type> #include<unordered_set>无序关联集合不会对关键字进行排序。哈希表

2.3 关键字类型要求:

        1.无序关联容器都是基于哈希表实现的无序容器,因此它们的键必须支持哈希操作

        2.默认情况下,无序关联容器使用 std::hash 来生成键的哈希值。如果键类型没有定义 std::hash,你必须提供自定义的哈希函数

        3.需要提供一个相等性比较函数,默认使用 == 运算符。

3. 有序容器和无序容器的比较

容器底层实现key是否排序key是否可重复key是否可更改查询效率增删效率
std::set红黑树不是不可O(log n)O(log n)
sed::map红黑树不是不可O(log n)O(log n)
std::multimap红黑树不可O(log n)O(log n)
std::multiset红黑树不可O(log n)O(log n)
std::unordermap哈希表不是不是不可O(1)O(1)
std::unorderset哈希表不是不是不可O(1)O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值