c++基础(五)——关联容器
1.关联容器
关联容器中的元素时按照关键字来保存和访问的,与之相对的,顺序容器中的元素时按它们在容器中的位置来顺序保存和访问的。两个主要关联容器是 map 和 set。标准库提供了8个关联容器,这8个容器间的不同体现在
三个维度上:
- 或是一个 map 或是一个 set
- 或者要求不重复关键字,或者允许重复关键字
- 按顺序保存元素,或无序保存
2.使用关联容器
- map
//统计每个单词在输入中出现的次数
map<string, size_t> word_count; //string到size_t的空map
string word;
while (cin >> word)
++word_count[word]; //提取word的计数器并将其加1
for(const auto &w : word_count) //对map中的每个元素
//打印结果
cout << w.first << " occurs " << w.second
<< ((w.second > )? " times ": "time") << endl;- set
//统计输入中每个单词出现的次数
map<string, size_t> word_count; //string到size_t的空map
set<string> exclude = {"The", "But", "And", "Or", "An", "A",
"the", "but", "and", "or", "an", "a"};
string word;
while (cin >> word)
//只统计不在exclude中的单词
if (exclude.find(word) == exclude.end())
++word_count[word]; //获取并递增word的计数器
3.关联容器概述
关联容器不支持顺序容器的位置相关操作,例如push_front或push_back。原因是关联容器中元素是根据关键字存储的,这些操作对关联容器没有意义。关联容器的迭代器都是双向的。
- 初始化 multimap 和 multiset。一个map或set中的关键字必须是唯一的,容器multimap和multiset没有此限制,它们允许多个元素具有相同的关键字。
//定义一个有20个元素的vector,保存0到9每个整数的两个拷贝
vector<int> ivec;
for (vector<int>::size_type i = ; i != ; ++i){
ivec.push_back(i);
ivec.push_back(i); //每个数重复保存一次
}
//iset包含来自ivec的不重复的元素,miset包含所有20个元素
set<int> iset(ivec.begin(), ivec.end());
multiset<int> miset(ivec.begin(), ivec.end());
cout << ivec.size() << endl; //打印出20
cout << iset.size() << endl; //打印出10
cout << miset.size() << endl; //打印出20
3.1 set,map自定义函数排序
关联容器对其关键字类型有一些限制。对于有序容器,关键字类型必须定义元素比较的方法。默认情况下,标准库使用关键字类型<运算符来比较两个关键字。
用来组织一个容器中元素的操作的类型也是该容器类型的一部分。为了指定使用自定义的操作,必须在定义关联容器类型时提供此操作的类型。使用方法如下:用尖括号指定要定义的那种类型的容器,自定义的操作类型必须在尖括号中紧跟元素类型给出。例如:我们不能直接定义一个Sales_data的multiset,因为Sales_data没有<运算符。因此需要定义一个compareIsbn:
bool compareIsbn (const Sales_data &lhs, const Sales_data &rhs)
{
return lhs.isbn() < rhs.isbn();
}
为了使用自己定义的操作,在定义multiset时我们必须提供两个类型:关键字类型Sales_data,以及比较操作类型——应该是一种函数指针类型,可以指向compareIsbn。
//bookstore中多条记录可以有相同的ISBN
//bookstore中的元素以ISBN的顺序进行排列
multiset<Sales_data, decltype(compareIsbn)*> bookstore(compareIsbn);
此处,我们使用decltype来指出自定义操作的类型。记住,当用decltype来获得一个函数指针类型时,必须加上一个*来指出我们要使用一个给定函数类型的指针;用compareIsbn来初始化bookstore对象,这表示当我们想bookstore添加元素时,通过调用compareIsbn来为这些元素排序。
下面举两个实例:均按照降序进行排列,容器默认是使用“<”。
#include <set>
#include <map>
#include <vector>
#include <string>
#include <iostream>
using namespace std; class st {
public:
int id;
string name;
st(int id, string name);
~st() {};
}; st::st(int id, string name) :id(id), name(name) { } bool compareST(const int &s, const int &r) {
return s > r;
} bool compareST2(const st *s, const st *r) {
return s->id > r->id;
} int main()
{
/// map
st *st1 = new st(, "st1");
st *st2 = new st(, "st2");
st *st3 = new st(, "st3"); map<int, st*, decltype(compareST)*> temp(compareST);
temp.insert(make_pair(st1->id, st1));
temp.insert(make_pair(st2->id, st2));
temp.insert(make_pair(st3->id, st3)); for (auto item : temp) {
cout << item.first << "\t" << item.second->name << endl;
} cout << "========================" << "\n"; /// set
set<st*, decltype(compareST2)*> temp2(compareST2);
temp2.insert(st1);
temp2.insert(st2);
temp2.insert(st3); for (auto item : temp2) {
cout << item->id << "\t" << item->name << endl;
} getchar();
return ;
}
3.2 pair 类型
它定义在头文件utility中。类似容器,pair是一个用来生成特定类的模板,与其他标准库类型不同,pair的数据成员是public的。两个成员分别命名为first和second,我们用普通的成员访问符号来访问它们。
如下是一个错误写法:
map<int, string> temp;
pair<int, string> p(); // 显得不伦不类了。①不加括号,即采用第一种进行值初始化②采用(1,"test")利用第二种方式初始化
temp.insert(p);
改正:
map<int, string> temp;
pair<int, string> p(, "dd");
pair<int, string> p2;
temp.insert(p);
temp.insert(p2);
temp.insert(make_pair(, "dd"));
3.3 关联容器的操作
关联容器额外的类型别名:
对于 set 类型,key_type 和 value_type 是一样的:set 中保存的就是关键字。
在 map 中,元素是关键字-值对,即每一个元素是一个 pair 对象,包含一个关键字和一个关联的值,同时因为不能改变一个元素的关键字,因此这些 pair 的关键字部分是 const 的。
map<int, string>::key_type v; // v 是一个 int
map<int, string>::mapped_type v2; // v 是一个 string
set<string>::key_type s; // s 是一个 string
set<string>::value_type s2; // s 是一个 string
5 map<int, string>::value_type v3;// 是一个 pair<int, string> 类型
4. 关联容器迭代器
map 中的 key 值是const的,不能够被改变。
map<int, string> m;
m.insert({ , "a" });
m.insert({ , "b" });
for (auto iter = m.begin(); iter != m.end(); ++iter) {
cout << iter->first << iter->second<<endl;
}
set的迭代器是const的。set 中的值 也只能访问不能修改。
4.1 添加元素
由于map和set包含不重复的关键字,因此插入一个已存在的元素对容器没有任何影响:
注:insert有两个版本,分别接受一对迭代器,或是一个初始化器列表,这两个版本的行为类似对应的构造函数。
vector<int> ivec = { , , , , ,, , };
set<int> set2;
set2.insert(ivec.begin(), ivec.end()); //set2有4个元素
4.1.1 向 map 添加元素
//向word_count插入word的4中方法
word_count.insert({word, }); // 最简单
word_count.insert(make_pair(word, ));
word_count.insert(pair<string, size_t>(word, ));
word_count.insert(map<string, size_t>::value_type(word, )); //构造一个恰当的 pair 类型,并构造该类型的一个对象,插入到map中
4.1.2 检测 insert 的返回值
insert(或emplace)返回的值依赖于容器类型和参数。对于不包含重复关键字的容器,添加单一元素的insert和emplace版本返回一个pair,告诉我们插入操作是否成功。pair的first成员是一个迭代器,指向具有给定关键字的元素;second成员是一个bool值,指出元素是插入成功还是已经存在于容器中。
4.1.3 删除元素
关联容器定义了三个版本的erase,与顺序容器一样,我们可以通过传递给erase一个迭代器或一个迭代器对来删除一个元素或一个元素范围;关联容器还提供一个额外的erase操作,它接受一个key_type参数。
4.1.4 map 的下标操作
map和unordered_map支持下标运算和一个对应的 at 函数,但是 set 不支持,因为set中本身存放的就是 关键字。
与其他下标运算符不同的是,但是如果关键字并不在map中,会为它创建一个元素并插入到map中,关联值将进行初始化。比如下面的例子:
map<int, int> m;
m.insert({ , });
m.insert({ , }); cout << m.size() << endl; //
cout << m[] << endl; // 0. key=3 的值不存在,插入并初始化
cout << m.size() << endl; //
cout << m[] << endl; // 0
4.2 访问元素
如果我们所关心的只不过是一个特定元素是否在容器中,可能find是最佳选择。
set<int> iset = {, , , , , , , , , };
iset.find(); //返回一个迭代器,指向key==1的元素
iset.find(); //返回一个迭代器,其值等于iset.end()
iset.count(); //返回1
iset.count(); //返回0
map 中利用 find 代替下标操作。当我们不想改变 map 的时候,下标操作会带来麻烦。
if (word_count.find("foobar") == word_count.end())
cout << "foobar is not in the map " << endl;
在multimap或multiset中查找元素。如果 multimap 中有多个元素具有给定的关键字,这些元素会在容器中相邻存储。
string search_item("Alain de Botton"); //要查找的作者
auto entries = authors.count(search_item); //元素的数量
auto iter = authors.find(search_item); //此作者的第一本书
//用一个循环查找此作者的所有著作
while(entries){
cout << iter->second << endl; //打印每个题目
++iter; //前进到下一本书
--entries; //记录已经打印了多少本书
}
c++基础(五)——关联容器的更多相关文章
- C++基础之关联容器
关联容器 关联容器和顺序容器的本质区别:关联容器是通过键存取和读取元素.顺序容器通过元素在容器中的位置顺序存储和访问元素.因此,关联容器不提供front.push_front.pop_front.ba ...
- 《STL源码剖析》——第五、六:关联容器与算法
第五章.关联容器 5.0.关联容器 标准的STL关联式容器分为set(集合)和map(映射表)两大类,以及这两大类的衍生体multiset(多键集合)和multimap(多键映射表).这些容器的底层 ...
- day 57 Django基础五之django模型层之关联管理器
Django基础五之django模型层之关联管理器 class RelatedManager "关联管理器"是在一对多或者多对多的关联上下文中使用的管理器.它存在于下面两种情况 ...
- C++学习基础四——顺序容器和关联容器
—顺序容器:vector,list,queue1.顺序容器的常见用法: #include <vector> #include <list> #include <queue ...
- C/C++基础----关联容器
基本属性 与顺序容器的差别,按照关键字来保存和访问,而顺序容器是按照容器中的位置来顺序保存和访问. map:每个元素是一对键值(key-valye)组合:set每个元素只包含关键字.. 每个根据关键字 ...
- 容器基础(五): 实现一个简单容器sdocker
在前面几部分的基础上, 我们更新一下代码,实现一个简单容器 sdocker. sdocker目录构成 linux: # tree . ├── Makefile ├── cpu-test.c # 由cp ...
- Bootstrap <基础五>表格
Bootstrap 提供了一个清晰的创建表格的布局.下表列出了 Bootstrap 支持的一些表格元素: 标签 描述 <table> 为表格添加基础样式. <thead> 表格 ...
- c++11の关联容器
一.关联容器 C++的容器类型可以分为顺序容器和关联容器两大类.对于关联容器,主要有map和set,对于这两种,根据不同的维度,衍生出了8种容器 map ...
- C#_02.14_基础五_.NET类
C#_02.14_基础五_.NET类 一.类实例: 我们前面说过类是一个模板,我们通过类创建一个又一个的实例,通常情况下类当中的变量是每一个实例都各有一份的,互相不影响,而静态字段是除外的,静态字段是 ...
随机推荐
- MongoDB 4.2 的主要亮点(转载)
在6月份召开的MongoDB全球用户大会上, MongoDB官宣了MongoDB Server 4.2,在经过100,000多个运行实例的测试后,MongoDB 4.2表现强劲.现在4.2版本正式上线 ...
- OKR的两个基本原则
<启示录>作者,前易贝高级副总裁,硅谷产品集团创始人马蒂·卡根在<OKR工作法>的序言中提到了目标管理法的两个原则: 不要告诉下属具体怎么做,要告诉他们你要什么,他们就会给你满 ...
- WinDbg常用命令系列---!heap
!heap 简介 !heap扩展显示堆使用信息.控制堆管理器中的断点.检测泄漏的堆块.搜索堆块或显示页堆信息.此扩展支持段堆和NT堆.使用!heap没有参数列出所有堆及其类型的堆. 使用形式 !hea ...
- javascript 百度地图无秘钥(appkey)创建marker标记地图
创建简单的marker地图不一定需要去百度地图申请key,简单代码实现marker地图,效果如图: html代码如下,代码中的baidu.api.js参考后面的隐藏代码: <!DOCTYPE h ...
- nuxt如何处理用户登录状态持久化:nuxtServerInit 页面渲染前的store处理
vue-cli项目中,我们可以用vuex-persistedstate,它可以使vuex的状态持久化,页面刷新都不会丢失,原理当然是localStorage啦!当然也可以使用vue-cookies进行 ...
- 一篇文章了解Github和Git教程
有趣有内涵的文章第一时间送达! 喝酒I创作I分享 关注我,每天都有优质技术文章推送,工作,学习累了的时候放松一下自己. 本篇文章同步微信公众号 欢迎大家关注我的微信公众号:「醉翁猫咪」 生活中总有些东 ...
- Eclipse各个版本及其对应代号、下载地址列表【转】
Eclipse各个版本及其对应代号.下载地址列表 Eclipse各个版本及其对应代号.下载地址列表版本号 代码 日期 下载地址Eclipse 3.1 IO[木卫一,伊奥] 2005 http://ar ...
- Intellij IDEA 智能补全的 10 个姿势,太牛逼了。。
一年多前,栈长那时候刚从 Eclipse 转型 IDEA 成功,前面转了好多次,都是失败史,都是泪..后面我就在微信公众号 "Java技术栈" 写了这篇文章:Intellij ID ...
- Hadoop版本升级(2.7.6 => 3.1.2)
自己的主机上的Hadoop版本是2.7.6,是测试用的伪分布式Hadoop,在前段时间部署了Hive on Spark,但由于没有做好功课,导致了Hive无法正常启动,原因在于Hive 3.x版本不适 ...
- 《恶魔人crybaby》豆瓣短评爬取
作业要求来源:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/3159 爬虫综合大作业 选择一个热点或者你感兴趣的主题. 选择爬取的对象 ...