天天看点

C++中的容器-概览

容器概览

一个容器是特定类型对象的集合。容器分为顺序容器和关联容器,其中顺序容器中元素顺序与其加入容器时的位置相对应,而关联容器中元素的位置由相关联的关键字值决定。所有的容器类都有共享公共接口,不同容器按不同的方式对其进行扩展。

公共操作

容器类型上的操作中包含共有操作和各自的扩展操作,其中公共操作一般适用于所有的容器。

//类型别名
iterator  //此容器类型的迭代器类型
const_iterator  //可以读取元素,但不能修改元素的迭代器类型
size_type   //无符号整型,足够保存此种容器类型最大可能容器的大小
difference_type  //带符号整型,醉意保存两个迭代器之间的距离
value_type   //元素类型
reference   //元素的左值类型:与value_type&含义相同
const_reference  //元素的const左值类型   
           
//构造函数
C c; //默认构造函数,构造空容器
C c1(c2);  //构造c2的拷贝c1
C c(b, e);  //构造c,将迭代器b和e的指定范围的元素拷贝到c,array不支持此操作
C c{a, b, c, ...};  //列表初始化c
           
//赋值
c1 = c2;  //将c1中的元素替换为c2中的元素
c1 = {a, b, c,...};  //列表赋值,不适用于array
           
//swap操作
a.swap(b);  //交换a、b的元素
swap(a, b);  //交换a、b的元素
           
//大小
c.size();  //c中元素的数目,不支持forward_list
c.max_size();  //c可保存的最大元素数目
c.empty();  //c为空则返回true,否则返回false
           
//添加、删除元素,不适用于array
c.insert(args)   //将args中的元素拷贝进c
c.emplace(inits)   //使用inits构造c中的一个元素
c.erase(args)  //删除args指定的元素
c.clear()  //删除c中所有元素,返回void
           
//关系运算
==, !=    //所有容器都支持
<, <=, >, >=   //无序容器不支持
           
//获取迭代器
c.begin(), c.end()  //返回指向c的首元素和尾元素之后位置的迭代器
c.cbegin(), c.cend()  //返回const_iterator
           
//反向容器的额外成员
reverse_iterator   // 按逆序寻址元素的迭代器
const_reverse_iterator   //不能修改元素的逆序迭代器
c.rbegin(), c.rend()   //返回指向c的尾元素和首元素之前位置的迭代器
c.crbegin(), c.crend()  //返回const_reverse_iterator 
           

顺序容器

类型

顺序容器有6种类型,支持快速顺序访问元素。除了array外,其余的顺序容器都支持都提供高效、灵活的内存管理,可以添加、删除元素以扩张或者收缩容器的大小。

vector   //可变大小数组,支持随机访问
deque   //双端队列,支持随机访问
list    //双向链表,只支持双向顺序访问
forward_list  //单向链表,只支持单向顺序访问
array  //固定大小数组,支持随机访问,不能添加或者删除元素
string  //专门用于保存字符
           

顺序容器的选择原则:

1)除非有很好的理由,一般选择vector;

2)如果程序有很多小的元素,且空间的额外开销很重要,此时不要使用list或者forward_list;

3)如果需要支持随机访问,应当使用vector或者deque;

4)如果程序要求在容器的中间插入或者删除元素,应当使用list或者forwar_list;

5)如果程序需要在头尾插入或者删除元素但不会在中间位置删除或者插入元素,应当使用deque;

操作

1、添加元素 除array外,所有标准库容器都提供灵活的内存管理,在运行时可以动态添加或者删除元素来改变容器大小。

//array不支持以下操作
//forward_list不支持push_back和emplace_back操作,并且有自己版本的insert和emplace
//vector和string不支持push_front和emplace_front
c.push_back(t)  //在c的尾部创建一个值为t的元素,返回void
c.emplace_back(args)  //在c的尾部创建一个由args创建的元素,返回void
c.push_front(t)  //在c的头部创建一个值为t的元素,返回void
c.emplace_front(args)  //在c的头部创建一个由args创建的元素,返回void
c.insert(p, t)  //在迭代器p指向的元素之前创建一个值为t的元素,并返回指向新元素的迭代器
c.emplace(p, args)  //在迭代器p指向的元素之前创建一个由args创建的元素,并返回指向新元素的迭代器
c.insert(p, n, t)  //在迭代器p指向的元素之前添加n个值为t的元素,返回指向新添加的第一个元素的迭代器
c.insert(p, b, e)  //将迭代器b和e指定范围内的元素插入到迭代器p指向的元素之前,返回指向新添加的第一个元素的迭代器
c.insert(p, il)  //il是一个花括号包围的元素值列表,将这些给定值插入到迭代器p指向的元素之前,返回指向新添加的第一个元素的迭代器。2
           

2、访问元素 对一个空容器使用front和back操作的行为等价于下标访问越界,都是未定义的行为。

//at和下标操作只适用于vector、string、deque、array
//back不适用于forward_list
c.back()  //返回c中尾元素的引用。若c为空,该操作为未定义。
c.front()  //返回c中首元素的引用。若c为空,该操作为未定义。
c[n]  //返回c中下标为n的元素的引用,n是一个无符号整数。若n超过边界,则未定义。
c.at(n)   //返回下标为n的元素的索引,如果下标越界,则抛出异常。
           

3、删除元素

//删除操作不适用于array
//forward_list有特殊版本的earse且不支持pop_back
//vector和string不支持pop_front
c.pop_back()  //删除尾元素
c.pop_front()  //删除首元素
c.erase(p)  //删除迭代器p所指的元素,返回指向下一个元素或者尾后迭代器
c.erase(b, e)  //删除迭代器b和e之间的元素,返回指向下一个元素或者尾后迭代器
c.clear()  //删除所有的元素
           

4、特殊的forward_list操作

lst.before_begin()  //返回指向列表首元素之前不存在的元素的迭代器。此迭代器不能被解引用。
lst.cbefore_begin()  //返回一个const_iterator。
lst.insert_after(p, t) //在迭代器p之后插入元素t,返回最后一个插入元素的迭代器。
lst.insert_after(p, n, t) //在迭代器p之后插入n个t,返回最后一个插入元素的迭代器。
lst.insert_after(p, b, e) //在迭代器p之后插入迭代器b和e之间的元素,返回最后一个插入元素的迭代器。
lst.insert_after(p, il) //在迭代器p之后插入列表il之中的元素,返回最后一个插入元素的迭代器。
lst.erase_after(p)  //删除迭代器p之后的元素,返回最后一个删除元素的下一个元素的迭代器。
lst.erase_after(b, e)  //删除迭代器b和e(不包含e)之间的元素。
           

5、改变容器大小

//resize不适用于array
c.resize(n)  //调整c的大小为n个元素,若n<c.size(),则多余的元素被丢弃,反之新添加的元素进行值初始化
c.resize(n, t)  //调整c的大小为n个元素,任何新添加的元素初始化为t
           

容器适配器

标准库还定义了三个顺序容器适配器:stack、queue、priority_queue。

关联容器

关联容器中的元素是按照关键字来保存和访问的,支持高效率的关键字查找和访问。

类型

标准库提供了8种关联容器,其中:map和multimap类型定义在map头文件中;set和multiset定义在头文件set中;无序容器定义在头文件unordered_map和unordered_set中。

//按关键字有序保存元素
map  //关联数组:保存关键字-值对
set    //关键字即值,即只保存关键字
multimap  //关键字可重复出现的map
multiset  //关键字可重复出现的set
//无序集合
unordered_map  //用哈希函数组织的map
unordered_set    //用哈希函数组织的set
unordered_multimap  //哈希函数组织的map,关键字可重复出现
unordered_multiset  //哈希函数组织的set,关键字可重复出现
           

操作

1、额外的类型

key_type  //此容器类型的关键字类型
mapped_type  //每个关键字关联的类型,只用于map
value_type  //对于set:与key_type相同;对于map:为pair<const key_type,mapped_type>
           

2、添加元素

//v是value_type类型的对象;args用来构造一个对象
//对于map和set,只有当前元素的关键字不在c中才能插入元素。函数返回一个pair:指向具有指定关键字的元素的迭代器,指示是否成功插入的bool。
c. insert(v) 
c.emplace(args)

c.insert(b, e)  //b和e是迭代器,表示一个c::value_type类型值的范围
c.insert(il)  //il是上述类型的一个列表值

//将迭代器p作为一个提示,指出从哪里开始搜索新元素应该存储的位置。返回一个迭代器,指向指向具有给定关键字的元素
c.insert(p, v) 
c.emplace(p, args)
           

3、删除元素

c.erase(k)  //从c中删除每个关键字为k的元素,返回一个size_type值,指出删除了多少个元素。
c.erase(p)  //从c中删除迭代器p指出的真正元素,返回一个指向p之后一个元素的迭代器。
c.erase(b, e)  //删除迭代器对b和e所表示的范围中的元素。
           

4、访问元素

//map和unordered_map的下标操作
c[k]  //返回关键字为k的元素,如果k不在c中,则创建一个。
c.at(k)  //访问关键字为k的元素,带参数检查,若不存在则抛出异常
           
//lower_bound,upper_bound不适用于无序容器
//下标和at只适用于非const的map和unordered_map
c.find(k)  //返回第一个关键字为k的元素的迭代器,若不存在则返回尾后迭代器
c.count(k)  //返回关键字等于k的数目
c.lower_bound(k)  //返回一个迭代器,指向第一个关键字不小于k的元素
c.upper_bound(k)  //返回一个迭代器,指向第一个关键字大于k的元素
c.equal_range(k)  //返回一个迭代器pair,表示关键字等于k的元素的范围,若k不存在,pair的两个成员均等于c.end()
           

无序容器

标准定义了4个无序关联容器。

//桶接口
c.bucket_count()  //正在使用桶的数目
c.max_bucket_count  //容器能容纳的最多的桶的数量
c.bucket_size()  //第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版本

//哈希策略
c.load_factor()  //每个桶中平均元素数量,返回float值
c.max_load_factor()  //维护桶的平均大小,返回float值
c.rehash(n)  //重组存储
c.reserve(n)  //重组存储
           

继续阅读