【C++基础 04】vector详解

按照写博客的习惯一开始总要加点鸡汤文什么的,请原谅我今天想不起来。

=============================================

今天要写的内容是顺序型容器。首先,标准库定义了三种顺序容器类型:vector,list和deque(双端队列),这篇博客介绍的是vector容器。

首先要知道,vector不是一种数据类型,而是一个类模板,可以用来定义任意多种数据类型,比如说vector<int>是一种数据类型,vector<string>也是一种数据类型。使用vector之前我们要先包含头文件

#include<vector>
using std::vector;

1.vector初始化

vector<T> v1;       //初始化一个为空的vector
vector<T> v2(v1);   //v2是v1的一个副本
vector<T> v3(n,i);  //n个值为i的vector
vector<T> v4(n);    //v4含n个默认初始化值的vector(如int默认0,string默认"")

2.迭代器

每个标准库容器类型都定义了名为iterator的成员,也就是迭代器,迭代器所指向的类型为vector容器中实际存储的类型,比如

vector<int>iterator iter;

迭代器常用于遍历容器,最常见的便是begin和end操作,vector.begin()返回vector中的第一个元素,vector.end()返回末端元素的下一个。

vector<int> ivec;
for(int i = 0; i <= 10; i++)
  ivec.push_back(i);

for(vector<int>::iterator iter = ivec.begin(); iter != ivec.end(); ++iter)
{
  *iter = 0;   //遍历vector,更改值为0
}

需要注意的是,如果有元素添加或者删除,会使迭代器失效,从而需要调整迭代器的值。否则很可能会导致运行时崩溃,者点很重要。

3.vector的常用操作

添加:需要注意的是添加新元素可能会使迭代器失效,所以程序需要保证迭代器在插入或者push操作后能得到更新。

//添加元素
v.push_back(t);               //在vector尾部添加一个元素t
v.insert(iter,t);            //在迭代器iter所指向的元素前面插入元素t,返回新添加的元素的迭代器
v.insert(iter,n,t);          //在迭代器iter所指向的元素前面插入n个元素t,返回void
v.insert(iter,iter1,iter2);  //在迭代器iter所指向的元素前面插入迭代器[iter1,iter2)之间的元素(左闭右开),返回void

所有容器类型都支持关系操作符来比较大小,规则是:

//v1和v2长度和所有元素都相等,则v1=v2,否则不等。
//v1长度小于v2,但是v1所有元素和v2 相等,则 v1 < v2。
//v1和v2元素不等,则比较结果取决于第一个不相等的元素。

vector大小的操作:

v.size();      //返回v中元素的个数,返回类型 v::size_type
v.max_size();  //返回v可容纳最多元素个数
v.empty();     //判断是否为空
v.resize(n);   //调整v长度大小,使其能容纳n个元素,如果n<v.size(),则删除多出来的元素,否则添加采用值初始化的元素
v.resize(n,t); //调整v长度大小,使其能容纳n个元素,所有新添加的元素值都为t

vector访问:

v.back();   //返回v最后一个元素的引用
v.front();  //返回v第一个元素的引用
v[n];       //返回v下标为n的引用
v.at[n];    //返回v下标为n的引用

//返回的是引用,注意和迭代器的区别,迭代器返回的是指针
vector<int> v;
//迭代器
vector<int>::iterator iter = v.begin();
//引用,下面val = val2
vector<int>::reference val = v.front();
vector<int>::reference val2 = *v.begin();

vector删除操作:

v.erase(iter);        //删除iter所指向的元素,返回iter下一个元素
v.erase(iter1,iter2); //删除[iter1,iter2)之间的元素(左闭右开)
v.clear();            //全删,返回void
v.pop_back();         //删除最后一个,返回void

赋值操作:

v1 = v2;                //复制v2到v1
v1.swap(v2);            //交换内容:交换v1和v2之间的元素,速度比v2复制到v1快
v1.assign(iter1,iter2); //重新设置:将[iter1,iter2)之间的元素(左闭右开)复制到v中
v1.assign(n,t);         //重新设置:将v中重新设置为n个值为t的元素

注意swap不会使迭代器失效。

assign会将vector中所有元素删除,然后再插入新元素。assing可以用于:相同或者不同的容器内,元素类型不同但是相互兼容之间的转换赋值。(比如vector<char*>和list<string>之间的赋值)

vector<char*> v1;
for(int i = 0; i <= 10; i++)
  v1.push_back("dddd");
list<string> list1;
list1.assign(v1.begin(),b1.end());

4.vector容器自增长

首先要明白vector容器的元素在内存中是以连续的方式存放。想一下如果添加新元素的时候时候已经没有空间来容纳新元素,又不能随便找个地儿来放新元素,所以需要重新分配vector的存储空间:copy旧元素到新存储空间,插入新元素,删除旧存储空间。

如果vector在每次添加新元素的时候都这么搞一个,那效率何在?所以,显然vector设计的时候也考虑到这方面的问题,作者使用的内存分配策略是:以最小的代价连续存储元素。用通俗大大白话来讲,就是每次分配的时候会比你当前所需要的空间多一些,当已经分配的空间使用完后才会开辟新的空间。

首先来看一下capacity和reserve操作

v.size();     //返回vector中元素的个数
v.capacity(); //返回vector能够存储的元素总数
v.reserve(n); //手动设置vector容器应该预留n个元素的空间

举一个简单的例子来说明他们之间的关系:

vector<int> v;
cout<<"vector size:"<<v.size()<<endl;        //输出0
cout<<"vector capacity:"<<v.capacity()<<endl;//输出0

//添加24个元素
for(int i = 0; i < 24; i++)
  v.push_back(i);

cout<<"vector size:"<<v.size()<<endl;        //输出24
cout<<"vector capacity:"<<v.capacity()<<endl;//输出32

明白了吧,capacity总是要大于或等于size的,至于为什么是32?因为每当vector不得不分配新的存储空间时,会以加倍当前容量 的分配策略来重新分配。比如你添加1个元素,size为1,capacity也为1,然后再添加,capacity 乘2,然后再添加再乘2,如下:

//添加的时候size和capacity的关系:
//v.size() —— v.capacity()
        0  -  0
        1  -  1
        2  -  2
        3  -  4
        4  -  4
        5  -  8
        9  -  16
        以此类推...

或者我们可以自己设置预留空间,修改上面的例子:

vector<int> v;
v.reserve(50);
cout<<"vector size:"<<v.size()<<endl;        //输出0
cout<<"vector capacity:"<<v.capacity()<<endl;//输出50
//添加50个元素
for(int i = 0; i < 50; i++)
  v.push_back(i);
//再多添加一个
v.push_back(51);
cout<<"vector size:"<<v.size()<<endl;        //输出51
cout<<"vector capacity:"<<v.capacity()<<endl;//输出100

5.容器优缺点:

vector:优点:快速随机访问缺点:在容器任意位置插入或删除,比在容器尾部插入或删除,开销大。

list:是不连续存储的,优点:在容器中任何位置高效的插入和删除元素。缺点:不支持随机访问,访问元素需要遍历其他元素。

deuqe :拥有更复杂的数据结构,优点:从容器两端插入和删除都非常快,支持高效随机访问。缺点:在中间插入或删除效率很低。

6.判断选择哪种容器:

(1)需要高效随机访问元素,则使用vector或者deque。

(2)需要高效在容器中间位置插入或者删除元素,则使用list。

(3)若不是在中间位置插入,而是容器首部或者尾部插入,则使用deque。

(4)若既需要高效随机访问又需要高效中间插入,则可以将元素添加到list中然后排序啥的,再复制到vector中。

=========================================

再不睡觉就作死了。。

转载请注明出处:http://blog.csdn.net/shun_fzll/article/details/37917133

【C++基础 04】vector详解

时间: 2024-10-09 04:22:23

【C++基础 04】vector详解的相关文章

Linux 程序设计学习笔记----终端及串口编程基础之概念详解

转载请注明出处,谢谢! linux下的终端及串口的相关概念有: tty,控制台,虚拟终端,串口,console(控制台终端)详解 部分内容整理于网络. 终端/控制台 终端和控制台都不是个人电脑的概念,而是多人共用的小型中型大型计算机上的概念. 1.终端 一台主机,连很多终端,终端为主机提供了人机接口,每个人都通过终端使用主机的资源. 终端有字符哑终端和图形终端两种. 控制台是另一种人机接口, 不通过终端与主机相连, 而是通过显示卡-显示器和键盘接口分别与主机相连, 这是人控制主机的第一人机接口.

(赵小明RHCE笔记)linux基础之四 权限详解

一.special permissions for executables1.special permissions for executables:  -suid:command run with permissions of the owner of the command,not executor of   the command  -sgid:command runs with group affiliation of the group of the commandeg:file:us

java笔记--反射机制之基础总结与详解

一.反射之实例化Class类的5种方式: java的数据类型可以分为两类,即引用类型和原始类型(即基本数据类型). 对于每种类型的对象,java虚拟机会实例化不可变的java.lang.Class对象. 它提供了在运行时检查对象属性的方法,这些属性包括它的成员和类型信息. 更重要的是Class对象是所有反射API的入口. Class类是泛型类,可以使用@SuppressWarnings("unchecked")忽略泛型或者使用Class<V>类型. 获得Class对象的5种

基础拾遗------webservice详解

基础拾遗 基础拾遗------webservice详解 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗------接口详解 基础拾遗------泛型详解 前言 工作当中常用的服务接口有三个wcf,webservice和webapi.首先第一个接触的就是webservice,今天大致总结一下. 1.webservice概念相关 1.1.Web Service也叫XML Web Service WebService 是一种可以接收从Inter

基础拾遗------redis详解

基础拾遗 基础拾遗------redis详解 基础拾遗------反射详解 基础拾遗------委托详解 基础拾遗------接口详解 基础拾遗------泛型详解 前言 这篇文章和以往的基础拾遗有所不同,以前的介绍的都是c#基础,今天介绍的是redis.因为项目中一只在使用,我想现在大部分项目中都会用到nosql,缓存,今天就介绍一下redis..废话少说下面开始正题. 1.redis是什么? Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库. 对的redi

45 puppet基础、资源详解、配置语言、puppet类与模板及模块

01 puppet基础 配置: node1:192.168.1.131 CentOS7.2 node2:192.168.1.132 CentOS7.2 [[email protected] ~]# rpm -ivh epel-release-latest-7.noarch.rpm [[email protected] ~]# yum list all | grep -i "puppet" puppet.noarch                           3.6.2-3.e

java基础之:详解内部类(转载)

可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二). 第一次见面 内部类我们从外面看是非常容易理解的,无非就是在一个类的内部在定义一个类. [java] view plain copy print? public class OuterClass { private String name ; private int age; public String getName() {

AngularJS语法基础及数据绑定——详解各种数据绑定指令、属性应用

AngularJS简单易学,但是功能强大.特别是在构建单页面应用方面效果显著.而 数据绑定 可以说是他被广泛使用的最主要的优点.他舍弃了对DOM的操作方式,一切都由AngularJS来自动更新视图,我们不必写操作dom的代码.接下来我们就详细解释下AngularJS中数据绑定的方式,及其具体的使用规则.技巧. 首先介绍下此次博客的内容: 1.第一部分,介绍最最基本的AngularJS的根应用.控制器的基本语法,为初学者准备的. 2.第二部分,详解如何数据绑定,3种绑定方式的区别.分别用于什么情况

Vim基础入门之详解

一.简介 Vim(Vi[Improved])编辑器是vi的扩展版,比vi功能更加强大,是功能强大的跨平台文本文件编辑工具,可以利用它可以建立.修改文本文件等.Vim有三种操作模式,分别称为 编辑模式.插入模式 和 命令模式,当运行Vim时,首会进入命令模式. 二.命令模式 Vim命令模式下可以进行很多操作,例如光标跳动到指定的单词.行:复制.删除某行甚至很多行以及全文都可以,反正功能真的太强大了,以下就作出详解: (1)光标移动 ①如果键盘上有上.下.左.右箭头的导航键,就由这些键来完成光标的移