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类 一.类实例: 我们前面说过类是一个模板,我们通过类创建一个又一个的实例,通常情况下类当中的变量是每一个实例都各有一份的,互相不影响,而静态字段是除外的,静态字段是 ...
随机推荐
- centos gcc 新版本安装的一种方法
最近出来一个v 语言,打算试用下,但是需要编译,centos 7 gcc 版本太低,一种可选的解决方法 使用Software Collections Software Collections 安装方法 ...
- zabbix-trap
安装 yum -y install zabbix-sender zabbix sender 在客户端给server端发送信息, -z 指定server的ip -p 指定端口 10051 -s 被监控设 ...
- 移动端touch触摸事件(滑动效果和手势操作)
一.定义 ①touch是移动端的触摸事件,而且是一组事件,主要有以下事件: touchstart 事件:当手指触摸屏幕的时候触发 touchmove 事件:当手指在屏幕来回滑动的时候触发 touche ...
- CSS链接伪类:超链接的状态
一.状态: a:link{属性:值;} 链接默认状态 a:visited{属性:值;} 链接访问之后的状态 a:hover{属性:值;} 鼠标放到链接上显示的状态 a:active{属性:值;} 链接 ...
- 1-ESP8266 SDK开发基础入门篇--开发环境搭建
因为今天终于做好了自己的另一块工控板,所以我就开始写基础公开篇的内容,希望自己小小的努力能够帮到大家 自己做的另一块板子 https://www.cnblogs.com/yangfengwu/cate ...
- 2、kafka集群搭建
以三台为例,先安装一台,然后分发: 一.准备 1.下载 http://kafka.apache.org kafka_2.11-2.0.1.tgz 前面的数字2.11是scala的版本,2.0.1是ka ...
- JavaScript操作BOM
window对象的属性: history: 方法: back() 加载 history 对象列表中的前一个URL forward() 加载 history 对象列表中的下一个URL go() 加载 h ...
- leetcode 删除一张表中重复邮箱的数据,并且保留最小id 的 那条
/* create view testview as SELECT subject,MIN(Id) as id FROM test GROUP BY subject; select * FROM te ...
- Java获取两个指定日期之间的所有月份
String y1 = "2016-02";// 开始时间 String y2 = "2019-12";// 结束时间 try { Date startDate ...
- hbase 由于zookeeper问题导致连接失败问题
问题现象: 使用hbase shell 连接报如下问题: 2019-10-09 10:37:18,855 ERROR [main] zookeeper.RecoverableZooKeeper: Zo ...