c++ primer 10 关联容器

关联容器和顺序容器的本质差别在于:关联容器通过键(key)存储和读取元素,顺序容器则通过元素在容器中的位置顺序存储和访问元素

关联容器类型


map


关联数组:元素通过键来存储和读取


set


大小可变的集合,支持通过键实现的快速读取


multimap


支持同一个键多次出现的 map 类型


multiset


支持同一个键多次出现的 set 类型

pair类型

pair是一种模版类型,在创建pair对象,必须提供两个类型名。

头文件 utility

pairs 类型提供的操作


pair<T1, T2> p1;


创建一个空的 pair 对象,它的两个元素分别是T1 和 T2 类型,采用值初始化


pair<T1, T2> p1(v1, v2);


创建一个 pair 对象,它的两个元素分别是 T1 和 T2 ,其中 first 成员初始化为 v1,而 second 成员初始化为 v2


make_pair(v1, v2)


以 v1 和 v2 值创建一个新 pair 对象,其元素类型分别是 v1 和 v2 的类型


p1 < p2


两个 pair 对象之间的小于运算,其定义遵循字典次序:如果 p1.first < p2.first 或者 !(p2.first < p1.first) && p1.second < p2.second,则返回
true


p1 == p2


如果两个 pair 对象的 first 和 second 成员依次相等,则这两个对象相等。该运算使用其元素的 == 操作符


p.first


返回 p 中名为 first 的(公有)数据成员


p.second


返回 p 的名为 second 的(公有)数据成员

pair对象的创建(三种方法:直接初始化,.firs .second ,make_pair)

10.2

 1 #include <iostream>
 2 using namespace std;
 3 #include <utility>
 4 #include <vector>
 5
 6 int main()
 7 {
 8     vector< pair<string,int> > vec;
 9     string str;
10     int n;
11     cout<<"Enter a string and an integer(Ctrl +Z to end)"<<endl;
12     while(cin>>str>>n)
13     {
14         pair<string,int> pr1(str,n);//直接创建pair对象
15         vec.push_back(pr1);
16
17         pair<string,int> pr2;//使用make_pair创建pair对象
18         pr2 = make_pair(str,n);
19         vec.push_back(pr2);
20
21         pair<string,int> pr3;//用成员first,second创建pair对象
22         pr3.first = str;
23         pr3.second = n;
24         vec.push_back(pr3);
25     }
26
27     vector< pair<string,int> >::iterator ite = vec.begin();
28     while(ite != vec.end())
29     {
30         cout<<(*ite).first<<" "<<(*ite).second<<endl;
31         ite++;
32     }
33
34     return 0;
35 }

map类型

定义map对象时,必须分别指明键和值的类型

map 对象的定义


map<k, v> m;


创建一个名为 m 的空 map 对象,其键和值的类型分别为 k 和 v


map<k, v> m(m2);


创建 m2 的副本 mm 与 m2 必须有相同的键类型和值类型


map<k, v> m(b, e);


创建 map 类型的对象 m,存储迭代器 b 和 e 标记的范围内所有元素的副本。元素的类型必须能转换为 pair<const k, v>

在使用关联容器时,它的键不但有一个类型,而且还有一个相关的比较函数。 所用的比较函数必须在键类型上定义严格弱排序。所谓的严格弱排序可理解为键类型数据上的“小于”关系。对于键类型,唯一的约束就是必须支持 < 操作符

map 类定义的类型


map<K, V>::key_type


在 map 容器中,用做索引的键的类型


map<K, V>::mapped_type


在 map 容器中,键所关联的值的类型


map<K, V>::value_type


一个 pair 类型,它的 first 元素具有 const map<K, V>::key_type 类型,而 second 元素则为 map<K, V>::mapped_type 类型

map的键值是不能修改的,必须先删除再添加

map迭代器返回value_type类型的值——包含const key_type和mapped_type类型的值

使用下标访问map对象

访问不存在的元素将导致在map容器中添加一个新元素,它的键即为该下标值

map下标操作符返回mapped_type,map迭代器返回pair类型

添加新元素可以利用下标行为的特点:

10.9 编写程序统计并输入所读入单词出现的次数

#include <iostream>
using namespace std;
#include <map>
#include <string>

int main()
{
    map<string,int> word_count;
    string str;
    cout<<"Enter some words(Ctrl + Z to end:)"<<endl;
    while(cin>>str)
        ++word_count[str];
    map<string,int>::iterator ite = word_count.begin();
    while(ite != word_count.end())
    {
        cout<<(*ite).first<<"\t"<<(*ite).second<<endl;
        ite++;
    }

    return 0;
}

map::insert

容器提供的 insert 操作


m.insert(e)


e 是一个用在 m 上的 value_type 类型的值。如果键(e.first)不在 m 中,则插入一个值为 e.second 的新元素;如果该键在 m 中已存在,则保持 m 不变。该函数返回一个 pair 类型对象,包含指向键为 e.first 的元素的 map 迭代器,以及一个 bool 类型的对象,表示是否插入了该元素


m.insert(beg,end)


beg 和 end 是标记元素范围的迭代器,其中的元素必须为 m.value_type 类型的键-值对。对于该范围内的所有元素,如果它的键在 m 中不存在,则将该键及其关联的值插入到 m。返回void 类型


m.insert(iter, e)


e 是一个用在 m 上的 value_type 类型的值。如果键(e.first)不在 m 中,则创建新元素,并以迭代器 iter 为起点搜索新元素存储的位置。返回一个迭代器,指向 m 中具有给定键的元素

比如:

word_count.insert(map<string,int>value_type("a",1))

传递给 insert 的实参相当笨拙。可用两种方法简化:使用 make_pair:

word_count.insert(make_pair("Anna", 1));

或使用 typedef

typedef map<string,int>::value_type valType;
word_count.insert(valType("Anna", 1));

insert返回类型是pair对象,包含一个迭代器和一个bool。如果键已在容器中,bool返回false;不在返回true。这两种情况下迭代器都指向具有给定键的元素

也就是说insert的参数和返回值都是pair类型,返回值pair.second是bool类型

 1 #include <iostream>
 2 using namespace std;
 3 #include <map>
 4 #include <string>
 5 #include <utility>
 6
 7 int main()
 8 {
 9     map<string,int> word_count;
10     string str;
11     cout<<"Enter some words(Ctrl + Z to end:)"<<endl;
12     while(cin>>str)
13     {
14         pair< map<string,int>::iterator,bool > ret =
15             word_count.insert(make_pair(str,1));
16         if( !ret.second )
17             ++ret.first->second;    //如果插入元素存在,.second加一
18     }
19
20     map<string,int>::iterator ite = word_count.begin();
21     while(ite != word_count.end())
22     {
23         cout<<(*ite).first<<"\t"<<(*ite).second<<endl;
24         ite++;
25     }
26
27     return 0;
28 }

以上用下标和用insert方法就是map插入元素的两种方法

查找并读取map中的元素

不修改 map 对象的查询操作


m.count(k)


返回 m 中 k 的出现次数


m.find(k)


如果 m 容器中存在按 k索引的元素,则返回指向该元素的迭代器。如果不存在,则返回超出末端迭代器

注意这里对m.count(k)返回值的理解,对map,返回值只有0或者1,k出现的次数是对multimap容器

用两种方法返回.second

1 int count;
2 if(word_count.count(‘a‘))
3     count = word_count("a")
4 map<string,int>::iterator ite = word_count.find("a");
5 if(ite != word.count.end())
6     count = ite->second;

注意:对于用迭代器表示map中的元素可以用(*ite).frist,等价于用ite->first,遍历的两种表示

从 map 对象中删除元素


m.erase(k)


删除 m 中键为 k 的元素。返回 size_type 类型的值,表示删除的元素个数


m.erase(p)


从 m 中删除迭代器 p 所指向的元素。p 必须指向 m 中确实存在的元素,而且不能等于 m.end()。返回 void


m.erase(b,e)


从 m 中删除一段范围内的元素,该范围由迭代器对 b 和 e 标记。b 和 e 必须标记 m 中的一段有效范围:即 b 和 e 都必须指向 m 中的元素或最后一个元素的下一个位置。而且,b 和 e 要么相等(此时删除的范围为空),要么 b 所指向的元素必须出现在 e 所指向的元素之前。返回 void 类型

 set

当只想知道一个值是否存在时,使用 set 容器是最适合的。

两种例外包括:set 不支持下标操作符,而且没有定义 mapped_type 类型。在 set 容器中,value_type 不是 pair 类型,而是与 key_type 相同的类型。它们指的都是 set 中存储的元素类型。这一差别也体现了 set 存储的元素仅仅是键,而没有所关联的值。与 map 一样,set 容器存储的键也必须唯一,而且不能修改。

插入

可使用 insert 操作在 set 中添加元素:

set<string> set1; // empty set
 
set1.insert("the"); // set1 now has one element

 
set1.insert("and"); // set1 now has two elements

另一种用法是,调用 insert 函数时,提供一对迭代器实参,插入其标记范围内所有的元素。该版本的 insert 函数类似于形参为一对迭代器的构造函数——对于一个键,仅插入一个元素:

set<int> iset2;  // empty set
iset2.insert(ivec.begin(), ivec.end()); // iset2 has 10 elements

与 map 容器的操作一样,带有一个键参数的 insert 版本返回 pair类型对象,包含一个迭代器和一个 bool 值,迭代器指向拥有该键的元素,而 bool 值表明是否添加了元素。使用迭代器对的insert 版本返回 void 类型。

正如不能修改 map 中元素的键部分一样,set 中的键也为 const

// set_it refers to the element with key == 1     
set<int>::iterator set_it = iset.find(1);     

*set_it = 11; // error: keys in a set are read-only
 
cout << *set_it << endl; // ok: can read the key

map 和 set 容器中,一个键只能对应一个实例。而 multiset 和 multimap 类型则允许一个键对应多个实例。 注意到,关联容器 map 和 set 的元素是按顺序存储的。而 multimap 和 multset 也一样。因此,在 multimap 和 multiset 容器中,如果某个键对应多个实例,则这些实例在容器中将相邻存放。 迭代遍历 multimap 或 multiset 容器时,可保证依次返回特定键所关联的所有元素。

小结

关联容器的元素按键排序和访问。关联容器支持通过键高效地查找和读取元素。键的使用,使关联容器区别于顺序容器,顺序容器的元素是根据位置访问的。

map 和 multimap 类型存储的元素是键-值对。它们使用在 utility 头文件中定义的标准库 pair 类,来表示这些键-值对元素。对 map 或 multimap 迭代器进行解引用将获得 pair类型的值。pair 对象的first 成员是一个 const 键,而 second 成员则是该键所关联的值。set 和 multiset 类型则专门用于存储键。在 map 和 set 类型中,一个键只能关联一个元素。而multimap 和 multiset 类型则允许多个元素拥有相同的键。

关联容器共享了顺序容器的许多操作。除此之外,关联容器还定义一些新操作,并对某些顺序容器同样提供的操作重新定义了其含义或返回类型,这些操作的差别体现了关联容器中键的使用。

关联容器的元素可用迭代器访问。标准库保证迭代器按照键的次序访问元素。begin操作将获得拥有最小键的元素,对此迭代器作自增运算则可以按非降序依次访问各个元素。

时间: 2024-10-23 07:20:38

c++ primer 10 关联容器的相关文章

C++11(10):关联容器

关键字有序保存元素, map,关联数组,保存关键字-值对, set,关键字即值,只保存关键字的容器 multimap,关键字可重复出现 multiset, 无序集合 unordered_map,用哈希函数组织的map unordered_set,用哈希函数组织的set unordered_multimap,哈希组织的map:关键字可重复出现 unordered_multiset,哈希组织的set:关键字可重复出现 通常map称为关联数组,与数组不同的是其下标不必是整数 //统计每个单词在输入中出

【足迹C++primer】37、关联容器概述

关联容器概述 关联容器不支持顺序容器的位置操作,如push_back或push_front 也不支持构造函数或插入操作这些接受一个元素值和一个数量值的操作. 定义关联容器 这里注意哦,我这是一个函数,里面关联容器map是包含在头文件map中的!!! 还有就是set是包含在头文件set中的,string是包含在头文件string中的!!! //关联容器初始化 void fun1() { map<string, size_t> word_count; //空容器 //列表初始化 set<st

C++ Primer笔记7_STL之关联容器

关联容器 与顺序容器不同,关联容器的元素是按关键字来访问和保存的.而顺序容器中的元素是按他们在容器中的位置来顺序保存的. 关联容器最常见的是map.set.multimap.multiset map的元素以键-值[key-value]对的形式组织:键用作元素在map中的索引,而值则表示所存储和读取的数据. set仅包含一个键,并有效的支持关于某个键是否存在的查询. pair类型 首先介绍下pair,pair定义在utility头文件中,一个pair保存两个数据成员,类似容器,pair是一个用来生

0717-----C++Primer听课笔记----------STL之关联容器

1.Map 1.1 map<K, V>是一种pair的容器,pair的种类是pair<K, V>.map采用下标访问一个已存在的key, 会更新value,访问map中不存在的元素时,会增加一个新的键值对.map中的元素按照key进行从小到大排列.map的底层实现是采用二叉树,一般是使用红黑树. #include <iostream> #include <string> #include <map> using namespace std; /*

c++ primer(第五版)学习笔记及习题答案代码版(第十一章)关联容器

笔记较为零散,都是自己不熟悉的知识点. 习题答案至于一个.cc 中,包含Chapter7.h头文件,读入文件包括./test ./rules .需要演示某一题直接修改 #define NUM****, 如运行11.23题为#define NUM1123: chapter 11 1.  关联容器不支持顺序容器的位置相关的操作,例如push_front或push_back.原因是关联容器中元素是根据关键字存储的,这些操作对 关联容器没有意义.而且关联容器也不支持构造函数或插入操作这些接收一个元素值和

【足迹C++primer】38、关联容器操作(2)

关联容器操作(2) map的下标操作 map的下标操作 map和unordered_map容器提供了下标运算符合一个对应的at函数 对于一个map使用下标操作,其行为与数组或vector上的下标操作很不相同: 使用一个不再容器中的关键字作为下标,会添加一个此关键字的元素到map中 map和unordered_map的下标操作 c[k] 返回关键字为k的元素,如果关键字k不再c中,添加一个关键字为k的元素,对其进行值初始化 c.at(k) 访问关键字为k的元素,带参数检测,如果k不再c重那么返回一

C++primer第十章 关联容器

关联容器和顺序容器的本质差别在于:关联容器通过键(key)存储和读取元素,而顺序容器则通过元素在容器中的位置顺序存储和访问元素. 一般来说,如果希望有效地存储不同值的集合,那么使用 set 容器比较合适,而 map 容器则更适用于需要存储(乃至修改)每个键所关联的值的情况.在做某种文本处理时,可使用 set 保存要忽略的单词.而字典则是 map 的一种很好的应用:单词本身是键,而它的解释说明则是值. set 和 map 类型的对象所包含的元素都具有不同的键,不允许为同一个键添加第二个元素.如果一

《C++primer》v5 第11章 关联容器 读书笔记 习题答案

11.1 map是关联容器,vector是顺序容器 11.2 略 11.3 int main() { map<string,int> word; string s; while(cin>>s) word[s]++; for(auto i:word) cout<<i.first<<" "<<i.second<<endl; return 0; } 11.4 void convers(string &s) { s

【足迹C++primer】36、使用关联容器

使用关联容器 两个主要的关联容器map和set 8个容器:(1)或者是一个set一个map:(2)或者要求不重复的关键字,或者允许重复关键字: (3)按顺序保存元素,或无序保存.允许重复关键字的容器的名字中都包含单词multi:不 保持关键字按顺序存储的容器的名字都以单词unordered开头. map类型常常被叫成关联容器,这个是关键字查找 set就是全由关键字组成 这次写博客的时候有点晚,早上有考试,没办法,不然挂了那就 咳咳,还有现在我发现一个写好博客的好方法了,我不在边写博客边看书了,感