关联容器
使用关联容器
关联容器
使用关联容器
map
1 | //统计每个单词在输入中出现的次数 |
set
1 | //统计输入中每个单词出现的次数 |
关联容器概述
定义关联容器
1 | map<string,size_ t> word_ count; //空容器 |
初始化multimap或multiset
multi容器允许多个元素具有相同的关键字:
1 | // 定义一个有20个元素的vector,保存0到9每个整数的两个拷贝 |
关键字类型的要求
对于有序容器中的关键字类型必须定义比较元素的方法。
使用关键字类型比较函数
可以指定一个比较函数来进行比较,需要在容器定义时紧跟着关键字类型给出。
当使用Sales_data类时因为没有<运算符,所以我们需要自己定义:
1 | bool compareIsbn (const Sales_data &1hs, const Sales_data &rhs) |
使用decltype指出自定义操作的类型,必须加上*指出给定的函数指针。
pair类型
在头文件utility中,一个pair保存两个数据成员:
1 | pair<string, string> anon; //保存两个string |
也可以使用列表初始化
1 | pair<string, string> author{"James", "Joyce"}; |
成员均为public使用first和second进行访问
1 | //打印结果 |
返回pair的函数
1 | pair<string,int> process (vector<string> &V) |
else中返回的是一个空pair
早期版本中不可以列表初始化返回则必须显示构造或使用make_pair来生成:
1 | if (!v.empty()) |
关联容器的操作
关联容器迭代器
解引用关联容器得到迭代器得到一个value_type,对于map得到一个pair,first成员中保存的是const关键字,它是不可以更改的,second保存值。而set中value_type与value_type是一样的。
遍历关联容器
使用迭代器遍历容器
1 | //获得一个指向首元素的迭代器 |
打印出来的函数为升序排列。
关联容器和算法
通常不对关联容器使用泛型算法,关键字的const特性意味着不可以重排或修改元素,set中的元素时const的,所以只可以使用只读的算法,推荐使用容器内部的find,它会比泛型算法快得多,泛型find使用的是顺序搜索。
添加元素
使用insert添加一个元素或元素范围,
1 | //set容器 |
检测insert返回值
insert返回值依赖容器类型和参数,对于map和set,添加单一元素返回的是一个pair,first指向给定的关键字元素,second是bool值,指出插入成功还是失败(已存在)。
1 | //统计每个单词在输入中出现次数的一种更烦琐的方法 |
展开递增语句
++ret.first->second;
这句话就代表增加插入的那个元素中的second++。
multi容器添加元素
这种容器可以包含多个相同的关键字
1 | mul timap<string, string> authors; |
删除元素
erase可以接受一个迭代器或者是一对迭代器来删除一个或一个范围的元素。还可以接受一个key_type,删除所匹配的关键字元素。
1 | //删除一个关键字,返回删除的元素数量 |
如果是multi容器,可能删除多个元素
1 | auto cnt = authors.erase ("Barth,John") ; |
上面authors中添加了两个相同的元素,则cnt等于2。
map的下标操作
map和unordered_map具有下标运算和at函数,set中不可以使用。
map通过下标运算,接受一个索引(即关键字)获取与之关联的值,但不同的是,如果没有此关键字,会创建一个关键字,并将对应的值初始化。
1 | map <string, size_t> word_count; / / empty map |
- 在word_ _count中搜索关键字为Anna的元素,未找到。
- 将一个新的关键字-值对插入到word _count中。关键字是-一个const string,保存Anna。值进行值初始化,在本例中意味着值为0。
- 提取出新插入的元素,并将值1赋予它。
使用下标操作的返回值
通常解引用的一个迭代器的类型与下标运算返回的类型是一样的,但map不同,会得到有个mappped_type对象,且为左值。
访问元素
count可以统计元素个数,对于不允许重复元素存在的容器,推荐使用find。
map使用find代替下标操作
map容器的下标操作如果关键字不存在,则会插入这个新的关键字,所以在只是想知道有没有这个关键字时可以用find代替。
multi容器查找元素
方法一:
1 | string search_ item("Alain de Botton") ; //要查找的作者 |
方法二
lower_bound和up_bound分别返回匹配的第一个位置和最后一个位置的后一个位置。不存在则返回可插入位置
1 | // authors 和search_ item 的定义,与前面的程序一样 |
方法三
equal_range函数接受关键字,返回pair。若关键字存在则第一个指向第一个与之匹配的位置,第二个是最后一个与之匹配位置的后一个位置。若不存在则返回可插入位置。
1 | // authors 和search_item的定义, 与前面的程序一样 |
单词转换map(跳)
无序容器
使用无序容器
unordered_map或者unordered_set,他们都有与前面类似的操作,通常可以用一个无序容器替换对应的有序容器,但顺序会与有序容器不同。
管理桶
无序容器在储存上为一组桶,无序容器使用一个哈希函数将所有元素映射到桶中,容器将具有一个特定的哈希值的所有元素保存在相同的桶中,访问时先按照哈希值找到对应的桶,再在桶中找对应的元素。因此容器性能依赖哈希函数的质量和桶的数量和大小。
最理想的情况应该是哈希函数将所有元素尽可能的均匀的分配到每个桶中。
无序容器对关键字类型的要求
默认情况下,无序容器使用关键字类型的==运算符来比较元素,还使用一个hash
但是我们不能直接定义关键字类型为自定义类类型的无序容器。可以不直接使用哈希模板而是使用自己的hash版本。例如Sale_data用作关键字,我们需要提供函数来代替==运算符和哈希计算函数。
1 | size_t hasher(const Sales_ data &sd) |
1 | using SD_multiset = unordered multiset<Sales_data, |
如果类内具有==运算符,可以只重载哈希函数
1 | //使用FooHash生成哈希值; Foo必须有==运算符 |