c++ 关联容器

c++ 第十一章:关联容器

2:在c++中,顺序容器和关联容器之间本质的区别在于:关键字,关联容器中的元素是按照关键字来保存的,顺序容器中的元素是按照它们在容器中的位置来保存的。

3:我们可以按照关键字是否有序或者是否允许重复关键字来区分关联容器。

  • 关键字有序:map,set,multimap,multiset,它们按照有序存储的。
  • 关键字无序:unordered_map,unordered_set,unordered_multimap,unordered_multiset。它们按照hash来组织。

4:关联容器不支持顺序容器相关的操作,例如push_front或者push_back,原因是关联容器中的值是按照关键字存储的。

5:带有multi的都是允许重复关键字的。允许我们重复添加。

#include
#include
#include

using std::cout;
using std::cin;
using std::endl;

int main(int argc,char *argv[])
{
    std::vector<int> ivec;
    for(std::vector<int>::size_type i = 0;i != 10;++i) {
        ivec.push_back(i);   
        ivec.push_back(i);   //我们再次重复添加
    }
    //对于iset,不允许重复关键字
    std::set<int> iset(ivec.cbegin(),ivec.cend());
    //对于multiset允许重复关键字
    std::multiset<int> miset(ivec.cbegin(),ivec.cend());
    for(auto u:ivec) cout << u << " "; cout << endl;
    for(auto u:iset) cout << u << " "; cout << endl;
    for(auto u:miset) cout << u << " "; cout << endl;
    return 0;
}

这里写图片描述

6:pair类型

一个pair保存两个数据成员,类似容器,pair是一个用来生成特定类型的模板,当创建一个pair时候,必须提供两个类型名,map中的元素类型就是pair。下面是pair的一些操作

操作 含义
pair 定义一个pair,类型为T1和T2,默认进行值初始化
pair p(v1,v2) = pairp = {v1,v2} 用v1和v2分别对first和second成员进行了初始化
make_pair(v1,v2) 返回一个用v1和v2初始化的pair,pair的类型从v1和v2推断
p.first 返回第一个成员
p.second 返回第二个成员
==,!=,<,>,<=,>= pair支持算术运算符

7:关联容器迭代器

(1):map的value_type是pair类型的,第一个参数也就是.first即关键字,是不能被修改的。

(2):set的迭代器是const类型的。也就是我们只能读取一个set集合中的元素,而不能通过迭代器修改它。

(3):当我们使用迭代器遍历一个map、set、multimap、multiset时候,是按照关键字升序来遍历元素的。

(4):添加元素

操作 含义
c.insert(v),c.emplace(v) 插入v,对于map和set,当关键字不存在时才插入,返回的是一个pair(.first成员是一个迭代器,.second成员是一个bool值,表示插入是否成功)
c.insert(b,e) b和e是迭代器,表示一个范围
c.insert(p,v) 类似于insert(v),但是将迭代器p作为一个提示,指出从哪里搜索新元素应该存储的位置

(5):删除元素

操作 含义
c.erase(k) 从c中删除每个关键字为k的元素,返回一个size_type的值,指出删除的数量
c.erase(p) 从c中删除迭代器p指定的元素,返回一个迭代器指向被删除元素之后的元素
c.erase(b,e) 删除迭代器b和e所表示范围中的元素。返回e

(6):map的下标操作

  • 只有map和unorderedmap支持下标操作。
  • 如果下标操作接受的关键字不在map中,则map会自动创建一个关键字。
  • map的下标操作返回的是一个mapped_type对象,也就是.second成员。

(7):访问元素

操作 含义
c.find(k) 返回一个迭代器,指向第一个关键字为k的元素,若k不在容器中,返回尾后迭代器
c.count(k) 返回关键字等于k的数量
c.lower_bound(k) 返回一个迭代器,指向第一个关键字不小于k的元素
c.upper_bound(k) 返回一个迭代器,指向第一个关键字大于k的元素
c.equal_range(k) 返回一个pair

注意:

1:对于map和unordered_map类型,下标运算符提供了最简单的提取元素的方法,但是有时候我们不需要插入元素,只是想判断某个元素在不在容器中,这时候就应该使用find。

if(map1.find("foobar") == map1.end()) {
    cout << "foobar is not in the map" << end;
}

2:对于multimap或者multiset,其中的元素可能具有相同的关键字,但是具有相同关键字的元素会在容器中连续存储。

//对于一个multimap的authors,一个作者可能对应多本书

std::string search_item("Tom"); 
auto entries = authors.count(search_item);    //确定一共有多少个
auto iter = authors.find(search_item);       //确定第一个位置
while(entries) {
    cout << iter->second << endl;
    ++iter;
    --entries;                               //直到entries为0,所有相邻的元素都会被访问
}

//实际上对于上面的问题,我们可以用lower_bound和upper_bound来处理,因为他们会返回一个范围
for(auto beg = authors.lower_bound(search_item),end = authors.upper_bound(search_item);beg != end;cout << *beg << endl)


//更简便的方法是使用equal_range:返回一个迭代器pair,第一个指向第一个与关键字匹配的类型,第二个指向最后一个,实际上也是返回了一个范围  
for(auto pos = authors.equal_range(search_item);pos.first != pos.second;++pos.first) {
    cout << pos.first->second << endl;
}

8:无序容器

使用hash函数管理关键字。所有具有相同hash值的元素都会被保存在同一个桶中,如果容器允许重复关键字,则具有相同关键字的元素也会在一个桶中。无序容器的性能取决于hash函数的质量和桶的数量以及大小。下面是管理桶的函数

操作 含义
桶接口
c.bucket_count() 正在使用的桶的数目
c.max_bucket_count() 容器能容纳的最多的桶的数量
c.bucket_size(n) 第n个桶中有多少个元素
c.bucket(k) 关键字为k的元素在哪个桶
桶迭代
c.begin(n),c.end(n) 桶n的首元素迭代器和尾后迭代器
c.cbegin(n),c.cend(n) 返回const_loacl_iterator
哈希策略
c.load_factor() 每个桶平均元素数量,返回float
c.max_load_factor() c试图维护的平均桶的大小,返回float值,c会在需要时添加新的桶,使得load_factor <= max_load_factor
c.rehash(n) 重组存储,使bucket_count >= n
c.reserve(n) 重组存储,使得c可以保存n个元素且不必rehash

你可能感兴趣的:(C++)