如果想看set与multiset的使用,可以点下面的这个链接----》set/multiset的使用《----
《二》map
首先,我们学习map之前,和上面的set是一样的,我们要有查文档的习惯,下面,如果需要文档的,点这里——》》map文档的链接《《——
【1】map的介绍
- map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。
- 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair:typedef pair value_type;
- 在内部,map中的元素总是按照键值key进行比较排序的。
- map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
- map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
- map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
【2】map的使用
2.1—map的参数说明
key: 键值对中key的类型
T: 键值对中value的类型
Compare: 比较器的类型,map中的元素是按照key来比较的,缺省情况下按照小于来比较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的空间配置器
注意:在使用 map 时,需要包含 map 头文件。
【2.2】map的使用,这里文档里面说的很清楚了,所以我在这里就不多说什么了,我们还是看一下,一些有用的接口实现吧。
我们先看以下部分代码;
《 2.2.1 》 map的构造
首先,我们先看看一下,插入数据的实现代码。
void test_map1()
{
std::map<int, int> m;
m.insert(make_pair(1, 1));
m.insert(make_pair(3, 3));
m.insert(make_pair(2, 2));
m.insert(make_pair(5, 5));
m.insert(make_pair(4, 4));
std::map<int, int>::iterator it = m.begin();
while (it != m.end())
{
//cout << (*it).first << ":" << (*it).second << endl;
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
}
map的插入实现代码就是这些,我们在可以看一下上面的执行测试结果:
【2.2.2】map的可以统计数据的次数
//统计次数
void test_map2()
{
string s[] = { "苹果", "苹果", "苹果", "苹果", "橘子", "苹果", "苹果", "香蕉", "苹果", "香蕉", "苹果" };
map<string, int> countmap;
for (const auto& e : s)
{
//map<string, int>::iterator it = countmap.find(e);
auto it = countmap.find(e);
if (it != countmap.end())
{
it->second++;
}
else
{
countmap.insert(make_pair(e, 1));
}
}
map<string, int>::iterator cit = countmap.begin();
while (cit != countmap.end())
{
//cout << (*it).first << ":" << (*it).second << endl;
cout << cit->first << ":" << cit->second << endl;
++cit;
}
}
下面,我们看一下代码执行的情况:
分析一下:先找到第一次出现的字符串,然后直接插入进去,当判断还不是 end 的时候,继续往下面走,如果是第一次出现的字符串,那么向第一次的基础上面加加,如果是新的字符串,那么直接在后面继续插入,这里就是统计次数的大致分析步骤。
【2.2.3】还是统计次数,但是不让你使用find,该怎么样实现呢?
下面,我们还是看一下,实现代码。
void test_map3() //统计次数
{
string s[] = { "苹果", "苹果", "苹果", "苹果", "橘子", "苹果", "苹果", "香蕉", "苹果", "香蕉", "苹果" };
map<string, int> countmap;
for (const auto& e : s) //不让用find();
{
pair<std::map<string, int>::iterator, bool> ret = countmap.insert(make_pair(e, 1));
//auto ret = countmap.insert(make_pair(e, 1));
//auto缺陷,不容易读取,不知道里面什么内容
if (ret.second == false)
{
ret.first->second++;
}
}
map<string, int>::iterator cit = countmap.begin();
while (cit != countmap.end())
{
//cout << (*it).first << ":" << (*it).second << endl;
cout << cit->first << ":" << cit->second << endl;
++cit;
}
}
还是和上面一样,我在看一下执行程序:
总结分析:这里我们还是使用迭代器,但是不让我们使用 find(),我们可以选择使用 insert()接口,来实现统计次数,那是怎么样实现的呢?首先,再插入之前,我们看到程序,显示遍历了一遍,然后再插入新的字符串的时候,直接插入,后面,如果出现的是同一个字符串,那么就实现下面的代码,进行次数的加加爱,如果是新的字符串,那么就直接插入就可以了。
【2.2.4】还是统计次数,不让使用 find() ,并且不让使用迭代器,那么又该怎么实现呢?
下面,我们看一下代码。
void test_map4()
{
string strs[] = { "苹果", "苹果", "西瓜", "苹果", "西瓜", "草莓", "草莓", "香蕉", "苹果", "苹果", "香蕉", "香蕉", "苹果", "苹果" };
map<string, int> countmap;
for (const auto& e : strs)
{
countmap[e]++;
}
for (const auto& e : countmap)
{
cout << e.first << ":" << e.second << endl;
}
}
下面,我们来看一下实现代码的执行程序:
**总结分析:**先用范围for遍历一遍,排序,然后,将相同的字符串进行加起来,不同的,进行下一次的相加,直到整个字符串的结束,这样就实现了统计次数了,
通过上面的学习,我们可以实现部分map的 使用了,但是这些还不够,我还写了一些基础的小接口,我们可以在看一下:
void test_map5()
{
map<int, int> m;
m.insert(make_pair(1, 1));
m.insert(make_pair(3, 3));
m.insert(make_pair(2, 2));
m.insert(make_pair(5, 5));
m.insert(make_pair(4, 4));
m[1] = 1;
//再某一个位置插入一个值
m.insert(m.find(2), make_pair(6, 6));
cout << m.size() << endl;
//将这个程序遍历一遍,打印
for (auto& e : m )
{
cout << e.first << "--->" << e.second << endl;
}
// map中的键值对key一定是唯一的,如果key存在将插入失败
auto ret = m.insert(make_pair(7, 7));
if (ret.second)
cout << "<7, 7>不在map中, 已经插入" << endl;
else
cout << "键值为peach的元素已经存在:" << ret.first->first << "--->"
<< ret.first->second << " 插入失败" << endl;
//将上面的打印出来
for (auto& e : m)
{
cout << e.first << "--->" << e.second << endl;
}
cout << "————————————"<<endl;
//删除key为4的值
m.erase(4);
for (auto& e : m)
{
cout << e.first << "--->" << e.second << endl;
}
cout << "————————————" << endl;
if (4 == m.count(4))
cout << "4还在" << endl;
else
cout << "4不在了" << endl;
}
这里我已经把他的说明,在代码里面强调过了,所以,我这里就不用多说什么说明了,我们直接看执行程序结果。
最后一个截不上屏,但是,我相信,看代码一下就看懂了。这里就是我们实现的map的使用。
【总结】
- map中的的元素是键值对
- map中的key是唯一的,并且不能修改
- 默认按照小于的方式对key进行比较
- map中的元素如果用迭代器去遍历,可以得到一个有序的序列
- map的底层为平衡搜索树(红黑树),查找效率比较高O(log2 N)
- 支持[]操作符,operator[]中实际进行插入查找。
《二》multimap
首先. 和上面还是一样,还是可以用一下查文档的形式,首先,我先把文档的入口链接写在下面multimap的文档入口
【1】multimap的介绍
- Multimaps是关联式容器,它按照特定的顺序,存储由key和value映射成的键值对<key, value>,其中多个键值对之间的key是可以重复的。
- 在内部,multimap中的元素总是通过其内部比较对象,按照指定的特定严格弱排序标准对key进行排序的。
- multimap通过key访问单个元素的速度通常比unordered_multimap容器慢,但是使用迭代器直接遍历multimap中的元素可以得到关于key有序的序列
- multimap在底层用二叉搜索树(红黑树)来实现
【2】multimap的部分接口实现
注意:
1. multimap中的key是可以重复的。
2. multimap中的元素默认将key按照小于来比较
3. multimap中没有重载operator[]操作(同学们可思考下为什么?)。
4. 使用时与map包含的头文件相同:
【2.1】首先,我们先看一下,multimap的第一个特性,不去重,也有自己的用处。
下面,我们先看一下代码
void test_multimap6()
{
multimap<string, string> m;
m.insert(make_pair("李逵", "黑旋风"));
m.insert(make_pair("林冲", "豹子头"));
m.insert(make_pair("鲁达", "花和尚"));
m.insert(make_pair("李逵", "铁牛"));
cout << m.size() << endl;
for (auto& e : m)
{
cout << "<" << e.first << "," << e.second << ">" << endl;
}
// key为李逵的元素有多少个
cout << m.count("李逵") << endl;
}
下面,我们看一下执行结果;
这个接口是比较常用的,下面的接口就不太常用,但是,还是有一点用处的,所以,我就直接在代码区直接写了它的用途。
void test_multimap7()
{
multimap<int, int> m;
for (int i = 0; i < 10; ++i)
{
m.insert(pair<int, int>(i, i));
}
for (auto& e : m)
{
cout << e.first << "--->" << e.second << endl;
}
cout <<"——————————————"<< endl;
// 返回m中大于等于5的第一个元素
auto it = m.lower_bound(5);
cout << it->first << "--->" << it->second << endl;
// 返回m中大于5的元素
it = m.upper_bound(5);
cout << it->first << "--->" << it->second << endl;
}
当然,multimap,里面还有很多的接口,我就不实现了, 想要自己实现的同学们可以根据文档实现,自己的代码。
《三》set / map 区别
set O(logN)
1. 快速查找 key在不在?
2.排序+去重
map O(logN)
1.快速查找 通过key查找value;
2.附带作用,对key进行排序。通过字符串的大小进行排序的