当前位置: 首页 > 编程日记 > 正文

容器使用之vector

出处:http://blog.csdn.net/edify/article/details/4035243

C++内置的数组支持容器的机制,但是它不支持容器抽象的语义。要解决此问题我们自己实现这样的类。在标准C++中,用容器向量(vector)实现。容器向量也是一个类模板。 标准库vector类型使用需要的头文件:#include <vector>。vector 是一个类模板。不是一种数据类型,vector<int>是一种数据类型。Vector的存储空间是连续的,list不是连续存储的。

一、 定义和初始化 vector< typeName > v1;       //默认v1为空,故下面的赋值是错误的v1[0]=5; vector<typeName>v2(v1); 或v2=v1;或vector<typeName> v2(v1.begin(), v1.end());//v2是v1的一个副本,若v1.size()>v2.size()则赋值后v2.size()被扩充为v1.size()。 vector< typeName > v3(n,i);//v3包含n个值为i的typeName类型元素 vector< typeName > v4(n); //v4含有n个值为0的元素 int a[4]={0,1,2,3,3}; vector<int> v5(a,a+5);//v5的size为5,v5被初始化为a的5个值。后一个指针要指向将被拷贝的末元素的下一位置。 vector<int> v6(v5);//v6是v5的拷贝 vector< 类型 > 标识符(最大容量,初始所有值);

二、 值初始化 1>     如果没有指定元素初始化式,标准库自行提供一个初始化值进行值初始化。 2>     如果保存的式含有构造函数的类类型的元素,标准库使用该类型的构造函数初始化。 3>     如果保存的式没有构造函数的类类型的元素,标准库产生一个带初始值的对象,使用这个对象进行值初始化。

三、vector对象最重要的几种操作 1. v.push_back(t)    在容器的最后添加一个值为t的数据,容器的size变大。     另外list有push_front()函数,在前端插入,后面的元素下标依次增大。 2. v.size()        返回容器中数据的个数,size返回相应vector类定义的size_type的值。v.resize(2*v.size)或

v.resize(2*v.size, 99) 将v的容量翻倍(并把新元素的值初始化为99) 3. v.empty()     判断vector是否为空 4. v[n]           返回v中位置为n的元素 5. v.insert(pointer,number, content)    向v中pointer指向的位置插入number个content的内容。     还有v. insert(pointer, content),v.insert(pointer,a[2],a[4])将a[2]到a[4]三个元素插入。 6. v.pop_back()    删除容器的末元素,并不返回该元素。 7.v.erase(pointer1,pointer2) 删除pointer1到pointer2中间(包括pointer1所指)的元素。    vector中删除一个元素后,此位置以后的元素都需要往前移动一个位置,虽然当前迭代器位置没有自动加1,    但是由于后续元素的顺次前移,也就相当于迭代器的自动指向下一个位置一样。 8. v1==v2          判断v1与v2是否相等。 9. !=、<、<=、>、>=      保持这些操作符惯有含义。 10. vector<typeName>::iterator p=v1.begin( ); p初始值指向v1的第一个元素。*p取所指向元素的值。       对于const vector<typeName>只能用vector<typeName>::const_iterator类型的指针访问。 11.   p=v1.end( ); p指向v1的最后一个元素的下一位置。 12.v.clear()      删除容器中的所有元素。12.v.clear()      删除容器中的所有元素。

#include<algorithm>中的泛函算法 搜索算法:find() 、search() 、count() 、find_if() 、search_if() 、count_if() 分类排序:sort() 、merge() 删除算法:unique() 、remove()
生成和变异:generate() 、fill() 、transformation() 、copy() 关系算法:equal() 、min() 、max() sort(v1.begin(),vi.begin()+v1.size/2); 对v1的前半段元素排序 list<char>::iterator pMiddle =find(cList.begin(),cList.end(),'A');找到则返回被查内容第一次出现处指针,否则返回end()。 vector< typeName >::size_type x ; vector< typeName >类型的计数,可用于循环如同for(int i)

初学C++的程序员可能会认为vector的下标操作可以添加元素,其实不然:

vector<int> ivec;   // empty vector

for (vector<int>::size_type ix = 0; ix != 10; ++ix)

ivec[ix] = ix; // disaster: ivec has no elements

上述程序试图在ivec中插入10个新元素,元素值依次为0到9的整数。但是,这里ivec是空的vector对象,而且下标只能用于获取已存在的元素。

这个循环的正确写法应该是:

for (vector<int>::size_type ix = 0; ix != 10; ++ix)

ivec.push_back(ix); // ok: adds new element with value ix

警告:必须是已存在的元素才能用下标操作符进行索引。通过下标操作进行赋值时,不会添加任何元素。仅能对确知已存在的元素进行下标操作

四、内存管理与效率

1.使用reserve()函数提前设定容量大小,避免多次容量扩充操作导致效率低下。

关于STL容器,最令人称赞的特性之一就是是只要不超过它们的最大大小,它们就可以自动增长到足以容纳你放进去的数据。(要知道这个最大值,只要调用名叫max_size的成员函数。)对于vector和string,如果需要更多空间,就以类似realloc的思想来增长大小。vector容器支持随机访问,因此为了提高效率,它内部使用动态数组的方式实现的。在通过 reserve() 来申请特定大小的时候总是按指数边界来增大其内部缓冲区。当进行insert或push_back等增加元素的操作时,如果此时动态数组的内存不够用,就要动态的重新分配当前大小的1.5~2倍的新内存区,再把原数组的内容复制过去。所以,在一般情况下,其访问速度同一般数组,只有在重新分配发生时,其性能才会下降。正如上面的代码告诉你的那样。而进行pop_back操作时,capacity并不会因为vector容器里的元素减少而有所下降,还会维持操作之前的大小。对于vector容器来说,如果有大量的数据需要进行push_back,应当使用reserve()函数提前设定其容量大小,否则会出现许多次容量扩充操作,导致效率低下。

reserve成员函数允许你最小化必须进行的重新分配的次数,因而可以避免真分配的开销和迭代器/指针/引用失效。但在我解释reserve为什么可以那么做之前,让我简要介绍有时候令人困惑的四个相关成员函数。在标准容器中,只有vector和string提供了所有这些函数。

(1) size()告诉你容器中有多少元素。它没有告诉你容器为它容纳的元素分配了多少内存。 (2) capacity()告诉你容器在它已经分配的内存中可以容纳多少元素。那是容器在那块内存中总共可以容纳多少元素,而不是还可以容纳多少元素。如果你想知道一个vector或string中有多少没有被占用的内存,你必须从capacity()中减去size()。如果size和capacity返回同样的值,容器中就没有剩余空间了,而下一次插入(通过insert或push_back等)会引发上面的重新分配步骤。
(3) resize(Container::size_type n)强制把容器改为容纳n个元素。调用resize之后,size将会返回n。如果n小于当前大小,容器尾部的元素会被销毁。如果n大于当前大小,新默认构造的元素会添加到容器尾部。如果n大于当前容量,在元素加入之前会发生重新分配。
(4) reserve(Container::size_type n)强制容器把它的容量改为至少n,提供的n不小于当前大小。这一般强迫进行一次重新分配,因为容量需要增加。(如果n小于当前容量,vector忽略它,这个调用什么都不做,string可能把它的容量减少为size()和n中大的数,但string的大小没有改变。在我的经验中,使用reserve来从一个string中修整多余容量一般不如使用“交换技巧”,那是条款17的主题。)

这个简介表示了只要有元素需要插入而且容器的容量不足时就会发生重新分配(包括它们维护的原始内存分配和回收,对象的拷贝和析构和迭代器、指针和引用的失效)。所以,避免重新分配的关键是使用reserve尽快把容器的容量设置为足够大,最好在容器被构造之后立刻进行。

例如,假定你想建立一个容纳1-1000值的vector<int>。没有使用reserve,你可以像这样来做:

vector<int> v; for (int i = 1; i <= 1000; ++i) v.push_back(i); 在大多数STL实现中,这段代码在循环过程中将会导致2到10次重新分配。(10这个数没什么奇怪的。记住vector在重新分配发生时一般把容量翻倍,而1000约等于210。)

把代码改为使用reserve,我们得到这个:

vector<int> v; v.reserve(1000); for (int i = 1; i <= 1000; ++i) v.push_back(i); 这在循环中不会发生重新分配。

在大小和容量之间的关系让我们可以预言什么时候插入将引起vector或string执行重新分配,而且,可以预言什么时候插入会使指向容器中的迭代器、指针和引用失效。例如,给出这段代码,

string s; ... if (s.size() < s.capacity()) { s.push_back('x'); } push_back的调用不会使指向这个string中的迭代器、指针或引用失效,因为string的容量保证大于它的大小。如果不是执行push_back,代码在string的任意位置进行一个insert,我们仍然可以保证在插入期间没有发生重新分配,但是,与伴随string插入时迭代器失效的一般规则一致,所有从插入位置到string结尾的迭代器/指针/引用将失效。

回到本条款的主旨,通常有两情况使用reserve来避免不必要的重新分配。第一个可用的情况是当你确切或者大约知道有多少元素将最后出现在容器中。那样的话,就像上面的vector代码,你只是提前reserve适当数量的空间。第二种情况是保留你可能需要的最大的空间,然后,一旦你添加完全部数据,修整掉任何多余的容量。

2.使用“交换技巧”来修整vector过剩空间/内存

有一种方法来把它从曾经最大的容量减少到它现在需要的容量。这样减少容量的方法常常被称为“收缩到合适(shrink to fit)”。该方法只需一条语句:vector<int>(ivec).swap(ivec); 表达式vector<int>(ivec)建立一个临时vector,它是ivec的一份拷贝:vector的拷贝构造函数做了这个工作。但是,vector的拷贝构造函数只分配拷贝的元素需要的内存,所以这个临时vector没有多余的容量。然后我们让临时vector和ivec交换数据,这时我们完成了,ivec只有临时变量的修整过的容量,而这个临时变量则持有了曾经在ivec中的没用到的过剩容量。在这里(这个语句结尾),临时vector被销毁,因此释放了以前ivec使用的内存,收缩到合适。

3.用swap方法强行释放STL Vector所占内存

template < class T> void ClearVector( vector<T>& v ) {
    vector<T>vtTemp;     vtTemp.swap( v ); } 如     vector<int> v ;     nums.push_back(1);     nums.push_back(3);     nums.push_back(2);     nums.push_back(4);     vector<int>().swap(v);

/* 或者v.swap(vector<int>()); */

/*或者{ std::vector<int> tmp = v;   v.swap(tmp);   }; //加大括号{ }是让tmp退出{ }时自动析构*/

五、Vector 内存管理成员函数的行为测试 C++ STL的vector使用非常广泛,但是对其内存的管理模型一直有多种猜测,下面用实例代码测试来了解其内存管理方式,测试代码如下:

#include <iostream> #include <vector> using namespace std;

int main() { vector<int> iVec; cout << "容器 大小为: " << iVec.size() << endl; cout << "容器 容量为: " << iVec.capacity() << endl; //1个元素, 容器容量为1

iVec.push_back(1); cout << "容器 大小为: " << iVec.size() << endl; cout << "容器 容量为: " << iVec.capacity() << endl; //2个元素, 容器容量为2

iVec.push_back(2); cout << "容器 大小为: " << iVec.size() << endl; cout << "容器 容量为: " << iVec.capacity() << endl; //3个元素, 容器容量为4

iVec.push_back(3); cout << "容器 大小为: " << iVec.size() << endl; cout << "容器 容量为: " << iVec.capacity() << endl; //4个元素, 容器容量为4

iVec.push_back(4); iVec.push_back(5); cout << "容器 大小为: " << iVec.size() << endl; cout << "容器 容量为: " << iVec.capacity() << endl; //5个元素, 容器容量为8

iVec.push_back(6); cout << "容器 大小为: " << iVec.size() << endl; cout << "容器 容量为: " << iVec.capacity() << endl; //6个元素, 容器容量为8

iVec.push_back(7); cout << "容器 大小为: " << iVec.size() << endl; cout << "容器 容量为: " << iVec.capacity() << endl; //7个元素, 容器容量为8

iVec.push_back(8); cout << "容器 大小为: " << iVec.size() << endl; cout << "容器 容量为: " << iVec.capacity() << endl; //8个元素, 容器容量为8

iVec.push_back(9); cout << "容器 大小为: " << iVec.size() << endl; cout << "容器 容量为: " << iVec.capacity() << endl; //9个元素, 容器容量为16 /* vs2005/8 容量增长不是翻倍的,如     9个元素   容量9     10个元素 容量13 */

/* 测试effective stl中的特殊的交换 swap() */ cout << "当前vector 的大小为: " << iVec.size() << endl; cout << "当前vector 的容量为: " << iVec.capacity() << endl; vector<int>(iVec).swap(iVec);

cout << "临时的vector<int>对象 的大小为: " << (vector<int>(iVec)).size() << endl; cout << "临时的vector<int>对象 的容量为: " << (vector<int>(iVec)).capacity() << endl; cout << "交换后,当前vector 的大小为: " << iVec.size() << endl; cout << "交换后,当前vector 的容量为: " << iVec.capacity() << endl;

return 0; }

六、vector的其他成员函数

c.assign(beg,end) 将[beg; end)区间中的数据赋值给c。 c.assign(n,elem) 将n个elem的拷贝赋值给c。
c.at(idx) 传回索引idx所指的数据,如果idx越界,抛出out_of_range。
c.back() 传回最后一个数据,不检查这个数据是否存在。 c.front() 传回地一个数据。
get_allocator 使用构造函数返回一个拷贝。 c.rbegin() 传回一个逆向队列的第一个数据。
c.rend() 传回一个逆向队列的最后一个数据的下一个位置。 c.~ vector <Elem>() 销毁所有数据,释放内存

转载于:https://www.cnblogs.com/Skyxj/p/3200094.html

相关文章:

Hyperloop 让发布简洁高效

原文链接&#xff1a;https://mp.weixin.qq.com/s/MZMqzaKLqQN0zJikNYEbwgHyperloop 是服务于美团点评客户端的组件发版、持续集成、App 打包构建、资源调度等各个环节的发布调度系统。名称起源于美国 Elon Musk 构想的 Hyperloop 超级高铁&#xff0c;象征着现代、简洁、高效。…

数据通信技术(十一:无中继的DHCP配置(ZTE))

路由器的无中继DHCP配置(ZTE) 一&#xff0e;知识准备 1、掌握DHCP的基本原理和作用&#xff1b; 2、掌握DHCP的网络架构。 二&#xff0e;实验目的 1、掌握中兴路由器DHCP的配置方法和功能验证&#xff1b; 三&#xff0e;实验内容 1、完成中兴路由器DHCP的基本配置和结…

小米4手机在DDMS下获取data/data目录权限

1.首先先root手机 2.进入adb adb shell su //获取root权限 mount -0 remount,rw /data //重新挂载分区为可读写(可以用 df命令查看分区情况) chmod 777 /data //更改文件夹权限可读写 3.adb 常用命令大全 1. 显示系统中全部Android平台&#xff1a; android list targets 2. 显…

工程大小优化之图片资源

工程大小优化之图片资源 摘要&#xff1a;点点iOS项目本身功能较多&#xff0c;导致应用体积也比较大。一个Xcode工程下图片资源占用了很大的空间&#xff0c;且如果有些App需要一键换肤功能&#xff0c;呵呵&#xff0c;不知道得做多少图片。每套图片还需要设置1x,2x,3x等 简介…

鼠标悬浮变手指

style"cursor:pointer" 转载于:https://www.cnblogs.com/dreamzcy/p/3200897.html

Spring Boot项目快速搭建

实验要求及目的&#xff1a; &#xff08;1&#xff09;掌握ApplicationContext容器使用属性setter方法注入的实现&#xff1b; &#xff08;2&#xff09;了解Spring的概念和优点&#xff1b; &#xff08;3&#xff09;熟悉Spring中的IOC和DI&#xff1b; 实验环境&#xff1…

wcf入门教程

一、概述 Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口&#xff0c;可以翻译为Windows通讯接口&#xff0c;它是.NET框架的一部分。由 .NET Framework 3.0 开始引入。 WCF的最终目标是通过进程或不同的系统、通过本地网络或是通过Inter…

Swift iOS : 字体图标

厌倦了使用位图在xcode的Assets.xcassets内&#xff0c;因为麻烦&#xff0c;包括如下的麻烦&#xff1a; 找图图需要分尺寸需要操作员类似工作去管理 然后&#xff0c;现在有了字体图标&#xff0c;就方便多了&#xff1a; 比较成熟的几套库&#xff0c;用名字就可以查矢量…

巧用Excel 2010数据透视表制作销售报表

小刘需要根据2010-2011两年间的订单记录创建季度报表&#xff0c;以便分析各类图书的销售情况。面对如此庞大的订单记录&#xff0c;该从何下手呢? 其实最快捷的办法是使用Excel 2010创建数据透视表&#xff0c;以快速合并和比较这些数据。在数据透视表中&#xff0c;可以很清…

Spring的基础应用

实验目的及要求 掌握ApplicationContext容器使用属性setter方法注入的实现&#xff1b;了解Spring的概念和优点&#xff1b; 熟悉Spring中的IOC和DI 实验环境 Java jdk 1.8&#xff1b;apache-maven-3.6.0&#xff1b;Myeclipse C10&#xff1b; 实验内容&#xff1a; 任务一…

iOS App 连接外设的几种方式

原创作者: Max_Marry 文章地址: http://www.jianshu.com/p/852bf92c5c92 随着近年来车联网和物联网的兴起&#xff0c;智能家居和智能硬件的逐步火热&#xff0c;越来越多的 App 被用来跟硬件设备进行来连接&#xff0c;获取硬件相关信息用以展示或者发送指令控制硬件来提供服务…

Android深度探索(卷1)HAL与驱动开发第五章总结

开发板是开发和学习嵌入式技术的主要硬件设备&#xff0c;开发板的型号和种类很多&#xff0c;目前流行的是基于S3C6410 ARM11架构的开发板&#xff0c;S3C6410是由三星公司推出的一款低功耗&#xff0c;高性价比的RISC处理器&#xff0c;它基于ARM11内核&#xff0c;可广泛应用…

controlfile

1、如何恢复控制文件 Your database instance is started using the server parameter file (SPFILE). Control files are multiplexed and stored on different disks. Because of a disk failure, you lost one of these control files. You replaced the damaged disk. What…

Spring servlet

1、修改pom.xml文件&#xff0c;添加以下内容&#xff1a; 代码&#xff1a; <dependency><groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> <dependency> <groupId>org.apac…

iOS传感器:实现一个随屏幕旋转的图片

作者 非典型技术宅 关注 2017.05.24 17:22* 字数 1568 阅读 351评论 7喜欢 14在写上一个动画系列的时候学到了非常多的知识&#xff0c;也认识了很多人。例如受邀进入了某个神秘的动效组织&#xff0c;全是一线的大神啊。有UI的大牛、UED的大神、iOS的大神。加入组织可以阅读这…

构建之法-读后感

大二快结束&#xff0c;从大二初开始接触项目的工程开发&#xff0c;到现在也差不多一年了。之前一直在用c# 结合winform开发一些简单的桌面应用&#xff0c;也看过一些是实验室学长们用c#和其他多种技术结合 开发出来的系统&#xff0c; 接触过其源代码&#xff0c;为深入了解…

Java 理论与实践: 非阻塞算法简介——看吧,没有锁定!(转载)

简介&#xff1a; Java™ 5.0 第一次让使用 Java 语言开发非阻塞算法成为可能&#xff0c;java.util.concurrent 包充分地利用了这个功能。非阻塞算法属于并发算法&#xff0c;它们可以安全地派生它们的线程&#xff0c;不通过锁定派生&#xff0c;而是通过低级的原子性的硬件原…

pring Boot与MyBatista的集成

1、准备数据库环境&#xff0c;在MySQL数据库中&#xff0c;创建一个名为microservice的数据库&#xff0c;在microservice中创建表tb_user&#xff0c;并在表中插入3条数据&#xff1b; 2、创建项目&#xff0c;添加依赖。 3、编写配置文件&#xff0c;在application.properti…

iOS中UIDynamic物理仿真详解

本文中所有代码演示均有GitHub源码&#xff0c;点击下载 UIDynamic简介 简介&#xff1a; UIKit动力学最大的特点是将现实世界动力驱动的动画引入了UIKit&#xff0c;比如动力&#xff0c;铰链连接&#xff0c;碰撞&#xff0c;悬挂等效果&#xff0c;即将2D物理引擎引入了UIKi…

ADO与ADO.NET的区别与介绍

1. ADO与ADO.NET简介ADO与ADO.NET既有相似也有区别&#xff0c;他们都能够编写对数据库服务器中的数据进行访问和操作的应用程序&#xff0c;并且易于使用、高速度、低内存支出和占用磁盘空间较少&#xff0c;支持用于建立基于客户端/服务器和 Web 的应用程序的主要功能。但是A…

cucumber 文件目录结构和执行顺序

引用链接&#xff1a;http://www.cnblogs.com/timsheng/archive/2012/12/10/2812164.html Cucumber是Ruby世界的BDD框架&#xff0c;开发人员主要与两类文件打交 到&#xff0c;Feature文件和相应的Step文件。Feature文件是以 feature为后缀名的文件&#xff0c;以Given-When-T…

Spring Boot与Redis的集成

1、在Linux中安装Redis。 1.1、在线下载软件 1.2、安装软件 1.3、修改配置文件 1.4、启动Redis&#xff1b; 2、添加Redis起步缓存&#xff0c;在pom.xml中添加Spring Boot支持Redis的依赖配置。 3、添加缓存注解。 3.1、在引导类Application.java中&#xff0c;添加EnableCac…

Redis3.0 配置文件说明

背景&#xff1a; 以前有篇文章已经结果过了&#xff0c;现在复习一下&#xff0c;对Redis3.0进行说明&#xff1a; 参数说明&#xff1a; #redis.conf # Redis configuration file example. # ./redis-server /path/to/redis.conf################################## INCLUDES…

Core ML 文档翻译

概览 借助 Core ML&#xff0c;您可以将已训练好的机器学习模型&#xff0c;集成到自己的应用当中。 所谓已训练模型 (trained model)&#xff0c;指的是对一组训练数据应用了某个机器学习算法后&#xff0c;所生成的一组结果。举个例子&#xff0c;通过某个地区的历史房价来训…

jquery radio 取值

网上流行的说法就是 $(input[nameaaa][checked]).val()能取到选中项的value&#xff0c;但我测试后发现只在IE下有效&#xff0c;在firefox和Chrome中不论选中哪一项&#xff0c;或者不选&#xff0c;取到的值都是第一项的value正确做法应该是 $("input[nameaaa]:checked&…

Spring Boot与ActiveMQ的集成

1、ActiveMQ软见得安装配置 1.1、上传软件包并解压 1.2、配置并启动 1.3、浏览器验证 2、添加ActiveMQ起步依赖&#xff1b; 3、创建消息队列对象&#xff0c;在Application.java中编写一个创建消息队列的方法&#xff0c;其代码展示如下&#xff1b; 4、创建消息生产者&#…

iOS图片精确提取主色调算法iOS-Palette(附源码)

源码可见:[直接点击] 1.背景 图像提取主色调来增强浸入式交互体验的场景越来越常见&#xff0c;如知乎网页版的个人主页&#xff0c;Instagram的图片色调筛选。那如何去获得一张照片的主色调呢&#xff1f;Google在Android.support.v7里&#xff0c;给出了一个叫做Palette(调色…

jQuery UI 之 LigerUI 快速入门

LigerUI 快速开发UI框架 LigerUI 是基于jQuery 的UI框架&#xff0c;其核心设计目标是快速开发、使用简单、功能强大、轻量级、易扩展。简单而又强大&#xff0c;致力于快速打造Web前端界面解决方案&#xff0c;可以应用于.net,jsp,php等等web服务器环境。 LigerUI有如下主要特…

HTML5标签学习之~~~

<article> 标签 article 字面意思为“文章”。在web页面中表现为独立的内容&#xff0c;如一篇新闻&#xff0c;一篇评论&#xff0c;一段名言&#xff0c;一段联系方式。这其中包括两方面&#xff0c;一为整个页面的主旨内容&#xff0c;另外就是一些辅助内容。<arti…

将Spring Boot项目打包成jar包war包

任务一&#xff1a;将Spring Boot项目打包成jar包 1、在pom.xml文件中添加依赖 2、通过cmd命令行来进行打包jar包&#xff08;首先进入项目的目录中&#xff09; 3、进入项目中的target目录下查看包 4、使用命令执行jar包&#xff1b; 5、浏览器查看输出结果 任务二&#xff1…