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++基础(五)——关联容器的更多相关文章

  1. C++基础之关联容器

    关联容器 关联容器和顺序容器的本质区别:关联容器是通过键存取和读取元素.顺序容器通过元素在容器中的位置顺序存储和访问元素.因此,关联容器不提供front.push_front.pop_front.ba ...

  2. 《STL源码剖析》——第五、六:关联容器与算法

    第五章.关联容器  5.0.关联容器 标准的STL关联式容器分为set(集合)和map(映射表)两大类,以及这两大类的衍生体multiset(多键集合)和multimap(多键映射表).这些容器的底层 ...

  3. day 57 Django基础五之django模型层之关联管理器

    Django基础五之django模型层之关联管理器   class RelatedManager "关联管理器"是在一对多或者多对多的关联上下文中使用的管理器.它存在于下面两种情况 ...

  4. C++学习基础四——顺序容器和关联容器

    —顺序容器:vector,list,queue1.顺序容器的常见用法: #include <vector> #include <list> #include <queue ...

  5. C/C++基础----关联容器

    基本属性 与顺序容器的差别,按照关键字来保存和访问,而顺序容器是按照容器中的位置来顺序保存和访问. map:每个元素是一对键值(key-valye)组合:set每个元素只包含关键字.. 每个根据关键字 ...

  6. 容器基础(五): 实现一个简单容器sdocker

    在前面几部分的基础上, 我们更新一下代码,实现一个简单容器 sdocker. sdocker目录构成 linux: # tree . ├── Makefile ├── cpu-test.c # 由cp ...

  7. Bootstrap <基础五>表格

    Bootstrap 提供了一个清晰的创建表格的布局.下表列出了 Bootstrap 支持的一些表格元素: 标签 描述 <table> 为表格添加基础样式. <thead> 表格 ...

  8. c++11の关联容器

    一.关联容器 C++的容器类型可以分为顺序容器和关联容器两大类.对于关联容器,主要有map和set,对于这两种,根据不同的维度,衍生出了8种容器 map                        ...

  9. C#_02.14_基础五_.NET类

    C#_02.14_基础五_.NET类 一.类实例: 我们前面说过类是一个模板,我们通过类创建一个又一个的实例,通常情况下类当中的变量是每一个实例都各有一份的,互相不影响,而静态字段是除外的,静态字段是 ...

随机推荐

  1. 二分图匹配--KM算法

    Kuhn-Munkres算法 KM算法,求完备匹配下的最大权匹配,时间复杂度O(\(n^3\)) 所谓的完备匹配就是在二部图中,x点集中的所有点都有对应的匹配 且 y点集中所有的点都有对应的匹配 ,则 ...

  2. 查vue版本号

    在项目中,找到package.json文件夹 找"dependencies"然后就可以看到你装的vue的版本了.

  3. js之大文件分段上传、断点续传

    文件夹上传:从前端到后端 文件上传是 Web 开发肯定会碰到的问题,而文件夹上传则更加难缠.网上关于文件夹上传的资料多集中在前端,缺少对于后端的关注,然后讲某个后端框架文件上传的文章又不会涉及文件夹. ...

  4. 【洛谷P4319】 变化的道路 线段树分治+LCT

    最近学了一下线段树分治,感觉还蛮好用... 如果正常动态维护最大生成树的话用 LCT 就行,但是这里还有时间这一维的限制. 所以,我们就把每条边放到以时间为轴的线段树的节点上,然后写一个可撤销 LCT ...

  5. Gift to XBACK(小小礼物)

    什么白天 什么黑夜 我没有 准备着给你的 Surprise 你给我的爱 让我觉得已足够 是你让我相信爱会有 是你的爱陪我绕宇宙 打开日记本写下忧愁 你却让我看时间轴 我才知道现在我能看到的画面 拥有你 ...

  6. 洛谷P1265 公路修建题解

    题目描述 某国有n个城市,它们互相之间没有公路相通,因此交通十分不便.为解决这一“行路难”的问题,政府决定修建公路.修建公路的任务由各城市共同完成. 修建工程分若干轮完成.在每一轮中,每个城市选择一个 ...

  7. mysql 获取数学成绩最高以及最低的同学

    mysql> select * from test; +----+----------+-------+-----------+ | id | name | score | subject | ...

  8. 「ZJOI2019」Minmax搜索

    传送门 Solution 叶子节点的变化区间是连续的,可得知非叶子节点的权值变化区间也是连续的 由此可知,\(W\)的变化值的可行域也是连续的,所以只需要看它能否变为\(W+1\)或\(W-1\) 对 ...

  9. ranger 使用外置的solr

    一.solrcloud部署 1.下载部署 1).下载二进制包 #wget http://mirrors.tuna.tsinghua.edu.cn/apache/lucene/solr/8.3.0/so ...

  10. plsql 如何导入excel数据?

      oracle 导入excel数据? 通过plsql实现 1.准备工作 Excel中的字段名称,必须和表结构字段一 一对应 下面以tdoctor_apply表为例,进行演示 表结构 Excel表数据 ...