构造函数

使用迭代器构造vector的一种方式:

//将v[begin(), end())区间中的元素拷贝给本身
vector(v.begin(),v.end());

在这个构造函数中,传入普通数组也是可以的。如:

int arr[] = {1,2,3,4,5};
vector<int> v(arr,arr + sizeof(arr)/sizeof(int));

assign,at函数

这个assign函数原型有2个:

assign(beg, end);   //将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem); //将n个elem拷贝赋值给本身

这个和上一篇介绍的string里面的assign效用一致,就不多说,at也一样。知道vector也有就行了。上一篇

resize和reverse函数

resize(int num);        //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
resize(int num, int elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
reserve(int len); //容器预留len个元素长度,预留位置不初始化,元素不可访问。

就如注释上说的一样。

resize函数

resize函数变短时,容量capacity不会缩小。

resize函数有两个重载版本:

  • 只有一个参数int num时,表示重置容器的长度为num。若变长,则用默认值(vector为0)填充,若变短,超出末尾的元素直接被删除。
  • 参数为int num和int elem时,num还是表示重置大小,elem为新填充的元素。只有变大的时候elem才会填充。

看以下例子以及输出结果:

int main()
{
// 构造一个vector,内含100个1,看size和capacity
vector<int> v(100, 1);
cout << "v's size = " << v.size() << endl;
cout << "v's capacity = " << v.capacity() << endl << endl; // resize成5个,看size和capacity,以及打印出每个值
v.resize(5);
for (auto it = v.begin(); it != v.end(); ++it)
cout << *it << " ";
cout << endl << "v's size = " << v.size() << endl;
cout << "v's capacity = " << v.capacity() << endl; // resize成10个,看size和capacity,以及打印出每个值
v.resize(10);
cout << endl << "v's size = " << v.size() << endl;
cout << "v's capacity = " << v.capacity() << endl << endl;
for (auto it = v.begin(); it != v.end(); ++it)
cout << *it << " "; // resize成15个,将新位置填充为指定值,看size和capacity,以及打印出每个值
v.resize(13, -1);
cout << endl << "v's size = " << v.size() << endl;
cout << "v's capacity = " << v.capacity() << endl << endl;
for (auto it = v.begin(); it != v.end(); ++it)
cout << *it << " "; // resize成131个
v.resize(131);
cout << endl << "v's size = " << v.size() << endl;
cout << "v's capacity = " << v.capacity() << endl << endl;
return 0;
}

输出结果:

从图中可以看出来:

  • 若resize成一个比原来小的长度时,capacity不会改变,仅仅改变size.
  • 若resize成一个比原来大的长度且capacity需要改变时,会重新分配capacity,不是与resize的长度一致,而是按照扩容的策略来。

reverse函数

既然有了resize,为什么还需要有reverse函数来改变大小呢?关于resize要很明确:

  • 不初始化,不初始化,不初始化!

  • 不可访问,不可访问,不可访问!

也就是说,reserve只是开辟了这个空间,并没有去做初始化,没有初始化的位置就不能访问,否则会出现不可预料的结果。那么很明显,reserve是直接改变了capacity的值到指定大小。而resize还是采取vector的扩容策略,不断增加(以2倍或1.5倍,不同编译器不同),直到容量满足。

reserve的例子如下:

int main()
{
vector<int> v(10, 1);
cout << "最初:" << endl;
for (auto it = v.begin(); it != v.end(); ++it)
cout << *it << " ";
cout << "v's size = " << v.size() << endl;
cout << "v's capacity = " << v.capacity() << endl;
// 第一次reserve
cout << endl << "reserve to 5:" << endl;
v.reserve(5);
for (auto it = v.begin(); it != v.end(); ++it)
cout << *it << " ";
cout << endl << "v's size = " << v.size() << endl;
cout << "v's capacity = " << v.capacity() << endl;
// 第二次reserve
cout << endl << "reserve to 12:" << endl;
v.reserve(12);
for (auto it = v.begin(); it != v.end(); ++it)
cout << *it << " ";
cout << endl << "v's capacity = " << v.capacity() << endl;
cout << "v's size = " << v.size() << endl;
return 0;
}

结果如下:

从这个例子可以看出:

  • reserve长度减小的时候,是不起作用的。
  • reserve长度增加的时候,会新开辟相应的空间,不做初始化,不能访问。且容量capacity就是reserve的大小,而不是采用以往的扩容策略。

reserve的好处在哪里?

当我们的容器容量需要比较大,且可以预估我们容器的大小的时候,最好使用reserve。

如果我们使用普通的扩容策略,那么要扩容很多次(耗费性能,搬迁数据)才可能达到我们所需要的容量,且可能超出我们所需要容量的许多(空间冗余),等等问题。

插入、删除函数

erase函数

erase(const_iterator start, const_iterator end);//删除迭代器从[start,end)之间的元素
erase(const_iterator pos); //删除迭代器指向的元素

还是和上一篇讲述的差不多,可以参照上一篇

只需注意,返回的是删除之后指向的第一个元素的迭代器。

insert函数

几个函数原型:

// 在迭代器position之前插入单个val
iterator insert (const_iterator position, const value_type& val);
// 在迭代器position之前插入n个val
iterator insert (const_iterator position, size_type n, const value_type& val);
// 在迭代器position之前插入迭代器first到end之间的数据,左闭右开。
iterator insert (const_iterator position, InputIterator first, InputIterator last);

注意到返回值都是迭代器类型,没错,它返回的都是指向新插入的元素的首元素的迭代器。

以上单个插入和范围插入,均可参照上一篇。不多赘述。

swap函数

swap函数就是将两个容器交换。内部是直接交换指向各自vector的指针,而不是数据交换,这样节省了大量的时间。

int main()
{
vector<int> v1(5, -1);
vector<int> v2(24, 1); cout << "v1地址: " << &v1[0] << endl;
cout << "v2地址: " << &v2[0] << endl; v1.swap(v2); cout << "v1地址: " << &v1[0] << endl;
cout << "v2地址: " << &v2[0] << endl;
return 0;
}

运行结果如下:

由结果可见,二者地址互换。

swap的技巧有很多,这里介绍两种:收缩空间与释放空间。

swap收缩容器空间和释放空间

现在考虑我们上述讲到的,我们resize时若长度变短,capacity值不会变,这样就造成了空间冗余,不需要了。我们可以用swap将它释放掉:

int main()
{
vector<int> v;
for (int i = 0; i < 100000; i++){
v.push_back(i);
}
cout << "初始状态:" << endl;
cout << "capacity:" << v.capacity() << endl;
cout << "size:" << v.size() << endl; //此时 通过resize改变容器大小
v.resize(10); cout << endl << "resize to 10 之后:" << endl;
cout << "capacity:" << v.capacity() << endl;
cout << "size:" << v.size() << endl; // swap收缩空间
vector<int>(v).swap(v); cout << endl << "收缩空间:" << endl;
cout << "capacity:" << v.capacity() << endl;
cout << "size:" << v.size() << endl; // swap释放空间
vector<int>().swap(v); cout << endl << "释放空间:" << endl;
cout << "capacity:" << v.capacity() << endl;
cout << "size:" << v.size() << endl;
return 0;
}

输出结果为:

可以看到进行resize之后,仅仅只改变了size,如果我们接下去只需要用resize之后的空间,那么剩余的空间就成了多余的。所以我们先收缩空间,使得capacity和size一样。

收缩空间的代码:

vector<int>(v).swap(v);

分析一下这一句做了什么操作。可看为:

{
vector<int> vTemp(v);
vTemp.swap(v);
}

我们创建一个临时对象vTemp,将v中数据拷贝进去,与我们的v进行swap操作,我们的v就指向了vTemp。而vTemp出了这个作用域就被自动析构了。也就是原来的v被析构了。 所以,上面我们创建一个匿名对象,这个匿名对象的初值就是用v来拷贝的,用这个匿名对象与v进行swap操作即可。

如果我们不再使用这个容器,可以将它释放掉。

同理,释放空间的代码:

vector<int>().swap(v);

与上述一致,只不过这一次我们创建的匿名对象没有给初值,就会调用默认构造函数,置空了。然后我们的v再指向了这个空容器,原本的v指向了匿名对象的空间,被自动析构,达到我们想要的效果。

补充,关于clear函数

上面讲到可以巧用swap来进行释放空间,那clear不行吗?这也是我在上一篇没有讲到的事情。 clear函数只能做到将size清零,也没有将capacity清理掉,所以这一块内存我们还在占用。如果我们要回收,将这些都释放,使用swap就可以办法。

这个很容易验证,创建个容器,赋值,调用clear,再查看此容器的size和capacity,会看到capacity不为0.(vector和string都是如此,但也有其它不是如此的,如deque,clear后会释放空间).

我不熟悉的vector的更多相关文章

  1. hdu 4409 Family Name List(LCA&amp;有坑点)

    Family Name List Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  2. ACM中使用 JAVA v2. 1

    ACM中使用JAVA v2.1 严明超 (Blog:mingchaoyan.blogbus.com Email:mingchaoyan@gmail.com) 0.前 言 文前声明:本文只谈java用于 ...

  3. c++转载系列 std::vector模板库用法介绍

    来源:http://blog.csdn.net/phoebin/article/details/3864590 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作 ...

  4. 6. support vector machine

    1. 了解SVM 1. Logistic regression 与SVM超平面 给定一些数据点,它们分别属于两个不同的类,现在要找到一个线性分类器把这些数据分成两类.如果用x表示数据点,用y表示类别( ...

  5. 学习RaphaelJS矢量图形包--Learning Raphael JS Vector Graphics中文翻译(一)

    (原文地址:http://www.cnblogs.com/idealer3d/p/LearningRaphaelJSVectorGraphics.html) 前面3篇博文里面,我们讲解了一本叫做< ...

  6. 快速熟悉Velocity

    果然公司用的东西跟平时学的东西不太一样,我们公司前台页面并不是我们熟悉的.html或者.jsp文件,而是很多人不知道的 .vm文件,其实只要我们理解了jsp文件,vm文件也就是一些基本语法不同而已. ...

  7. STL vector用法介绍

    STL vector用法介绍 介绍 这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作.本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()和f ...

  8. 斯坦福第十二课:支持向量机(Support Vector Machines)

    12.1  优化目标 12.2  大边界的直观理解 12.3  数学背后的大边界分类(可选) 12.4  核函数 1 12.5  核函数 2 12.6  使用支持向量机 12.1  优化目标 到目前为 ...

  9. c++ vector 简单实现。

    第二次修改: 1)熟悉基本的模板编程,头文件和定义必须放到一起. 2)熟悉内存管理模板类 allocator<T>. 1.使用标准库的内存管理类 allocator<T> 代替 ...

随机推荐

  1. __metaclass__方法

    metaclass这个属性叫做元类,它是用来表示这个类是由谁来帮他实例化创建的,说白了,就是相当于自己定制一个类. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...

  2. 从入门到自闭之Python字典如何使用

    字典: 定义:dict dict = {"key":"value"} -- 键值对 作用:存储大量数据,数据和数据起到关联作用 所有的操作都是通过键来完成 键: ...

  3. 数据结构之单链表的实现-java

    一.单链表基本概念 单链表是一种链式存取的数据结构,用一组地址任意的存储单元(一般是非连续存储单元)存放线性表中的数据元素.链表中的数据是以结点来表示的,每个结点的构成:元素data + 指针next ...

  4. ubuntu18.04系统安装及php7.2,apache2,mysql8,git,svn,composer,vs code 到安装 php 扩展配置php.ini 实现 laravel5.8 运行

    简介:记录自己从系统安装到环境配置完毕运行laravel的记录    • 下载ubuntu18.04桌面版        ○ ubuntu18.04中国官网 https://cn.ubuntu.com ...

  5. 18 Python之初识面向对象

    1. 类与对象 class Car: #类名首字母大写,严格遵守驼峰命名规范 pass #造车 c = Car() #类名() #创建对象 ##出场之后进行改装 c.color = "红色& ...

  6. 目标 - 在虚拟机CentOS7中无图形界面安装Oracle11G R2版本

    参考: https://www.cnblogs.com/yejingcn/p/10278473.html centos7启动oracle su - oracle //切换到自己的oracle账户 ls ...

  7. 记一次启动Tomcat 控制台以及log4j 乱码问题

    Tomcat启动乱码 问题描述:当你发现你的Tomcat启动时乱码了,而你只是换了个Tomcat版本而已. 在找到真正的问题之前,我在网上百度了N多的资料,都试过了,但是都不行.1.修改了 windo ...

  8. 服务器挂载 ntfs32 硬盘

    1,fdisk -l 查看硬盘名称 2,mount -t ntfs-3g /硬盘名/  /目标目录/ 3,umount   /硬盘名/ 4,如果卸载不了 就fuser -km /目标目录/

  9. 【转载】#pragma once与#ifndef

    本篇随笔为转载,原贴地址:#pragma once与#ifndef解析 为了避免同一个文件被include多次,C/C++中有两种方式,一种是#ifndef方式,一种是#pragma once方式.在 ...

  10. html背景图不随滚轮滚动,而且按住Ctrl并滚动滚轮时,图片不会变大缩小,就像百度的首页一样

    之前在百度知道我提问过这一个问题,后来解决了.不过好多人来问我时怎么解决的,源码.其实很简单.这里我贴一下代码.有需要的小伙伴不用再加我qq了,直接来这里取吧. 里面的图片是我随便找的. <!D ...