目录
引子
1.set(key模型)
1.2.set的使用
2.multisetset(支持键值冗余的set)
3.map(kv模型)
3.2map的插入(将使用pair和make_pair)
3.2.1pair和make_pair
3.3 map常使用typedef来缩短代码,增加可读性
3.4修改value
4.operator[]的底层和原理
4.1insert的奇怪的返回值
4.2operator[]是一定是随机访问吗?
4.3统计一下孩子最喜欢的运动
关联式容器和序列式容器
优势:关联式容器相较于序列式容器在数据检索时比序列式容器效率更高
键值对
用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值, value表示与key对应的信息
树形结构的关联式容器
1.1. set的模板参数列表
1.2.1.set的迭代器的使用
// 1、排序+去重
// 遍历方式1:
set::iterator it = s.begin();
while (it != s.end())
{
// 不能修改已经插入的值
// *it += 1;
cout << *it << " ";
++it;
}
cout << endl;
set::reverse_iterator rit = s.rbegin();
while (rit != s.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
// 遍历方式2:
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
执行结果
1.2.2.set的找(find)的使用
// 检查单词拼写是否正确
// 思路:词库中单词都放进set的对象中,把每个写出来的单词去set中查一下,在不在,在就是正确的,不在就是错误的拼写
set strSet;
strSet.insert("sort");
strSet.insert("left");
strSet.insert("right");
strSet.insert("insert");
for (const auto& e : strSet)
{
cout << e << " ";
}
cout << endl;
// ...
set::iterator ret = strSet.find("sort");
if (ret != strSet.end())
{
cout << "找到了" << endl;
}
else
{
cout << "没有找到" << endl;
}
ret = strSet.find("map");
if (ret != strSet.end())
{
cout << "找到了" << endl;
}
else
{
cout << "没有找到" << endl;
}
执行结果
1.2.3.set的删除(erase)的使用
没有判断且没有这个key,报错
set s;
s.insert(3);
s.insert(1);
s.insert(2);
s.insert(14);
s.insert(36);
s.insert(4);
s.insert(3);
s.insert(3);
// 先查找,找到了再删。没找到,也去删会报错
auto pos = s.find(4);
if (pos != s.end())
{
s.erase(pos);
}
pos = s.find(40);
//s.erase(pos);
if (pos != s.end())
{
s.erase(pos);
}
// 在就删除,不在就不处理也不报错
s.erase(3);
s.erase(30);
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
执行结果
2.1. multiset的模板参数列表
一模一样,multiset和set不同的是,multiset支持插入相同的key ,或者说支持键值冗余
2.2. multiset和set的使用上的一些不同
// multiset允许键值冗余,使用方法基本跟set一致
// 就下面几个地方有一些差异
multiset s;
s.insert(3);
s.insert(1);
s.insert(2);
s.insert(14);
s.insert(36);
s.insert(4);
s.insert(3);
s.insert(3);
s.insert(3);
// 排序
multiset::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
// find查找的val有多个的时候,那么他找到的是中序的第一个
multiset::iterator pos = s.find(3);
while (*pos == 3)
{
cout << *pos ;
++pos;
}
cout << endl;
//count的高光
cout << s.count(3) << endl;
cout << s.count(4) << endl;
//删除容器中key存在多份的,删一个则,全部删除
s.erase(3);
it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
执行结果
kv模型:成员变量有两个key和value,就是键值对
作用:例如key为中文,value为英文翻译
3.1. multiset的模板参数列表
学习map的插入必须先学习pair这个类,为什么?
插入格式:m.insert(pair
pair这个类不需要我们写,库里有
拿到key我们返回值拿不到value
template
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)
{}
};
make_pair,用函数调用构造会不会有效率上的下降?不会,这里被优化了
template
pair make_pair(T1 x, T2 y)
{
return (pair(x, y));
}
map的插入
map m;
//调用pair的构造函数,构造一个匿名对象来插入
m.insert(pair(1, 1.2));
m.insert(pair(3, 3.2));
m.insert(pair(2, 2.2));
//调用函数模板,构造对象
//好处:不需要声明pair的模板参数,让编译器推演,写起来更方便
m.insert(make_pair(4, 4.2));
map::iterator it = m.begin();
while (it != m.end())
{
//cout << *it << endl;
//cout << (*it).first << ":" << (*it).second << endl;
cout << it->first <<":"<< it->second << endl;
++it;
}
执行结果
typedef std::map DICT;
typedef std::pair DICT_KV;
typedef std::map::iterator DICT_ITER;
DICT dict;
dict.insert(DICT_KV("insert", "插入"));
dict.insert(std::make_pair("sort", "排序"));
dict.insert(std::make_pair("left", "左边"));
DICT_ITER dit = dict.begin();
//auto dit = dict.begin();
while (dit != dict.end())
{
cout << dit->first << ":" << dit->second << endl;
++dit;
}
cout << endl;
执行结果
typedef std::map DICT;
typedef std::pair DICT_KV;
typedef std::map::iterator DICT_ITER;
DICT dict;
dict.insert(DICT_KV("insert", "插入"));
dict.insert(DICT_KV("sort", "排序"));
dict.insert(DICT_KV("left", "左边"));
DICT_ITER dit = dict.begin();
while (dit != dict.end())
{
dit->second.insert(0, "{");
dit->second += "}";
++dit;
}
cout << endl;
dit = dict.begin();
while (dit != dict.end())
{
cout << dit->first << ":" << dit->second << endl;
++dit;
}
cout << endl;
// 修改map的value数据
auto ret = dict.find("left");
if (ret != dict.end())
{
//ret->second.insert(ret->second.size() - 1, "、剩余");
// 可读性优化技巧
string& str = ret->second;
str.insert(str.size() - 1, "、剩余");
}
dit = dict.begin();
while (dit != dict.end())
{
cout << dit->first << ":" << dit->second << endl;
++dit;
}
cout << endl;
执行结果
即然map是一个键值对为
//统计
string arr[] = { "足球","足球", "足球", "篮球", "足球", "足球","篮球","乒乓球","篮球","乒乓球","乒乓球", };
map countMap;
//核心算法
for (const auto& str : arr)
{
//先插入,如果str已经在map中,insert会放回str所在节点的迭代器,再++;
pair
执行结果
那么问题来了这句代码是什么鬼pair<map
以下资料都来自map::insert - C++ Reference (cplusplus.com)
查以下map的insert的返回值
插入成功和失败
不是随机访问,operator[]的实现,简化了insert
string arr[] = { "足球","足球", "足球", "篮球", "足球", "足球","篮球","乒乓球","篮球","乒乓球","乒乓球", };
map countMap;
for (const auto& str : arr)
{
countMap[str]++;
}
//打印
for (const auto& e : countMap)
{
cout << e.first << ":" << e.second << endl;
}
执行结果
operator的源码解析
operator[]的扩展用法
map dict;
dict.insert(make_pair("right", "右边"));
dict["key"] = "关键";//插入+修改
dict["insert"];//插入
dict["insert"] = "插入";//修改
dict["right"] = "右边,正确";//修改
for (const auto& e : dict)
{
cout << e.first << ":" << e.second << endl;
}
执行结果
思路先把数据统计在一个map,再用另一个map把diyigemap的value当做我的key
string arr[] = { "乒乓球","足球","足球", "足球", "篮球", "足球", "足球","篮球","乒乓球","篮球","乒乓球","乒乓球", };
map countMap;
for (const auto& str : arr)
{
countMap[str]++;
}
// 利用map排序 -- 拷贝pair数据
//map sortMap;
map> sortMap;
for (auto e : countMap)
{
sortMap.insert(make_pair(e.second, e.first));
}
for (const auto& e : sortMap)
{
cout << e.first << ":" << e.second << endl;
}
执行结构