C++学习笔记(三):再探顺序容器

容器的大小操作:

所有容器的类型都提供一下几种操作


c.szie()  
c.max_size()
c.empty()

c.resize(n) 调整容器c的大小,使其能够容纳n个元素。

c.resize(n, t) 调整容器c的大小, 使其能容纳n个元素。 所有新添加的元素值都为t

当使用resize来改变容器的大小时,如果当前的容器长度大于新的长度值,则该容器后部的元素会被删除; 如果当前的容器长度小于新的长度值, 则系统会在该容器候后部加新元素。

当使用resize操作时,迭代器可能会失效,迭代器失效的一个后果是原先被赋值的元素不可用或指向了一个不可知的元素。  

访问元素
如果容器非空, 那么容器类型的front和 back成员 将返回 容器内 第一个或最后 一个元素的 引用:

if(! ilist.empty())
{
     list<int>::reference val= *ilist.begin();
     list<int>::reference val2= ilist.front();

     list<int>::reference last= *--list.end();
     list<int>::reference last2= ilist.back();
}

注意这里 begin和end要用到解引用。所以  front和 back类似于数组操作, 而end和front类似于指针操作
这里更加好的解释是, front和back是直接对顺序容器元素进去取操作,而begin和end 是返回后的迭代器进行了解引用


访问顺序容器内元素的操作
c.back()       // 返回最后一个元素的引用,    如果c为空, 则该操作未定义
c.front()     // 返回容器c的第一个元素的引用, 如果c为空,则该操作未定义

c(n)          返回下表为n的元素的引用  如果下表越界, 则该操作未定义,只适用于vector和deque容器

c.at(n)    返回下标为n的元素的引用。 如果下标越界, 则该操作未定义,只适用于vector和deque容器

需要注意的是: 下标操作符本身不会做相关的检查。 因此在使用下标访问之前,一定要检查容器是否为空。操作是否未定义

初始定义的容器为空  即 vector<string> svec; 那么这个svec是空的,那么就不能对它进行 访问操作如: svec[0]或 svec.at(0)等操作。

删除元素
容器类型也提供了通用的erase操作和特定的 pop_front和 pop_back操作来删除容器内的元素

删除顺序容器内元素的操作
c.erase(p) 删除迭代器p所指向的元素, 返回一个迭代器,它指向被删除元素后面的元素。如果返回的迭代器超出末端的下一位置的迭代器,则该函数未定义

c.erase(b, e) 删除迭代器b和e所标记的范围内所有的元素, 返回的迭代器类似于c.erase(p)

c.clear() 删除容器c内的所有元素。 返回void


c.pop_back()和 c.pop_front() 删除容器c的最后一个和第一个元素,返回void。  如果c为空容器, 则该函数未定义。  c.pop_front()只适用于list或deque容器。  vector容器类型不支持pop_front操作。

删除容器内的一个元素
删除一个或一段元素更通用的方法是  erase操作。  如同其它操作一样, erase操作也不会检查它的参数。  程序员必须确保用作参数的迭代器或迭代器范围是有效的。  

find算法的结合使用
通常,寻找一个指定元素的最简单方法是使用标准库的find算法, 然后删除该元素。 find算法是一种泛型算法。  当使用泛型算法时, 必须将<algorithm>头文件包含进来。
find算法需要一对迭代器作为范围参数,然后一个值作为查找参数,具体如下:
list<string>::iterator iter= find(slist.begin(), slist.end(), searchvalue);
if(iter != slist.end())
     slist.erase(iter);


删除容器内所有的元素
可以调用clear函数

赋值与swap

与赋值相关的操作符都作用于整个容器。  赋值的操作,除了swap操作外,都可以用erase和insert操作实现。  
赋值操作符首先删除其做操作数容器中的所有元素, 然后将右操作数容器的所有元素插入到左边容器中

赋值和assign操作使左操作数的所有迭代器失效,swap操作则不会使迭代器失效。  完成swap操作后,尽管被交换的元素已经存放在另一容器中,但迭代器扔然指向相同的操作

顺序容器的赋值操作

c1=c2
c1.swap(c2) 调用该函数后, c1中存放的是c2原来的元素,c2中存放的则是c1原来的元素。 c1和c2的类型必须相同。  该函数的执行速度通常要比讲c2的元素复制到c1的操作快.
c.assign(b, e) 重新设置c的元素:  讲迭代器b和e 标记的范围内所有的元素复制到c中。 b和e必须不是指向c中元素的迭代器。
c.assign(n, t)  将容器c重新设置为存储n个值为t的元素。


使用assign

当两个容器中的元素类型一样其元素类型也一样时, 可以用赋值=操作, 但是当两个容器中,元素类型不同但相互兼容时,就必须使用assign操作
assign操作首先删除容器中所有的元素,然后将其参数所指定的新元素插入到该容器中。

由于assign操作首先删除容器中原来存储的所有元素,因此,传递给assign函数的迭代器不能指向调用该函数的容器内的元素。

assign操作的使用

1 用两个迭代器:
     slist1.assign(slist2.begin(), slist2.end());
 2 使用一个元素值和一个整形数值
     slist1.assign(10, a);    

使用swap操作以节省删除元素的成本
要交换的容器的类型必须匹配,  调用了swap函数后,右操作数原来存储的元素被存放在左操作数中,反之亦然

vector<string> svec1(10);
vector<string> svec2(24);
svec1.swap(svec2)
这样一来,sevc1中就存储了24个元素,而sevc2中存储了10个元素。

该操作不会删除或插入任何元素,由于容器内没有移动交换元素,因此迭代器不会失效。

例如,在swap运算之前,有一个迭代器iter指向svec[3]字符串, 实现swap运算后,该迭代器则指向svec2[3]字符串。

vector容器的自增长

vector容器  其实就是数据结构中的 顺序存储,因此如果我们想往里面插入某个元素,所带来的代价讲非常高  
而list容器,就是数据结构中 链表,因此插入某个元素非常容易

但是在实际应用中,还是以vector居多,这是因为标准库的实现者使用这样的内存分配策略: 以最小的代价连续存储元素。 由此而带来的访问元素的便利弥补了其存储代价

为了使vector容器实现快速的内存分配, 其实际分配的容量要比当前所需空间多一些。 vector容器预留了这些额外的存储区,用于存放新添加的元素。


vector类提供了两个成员函数:capacity和reserve, 使程序员可与vector容器内存分配的实现部分交互工作。
capacity操作获取在容器需要分配更多的存储空间之前能够存储的元素总数, 而reserve操作则告诉vector容器应该预留多少个元素的存储空间。

capacity是容器在新分配时必须分配的存储空间,而size()是指容器当前所拥有的元素总数,其结果是capacity>=size()

每次当容器添加元素时,都需要重新分配存储空间, 也就是在原来的基础上多增加了一个 capacity的容量。


reserve(n)是分配指定的容量(capacity), capacity可能等于这个容量,也可能多于这个容量。
capacity=size()+reserved capacity


容器的选用
list vector和deque容器的区别, 如果你学了数据结构,那么这些都不是难点
它们无非由两个性能指标: 存储元素是否容器, 访问元素是否容器

对于顺序存储, 如果从中间插入元素,那么插入位置后面的元素都要挨个的往后移,因此代价挺高。
而对于链表存储, 如果访问中间位置的元素,则需要从第一个开始,一个一个查找,因此代价挺高

vector和deque属于顺序存储,而list属于链表存储
deque与vector唯一不同的是,deque支持在容器首部进行快速存储





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值