🌈个人主页:秦jh_-CSDN博客
🔥 系列专栏:https://blog.csdn.net/qinjh_/category_12575764.html?spm=1001.2014.3001.5482
目录
前言
💬 hello! 各位铁子们大家好哇。
今日更新了map和set的相关内容
🎉 欢迎大家关注🔍点赞👍收藏⭐️留言📝
关联式容器
vector、list、deque等这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。
关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。
树形结构的关联式容器
STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结构的关联式容器主要有四种:map、set、multimap、multiset。
set
set的介绍
- 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。 set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
- set在底层是用二叉搜索树(红黑树)实现的。
注意:
- 与map/multimap不同,map/multimap中存储的是真正的键值对,set中只放 value,但在底层实际存放的是由构成的键值对。
- set中插入元素时,只需要插入value即可,不需要构造键值对。
- set中的元素不可以重复(因此可以使用set进行去重)。
- 使用set的迭代器遍历set中的元素,可以得到有序序列
构造
简单使用:
set的使用很简单,主要功能是key模型的搜索,次要功能是排序+去重。
set还支持迭代器区间构造和花括号构造。
删除
erase参数可以是值,也可以是迭代器。如果传值,如果有该值就删除,没有就没变化。erase还可以迭代器区间删除。
查找删除
lower_bound
上方是迭代器区间删除的例子。lower_bound就是大于等于,upper_bound就是大于,即左闭右开的区间。
multiset
multiset和set的区别就是允许冗余,不去重。
有多个相同的数时,multiset的find会找中序遍历的第一个 。
map
map的介绍
- map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元 素。
- 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的 内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型 value_type绑定在一起,为其取别名称为pair。
- 在内部,map中的元素总是按照键值key进行比较排序的。
- map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
- map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
value_type就是pair<const Key, T>。
插入
map插入时,类型得是pair。
插入的方式有很多,make_pair相当于函数模板,它会自动识别类型。最后一行是initializer_list的隐式类型转换构造。
遍历
不能直接对迭代器解引用,因为里面有两个值。所以这里的用法跟前面list的模拟很像。
注意上面传引用比较好,这样就不会因为进行深拷贝,而导致效率低下。
operator[]
上面的写法太过麻烦,可以使用[]。 如下图:
operator[]的使用相当于下面函数的作用:
自行翻译一下就变成下面的代码:
里面使用了insert,下面是insert的返回值:
解释一下版本(1)的返回值:
当插入pair后,返回值也是pair。该pair的first指向新插入的节点的迭代器或者已存在节点的迭代器,second为bool值,插入成功返回true,失败返回false。
即:key存在,插入失败,返回pair<存在的key所在节点的迭代器,false>
key不存在,插入成功,返回pair<新插入的key所在节点的迭代器,true>
了解了operator[]的底层实现,就有了其他用法:
operator[]的本质:给[]一个Key,如果存在,就返回Key对应val的引用。如果不存在,就插入Key,然后val给的是缺省值(string缺省值就是"") 。
count
count在map中一般用来判断是否存在,在multimap中可以用来数个数。
multimap
当我们想按数量排序时,因为有相同数量的水果,就需要用multimap。multimap没有重载[],所以只能使用insert。multimap不能重载[],因为已经允许冗余了,如果key有多个,就不知道返回哪个key对应的val。
注意:multimap和map的唯一不同就是:map中的key是唯一的,而multimap中key是可以重复的。
测试代码
#include<iostream>
#include<set>
#include<map>
#include<vector>
using namespace std;
void test_set1()
{
//主要功能:key模型搜索
//次要功能:排序+去重
set<int> s1;
s1.insert(1);
s1.insert(11);
s1.insert(3);
s1.insert(1);
s1.insert(4);
s1.insert(2);
set<int>::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
++it;
}
cout << endl;
vector<int> v = { 3,2,8,1,10,2 };
set<int> s2(v.begin(), v.end());
for (auto e : s2)
{
cout << e << " ";
}
cout << endl;
set<int>s3 = { 3,2,8,1,10,2 };
for (auto e : s3)
{
cout << e << " ";
}
cout << endl;
s3.erase(8);
s3.erase(18);
for (auto e : s3)
{
cout << e << " ";
}
cout << endl;
auto pos = s3.find(10);
if (pos != s3.end())
{
cout << *pos << endl;
s3.erase(pos);
}
else
{
cout << "找不到" << endl;
}
for (auto e : s3)
{
cout << e << " ";
}
cout << endl;
}
void test_set2()
{
set<int> myset;
for (int i = 1; i < 10; i++)
myset.insert(i * 10); // 10 20 30 40 50 60 70 80 90
for (auto e : myset)
{
cout << e << " ";
}
cout << endl;
//[30,70)
auto itlow = myset.lower_bound(30); // >=
auto itup = myset.upper_bound(60); // >
myset.erase(itlow, itup); // 10 20 70 80 90
for (auto e : myset)
{
cout << e << " ";
}
cout << endl;
}
void test_set3()
{
//主要功能:key模型搜索
//次要功能:排序 不去重
multiset<int> s1;
s1.insert(1);
s1.insert(2);
s1.insert(11);
s1.insert(3);
s1.insert(1);
s1.insert(4);
s1.insert(2);
multiset<int>::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
++it;
}
cout << endl;
auto pos = s1.find(2);
while (pos != s1.end()&&*pos==2)
{
cout << *pos << " ";
++pos;
}
}
void test_map1()
{
map<string, string> dict;
pair<string, string> kv1("sort", "排序");
dict.insert(kv1);
dict.insert(pair<string, string>("left", "左边"));
dict.insert(make_pair("right", "右边"));
// 隐式类型转换
//单参数和多参数都支持隐式类型转换
//如果是多参数,用花括号括起来即可
pair<string, string> kv2 = { "string","字符串" };
dict.insert({ "string","字符串" });
map<string, string> dict2 = { {"left", "左边"},{"right", "右边"} };
map<string, string>::iterator it = dict.begin();
while (it != dict.end())
{
//cout << *it << " "; //错误
cout << (*it).first << ":" << (*it).second << endl;
cout << it->first << ":" << it->second << endl;
cout << it.operator->()->first << ":" << it.operator->()->second << endl;
++it;
}
cout << endl;
for (auto& kv : dict)
{
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;
}
void test_map2()
{
string arr[] = { "苹果","西瓜","苹果","西瓜","苹果","苹果","西瓜","苹果","香蕉",
"苹果","香蕉","苹果","草莓","苹果","草莓" };
map<string, int> countMap;
for (auto& e : arr)
{
countMap[e]++;
/*auto it = countMap.find(e);
if (it != countMap.end())
{
it->second++;
}
else
{
countMap.insert({ e,1 });
}*/
}
for (auto& kv : countMap)
{
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;
multimap<int, string> sortMap;
for (auto& kv : countMap)
{
//sortMap[kv.second] = kv.first;
sortMap.insert({ kv.second,kv.first });
}
cout << endl;
for (auto& kv : sortMap)
{
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;
}
void test_map3()
{
map<string, string> dict;
dict.insert({ "string","字符串" });
//插入(一般不这么用)
dict["right"];
//插入+修改
dict["left"] = "左边";
//"查找"
cout << dict["string"] << endl;
//修改
dict["right"] = "右边";
string str;
cin >> str;
if (dict.count(str))
{
cout << "在" << endl;
}
else
{
cout << "不在" << endl;
}
}
int main()
{
test_map3();
return 0;
}