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

关键字有序保存元素,

map,关联数组,保存关键字-值对,

set,关键字即值,只保存关键字的容器

multimap,关键字可重复出现

multiset,

无序集合

unordered_map,用哈希函数组织的map

unordered_set,用哈希函数组织的set

unordered_multimap,哈希组织的map;关键字可重复出现

unordered_multiset,哈希组织的set;关键字可重复出现

通常map称为关联数组,与数组不同的是其下标不必是整数

//统计每个单词在输入中出现的次数

map<string,size_t> word_count;

string word;

while(cin>>word)

++word_count[word];

for(const auto &w:word_count)

cout<<w.first<<" occurs "<<w.second

<< ((w.second>1)?" times" : " time")<<endl;

定义一个map,我们必须指定关键字和值得类型。如果word还未在map中,下表运算符会创建一个新元素,其关键字为word,值为0

从map中提取一个元素时会得到一个pair类对象,first保存的是关键字

//忽略常见单词,用set保存

map<string,size_t> word_count;

set<string> exclude = {"The", "But", "And", "Or", "An", "A", "the", "but", "and", "or", "an", "a"};

string word;

while(cin>>word)

if(exclude.find(word)==exclude.end())//只统计不在exclude中的单词

++word_count[word];

关联容器都支持普通容器的基本操作,不支持顺序容器的位置相关的操作,如push_front或push_back。原因是关联容器中的元素是根据关键字存储的,这些操作对关联容器是没有意义的。而且,还不支持构造函数或插入操作这些接受一个元素值和一个数量值得操作

关联容器的迭代器是双向的

每个关联容器都定义了一个默认的构造函数,它创建一个指定类型的空容器。我们也可以将关联容器初始化为另一个同类型容器的拷贝,或是从一个范围来初始化关联容器,只要这些值可以转换为容器所需的类型就可以。

multimap或multiset允许多个元素具有相同的关键字。

对于有序的关联容器我们必须定义比较方法。默认是采用<

我们也可以提供自己的操作,但必须满足严格若需

当两个关键字同时关联了同一个元素,我们可以使用其中任何一个访问该元素

bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs)

{

return lhs.isbn() < rhs.isbn();

}

multiset<Sales_data,decltype(compareIsbn)*>      bookstore(compareIsbn);

这里我们使用decltype 来获取一个函数的指针类型时,必须加上一个*来指明我们要使用一个给定函数的指针。用compareIsbn来初始化bookstore对象,表示当我们想bookstore添加元素时,通过调用compareIsbn来为这些元素排序,可以用compareIsbn来代替&compareIsbn作为构造函数的参数,因为当我们使用一个函数名时,在需要的情况下会自动转换成指针,两者效果是一样的

pair定义在uitlity头文件中。pair上的操作:

pair<T1 , T2> p;   初始化,分别制定成员的类型

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

pair<T1 , T2> p = {v1 , v2};

make_pair(v1,v2)      返回一个用v1和v2初始化的pair。pair的类型是从v1和v2推断出来的

p.first    p.second       共有数据成员

两个对象之间可以使用关系运算符比较  p1 relop p2   当p1.first <p2.first  或!(p2.first < p2.first) && p1.second<p2.second 成立时p1<p2

p1 == p2    当first和second成员分别相等是,两个pair才相等

p1 != p2       用==判断

想象有一个函数需要返回一个pair。在新标准下,可以对返回值进行列表初始化

pair<string , int> process(vector<string> &v)

{

if (!v.empty())

return {v.back(), v.beck().size() }; //列表初始化

else

return pair<string , int>(); //隐式构造返回值

}

我们还可以用make_pair来返回

return make_pair(v.back() , v.back().size());

或是早期方法:

return pair<string , int>(v.back() , v.backe().size());

关联容器额外的类型名:

key_type     关键字的类型

mapped_type     每个关键字关联的类型,只适用于map

value_type         对于set与key_type相同,对于map为pair<const key_type,mapped_type>

set 和 map也有const和非const版本的迭代器

通常不对关联容器使用泛型算法,关键字是const,我们可以用只读算法,如find。但不是以个好主意,不能关键字进行(快速)查找。要用自己定义的成员函数的版本

在实际编程中,如果要对关联容器使用算法,要么是将它作为一个源序列,要么是一个目的位置

插入元素:

c.insert(v)     v是一个value_type类型的对象;args用来构造一个元素

c.emplace(args)       对于map和set, 只有当元素的关键字不在c中时才能插入。函数返回一个pair,包含一个迭代器。指向具有关键字的元素,以及一个指示插入是否成功的bool值。对于multimap和multiset,总会插入给定的元素,并返回一个指向新元素的迭代器

c.insert(b,e)    b,e是迭代器,表示一个c::value_type类型值得范围;il是这种值得初始化列表。函数返回void

c.insert(il);        对于set和map,只有插入关键字不存在的。对于multimap和multiset,则会插入范围中的每个元素

c.insert(p,v)   类似insert(v) (或emplace(args))但用p指出从哪里开始搜索新元素应该存储的位置。返回迭代器,指向给定原件字的元素

c.emplace(p,args)

删除操作:

c.erase(k)   从c中删除每个关键字为k的元素,返回一个size_type值。指出删除元素的数量,若果返回0表示要删除的元素么有在容器中

c.erase(p)     从c中删除迭代器p指定的元素。p必须指向c中真是元素,不能等于c.end()。返回一个指向p之后的元素的迭代器,若p指向c中的尾元素 ,则返回c.end()

c.erase(b,e)   删除迭代器b和e所表示的范围中的元素,返回e

由于下标运算符可能插入一个新元素,我们只可以对非const的map使用下标操作。

使用一个不再容器中的关键在作为下标,会添加一个具有此关键字的元素到map中。

c[k]

c.at(k)    访问关键字为k的元素,dai参数检查;若k不在c中,抛出一个out_of_range异常。

当对一个map进行下标操作时,会获得一个mapped_type的对象;担当解引用以个map迭代器时,会得到一个value_type对象

在一个关联容器中查找元素的操作:

lower_bound和upper_bound不适合于无序容器。

下标和at操作只适用于非const的map和unordered_map

c.find(k)   返回一个迭代器,指向第一个关键字为k的元素,若k不在容器中,则返回尾后迭代器

c.count(k)   返回关键字等于k的元素的数量。对于不允许重复关键字的容器,返回值永远是0或1

c.lower_bound(k)   返回一个迭代器,指向第一个关键字不小于k的元素

c.upper_bound(k)   返回一个迭代器,指向第一个关键字大于k的元素

c.equal_range(k)     返回一个迭代器pair,  表示关键字等于k的元素的范围。若k不存在,pair的两个成员等于c.end()

如果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;

}

当我们遍历一个multimap或multiset时,保证可以得到序列中所有具有给定关键字的元素

如果关键字在容器中,lower_bound返回的迭代器将指向第一个具有给定关键字的元素,upper_bound返回的迭代器将指向最后一个匹配给定关键字的元素之后的位置。用相同的关键字调用lower_bound和upper_bound会得到一个迭代器范围,表示所有具有该关键字的元素范围

这两个迭代器都有可能是尾后迭代器,如果我们查找的元素具有容器中的最大关键字,则此时关键字的upper_bound返回尾后迭代器。如果关键字不存在,且大于容器中任何关键字,则lower_bound返回的也是尾后迭代器。

lower_bound返回的迭代器可能指向一个具有给定关键字的元素,但也可能不指向。如果关键字不在容器中,则lower_bound会返回关键字的第一个安全插入点。

//重写前面的程序

for(auto beg=authors.lower_bound(search_item),end=authors.upper_bound(serch_item);beg!=end;++beg)

cout<<beg->second<<endl;

如果没有元素与给定的关键字匹配,则lower_bound和upper_bound会返回相等的迭代器,都指向给定关键字的插入点。

用equa_range再次修改我们的程序:

for(auto pos=authors.equal_range(search_item); pos.first != pos.second; ++pos.first)

cout<<pos.first->second<<endl;

无序关联容器使用一个哈希函数和关键字类型的==运算符来组织元素,是无序的,通常使用无序容器更为简单,性能也更好

如果关键字类型固有就是无序的,或者性能测试发现问题可以用哈希技术解决,就可以使用无序容器

除了哈希管理操作之外,无序容器还提供了于有序容器相同的操作(find、insert等),就是用于map。set的函数也能用于unordered_set和unordered_map,同样的无序容器也有multi_版本

//重写单词计数程序,唯一的区别是word_count的类型,得到的结果一样,就是顺序不太一样

unordered_map<string , size_t> word_count;

string word;

while (cin >> word)

++word_count[word];

for(const auto &w : word_count)

cout<<w.first<<" occurs "<<w.second<<((w.secound>1)?" times":" time")<<endl;

无序容器管理操作:

桶接口:

c.bucket_count()      正在使用的桶的个数

c.max_bucket_count()       容器能容纳的最多的桶的数量

c.bucket_size(n)      第n个桶中有多少元素

c.bucket_size(k)       关键字为k的元素在哪个桶中

桶迭代

local_iterator      可以用来访问桶中的元素的迭代器类型

const_local_iterator      桶迭代器的const版本

c.begin(n),c.end(n)      桶n的首元素和尾后迭代器

c.cbegin(n),c.cend(n)     const版本

哈希策略

c.load_factor()       每个桶的平均元素数量,返回float值

c.max_load_factor()        c试图维护的平均桶大小,返回float值。c会在需要时添加新的桶,以使load_factor<=max_load_factor

c.rehash(n)        重组存储,以使得backet_count >= n且backet_count>size/max_load_factor

c.reserve(n)      重组存储。使得c可以保存n个元素且不必rehash

对于无序容器,他们还定义了一个hash<key_type>类型的对象来生成每个元素的哈希值。标准库为内置类型(包括指针)提供了hash模板,还为一些标准库类型,包括string和智能指针定义了hash。因此可以直接定义无序容器

但是,我们不能直接定义关键字类型为自定义类类型的无序容器。于容器不同,不能直接使用哈希模板,而必须提供自己的hash模板版本

我们不使用默认方式而是一种类似于为有序容器添加重载关键字的默认比较操作。

size_t hasher(const Sales_data &sd)

{

return hash<string>()(sd.isbn());//调用构造函数

}

bool eqOp(const Sales_data &lhs, const Sales_data &rhs)

{

return  lhs.isbn() == rhs.isbn();

}

using SD_multiset = unordered_multiset<Sales_data, decltype(hasher)*, decltype(eqOp)*>

SD_multiset bookstore(42,hasher,eqOp);

当然如果我们的类定义了 == 我们只重载hash函数就行。

时间: 2024-08-03 07:09:37

C++11(10):关联容器的相关文章

C++ Primer学习总结 第11章 关联容器

第11章 关联容器 1.    使用map的简单例子: 运行结果为: 2.    初始化map和set: 3.    set与multiset的区别: 4.    使用map和set时,其元素类型必须是定义了严格弱序的(即定义了<号比较的),如果元素类型没有定义<号操作也可以通过外部函数来比较: 5.    pair类型:pair是一个用来生成特定类型的模板. pair的默认构造函数对数据成员进行值初始化. 6.    遍历map和set关联容器: 7.    如何往set和map中添加指定元

第11章 关联容器

map,管理数组,存储“关键字-值” set,简单集合,存储“关键字” 四个关联容器的头文件map.set.unordered_map.unordered_set 关联容器有8种,特点如下: 每个容器都是set或者map 分为允许关键字重复(multi)和不允许关键字重复 顺序保存和无序保存(unordered,哈希函数组织的结构) unordered_multiset是一个允许关键字重复,元素无序保存的集合 set是一个要求关键字不重复,元素有序保存的集合 map<string, size_t

《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 10 关联容器

关联容器和顺序容器的本质差别在于:关联容器通过键(key)存储和读取元素,顺序容器则通过元素在容器中的位置顺序存储和访问元素 关联容器类型 map 关联数组:元素通过键来存储和读取 set 大小可变的集合,支持通过键实现的快速读取 multimap 支持同一个键多次出现的 map 类型 multiset 支持同一个键多次出现的 set 类型 pair类型 pair是一种模版类型,在创建pair对象,必须提供两个类型名. 头文件 utility pairs 类型提供的操作 pair<T1, T2>

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

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

《C++primer(第五版)》学习之路-第十一章:关联容器

[ 声明:版权所有,转载请标明出处,请勿用于商业用途.  联系信箱:[email protected]] 11.1 使用关联容器 1. 关联容器类型 按关键字有序保存元素 map                    关联数组,保存关键字-值对 set                      关键字即值,即只保存关键字的容器 multimap            关键字可重复出现的map multiset              关键字可重复出现的set 无序集合 unordered_ma

无序关联容器(C++11)

2012-11-27 15:22 张海龙/袁国忠 译 人民邮电出版社 字号:T|T <C++Primer Plus(第6版)(中文版)>附录G标准模板库方法和函数:本附录总结了STL容器方法和通用的STL算法函数.本节为大家介绍无序关联容器(C++11). AD: G.4  无序关联容器(C++11) 前面说过,无序关联容器(unordered_set.unordered_multiset.unordered_map和 unordered_multimap)使用键和哈希表,以便能够快速存取数据

【C++ Primer 第11章】《关联容器》目录

关联容器 •   set的用法 原文地址:https://www.cnblogs.com/sunbines/p/9155009.html

C++拾遗(七)——关联容器

关联容器(Associative containers)支持通过键来高效地查找和读取元素.两个基本的关联容器类型是 map 和set.map 的元素以键-值(key-value)对的形式组织:键用作元素在 map 中的索引,而值则表示所存储和读取的数据.set仅包含一个键,并有效地支持关于某个键是否存在的查询.set 和 map 类型的对象所包含的元素都具有不同的键,不允许为同一个键添加第二个元素.如果一个键必须对应多个实例,则需使用 multimap 或 multiset,这两种类型允许多个元