1.关联容器:
- 关联容器的种类:
//有序关联容器:按关键字有序保存元素
map //保存关键字-值对
set //只保存关键字,即值
multimap //关键字可重复出现的map
multiset //关键字可重复出现的set
//类型map和multimap定义在头文件map中;set和multiset定义在头文件set中
//无序关联容器:使用哈希函数组织元素
unordered_map //用哈希函数组织的map
unordered_set //用哈希函数组织的set
unordered_multimap //用哈希函数组织的map;关键字可重复出现
unordered_multiset //用哈希函数组织的set;关键字可重复出现
- 定义和初始化关联容器:
//定义一个map时,必须指明关键字类型与值类型
map<string, size_t> word_count; //关键字类型是string,值类型是size_t
//定义一个set时,只需指明关键字类型
set<string> exclude; //关键字类型是string
/*初始化关联容器:1.可以将关联容器初始化为另一个同类型容器的拷贝
2.从一个值范围来初始化关联容器
3.当初始化multimap或multiset时,重复关键字不会被剔除
*/
2.关键字类型的要求:
- 对于有序容器,关键字类型必须定义元素比较的方法
- 在集合类型中,关键字类型就是元素类型;在映射类型中,关键字类型是元素的第一部分的类型
- 在实际编程中,如果一个类型定义了“行为正常”的<运算符,则它可以用作关键字类型
3.pair类型:
- 定义在utility头文件中
- 一个pair包含两个数据成员;当创建一个pair时,必须提供两个类型名;map的元素即为pair
- pair上的相关操作:
pair<T1,T2> p; //p是一个pair,两成员都进行了值初始化
pair<T1,T2> p(v1, v2) //first和second成员分别用v1和v2进行初始化
pair<T1,T2> p = {v1, v2}; //等价于p(v1, v2)
make_pair(v1, v2) //返回一个用v1 和v2初始化的pair
p.first
p.second
p1 relop p2 //关系运算符(<,>、<=、>=)按字典序定义
p1 == p2 //当first和second成员分别相等时,两个pair相等
p1 != p2
4.关联容器操作:
- 关联容器额外的类型别名:
key_type //关键字类型
mapped_type //关键字关联到的类型
value_type //对于set,与key_type相同;对于map,为pair<const key_type, mapped_type>
- 关联容器迭代器:
//1.当解引用一个关联容器迭代器时,得到一个类型为容器的value_type的值的引用
//2.对map而言,value_type是一个pair类型,first成员保存const的关键字,second成员保存值
auto map_it = word_count.begin();
//*map_it是指向一个pair<sonst string, size_t>对象的引用
//3.set的迭代器是const的,即只能用set迭代器读取元素的值而不能修改
//4.当使用一个迭代器遍历一个map、multimap、set或multiset时,迭代器按关键字升序遍历元素
//5.关联容器可用于只读取元素的算法
- 添加元素:
//关联容器insert操作
c.insert(v)
c.emplace(args)
/*v是一个value_type类型的对象;对于map和set,只有当元素的关键字不在c时
才插入,函数返回一个pair,为pair<iterator, bool>,bool值为指示插入是否
成功;对于multimap和multiset,总会插入(或构造)给定元素,并返回一个指向
新元素的迭代器*/
c.insert(b, e)
c.insert(il)
c.insert(p, v) //迭代器p作为一个提示,指出从哪里开始搜索新元素应该存储的位置
c.emplace(p, args) //返回一个迭代器,指向具有给定关键字的元素
//检测insert的返回值
/*使用insert返回的pair的first成员是一个迭代器,指向具有给定关键字的元素;second成员是一个bool值,指出元素是否插入成功;1.若关键字已在容器中,则insert什么事情也不做,且bool值为false,2.若关键字存在,则元素被插入到容器中,且bool值为true*/
//对允许重复关键字的容器,接受单个元素的insert操作返回一个指向新元素的迭代器,不须返回bool
- 删除元素:
//从关联容器删除元素
c.erase(k) //从c中删除关键字为k的元素;返回一个size_type值,指出删除的元素的数量
c.erase(p) //从c中删除迭代器p指定的元素;返回一个指向p之后元素的迭代器
c.erase(b, e) //删除迭代器对b和e所表示的范围中的元素,返回e
//对于保存不重复关键字的容器,erase的返回值总是0huo1;若返回值为0,则表明想要删除的元素并不在容器中
- map的下标操作:
c[k] //返回关键字为k的元素;如果k不在c中,添加一个关键字为k的元素,并对其进行值初始化
c.at(k) //访问关键字为k的元素,带参数检查;若k不在c中,抛出一个out_of_range异常
//对一个map进行下标操作,会获得一个mapped_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()
//如果lower_bound和upper_bound返回相同的迭代器,则给定关键字不在容器中
5.无序容器:使用一个哈希函数和关键字类型的==运算符
- 如果关键字类型固有就是无序的,或者性能测试发现问题可以用哈希技术解决,就可以使用无序容器
- 无序容器在存储组织上为一组桶,每个桶保存0个或多个元素;无序容器使用一个哈希函数将元素映射到桶
- 无序容器管理操作:
//桶接口
c.bucket_count() //正在使用的桶数目
c.max_bucket_count() //容器能容纳的最多的桶的数量
c.bucket_size(n) //第n个桶中有多少个元素
c.bucket(k) //关键字为k的元素在哪个桶中
//桶迭代
local_iterator //可以用来访问桶中元素的迭代器类型
const_local_iterator //const版本
c.begin(n), c.end(n) //桶n的首元素迭代器和尾后迭代器
c.cbegin(n), c.cend(n) //返回const_local_iterator
//哈希策略
c.load_factor() //每个桶的平均元素数量,返回float值
c.max_load_factor() //c试图维护的平均桶大小
c.rehash(n) //重组存储,使得bucket_count>=n且bucket_count>size/max_load_factor
c.reserve(n) //重组存储,使得c可以保存n个元素且不必rehash
- 无序容器对关键字类型的要求:类似于为有序容器提供比较操作,我们需要为无序容器提供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);
--------------------------------------------------------------------2018.12.16日再更新--------------------------------------------------------
map插入的三种方式:
//pair---> utility头文件
map<int, string> mapStudent;
//pair<--insert
mapStudent.insert(pair<int, string>(1, "student_one"));
//value_type<--insert
mapStudent.insert(map<int, string>::value_type (1, "student_ont"));
//mp[]<--数组下标
mapStudent[1] = "student_ont";
检查是否插入成功:
pair<map<int, string>::iterator, bool> insert_pair;
insert_pair = mapStudent.insert(pair<int, string>(1, "student_one"));
//插入成功则insert_pair.second为true,否则为false
遍历map的三种方式:
1. 前向迭代器
2. 反向迭代器
3. 数组方式