C++11(8):顺序容器

string和vector将原始保存在连续的内存空间,在尾部插入删除快
deque支持随机访问,在头尾插入、删除很快
 新版c++增加了forward_list和array,
现代c++程序应该使用标准库容器,而不是更原始的数据结构。新版的c++容器要比旧版的快得多
选择容器的一些原则,
除非你有很好的理由选择其他容器,否则使用vector
如果你的程序有很多小元素,且空间的额外开销很重要,则不要使用list或forward_list
如果要去随机访问,赢使用vector或deque
如果在中间插入删除,用list或forward_list
在头尾插入删除,不会在中间,用deque
如果程序只有在读入输入时才需要在容器中间位置插入元素,随后需要随机访问,则,首先,确定是否真的需要在容器中间位置添加元素,通常先在vector追加数据,然后用sort排序
如果必须在中间位置插入元素,考虑在输入阶段用list,一旦输入完,将list中的内容拷贝到一个vector中
如果不知道用那种,那么可以在程序中只使用vector和list公共的操作:使用迭代器,不使用下标,避免随机访问。必要时选择vector或list方便
 
不是所有的容器都要说明容器的元素信息、

我们不可以为不支持特殊操作需求的类型定义容器,如,vector允许只接受容器大小的参数,有些类没有默认构造函数,如果调用将出错
容器操作:(关联容器也支持的)
iterator,const_iterator
size_type  无符号整型,足够保存此种容器类型的最大可能的容器大小
difference_type    带符号整型类型,最够保存两个容器之间的距离
value_type 
reference     元素的左值类型:于value_type&含义相同
const_reference      元素的const左值类型,即,const value_type&
C  c;
C  c1(c2);
C  c(b,e)       将迭代器b和e指定范围元素拷贝到c,array  不支持
C c{a,b,c}  列表初始化    
c1= c2
c1 = {a,b,c..}        array不支持
a.swap(b)   交换a、b的元素
swap(a,b)于上边等价
c.size()                   不支持forward_list
c.max_size()     c可保存的最大元素数目
c.empty()
添加删除元素(不使用于array)
注,在不同容器中,这些操作的接口不同
c.insert(args)    
c.emplace(inits)     使用inits构造c中的一个元素
c.erase(args)    删除args指定的元素
c.clear()    

c.begin()   c.end()   c.cbegin()  c.cend()

反向容器的额外成员(forward_list不支持)
reverse_iterator
const_reverse_iterator
c.rbegin()   c.rend()    c.crbegin()  c.crend()

auto it7 = a.begin();   ///仅当a是const是,it7才是const_iterator
auto it8 = a.cbegin()  //it8  是const_iterator


array构造函数不能接收大小参数,如果元素类型是内置类型或有默认构造函数的类可以只提供以个容器大小的参数,如果类么有默认构造函数,就必须显示的指定元素的初始值
当将一个容器初始化为另一个容器时,两个容器必须类型一致

array具有固定大小:array<int,42>

assign操作部使用于关联容器和array,只有顺序容器可用,可以实现不同容器见的赋值
seq.assign(b,e)  将seq中的元素替换成迭代器b、e所表示的范围中的元素。b、e不能指向自身
seq.assign(i1)   将seq中的元素替换为初始化列表中的元素
seq.assign(n,t)    将seq中的元素替换为n个值为t的元素

swap 不会导致指向容器的迭代器,引用和指针失效(array和string除外)
数组下标类型size_t,在头文件cstddef中
初array外,swap不对任何元素进行拷贝,删除或插入操作,因此可以保证常数时间内完成
非成员版本的swap在泛型编程中重要,统一使用非成员比较好

向顺序容器添加元素:
这些操作会改变容器大小,array 不支持
forward_list 有自己专有的insert和emplace
forward_list不支持push_back和emplace_back
vector和string不支持push_front和emplace_front
c.push_back(t)      在c的尾部创建一个值为t或由args创建的元素。返回void
c.emplace_back(args)
c.push_front(t)      在c的头部创建一个值为t或args创建的元素,放回void
c.emplace_front(args)
c.insert(p,t);      在p之前创建一个值为t或由args创建的元素,返回指向新添加元素的迭代器
c.emplace(p,args);
c.insert(p,n,t);    在迭代器p指向的元素之前插入n个值为t的元素。返回指向新添加第一个元素的迭代器,若n为0,返回p
c.insert(p,b,e);     将迭代器b和e指定的范围内元素插入p之前,b,e不是c中元素,返回 第一个元素的迭代器,范围为空,返回p
c.insert(p,i1);       il是一个元素列表,将这些值插入迭代器p之前,返回第一个元素的指针,若为空返回p
  
向一个vector,string或deque插入元素会使所有指向容器的迭代器,引用,指针失效
在vector、string尾部外任何位置,或deque外任何位置添加元素都要移动元素,而且向vector、string添加元素可能引起整个对象存储空间的重新分陪
用一个对象插入和初始化时,实际放入的是对象的拷贝,就像将对象传给非引用参数
push  和   insert  是将对象传给他们,而emplace是去调用类的构造函数,参数和构造函数的参数一样

at和下标操纵符适用于,string,vector,deque,array  提供快速访问

当使用数组作为auto变量的初始值时,推断得到的类型是指针而不是数组。
但是当使用decltype时上述转化不会发生,放回的是数组

下标运算符返回的是元素的引用

如果担心下标越界,可使用at    ,如果越界at会抛出一个out_of_rang异常。

顺序容器的删除:操作会改变容器大小,不适用于array
forward_list 有特殊版本的erase,
forward_list 不支持pop_back;vector和string不支持pop_front
删除之前必须确保元素是存在的
c.pop_back()        删除c中尾元素。c若为空,则函数行为未定义 返回void
c.pop_front()
c.erase(P);   删除迭代器p所指定的元素,返回一个指向被删除元素之后元素的迭代器,若p指向尾元素,则返回尾后迭代器,p是尾后迭代器,则未定
c.erase(b,e);   删除b和e范围内的元素。返回最好一个被删除元素 之后的迭代器,若e本身是尾后迭代器,则也返回尾后迭代器
c.clear()   删除所有元素,返回void

删除deque中除首尾元素的任何元素都会使所有迭代器、引用和指针失效。指向vector和string中删除点之后位置的迭代器、引用和指针都会失效  

forward_list中特殊的操作:
lst.before_begin()   返回指向链表首元素之前不存在的元素的迭代器。此迭代器不能解引用。cbefore_begin()返回一个const_iterator
lst.cbefore_begin()
//在迭代器之后位置插入元素。t是一个对象,n是数量,b和e是一对范围迭代器(不能指到lst内),il是一个花括号列表,返回一个指向最后一个元素的迭代器。如果范围空,则返回p。若p为尾后迭代器,则函数行为未定义
lst.insert_after(p,t);     lst.insert(p,n,t);   lst.insert(p,b,e);    lst.insert(p,il);
emplace_after(P,args);   使用args在p指定的位置之后创建一个元素,返回指向这个新元素的迭代器。若p为尾后迭代器,则未定义
   
 //删除p指向的位置之后的元素,或删除从b之后直到e之前的元素。返回一个指向被删除元素之后元素的迭代器,若不存在,则返回尾后迭代器,如果p指向lst的尾元素或是一个尾后迭代器,则未定义
lst.erase_after(p)  ;      lst.erase_after(b,e);;

改变容器大小,resize不适用于array
c.resize(n)    调整c的大小为n个元素。若n<size() ,则多出的元素被丢弃。若必须添加新元素,对新元素进行初始化
c.resize(n,t)     调整c的大小为n个元素,任何新添加元素都初始化成t
如果resize缩小容器,则指向被删除元素的迭代器。引用和指针都会失效。对vector、string或deque进行resize可能导致迭代器、指针和引用失效

在向容器添加元素后:
如果容器是vector或string,且存储空间被重新分配,则指向容器的迭代器、指针和引用会失效。如果存储空间未重新分配,指向插入位置之前的元素的迭代器、指针和引用仍有效。但指向插入位置之后元素的迭代器。指针。引用将会失效
对于deque,插入到除首尾位置之外的任何位置都会导致迭代器、指针和引用失效。如果在首尾位置添加元素,迭代器会失效,但指向存在的元素的引用和指针不会失效
对于list和forward_list,指向容器的迭代器(包括尾后迭代器和首前迭代器),指针和引用扔有效

在容器删除元素,指向被删除元素的迭代器、指针和引用失效。
对于list和forward_list,指向容器其他位置的迭代器(包括尾后和首前)、引用指针仍有效
对于deque,如果在首尾之外的任何位置删除元素,那么指向被删除元素外其他元素的迭代器、引用或指针也会失效。如果是删除deque的尾元素,则尾后迭代器也会失效,但其他迭代器、引用和指针不受影响:如果删除首元素,这些也不会受影响
对于vector和string,指向被删除元素之前元素的迭代器、引用和指针仍然有效。注意当我们删除元素时,尾后迭代器总会失效
 建议每次改变容器后都要重新定位迭代器
在使用循环改变容器是注意迭代器,对于添加删除vector或string的元素后,或在deque中首元素之外任何位置添加删除元素后,原来的end()总会失效,所以要反复的调用end来判断结束

容器大小管理:
shrink_to_fit只适用于vector、string和deque 
capacity和reserve只适用于vector和string
c.shrink_to_fit() 请将capacity()减少为size()大小
c.capacity()     不重新分配内存空间的话,c可以保存多少元素
c.reserve(n)      分配至少能容纳n个元素的内存空间,不改变容器中元素的数量,仅影响预先分配多大的内存空间,如果想、需求大小小于或等于当前容量,reserve什么也不做,因此,调用reserve后,capacity将会大于或等于传递给reverse的参数,同样的我们可以用resize成员只会改变容器中元素的数目,而不是容器的容量。
对于分配新内存有一个原则:确保用push_back想vector添加元素有高效率。从技术角度说,就是通过在一个初始为空的vector上调用n次push_back来创建一个n个元素的vector,所花费的时间不能超过n的常数倍

除了顺序容器共同的操作之外,string还提供了额外的操作。
n、len2和pos2都是无符号值
string s(cp,n)      s是cp指向的数组中前n个字符的拷贝。次数组应该至少包含n个字符
string s(s2,pos2)     s是string s2从下标pos2开始的字符的拷贝。若pos2>s2.size()则行为未定义,抛出out_of_range
string s(s2,pos2,len2)    s是string  s2从下标pos2开始Len2个字符的拷贝,若pos2>s2.size()则行为未定义,至多拷贝s2.size()-pos2个字符

s.substr(pos,n)  返回一个string,包含s中从pos开始的n个字符的拷贝,pos的默认值为0,n的默认值为s.size()-pos.

args:
 str   字符串str,不能与s相同
str,pos,len
cp,len   字符数组
cp
n,c       n个字符c
b,e    迭代器b和e指定的范围内的字符
初始化列表

s.insert(pos,args)          在pos之前插入args指定的字符,pos可以是一个下标或,返回指向s的引用;
args的形式:str      str,pos,len       cp,len         n,c                                                                                                                                                                                      
s.insert(iter,args)          在pos之前插入args指定的字符,iter是一个迭代器,返回第一个插入字符的迭代器
args的形式:n,c      b2,b2     初始化列表
s.erase(pos,len)     删除从位置pos开始的len个字符。如果len被省略,则删除从pos开始到s末尾的所有字符,返回s的引用
s.assign(args)       将s中的字符替换成args指定的字符。返回s的引用
s.append(args)      将s追加到s。返回一个指向s的引用
注,sppend和assign可以使用所有形式
s.replace(pos,len,args)    删除s中范围range内的字符,替换为args指定的字符。返回的是一个指向s的引用
args的形式:  str     str,pos,len      cp,len    cp    n,c
s.replace(b,e,args)       返回的是一个指向s的引用
args的形式:  str     cp,len    cp  n,c     b2,e2     初始化列表

搜索操作:返回指定字符出现的下标,string::size_type,一个unsigned类型,如果未找到则返回npos
s.find(args)      查找s中args第一次出现的位置
s.rfind(args)      查找s中args最后一次出现的位置
s.find_first_of(args)      在s中查找args中任何一个字符第一次出现的位置
s.find_last_of(args)     在s中查找args中任何一个字符最后一次出现的位置
s.find_first_not_of(args)     在s中查找第一个不在args中的字符
s.find_last_not_of(args)       在s中查找最后一个不在args中的字符
args的形式:
c,pos     从pos开始查找字符c,pos默认为0
s2,pos      从pos开始查找字符串s2.默认为0
cp,pos      从s中位置pos开始查找指针cp指向的以空字符结尾的c风格字符串,pos默认为0
cp,pos,n       从s中位置pos开始查找指针cp指定的数组的前n个字符。pos和n无默认值

s.compare(args)
args的形式:
s2      比较s和s2
pos1,n1,s2           将s中从pos1开始的n1个字符于s2进行比较
pos1,n1,s2,pos2,n2         将s中从pos1开始的n1个字符与s2中从pos2开始的n2的字符进行比较
cp
pos1,n1,cp
pos1,n1,cp,n2

string 和 数值 之间的转换:如果string不能转换为一个数值,这些函数将会抛出一个invalid_argument。如果转换的类型无法用任何类型表示则会抛出一个out_of_range
to_string   一组重载函数,返回数值val的string表示,对每个浮点整型和int或更大的整型,都有相应的版本。小整型会被提升
stoi(s,p,b)      stol(s,p,b)     stoul(s,p,b)    stoll(s,p,b)     stoull(s,p,b)   
返回s的起始子串(表示整数的内容)的数值,返回 int、long、unsigned long、long long、usigned long long。b表示转换所用的基数,默认是10.p是size_t指针,用来保存s中第一个非数值字符的下标,p默认为0.即,函数不保存下标
stof(s,p)    stod(s,p)    stold(s,p)
返回s的起始子串(表示浮点数的内容)的数值,返回值类型分别是float、double、long double。参数p的同上


标准库定义的顺序容器适配器:stack、queue、priority_queue
适配器是标准库中的一个通用的概念,容器、迭代器、函数都有适配器。本质上,一个适配器是一种机制,能使某种事物的行为看起来像另一种事物一样。一个适配器接受一种已有的容器类型,使其行为看上去像一种不同的类型。如,stack适配器接受一个顺序容器(除array和forward_list),并使其操作看起来像一个stack一样。
所有容器适配器都支持的操作和类型
size_type     一种类型,足以保存当前类型的最大对象的大小
value_type      元素类型
container_type     实现适配器的底层容器类型
A  a;        创建以个名为a的空适配器
A  a(c);        带有容器c的一个拷贝
==   !=     <      <=      >    >=   返回容器底层的比较结果
a.empty()
a.size()
swap(a,b)      a.swap(b)     交换,ab必须类型相同,包括底层容器类型也必须相同

默认情况下,stack和queue是基于deque实现的,priority_queue是在vector之上实现的。我们可以再创建一个适配器时将一个命名的顺序容器作为第二个类型参数,来重载默认容器类型。
stack<string,vector<string>> str_stk;   在vector上实现的栈
所有的容器适配器都有添加和删除元素的能力。因此,适配器不能构造在array之上。
所有的容器适配器都有尾访问能力。因此,不能用forward_list 来够着适配器
stack只要求push_back   pop_back  和back操作,因此可以使用除array和forward_list外的任何容器类型来构造
queue适配器要求back、push_back    front    push_front   因此可以构造于list和deque之上。但不能是vector。
priority_queue除了front    push_back和pop_back 操作之外还有随机访问的能力,因此它可以构造在vector和deque之上,但不能使list

栈的其他操作:栈默认基于deque实现,也可以是list或vector之上实现
s.pop()
s.push(item)    创建一个新元素压入栈,该元素可以是通过拷贝或移动item而来。或者有args构造
s.emplace(args)   
s.top()
每个适配器基于底层容器定义了自己的操作,我们只能使用容器适配器提供的操作,不能使用底层容器的操作

queue和priority_queue适配器定义在queue头文件中,
queue默认是基于deque实现,priority_queue默认基于vector实现
queue 也可以用list或vector实现,priority_queue也可以用deque实现
q.pop()    返回queue的首元素或priority_queue的最高优先级的元素,
q.front()    返回首元素或尾元素,但不删除
q.back()    只适用于queue
q.top()    返回最高优先级的元素,不删除,只是用于priority_queue
q.push(item)
q.emplace(args)
默认情况,标准库元素使用<运算符来确定优先级

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值