顺序容器
- 顺序容器:删除和添加代价高,非顺序进行访问代价高;
- 常用的顺序容器:
vector
:可变大小数组,快速随机访问,但是元素随机插入代价高;deque
:双向队列,支持快速随机访问,在头尾删除添加元素很快;list
:双向列表,支持双向顺序访问,,插入删除速度很快;forward_list
:单向列表,支持单向顺序访问,任意位置,添加删除都很快;arry
:固定大小数组,支持随机访问,不能够添加和删除元素;string
:和vector
相似的容器,随机访问速度快,尾部添加删除速度快;- 通常情况下,使用
vector
使最好的选择;
- 关于选用容器的一些建议:
- 强烈建议使用
vector
,除非有更好的选择; - 如果程序包含很多小元素,并且额外的开销很大,不要使用
list
或者forward_list
; - 如果程序要求随机访问,则应该使用
vector
或者deque
; - 如果程序要求在中间插入或者删除元素,应该使用
list
或者forward_list
; - 如果程序知识在容器的头尾插入或者删除元素,但是不会再中间插入或者删除元素,应该使用
deque
; - 顺序容器几乎可以保存任意类型的元素,任意类型的含义是这种类型必须包含默认的构造函数,如果是一个没有默认构造函数的类型,就需要这声明:
vector<
,其中
NoDefau> v1(10,init)Init
表示是用来提供元素初始化容器;
- 强烈建议使用
迭代器
- 如果一个迭代器提供某种操作,那么所有提供相同操作的迭代器对这个操作的实现方式都是相同的;
forward_list
容器类型部支持递减运算符;- 迭代器的范围使用
begin
和end
来表示; - 几种重要的类型:
const_iterator
:可以读取元素,但是不能够修改迭代器的类型;size_type
:此种容器最大可能容器的大小;difference_type
:带符号类型,用于保存两个迭代器之间的类型;value_type
:表示元素类型;reference
:元素的左值类型,与value_type&
类型相同;begin
和end
成员:用于生成第一个元素的位置,以及最后一个元素的下一个位置,以r
开头的表示反向迭代器,c开头的表示const
迭代器;- 当不需要执行写访问时,应该使用
cbegin
和cend
来进行访问; 容器的定义和初始化:
- 每个人都定义了一个默认的构造函数,除了
arry
以外,其他容器的默认构造函数都会指定一个指定类型的容器,并且可以接受容器大小和元素初始值; 将一个容器作为另一个容器的拷贝:
- 直接拷贝整个容器:
Type C1(C2); Type C1=C2
; - 或者可以使用迭代器制定拷贝的范围,但是arry是不可以执行迭代器拷贝的;
- 为了一个容器创建另一个容器的拷贝时,两个容器的类型和元素类型必须匹配,当传递迭代器参数来拷贝一个范围时,就不需要容器类型时相同的;
- 将一个容器初始化为另一个容器的拷贝时,两个容器的类型和元素类型必须相同;
- 容器的另一种初始化方式:
deque<string> authors(authors.begin(),it)
;
- 直接拷贝整个容器:
列表初始化:
list<string> authors={"Lixun","Linux","element"}
,支持列表初始化;- 只有顺序容器的构造函数才能接受大小参数,关联容器并不支持;
- 标准库
array
除了需要指定容器的类型,还需要指定容器的大小,例如:array<int,42>
; - 由于大小是
array
类型的一部分,array
不支持普通的容器类型构造函数; - 默认构造的
array
是非空的,包含了与其大小一样多的元素; array
可以进行拷贝或者进行对象的赋值操作;- 在进行拷贝或者对象赋值时,初始值的类型必须与要创建的容器的类型相同,同样的
array
还要求元素的类型和大小都一样,因为大小也是
array
类型的一部分;
- 标准库
- 赋值和
swap
:
- 赋值运算符表示的是将左边容器中的全部元素替换为右边容器元素的拷贝;
- 其中标准库类型
array
也允许进行赋值操作,但是array
要求左右两边类型必须相等; swap()
是用来交换两个对象的元素,并且要求两个对象具有相同的类型,并且swap()
通常具有快的多;- 赋值运算符会导致指向左边容器内部的迭代器,引用和指针失效,通常
swap()
交换内容不会导致容器的迭代器,引用和指针失效,通常容器类型
为array
和string
的情况除外; assign
:
assign()
仅适用于顺序容器,但是array
并不能够使用;assign
允许我们从一个不同但是相容的类型进行赋值,或者从一个容器的子序列进行赋值;- 需要注意的是传递给
assign
的迭代器不能指向调用的容器;
swap
swap
用于交换两个像同类型的容器,swap
交换的并不是元素本身,而交换的是内部的数据结构;swap
除了array
以外,swap
不对任何元素进行拷贝,删除或者插入操作,可以保证交换时间在常数时间内部完成;array
在执行swap
交换的是本身的各个元素,时间的复杂度和元素数目成正比;
- 容器大小的相关操作:
empty()
:size()
为0时,返回值为true
;max_size()
:返回一个大于或者等于该容器所能容纳的最大元素的数值;forward_list
:支持max_size()
与empty()
,但是不支持size()
操作;
- 关系运算符
- 等于:如果两个容器具有相同的大小并且所有元素对应相等,则两个容器相等,否则不想等;
- 小于:较小容器中的每个元素都等于较大容器;
- 其他:如果两个元素的之间的元素没有关系,那么比较结果取决于第一个不想等元素的结果;
顺序容器的常用操作
- 向一个
vector
,string
,deque
,掺入元素时,会导致指向容器的迭代器,指针和引用失效; - 将元素插入
vector
,deque
,string
中的任何位置都是合法的,但是时间复杂度会比较高; - 范围掺入元素:
- 例如:
sevc.insert(sevc.end(),10,"Anna")
,也就是元素可以按照范围进行插入; insert
的返回值表示的是掺入元素之前的位置,所以可以使用这个返回值来循环执行push_front()
操作;
- 例如:
- 访问元素:
- 迭代器
end()
指向的是容器尾元素之后的元素; - 对于空容器调用
front
和back
是严重的错误; - 在容器中访问元素的成员函数,
front
,back
,at
和下表,返回的都是引用,如果容器是一个const
对象,那么返回的就是const
引用; - 对于空对象使用下表运算符是不合法的;
- 迭代器
- 删除元素
- 删除
deque
中除了首尾之外的任何元素都会使所有的迭代器,引用和指针失效; - 同样的删除
vector
,string
某个元素之后的迭代器,引用和指针都会失效; - 删除元素的成员函数同样的不见查参数,在删除元素之前,不许保证元素的位置是存在的;
- 不能够删除空容器;
clear()
用于删除容器里面的所有元素;- 改变容器的大小:
array
是不能够改变容器的大小的; - 如果
resize
缩小容器,那么指向被删除元素的迭代器,引用和指针都会失效;对vector
,string
或deque
进行resize
可能导致迭代器,
指针和引用失效;
- 删除
- 向一个
需要注意的几点:
- 如果容器是
vector
或者string
,如果存储空间重新被分配,那么指向容器的迭代器,指针和引用都会失效.如果空间没有重新分配,那么指向插入元
素之后位置的指着,引用和迭代器就会失效; - 对于
deque
来说,插入到首尾之外的任何位置,都会导致迭代器,指针和引用失效,在首尾插入元素,导致迭代器失效,引用和指针有效; - 对于
list
和forward_list
,迭代器,指针和引用都有效; - 删除元素需要注意的是:
- 对于
list
和forward_list
,指向容器其他位置的迭代器,引用和指针都有效; - 对于
deque
,如果再首尾之外的任何位置删除元素,那么指向被删除外其他元素的迭代器,引用或者指针也会失效,如果删除为元素,尾迭代器会失
效;如果删除首元素,不会被影响; - 对于
vector
和string
来说,指向被删除元素之前的指针,迭代器和引用依然有效; - 当删除元素之后的迭代器就会失效;
- 对于
- 如果再一个循环中插入/删除
deque
,string
或者vector
中的元素,不要缓存end
返回的迭代器;
- 如果容器是
vector()
对象是如何增长的:
vector
将元素按照顺序连续存储,vector
容器空间的分配策略不是按照每添加一个元素就增加一个元素的策略,而是按照2^n的策略进行增长;capacity()
:容器不在扩张内存的情况下可以容纳多少各元素;reserve()
:通知容器它应该准备保留多少个元素;reserve()
:并不改变容器中元素的数量,仅仅能够影响vector
预先分配多大的内存空间,容器的大小是不能够自动减小的;shrink_to_fit()
:可以用于退回内存空间;
- 每个人都定义了一个默认的构造函数,除了
string
的构造方法
string s(cp,n)
:s
里面的内容表示的是cp
里面,前n
个字符的拷贝;string s(s2,pos)
:s
里面表示的是从下表pos2
开始的字符的拷贝;pos < s2.size()
;string s(s2,pos1,len2)
:s
表示的是2
从pos2
复制len2
字符的长度;substr
:表示的是原始字符的拷贝;
s.substr(pos,n)
:表示的含义是从pos
开始复制n
个字符;- 如果不传递
pos
,那么默认就会从0
开始复制n
个字符;
append()
:表示在一个字符串的末尾添加一些字符串;replace()
:表示的是将字符串里面的某些字符进行替换;
- 容器适配器
- 三个容器顺序适配器:
stack()
,queue
和priority_queue
; - 容器,迭代器和函数都有适配器,适配器的含义是事某个事物的行为看起来更像另一个事物一样;
- 对于适配器来说,需要定义两个构造函数,默认的构造函数用于创建一个空对象, 接受一个容器的构造函数拷贝该容器来初始化适配器;
- 所有的适配器都要求容器具有添加和删除元素的能力;
- 适配器构造的要求:
- 适配器不能够构造在
array
之上; - 适配器不能够构造在
forward_list
之上; - 所有的适配器都要求容器具有添加,删除以及访问元素的能力;
stack
只要求具有push_back()
,pop_back()
以及back()
操作,可以使用array()
,forward_list()
之外的所有类型来构造stack()
;queue()
适配器要求具有back()
,push_back()
,front()
,push_front()
,因此可使用list
或者deque
来进行构造;priority_queue
:除了要求front
,push_back()
以及pop_back
之外,还要求具有随机访问能力,因此可以构造于vector
或者deque
之上,但是不
能够基于list
构造;- 栈适配器:
s.pop()
:表示删除栈顶元素,但是并不饭hi该元素的值;s.push(item)
:创建一个新的元素,然后压入栈顶;s.top()
:返回栈顶元素,但是不讲元素弹出;
- 队列适配器:
deque
默认是基于queue
实现,priority_queue
默认是基于vector
实现
- 适配器不能够构造在
- 三个容器顺序适配器: