【C++ STL】Vector
1、结构
vector模塑出一个动态数组,因此,它本身是“将元素置于动态数组中加以管理”的一个抽象概念。vector将其元素复制到内部的dynamic array中。元素之间总存在某种顺序,所以vector是一种有序群集。vector支持随机存取,因此只要知道位置,可以在常数时间内存取任何一个元素。根据vector的结构可知,在末端添加或者删除元素,性能相当好,如果在前端或者中部安插或删除元素,性能就不怎么样了,因为操作点之后的元素都需要移到另一位置,而每一次移动都需要调用assignement(赋值)操作符。

2、大小(size)和容量(capacity)
2.1 性能
vector的优异性能的秘诀之一就是配置比其容纳元素所需更多的内存。vector用于操作大小的函数有size(),empty(),max_size(),另一个有关大小的函数是capacity(),它返回的是vector实际能够容纳的元素数量,如果超越这个数量,vector就有必要重新配置内部存储器。
vector的容量之所以很重要,有以下两个原因:
- 一旦内存重新分配,和vector相关的所有元素都会失效,如:references,pointers,iterators。
- 内存分配很耗时间
2.2 内存分配
2.2.1 reserve
如果程序管理了和vector元素相关的reference,pointers,iterator,或者执行效率至关重要,那么就必须考虑容器的容量问题。可以使用reserve()来保留适当容量,避免一再的分配内存,只要保留的容量有剩余,就不用担心reference失效。
std::vector<T> v;
v.reserve(n); //为vector分配容量为n的内存
还有一点要记住的是,如果调用reserve()所给的参数比当前的vector容量还小,不会发生任何反应,vector不能通过reverse来缩减容量。如何达到时间和空间的最佳效率,由系统版本决定,很多时候为了防止内存破碎,即使不调用reserve,当你第一次安插元素的时候,也会一次性配置整块内存(例如2K)。vector的容量不会缩减,即使删除元素,其reference,pointers,iterators也不会失效,继续指向发生动作之前的位置,然而安插元素可能使这些元素失效(因为安插可能重新分配内存空间)。
2.2.2 构造分配
另外一种避免重新分配内存的方法是,初始化期间就像构造函数传递附加参数,构造出足够的空间。如果参数是个数值,它将成为vector的起始大小。
std::vector<T> v(); //分配能容纳500个T元素的内存大小
当然,要获得这种能力,这种元素必须提供一个default构造函数,如果类型很复杂,提供了default构造函数,初始化也会很耗时,如果只是为了保留足够的内存,建议使用reverse()。
2.2.3 内存缩减
当然,要想缩减vector内存还是有方法的,那就是两个vector交换了内容后,两者的容量也会交换,即保留元素,又缩减了内存。
template<class T>
void shrinkCapacity(std::vector<T> &v)
{
std::vector<T> temp(v); //初始化一个新的vector
v.swap(temp); //交换元素内容
}
或者通过下列语句:
std::vector<T> (v).swap(v);
不过应该注意的是,swap()之后,原先所有的reference,pointers,iterator都换了指涉对象,他们仍然指向原本位置,也就是说它们在交换之后,都失效了。
void mvTestSize()
{
// size 为20的vector
vector<int> veciSize1;
for (int i = ; i < ; i++)
{
veciSize1.push_back(i);
} cout << "v1 size:" << veciSize1.size() << endl;
cout << "v1 max size:" << veciSize1.max_size() << endl;
cout << "v1 capacity:" << veciSize1.capacity() << endl; // size为200的vector
vector<int> veciSize2;
for (int i = ; i < ; i++)
{
veciSize2.push_back(i);
} cout << "v2 size:" << veciSize2.size() << endl;
cout << "v2 max size:" << veciSize2.max_size() << endl;
cout << "v2 capacity:" << veciSize2.capacity() << endl; //分配固定的size
vector<int> veciSize3;
veciSize3.reserve();
for (int i = ; i < ; i++)
{
veciSize3.push_back(i);
} cout << "v3 size:" << veciSize3.size() << endl;
cout << "v3 max size:" << veciSize3.max_size() << endl;
cout << "v3 capacity:" << veciSize3.capacity() << endl;
}
输出结果:

3、 vector操作函数
3.1 构造、拷贝和析构
可以在构造时提供元素,也可以不提供。如果指定大小,系统会调用元素的default构造函数一一制造新元素。
|
操作 |
效果 |
|
vector<Elem> c |
产生一个空的vector,没有任何元素 |
|
vector<Elem> c1(c2) |
产生另一同一类型的副本 (所有元素都被拷贝) |
|
vector<Elem> c(n) |
利用元素的default构造函数生成一个大小为n的vector |
|
vector<Elem> c(n,elem) |
产生一个大小为n的vector,每个元素都是elem |
|
vector<Elem> c(beg,end) |
产生一个vector,以区间[beg,end)作为初始值 |
|
c.~vector<Elem>() |
销毁所有元素,释放内存 |
3.2 非变动操作
|
操作 |
效果 |
|
c.size() |
返回当前的元素数量 |
|
c.empty() |
判断大小是否为零,等同于0 == size(),效率更高 |
|
c.max_size() |
返回能容纳的元素最大数量 |
|
capacity() |
返回重新分配空间前所能容纳的最大元素数量 |
|
reserve() |
如果容量不足,扩大 |
|
c1 == c2 |
判断c1是否等于c2 |
|
c1 != c2 |
判断c1是否不等于c2(等同于!(c1==c2)) |
|
c1 < c2 |
判断c1是否小于c2 |
|
c1 > c2 |
判断c1是否大于c2 |
|
c1 <= c2 |
判断c1是否小于等于c2(等同于!(c2<c1)) |
|
c1 >= c2 |
判断c1是否大于等于c2 (等同于!(c1<c2)) |
3.3 赋值操作
|
操作 |
效果 |
|
c1 = c2 |
将c2的元素全部给c1 |
|
c.assign(n,elem) |
复制n个elem给c |
|
c.assign(beg,end) |
将区间[beg,end)赋值给c |
|
c1.swap(c2) |
将c1和c2元素互换 |
|
swap(c1,c2) |
将c1和c2元素互换,全局函数 |
值得注意的是,所有的赋值操作都可能调用元素的default构造函数,copy构造函数和assignment操作符或者析构函数。
3.4 元素存取
|
操作 |
效果 |
|
c.at(idx) |
返回索引idx标示的元素,如果越界,抛出越界异常 |
|
c[idx] |
返回索引idx标示的元素,不进行范围检查 |
|
c.front() |
返回第一个元素,不检查第一个元素是否存在 |
|
c.back() |
返回最后一个元素,不检查最后一个元素是否存在 |
按照c/c++的惯例,第一个元素的索引为0,所以n个元素的索引为n-1。只有at()会检查范围,其他函数不检查范围,如果越界,除了at()会抛出异常,其他函数会引发未定义行为,所以使用索引的时候,必须确定索引有效,对一个空的vector使用front()和back()都会发生未定义行为,所以调用他们,必须保证vector不为空。
对于non-const-vector,这些函数返回的都是reference,可以通过这些函数来改变元素内容。
3.5 迭代器相关函数
vector提供了一些常规函数来获取迭代器。vector的迭代器是random access iterators(随机存取迭代器),简单的来说就是数组一样的迭代器,可以直接使用下标操作。
|
操作 |
效果 |
|
c.begin() |
返回一个随机存取迭代器,指向第一个元素 |
|
c.end() |
返回一个随机存取迭代器,指向最后一个元素的下一个位置 |
|
c.rbegin() |
返回一个逆向迭代器,指向逆向迭代的第一个元素 |
|
c.rend() |
返回一个逆向迭代器,指向逆向迭代的最后一个元素的下一个位置 |
3.5.1迭代器失效条件
- 使用者在较小位置安插或移除元素。
- 由于容量变化而引起内存重新分配。
3.5.2 安插和移除元素
vector提供安插和移除操作函数,调用这些函数,必须保证参数合法:
- 迭代器必须指向一个合法位置。
- 区间的起始位置不能在结束位置之后。
- 不能从空容器中移除元素。
关于性能,下列情况的安插和移除操作可能效率高一些:
- 在容器的尾部安插或删除元素。
- 容量一开始就很大。
- 安插多个元素,调用一次比调用多次快。
安插和删除元素,会使“作用点”之后的各元素的reference、pointers、iterators失效,如果安插操作导致内存重新分配,该容器的所有reference、pointers、iterators都会失效。
|
操作 |
效果 |
|
c.insert(pos,elem) |
在pos位置上插入一个elem副本,并返回新元素位置 |
|
c.insert(pos,n,elem) |
在pos位置插入n个elem副本,无返回值 |
|
c.insert(pos,beg,end) |
在pos位置插入[beg,end]内所有元素的副本,无返回值 |
|
c.push_back(elem) |
在尾部添加一个elme副本 |
|
c.pop_back() |
移除最后一个元素 |
|
c.erase(pos) |
移除pos上的位置,返回下一个元素的位置 |
|
c.erase(beg,end) |
移除[beg,end)内的所有元素,并返回下一元素的位置 |
|
c.resize(num) |
将元素的位置改为num个(如果size变大了,多出来的元素需要default构造函数来完成构造)) |
|
c.resize(num,elem) |
将元素的位置改为num个(如果size变大了,多出来的元素都是elem的副本)) |
|
c.clear() |
移除所有元素,将容器清空 |
4、代码示例
// cont/vector1.cpp #include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std; int main()
{ //create empty vector for strings
vector<string> sentence; //reserve memory for five elements to avoid reallocation
sentence.reserve(); //append some elements
sentence.push_back("Hello,");
sentence.push_back("how");
sentence.push_back("are");
sentence.push_back("you");
sentence.push_back("?"); //print elements separated with spaces
copy (sentence.begin(), sentence.end(),
ostream_iterator<string>(cout," "));
cout << endl; //print ''technical data''
cout << " max_size(): " << sentence.max_size() << endl;
cout << " size(): " << sentence.size() << endl;
cout << " capacity(): " << sentence.capacity() << endl; //swap second and fourth element
swap (sentence[], sentence []); //insert element "always" before element "?"
sentence.insert (find(sentence.begin(),sentence.end(),"?"),
"always"); //assign "!" to the last element
sentence.back() = "!"; //print elements separated with spaces
copy (sentence.begin(), sentence.end(),
ostream_iterator<string>(cout," "));
cout << endl; //print "technical data" again
cout << " max_size(): " << sentence.max_size() << endl;
cout << " size(): " << sentence.size() << endl;
cout << " capacity(): " << sentence.capacity() << endl; }
输出:
Hello, how are you ?
max_size():
size():
capacity():
Hello, you are how always !
max_size():
size():
capacity():
【C++ STL】Vector的更多相关文章
- CSP 201612-3 权限查询 【模拟+STL】
201612-3 试题名称: 权限查询 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 授权 (authorization) 是各类业务系统不可缺少的组成部分,系统用户通过授权 ...
- 【STL】- vector的用法
初始化: 1. 默认构造: vector<int> vint; 2. 用包含10个元素的数组初始化: vector<int> vint(ia, ia+10); 算法: 1. v ...
- 【STL】vector的insert方法详解
#include<vector> #include<iostream> using namespace std; int main() { vector<int> ...
- Educational Codeforces Round 34 B. The Modcrab【模拟/STL】
B. The Modcrab time limit per test 1 second memory limit per test 256 megabytes input standard input ...
- (转)【C++ STL】细数C++ STL 的那些事 -- priority_queue(优先队列)
装载自http://blog.csdn.net/tianshuai1111/article/details/7652553 一,概述 priority_queue是拥有权值观念的queue,它允许加入 ...
- 【c++基础】vector初始化的几种方式
前言 STL中的vector有几种初始化方式,根据不同的需求选择合适的初始化方式. 源码 // constructing vectors #include <iostream> #incl ...
- 【C++ STL】Set和Multiset
1.结构 set和multiset会根据特定的排序原则将元素排序.两者不同之处在于,multisets允许元素重复,而set不允许重复. 只要是assignable.copyable.comparab ...
- 2017CCPC秦皇岛 C题Crusaders Quest&&ZOJ3983【模拟+STL】
链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3983 题意: 给定9个血槽,有三种物品,每次可以把连续相同的物品抵消 ...
- 【C++ STL】Stack
1.定义 class stack<> 实作出一个stack(也成为LIFO,后进先出),你可以使用push()将任意数量的元素置入stack中,也可以使用pop()将元素依次插入次序反序从 ...
随机推荐
- SGU 194 Reactor Cooling(无源无汇上下界可行流)
Description The terrorist group leaded by a well known international terrorist Ben Bladen is bulidin ...
- 异常概念和处理机制,try-catch-finally,throw和throws,自定义异常
异常概念和处理机制 什么是异常? 所谓异常就是指在程序运行的过程中发生的一些不正常事件.(如除0溢出,数组下标越界,所要读取的文件不存在); 异常导致的后果? Java程序的执行过程中如出现异常事件, ...
- 你代码写得这么丑,一定是因为你长得不好看----panboo第一篇博客
一.个人介绍 我叫潘博,软嵌162,学号1613072055. 以“panboo”名称混迹于各大开源IT论坛与博客. 除了编程,我的最大爱好是篮球与健身,热衷于各种IT技术与运动. 我做过的软件项目有 ...
- ava中普通代码块,构造代码块,静态代码块区别及示例
//执行顺序:(优先级从高到低.)静态代码块>mian方法>构造代码块>构造方法. 其中静态代码块只执行一次.构造代码块在每次创建对象是都会执行. 1 普通代码块 //普通代码块:在 ...
- 敏捷冲刺Day1
前言: 之前的各种对教务系统的分析,再加上我们两三天的讨论和一个小时的站立会议,我们做出最终的决定.--我们决定换个项目主题,将原来的教务辅助系统换成现在的校园帮帮帮服务,并在之后会将完成后的计划书附 ...
- [剑指Offer] 51.构建乘积数组
题目描述 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1].不 ...
- bzoj3502[PA2012]Tanie Linie(最大k区间和)
题意:给定一个长为n的数列,要求选出最多k个不相交的区间(可以不选),使得选中的数字之和最大.(1<=k<=n<=1000000)分析:首先我们通过预处理对问题做一些简化.原序列中的 ...
- 浅析Nim游戏(洛谷P2197)
首先我们看例题:P2197 nim游戏 题目描述 甲,乙两个人玩Nim取石子游戏. nim游戏的规则是这样的:地上有n堆石子(每堆石子数量小于10000),每人每次可从任意一堆石子里取出任意多枚石子扔 ...
- Select-poll-epoll-简介
1. Python的select()方法直接调用操作系统的IO接口,它监控sockets,open files, and pipes(所有带fileno()方法的文件句柄)何时变成readable 和 ...
- CentOS 转义字符
常用转义字符 反斜杠(\):使反斜杠后面的一个变量变为单纯的字符串. 单引号(''):转义其中所有的变量为单纯的字符串. 双引号(""):保留其中的变量属性,不进行转义处理. 反引 ...