三大顺序器皿的简单使用与异同

三大顺序容器的简单使用与异同

                            三大顺序容器的使用与对比

vector                支持快速随机访问

list                   支持快速插入和删除

deque                双端队列

 

 

 

容器的初始化:

C c; 创建一个名为c的空容器。c是容器类型名。

C c(c2);将c2容器赋值飞c容器。

C c(begin,end);    创建容器c,并用迭代器begin和end之间的元素进行初始化。

C c(n, t);       用n个值t的元素进行初始化。

C c(n);        创建n个值初始化。

 

容器内元素的约束类型

大多数类型都可用做容器的元素类型。容器元素类型必须满足两个约束:

元素类型必须支持赋值运算。

元素类型的对象必须可以复制。

引用不支持一般意义的赋值运算,所以没有元素是引用类型的容器。
io库类型不支持赋值和赋值,所以也不能创建存放io类型对象的容器。

 

迭代器的操作,以及vector和deque特有的

通用如下:

*iter

iter->mem

++iter

iter++

--iter

iter--

iter1 == iter2

iter1 != iter2

下面的迭代器操作是vector与deque特有的,list不可以使用

iter+n

iter-n

iter1+=iter2

iter1-=iter2

iter1-iter2

<=

>=

list中迭代器不支持大于小于操作符,所以迭代list的时候不要用iter < li.end()这样的操作,要用iter!=li.end()

容器内定义的类型别名

这是容器自己定义的类型,这个地方没什么好说的,把定义的类型别名做个列举吧。

size_type      无符号整形,足以存储迭代器类型最大可能容器长度

iterator              此容器类型的迭代器     

const_iterator        元素的只读迭代器类型

reverse_iterator    逆序寻址元素的迭代器

const_reverse_iterator     元素只读的逆序迭代器

difference_type     足够存储两个迭代器差值的有符号整形,可为负数

value_type              元素类型

reference          元素左值类型,是value_type&的同义词

const_reference    元素常量的左值类型,等效于const value_type&

插入元素

在顺序容器中添加元素有以下几种方法:

c.push_back(t);    在容器c的尾部添加值为t的元素。返回void,俗称尾插。

c.push_front(t);   与尾插相反,这个是在c容器的头部添加值为t的元素。返回同样是void,俗称头插,但一定要注意,这种方式只使用与list和deque,而不支持vector,在后面我们也会提到删除,vector也同样不支持头删。

c.insert(p,t);    在迭代器p所指向的元素前面插入值为t的新元素。返回指向新元素的迭代器。

c.insert(p, n, t);在迭代器p所指向的元素前面插入n个值为t的新元素。返回void类型。

c.insert(p, begin,end);  在迭代器p所指向的元素前面插入有迭代器begin和end标记的范围内的元素,返回值同样为void。

注意,想插入,删除这样的操作有可能使迭代器失效,只要是元素的位置发生了变化,那么指向它的迭代器就会失效。

 

 

关系操作符,从其大小操作

关系操作符比较简单,容器都支持关系操作符进行容器的比较,包括<,>,!=等操作,但是一定要注意,连个容器的类型一定要相同。

 

c.size();  返回c容器中元素的个数,返回容器内元素的个数。类型是c::size_type

c.max_size();返回容器c可容纳的最多元素个数

c.empty();返回容器是否为空,为空返回true,否则返回false

c.resize(n);调整容器的长度,如多n小于size的话,删除多余的元素,否则初始化多出来的新元素。

c.resize(n, t); 多出来的新元素用t进行初始化。

 

 

访问元素操作

c.back();访问容器最后一个元素

c.front();访问容器第一个元素

如果容器为空,上述操作未定义。

以下是比较方便的访问操作,但是只适用于vector和deque,list不支持。

c[n];访问容器中第n个元素。

c.at(n);访问容器中第n个元素。

下标越界的话,操作未定义。

 

 

删除元素操作

删除元素很容易理解,即删除容器当中指定的元素。

有以下几个操作。

c.erase(p);

删除迭代器p所指向的元素,返回一个被删除元素后面的元素的迭代器。不过要注意p并不是c.end();而是真实存在的元素。

c.erase(begin,end);

删除迭代器begin和end范围内容的元素,返回迭代器指向删除段的下一个元素。

c.clear();

删除容器全部元素,返回void。

c.pop_back();

删除容器中最后一个元素

只适用于list与deque的

c.pop_front();

删除容器中的第一个元素。这里面没有vector的事儿,vector不支持前插与前删。前删除与后删除返回值同样是void,如果容器为空的话,这样的操作未定义。

赋值操作与swap操作

与赋值相关的操作都将作用于整个容器。功能上理解起来非常简单,就是把左操作数容器的内容全部删除,在将右操作数容器插入到左操作数容器,有以下几种方式。

c1 = c2

将c1中的内容清除,将c2中的内容插入到c1中。

assign函数

这个函数有两个版本

c.assign(begin,end); 将迭代器begin和end中的元素插入到c中,但是这两个迭代器不能是不能是指向c中元素的迭代器。

c.assign(n, t); 将迭代器重置为n个t元素。

需要注意的是容器的类型一定要相同。操作完成迭代器失效。

swap操作可以节省删除元素的成本。

这个操作是将两个容器的内容互换,所以容器类型要相同。右操作容器中原来的内容放于左操作容器中。由于没有增加删除移动容器的元素,所以迭代器不会失效。

vector容器的自增长:

为什么是涉及到vector容器自增长的问题呢?因为vector容器内的元素在内存中是连续存放的,假如我想在后面加入一个元素,不能随便在内存的其他位置开辟一块空间,于是我们不得不开辟比现有容器更大的空间,然后把以前的容器元素复制到新的空间里,在把新元素加到后面,之后释放掉以前容器占用的空间。这样的话我们每插入一个元素的话只开辟原有vector容器再多一个的空间,这样vector的性能会非常非常的大。另外插一句额外的话,list容器使用的是链表的数据结构,新增加元素不用关心在内存什么位置添加,我只要修改结构里节点中指向下一个节点的指针指向即可。这也是为什么vector的随机访问性能优于list,而随机插入元素的性能低于list。

基于上述的原因,为了提高vector的性能,我们应该在vector添加元素的时候要多开辟一些空间,多开辟多少空间根据库的不同而不同。这里面还涉及一个概念叫做容量,容量是指这个vector容器新分配的存储空间能存放多少个元素。他和容器大小的区别是,大小只是容器装的元素的个数。举个例子,容量就好像是水杯的容量,而容器大小就是里面装的水的体积。所以容量只大于等于容器长度,不能小于。

capacity函数,返回容器的容量值。

例子程序:当我们耗尽了容器的容量,在插入才进行内存分配。因此是必要的时候才重新分配内存空间。

reserve函数,手动设置vector容器应该预留多大的容量。

例子: