高端的平面设计网站,ios7风格网站,网站建设开发程序代码,外网域名#x1f308;个人主页#xff1a;秋风起#xff0c;再归来~#x1f525;系列专栏#xff1a;C从入门到起飞 #x1f516;克心守己#xff0c;律己则安 目录 1. 序列式容器和关联式容器
2. set系列的使⽤
2.1 set和multiset参考⽂档
2.2 set类的介绍
2.3 se… 个人主页秋风起再归来~系列专栏C从入门到起飞 克心守己律己则安 目录 1. 序列式容器和关联式容器
2. set系列的使⽤
2.1 set和multiset参考⽂档
2.2 set类的介绍
2.3 set的构造和迭代器 2.4 set的增删查
2.5 multiset和set的差异
3、map系列的使用
3.1 map和multimap参考⽂档
3.2 map类的介绍
3.3 pair类型介绍
3.4 map的增删查
3.5 map的数据修改
3.6 multimap和map的差异
4、完结散花 1. 序列式容器和关联式容器
前⾯我们已经接触过STL中的部分容器如string、vector、list、deque、array、forward_list等这 些容器统称为序列式容器因为逻辑结构为线性序列的数据结构两个位置存储的值之间⼀般没有紧 密的关联关系⽐如交换⼀下他依旧是序列式容器。顺序容器中的元素是按他们在容器中的存储位 置来顺序保存和访问的。
关联式容器也是⽤来存储数据的与序列式容器不同的是关联式容器逻辑结构通常是⾮线性结构 两个位置有紧密的关联关系交换⼀下他的存储结构就被破坏了。顺序容器中的元素是按关键字来 保存和访问的。关联式容器有map/set系列和unordered_map/unordered_set系列。
本文讲解的map和set底层是红⿊树红⿊树是⼀颗平衡⼆叉搜索树。set是key搜索场景的结构 map是key/value搜索场景的结构。
2. set系列的使⽤
2.1 set和multiset参考⽂档
https://legacy.cplusplus.com/
2.2 set类的介绍
template class T, // set::key_type/value_typeclass Compare lessT, // set::key_compare/value_compareclass Alloc allocatorT // set::allocator_type class set;
• set的声明如上T就是set底层关键字的类型
• set默认要求T⽀持⼩于⽐较如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现仿函数传给第⼆个模 版参数
• set底层存储数据的内存是从空间配置器申请的如果需要可以⾃⼰实现内存池传给第三个参 数。
• ⼀般情况下我们都不需要传后两个模版参数。
• set底层是⽤红⿊树实现增删查效率是O(logN)迭代器遍历是⾛的搜索树的中序所以是有序 的。
• 前⾯部分我们已经学习了vector/list等容器的使⽤STL容器接⼝设计⾼度相似所以这⾥我们 就不再⼀个接⼝⼀个接⼝的介绍⽽是直接带着⼤家看⽂档挑⽐较重要的接⼝进⾏介绍。
2.3 set的构造和迭代器
set的构造我们关注以下⼏个接⼝即可。
set的⽀持正向和反向迭代遍历遍历默认按升序顺序因为底层是⼆叉搜索树迭代器遍历⾛的中 序⽀持迭代器就意味着⽀持范围forset的iterator和const_iterator都不⽀持迭代器修改数据修改 关键字数据破坏了底层搜索树的结构。
1无参数默认构造
explicit set (const key_compare comp key_compare(),const allocator_type alloc allocator_type());explicit set (const allocator_type alloc);上面的构造函数被声明为explicit这可阻止它们被用来执行隐式类型转化但它们仍可被用来执行显示类型转换。
被声明为explicit的构造函数通常比其兄弟non-explicit更受欢迎因为它们禁止编译器执行非预期往往也不被期望的类型转换。除非我有一个好理由允许构造函数被用于隐式类型转换否则我会把它声明为explicit。
(2) 迭代器区间构造
set (InputIterator first, InputIterator last,const key_compare comp key_compare(),const allocator_type allocator_type());
(3) 拷⻉构造
void insert (initializer_list il);
set (const set x);
set (const set x, const allocator_type alloc); (4) 列表构造
set (initializer_listvalue_type il,const key_compare comp key_compare(),const allocator_type alloc allocator_type()); 2.4 set的增删查
set的增删查关注以下⼏个接⼝即可
1单个数据插⼊如果已经存在则插⼊失败
pairiterator,bool insert (const value_type val);
pair其实是std库里面的一个类模版 setint s1;
auto it s1.insert(1);
cout *it.first endl;
cout it.second endl;
cout typeid(it).name() endl; 下面我们还会再提到pair类型
2列表插⼊已经在容器中存在的值不会插⼊
void insert (initializer_listvalue_type il);
3迭代器区间插⼊已经在容器中存在的值不会插⼊
template class InputIteratorvoid insert (InputIterator first, InputIterator last);
4查找val返回val所在的迭代器没有找到返回end()
iterator find (const value_type val);
5查找val返回Val的个数
size_type count (const value_type val) const;
6删除⼀个迭代器位置的值
iterator erase (const_iterator position);
7删除valval不存在返回0存在返回1
size_type erase (const value_type val);
8删除⼀段迭代器区间的值
iterator erase (const_iterator first, const_iterator last);
9返回⼤于等val位置的迭代器
iterator lower_bound (const value_type val) const;
10返回⼤于val位置的迭代器
iterator upper_bound (const value_type val) const;
2.5 multiset和set的差异
multiset和set的使⽤基本完全类似主要区别点在于multiset⽀持值冗余那么insert/find/count/erase都围绕着⽀持值冗余有所差异具体参看下⾯的样例代码理解。
// 相⽐set不同的是multiset是排序但是不去重
multisetint s { 4,2,7,2,4,8,4,5,4,9 };
auto it s.begin();
while (it ! s.end())
{cout *it ;it;
}
cout endl;// 相⽐set不同的是x可能会存在多个find查找中序的第⼀个
int x;
cin x;
auto pos s.find(x);
while (pos ! s.end() *pos x)
{cout *pos ;pos;
}
cout endl;
// 相⽐set不同的是count会返回x的实际个数
cout s.count(x) endl;
// 相⽐set不同的是erase给值时会删除所有的x
s.erase(x);
for (auto e : s)
{cout e ;
}
cout endl;
3、map系列的使用
3.1 map和multimap参考⽂档
https://legacy.cplusplus.com/reference/map/map/?kwmap
3.2 map类的介绍
map的声明如下Key就是map底层关键字的类型T是map底层value的类型set默认要求Key⽀持⼩于⽐较如果不⽀持或者需要的话可以⾃⾏实现仿函数传给第⼆个模版参数map底层存储数据的 内存是从空间配置器申请的。⼀般情况下我们都不需要传后两个模版参数。map底层是⽤红⿊树实 现增删查改效率是O(logN) 迭代器遍历是⾛的中序所以是按key有序顺序遍历的。
template class Key, // map::key_typeclass T, // map::mapped_typeclass Compare lessKey, // map::key_compareclass Alloc allocatorpairconst Key,T //
map::allocator_type class map;3.3 pair类型介绍
map底层的红⿊树节点中的数据使⽤pair存储键值对数据。
typedef pairconst Key, T value_type;
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){}templateclass U, class V pair (const pairU,V pr): first(pr.first), second(pr.second){}
};3.4 map的增删查
map的增删查关注以下⼏个接⼝即可 map增接⼝插⼊的pair键值对数据跟set所有不同但是查和删的接⼝只⽤关键字key跟set是完全类似的不过find返回iterator不仅仅可以确认key在不在还找到key映射的value同时通过迭代 还可以修改value
Member types
key_type - The first template parameter (Key)
mapped_type - The second template parameter (T)
value_type - pairconst key_type,mapped_type// 单个数据插⼊如果已经key存在则插⼊失败,key存在相等value不相等也会插⼊失败
pairiterator,bool insert (const value_type val);// 列表插⼊已经在容器中存在的值不会插⼊
void insert (initializer_listvalue_type il);// 迭代器区间插⼊已经在容器中存在的值不会插⼊
template class InputIterator
void insert (InputIterator first, InputIterator last);// 查找k返回k所在的迭代器没有找到返回end()
iterator find (const key_type k);// 查找k返回k的个数
size_type count (const key_type k) const;// 删除⼀个迭代器位置的值
iterator erase (const_iterator position);// 删除kk存在返回0存在返回1
size_type erase (const key_type k);// 删除⼀段迭代器区间的值
iterator erase (const_iterator first, const_iterator last);// 返回⼤于等k位置的迭代器
iterator lower_bound (const key_type k);// 返回⼤于k位置的迭代器
const_iterator lower_bound (const key_type k) const;
我们要注意到map是要插入一个pair类型的我们可以用匿名对象的方式插入
mapstring , string m;
m.insert(pairstring, string(left, 左边)); 不过这种方法太麻烦了所以我们通常用make_pair的方式 maek_pair是定义在std上的一个内联函数模版
template class T1,class T2
inline pairT1,T2 make_pair (T1 x, T2 y)
{return ( pairT1,T2(x,y) );
}mapstring, string m;
m.insert(make_pair(left, 左边));
3.5 map的数据修改
前⾯我提到map⽀持修改mapped_type数据不⽀持修改key数据修改关键字数据破坏了底层搜 索树的结构。
map第⼀个⽀持修改的⽅式时通过迭代器迭代器遍历时或者find返回key所在的iterator修改map 还有⼀个⾮常重要的修改接operator[]但是operator[]不仅仅⽀持修改还⽀持插⼊数据和查找数据所以他是⼀个多功能复合接
需要注意从内部实现⻆度map这⾥把我们传统说的value值给的是T类型typedef为 mapped_type。⽽value_type是红⿊树结点中存储的pair键值对值。⽇常使⽤我们还是习惯将这⾥的 T映射值叫做value。
Member types
key_type - The first template parameter (Key)
mapped_type - The second template parameter (T)
value_type - pairconst key_type,mapped_type// 查找k返回k所在的迭代器没有找到返回end()如果找到了通过iterator可以修改key对应的
mapped_type值
iterator find (const key_type k);// ⽂档中对insert返回值的说明
// The single element versions (1) return a pair, with its member pair::first
set to an iterator pointing to either the newly inserted element or to the
element with an equivalent key in the map. The pair::second element in the pairis set to true if a new element was inserted or false if an equivalent key
already existed.// insert插⼊⼀个pairkey, T对象 // 1、如果key已经在map中插⼊失败则返回⼀个pairiterator,bool对象返回pair对象
first是key所在结点的迭代器second是false // 2、如果key不在在map中插⼊成功则返回⼀个pairiterator,bool对象返回pair对象
first是新插⼊key所在结点的迭代器second是true // 也就是说⽆论插⼊成功还是失败返回pairiterator,bool对象的first都会指向key所在的迭
代器 // 那么也就意味着insert插⼊失败时充当了查找的功能正是因为这⼀点insert可以⽤来实现
operator[]// 需要注意的是这⾥有两个pair不要混淆了⼀个是map底层红⿊树节点中存的pairkey, T另
⼀个是insert返回值pairiterator,bool
pairiterator,bool insert (const value_type val);
mapped_type operator[] (const key_type k);// operator的内部实现
mapped_type operator[] (const key_type k)
{// 1、如果k不在map中insert会插⼊k和mapped_type默认值同时[]返回结点中存储
mapped_type值的引⽤那么我们可以通过引⽤修改返映射值。所以[]具备了插⼊修改功能 // 2、如果k在map中insert会插⼊失败但是insert返回pair对象的first是指向key结点的
迭代器返回值同时[]返回结点中存储mapped_type值的引⽤所以[]具备了查找修改的功能 pairiterator, bool ret insert({ k, mapped_type() });iterator it ret.first;return it-second;
}3.6 multimap和map的差异
multimap和map的使⽤基本完全类似主要区别点在于multimap⽀持关键值key冗余那么 insert/find/count/erase都围绕着⽀持关键值key冗余有所差异这⾥跟set和multiset完全⼀样⽐如 find时有多个key返回中序第⼀个。其次就是multimap不⽀持[]因为⽀持key冗余[]就只能⽀持插⼊了不能⽀持修改。
4、完结散花
好了这期的分享到这里就结束了~
如果这篇博客对你有帮助的话可以用你们的小手指点一个免费的赞并收藏起来哟~
如果期待博主下期内容的话可以点点关注避免找不到我了呢~
我们下期不见不散~~