【C++】map|set|原理使用|multiset|multimap|operator[]|

目录

 

一,关联式容器

二,键值对

2.1为什么使用键值对

2.2make_pair()

三,STl关联容器

四,set 

4.1模板参数 

 4.2默认构造

 4.3使用

去重功能和自动排序

4.4增删查

insert

find

erase

五,multiset 

count

erase

find 

六,map 

6.1默认构造 

特性 

6.2使用 

insert

operator[]

示例

方法1

方法2 

 七,multimap


一,关联式容器

  • 在STL中vector,list,stack,queue等都属于序列式容器,底层是线性结构,里面存储的是元素本身;
  • 关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是 <key, value> 结构的键值对,在数据检索时比序列式容器效率更高,set map 便是关联式容器 

二,键值对

  键值对是用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量keyvalue

set map 就使用了键值对,这个键值对名为 pair,它是一个 struct 定义的类模板,即可以在外部访问 pair里面的成员变量 

template <class T1, class T2>
struct pair
{
    typedef T1 first_type;
    typedef T2 second_type;
    T1 first;
    T2 second;
    pair() : first(T1()), second(T2())
    {}
    pair(const T1& a, const T2& b) : first(a), second(b)
    {}
};

所以pair就是一个类模板,根据<>里的两个参数来实例化类,第一个参数表示key,第二个表示value

  • pair的两个成员变量first表示key,second表示value 

2.1为什么使用键值对

为什么不直接在容器中定义 key value 变量,而是将 key value 合并到 pair 中整体作为一个类型来使用呢?

        这是因为 C++ 一次只能返回一个值,如果我们将 key value 单独定义在容器中,那么我们就无法同时返回 key value ;而如果我们将 key value 定义到另一个类中,那我们就可以直接返回 pair ,然后再到 pair 中分别去取 first second 即可。

2.2make_pair()

该函数是用来制作一个pair类型的匿名对象的:

make_pair - C++ Reference (cplusplus.com)

	map<string, string> dict;
	pair<string, string> kv1("sort", "排序");
	//三种插入
	
	dict.insert(kv1);		//有名
	dict.insert(pair<string,string>("left", "左边"));	//匿名
	dict.insert(make_pair("right", "右边"));	//更快速的匿名

make_pair()是为了让我们更加方便的使用键值对。

三,STl关联容器

  • STL关联容器有两种结构:树形结构,哈希结构;
  • 常见的树形结构关联容器有:mapsetmultimapmultiset;
  • 这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列

四,set 

set是按照一定次序存储元素的容器,其底层是一棵平衡二叉搜索树 (红黑树);

  由于二叉搜索树的每个节点的值满足左孩子 < 根 < 右孩子,并且二叉搜索树中没有重复的节点,所以set可以用来排序、去重和查找,同时由于这是一棵平衡树,所以 set查找的时间复杂度为 O(logN),效率非常高;

  • map等容器不同,set存储的元素其实只有value,在底层是<value, value>
  • 所以在插入元素时,只需要提供value即可,不需要构造键值对。使用set的迭代器进行遍历set时,会得到一个有序的序列。这是因为遍历的方式其实是二叉搜索树的中序遍历。
  • set中的元素也不允许修改,因为这可能会破坏搜索树的结构,但是 set允许插入和删除。

4.1模板参数 

class T:是 set 中存放元素的类型,实际在底层存储 <value, value> 的键值对 ;

class Compare = less<T>compare是仿函数,set中元素默认按照小于来比较(less);

class Alloc = allocator<T>:控制set的空间管理方式,使用STL提供的空间管理配置器.

 4.2默认构造

set::set - C++ Reference (cplusplus.com)

set提供了三种构造:默认空构造,迭代器区间构造和拷贝构造;

	set<int> s1;

	//迭代器区间构造
	s1 = { 1,2,3,4,5 };
	set<int> s2(s1.begin(),s1.end());

	//拷贝构造
	set<int> s3(s2);

 4.3使用

去重功能和自动排序

  • set具有降重的功能,当插入的数据已经存在时就不会再插入
  • 在打印set中的数据时,我们发现打印出来的结果是升序的,在二叉搜索树中,采用中序遍历的方式打印出来的结果就是升序的。

4.4增删查

insert

有三种插入方式,不建议用指定位置插入,有可能会破坏原二叉搜索结构

set::insert - C++ Reference (cplusplus.com)

find

 查找容器中是否存在某个特定的元素

  • 如果存在,返回该位置所在的迭代器;
  • 如果不存在,则返回set的结束位置的迭代器end()。

count 函数与其类似,只不过返回的是1和0,返回的是数字

set::count - C++ Reference (cplusplus.com)

 

erase

删除指定位置的值;set::erase - C++ Reference (cplusplus.com)

注:

  • 第二个重载函数,由于set中没有重复值,所以返回的值就是1。

  • 使用迭代器位置删除时,先find找到位置,再erase;
  •  使用指定数据的erase时,删除成功返回1,如果不存在则返回0。
  •  使用迭代器区间的erase时,将区间内的数据全部删除。

五,multiset 

成员函数和set一样,区别在于multiset支持数据重复,set不可以;

multiset - C++ Reference (cplusplus.com)

  • set:排序 + 降重
  • multiset:排序(不降重)

count

setcount成员函数和find功能类似,但是在multiset中它就有了它的作用。

multiset::count - C++ Reference (cplusplus.com)

erase

multiset::erase - C++ Reference (cplusplus.com)

 multiset中没有100,所以返回值就是0。 

find 

 multiset容器中存在重复元素,使用查找find函数,返回的是中序遍历中第一个元素;

multiset::find - C++ Reference (cplusplus.com)

其它函数基本上set一模一样了 

六,map 

map和set一样,也是一个关联式容器,底层是二叉搜索树。

map - C++ Reference (cplusplus.com)

  • 键值对映射 :map中的元素是一对键值对(pair),每一个key都有一个value对应。
  • 自动排序:与set类似,map中的元素在插入的同时会进行排序,默认情况下是key小的排在前面。
  • 唯一键:每个键在map中都是唯一的。
  • map查找的时间复杂度是O(logn).
  • 迭代器支持:支持使用迭代器来遍历map中的元素。本质上是搜索二叉树的中序遍历
  • 底层是用二叉搜索树(红黑树)实现的。
  • 可以使用[key]访问对应的value;(operator[])

6.1默认构造 

  • 使用默认构造函数创建的map是空的。
  •  插入键对值时,使用make_pair创建匿名对象更加方便。

特性 

  •  map具有降重功能,和set一样。
  •  不能插入相同的键值对,和set一样,map不支持重复数据。
  •  不能插入key值相同,val值不同的键值对。
  • map中虽然存放的是键值对,但是它的判断逻辑都只看key值,也就是first所表示的变量。
  • map也具有排序 + 降重的功能,依据只看key值而不管value值。

6.2使用 

insert

  • 参数类型 value_type pair<const key_type, mapped_type> 进行 typedef 得到的,也就是说参数是一个键值对,并使用引用传参
  • insert 第一个(框起来的)的返回类型为 pair<iterator, bool>
  • pair<iterator, bool>第一个iterator是迭代器;
    • 第二个是 bool,用于反映是否插入成功,成功返回true,否则返回false
  • 如果插入成功(即元素不存在进行插入):返回为 pair<iterator, true>;迭代器返回的是新插入元素位置的迭代器(pair
  • 如果插入失败(即元素已经存在):返回为 pair<iterator, false>,迭代器返回的是已存在元素位置的迭代器(pair);
  • map::insert - C++ Reference (cplusplus.com)

operator[]

通过键来访问或插入元素:

  • 如果键存在,它将返回对应的值的引用,即返回 Key 值的引用;
  • 如果键不存在,它会自动插入一个键值对,其中值部分为默认构造的值,并返回这个新插入值的引用。

:即使没有为元素分配映射值(即不给T传值,T为空),该元素使用其默认构造函数构造,插入新元素后,这会将容器大小增加1

map::operator[] - C++ Reference (cplusplus.com)

  • at 成员函数功能与 [] 类似,但是在具有键的元素存在时具有相同的行为(即查找的元素 Key 是存在的时候,at [] 的功能是一样的);
  • 但当不存在时抛出异常(即查找的 Key 不存在,[] 的功能是把这个 Key 直接插入map中,但是 at 是抛异常,不会进行插入);
示例

计算水果数量 

方法1

方法2 

总结

  • [] 的功能是 查找+修改+插入 (修改的原因是 [] 返回 mapped_type(T)值的引用)
  • at 的功能是 查找+修改(不支持插入)

 七,multimap

multimapmap的不同就是:

  • map中的key是唯一的,而multimapkey是可以重复的

multimap中没有重载 operator[] 操作,因为 multimapkey可能不唯一;(multimap不支持[key]操作);

使用时与map包含的头文件相同

 

  • 28
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值