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类 一.类实例: 我们前面说过类是一个模板,我们通过类创建一个又一个的实例,通常情况下类当中的变量是每一个实例都各有一份的,互相不影响,而静态字段是除外的,静态字段是 ...
随机推荐
- Goexit
package main import ( "fmt" "runtime" ) func test() { defer fmt.Println("cc ...
- 解决bash: less: command not found
问题描述 使用less命令查找日志时,less命令未找到: 解决办法 安装less,执行如下命令: npm install -g less
- .net core 多sdk 多版本 环境切换
在讲述.net core多版本之前,我们先理解一下.net core sdk与.net core runtime之前的联系与区别,根据官网的解释我们可以简单地理解为:sdk是在开发过程中进行使用,而r ...
- pip包管理工具 基本使用
# 简介 pip是一款包管理工具, 和apt, yum, brew功能类似 # 安装 wget --no-check-certificate https://bootstrap.pypa.io/get ...
- 25-ESP8266 SDK开发基础入门篇--控制WIFI连接路由器
https://www.cnblogs.com/yangfengwu/p/11324411.html 说个事情,现在SDK的版本已经出到3.0了,但是我还是使用2.0 如果只是为了学习研究 选择3 ...
- 洛谷 P4707 重返现世
洛谷 P4707 重返现世 k-minimax容斥 有这一个式子:\(E(\max_k(S))=\sum_{T\subseteq S}(-1)^{|T|-k}C_{|T|-1}^{k-1}\min(T ...
- ajax post data 获取不到数据,注意 content-type的设置 、post/get(转)
ajax post data 获取不到数据,注意 content-type的设置 .post/get 关于 jQuery data 传递数据.网上各种获取不到数据,乱码之类的. 好吧今天我也遇到了 ...
- 【06NOIP普及组】数列(信息学奥赛一本通 1937)(洛谷 1062)
[题目描述] 给定一个正整数k(3≤k≤15),把所有k的方幂及所有有限个互不相等的k的方幂之和构成一个递增的序列,例如,当k=3时,这个序列是: 1,3,4,9,10,12,13,… (该序列实际上 ...
- CNN中各类卷积总结:残差、shuffle、空洞卷积、变形卷积核、可分离卷积等
CNN从2012年的AlexNet发展至今,科学家们发明出各种各样的CNN模型,一个比一个深,一个比一个准确,一个比一个轻量.我下面会对近几年一些具有变革性的工作进行简单盘点,从这些充满革新性的工作中 ...
- 算法练习题---罗马数字转int
连接:https://leetcode-cn.com/problems/roman-to-integer/submissions/ 题目: 罗马数字包含以下七种字符: I, V, X, L,C,D 和 ...