STL——vector容器

  • vector对象的概念
  • vector基本操作
  • vector对象的初始化、赋值
  • vector查找、替换(已在上一片 string类 博客总结过了,不再总结)
  • vector添加、弹出元素(头部、尾部)
  • vector容器的遍历(通过数组的方式、通过迭代器)
  • vector删除、插入操作(指定元素删除/插入、区间删除/插入、一次插入多个相同的元素)
  • 迭代器介绍(输入迭代器、输出迭代器、正向迭代器、双向迭代器)
  • vector举例应用

在这片文章中我参考了许多人的博客,甚至有一些部分是直接copy的,最终做了一个详细的vector用法总结

vector用法参考


vectot容器的简介

  1. vector 是一个将元素置于动态数组中加以管理的容器。
  2. vector 支持随机存取元素(支持索引值直接存取,用[]操作符或 at()方法,来下标来访问)
  3. vecotr 在尾部添加和移除元素非常快,但是在中间和头部添加和移除却很费事。
  4. vector存储数据时,会分配一个存储空间,如果继续存储,该分配的空间已满,就会分配一块更大的内存,把原来的数据复制过来,继续存储,这些性能也会一定程度上会有损耗

vector基本操作

(1). 容量
向量大小: vec.size();
向量最大容量: vec.max_size();
更改向量大小: vec.resize();
向量真实大小: vec.capacity();
向量判空: vec.empty();
减少向量大小到满足元素所占存储空间的大小: vec.shrink_to_fit(); //shrink_to_fit
(2). 修改 多个元素赋值: vec.assign(); //类似于初始化时用数组进行赋值
末尾添加元素: vec.push_back();
末尾删除元素: vec.pop_back();
任意位置插入元素: vec.insert();
任意位置删除元素: vec.erase();
交换两个向量的元素: vec.swap();
清空向量元素: vec.clear();

vector类的对象的构造

    //vector 采用模版类来实现 vector<T> vec;
vector<int> v1 //从模版实例化出存放int类型元素的 v1 容器
vector<double> v2 //从模版实例化出存放double类型元素的 v1 容器 //vector 尖括号内可以实例化出 指针类(包括自定义的数据类型的指针)型和自定义的 数据类型的 容器
vector<int *> v3// 定义存放 int型变量的地址的容器
class A {}; // 自几定义数据类型 A
vector<A> v4; //定义存放A类型数据的容器
vector<A *> v5;//定义存放 A类型变量的地址的容器 //⚠️注意:由于容器元素的初始化/赋值是按值传递复制的进行的,所以此时 A类 必须提供拷贝构造函数,以保证 A类的对象之间拷贝正常

初始化

    v1.push_back(1); //向v1中添加一个 1
v1.push_back(2); //向v2中添加一个 2
v1.push_back(3); //向v3中添加一个 3
int ar[3] = {1,3,5};
vector<int> vec={1,3,5}; //用列表初始化
vector<int>v2 = v1; //用vector的拷贝构造函数
vector<int>v3(v1);
vector<int>v4(v1.begin(),v1.end());//区间初始化
vector<int>v5(ar,ar+3); //用数组区间初始化
vector<int>v6(5,0); //用五个0进行初始化

赋值


    //vector赋值
//第一类赋值法
v4.assign(10,0); //给v4赋上10个零
v3.assign(ar,ar+2);
v2.assign(v1.begin(),v1.end());
//第二类赋值法(⚠️运用下标法 [] 必须先给vector容器申请空间,以供下标访问否则出错,如果此时用push_back()将把元素插入到先前申请的空间之后)
vector<int> v5(10); //提前申请存储10元素的空间,此时10个元素的值均为0
for(int i=0;i<10;i++)
v5[i]=i+1;
//第三类赋值法,通过迭代器的方式去赋值
for(vector<int>::iterator it =v5.begin();it<v5.end();it++)
*it = 0;

添加、弹出元素(头部、尾部)

    vector<int> v1;
//vector 的增添、弹出、删除元素
//添加
v1.push_back(1); //向v1中添加一个 1
v1.push_back(2); //向v2中添加一个 2
v1.push_back(3); //向v3中添加一个 3
print(v1);
//弹出
v1.pop_back(); //弹出尾部的一个元素
print(v1);
//尾元素的访问与修改
cout<<v1.back(); //通过back()函数去访问v1的尾元素
cout<<v1.front();//通过front()函数去访问v1的首元素
v1.back() = 10; //由于back()函数返回值为引用,所以可以通过back(),来改变尾元素的值
v1.front() = 20; // 与⬆️同理

遍历

    vector<int> v1={1,3,5};
//vector的遍历
//1.用for循环
for(int i=0;i<3;i++)
cout<<v1[i];
//2.用基于范围的for循环
for(int &i:v1)
{
cout<<i;
i = 10; //有 i 被声明的时候是以引用的方式,所以可以通过 i 来改变v1中元素的值
}
//3.用迭代器
for(vector<int>::iterator it = v1.begin();it<v1.end();it++)
{
cout<<*it;
* it = 10; //通过it指针去改变v1的值
}

删除,插入操作

    int ar[3] = { 1, 3, 5};
vector<int> v1={1,2,3};
vector<int> vec={1,3,5};
//删除操作
注意⚠️:用erase()删除完后元素后,它的返回值是一个指向下一个元素(挨着最后一个被删除的元素的元素)的迭代器
vec.erase(vec.begin(),vec.end()); //删除[vec.begin(),vec.end())区间的元素
vec.erase(vec.begin()); //删除vec.begin()这个位置的元素
//插入
vec.insert(vec.begin(), 0); //在vec.begin() 位置之前 插入元素
vec.insert(vec.end(), v1.begin(),v1.end()); //在vec.end() 之前插入在[v1.begin(),v1.end())区间内的元素
vec.insert(vec.begin(),10,0); //在vec.begin()之前插入10个0元素
vec.insert(vec.begin(),ar,ar+3);![ebd4c8678baf58da184575ee8ca5b528.png](evernotecid://2C354EAE-828A-4D61-888B-9453DC360564/appyinxiangcom/25418762/ENResource/p334)

迭代器


迭代器的介绍:

  • 迭代器类似于指针类型,它只想一个特定的位置,它也提供了对对象的间接访问
  • 指针是C语言中就有的东西,而迭代器是C++中才有的
  • 使用迭代器:和指针不一样的是,获取迭代器不是使用取地址符,有迭代器的类型同时拥有返回迭代器的成员,比如,容器都有的成员begin和end,其中begin成员负责返回指向容器第一个元素的迭代器,如:auto b = v.begin();end成员则负责返回指向容器的尾元素的下一个位置的迭代器,也就是说指向的是容器的一个本不存在的尾部。如果容器为空,则begin和end返回的是同一个迭代器,都是尾后迭代器。
  • 迭代器提供一个对容器对象或者string对象访问的方法,并且定义了容器范围

输入、输出迭代器

  • 输入迭代器:又叫“只读迭代器“,它只能从容器中读取元素,一次读出一个迭代器向前移,同一个输入迭代器不能遍历两次容器
  • 输出迭代器:又叫“只写迭代器”,它只能从容器总写入元素,一次写入一个迭代器向前移,同一个输出迭代器不能遍历两次容器

正向迭代器、双向迭代器

  • 正向迭代器:所谓正向迭代器指的是只能正向走,而不能反向走,一个在一个指着(停留在)一个元素多次,而且一次移动多个位置,可以通过 ++ += (不可以通过 – -= 运算符)
  • 双向迭代器:所谓正向迭代器指的是可以可以正反两个方向走,支持随机访问容器,一次移动多个位置,可以通过 ++ – += -= 运算符来完成

迭代器理解

  • 迭代器的类型:
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xP89GMwr-1574571844427)(evernotecid://2C354EAE-828A-4D61-888B-9453DC360564/appyinxiangcom/25418762/ENResource/p332)]
  • 1vector::iterator it;//it可以读写vector的元素
  • 2string::iterator it2;//it2可以读写string对象中的字符
  • 3vector::const_iterator it3;//it3只能读元素,不能写元素
  • 4string::const_iterator it4;//it4只能读字符,不能写字符

  • 迭代器的区别

    const_iterator和常量指针差不多,能读取但不能修改它所指的元素值,而iterator可读可写。如果容器或string对象是一个常量,只能使用const_iterator,如果不是常量,那么既能使用iterator又能使用const_iterator。

    如果容器或对象只需读操作而无需写操作的话最好使用常量类型(const_iterator),为了便于获取常量迭代器,C++11新引入了两个新函数,分别是cbegin和cend,类似于begin和end,不同之乎在于只能返回const_iterator.

    注意:但凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素

  • 迭代器运算

1iter + n 迭代器加上一个数值仍得一个迭代器,所指位置向前移动n个元素

2iter - n 迭代器减去一个数值仍得一个迭代器,所指位置向后移动n个元素

3iter += n 等价于iter + n

4iter -= n 等价于iter - n

5iter1 - iter2 两个迭代器相减的结果是他们之间距离,其类型是名为difference_type的带符号整数

6 >、>=、<、<= 位置离begin近的元素较小


迭代器的应用

    //迭代器的应用
//1. 迭代器的声明
vector<int> v1{1,3,5};
vector<int>::iterator it1 = v1.begin(); //声明一个双向迭代器,(begin())并赋值为v1元素的首地址
vector<int>::const_iterator it2 = v1.cbegin(); //只能读容器的值,而不能改变容器的值,cbegin(),是一个指向容器首元素的地址常量,cend()同理如此
vector<int>::reverse_iterator it3 = v1.rbegin(); //声明一个反向迭代器,(rbegin()指向最后一个元素,rend()指向容器第一个元素位置之前)
for( ;it2 < v1.cend();it2++)
{
cout<<*it2;
//*it2 = 10; 这一条错误 因为 it2 是常量迭代器
}
for( ;it3 < v1.rend();it3++)
{
cout<<*it3<<endl; //输出结果:3 2 1
*it3 = 10; //通过指针去赋值
cout<<*it3<<endl;
}
  • 对rbegin()和rend()的理解

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h1dfhtf2-1574571844431)(evernotecid://2C354EAE-828A-4D61-888B-9453DC360564/appyinxiangcom/25418762/ENResource/p334)]

vector与迭代器 举例应用

//关于STL中vector容器的学习,编译运行后边看代码,边看执行结果效果更佳,不过看别人的代码一百遍,不如自己动手写一遍
#include <vector>//头文件
#include <iostream>
#include <algorithm>
using namespace std; void print(vector <int> v);
bool mycmpare(const int &a, const int &b){
return a>b;
}
int main ()
{
//创建vector对象三种常用的方式,此处存储元素类型是int,还可以是double、char、long long等基本数据类型,甚至是string基本字符序列容器
vector <int> v1;//不指定容器的元素个数的定义一个用来存储整型的向量容器
cout<<"v1:"<<endl;
print(v1);
/*运行结果
v1:
大小为:0
*/ vector <int> v2(5);//指定容器的元素个数的定义一个大小为10的用来存储整型的向量容器,默认初始化为0
cout<<"v2:"<<endl;
print(v2);
/*运行结果
v2:
大小为:5
0 0 0 0 0
*/ vector <int> v3(5,1);//也可指定初始值,此处指定为1
cout<<"v3:"<<endl;
print(v3);
/*运行结果
v3:
大小为:5
1 1 1 1 1
*/ //另外事先指定不指定大小都无所谓,指定了大小也可以随时使用push_back()对vector容器进行尾部扩张
v1.push_back(1);//向空的vector容器尾部扩张,追加元素为1
cout<<"v1:"<<endl;
print(v1);
v3.push_back(2);//向已有元素的vector容器尾部扩张,追加元素为2
cout<<"v3:"<<endl;
print(v3);
/*运行结果
v1:
大小为:1
1 v3:
大小为:6
1 1 1 1 1 2
*/ //插入元素使用insert()方法,要求插入的位置是迭代器的位置,而不是元素的下标
v3.insert(v3.begin(),3);//在最前面插入3
cout<<"v3:"<<endl;
print(v3); v3.insert(v3.end(),3);//在末尾追加3,此处等同于push_back()
cout<<"v3:"<<endl;
print(v3);
/*运行结果
v3:
大小为:7
3 1 1 1 1 1 2 v3:
大小为:8
3 1 1 1 1 1 2 3
*/ int i;
for(i=0;i < v3.size();i++){//只可赋值到已扩张位置
v3[i]=i;
}
//要删除一个元素或者一个区间中的所有元素时使用erase()方法
v3.erase(v3.begin()+2);//删除第2个元素,从0开始计数
cout<<"v3:"<<endl;
print(v3);
/*运行结果
v3:
大小为:7
0 1 3 4 5 6 7
*/
v3.erase(v3.begin()+1,v3.begin()+3);//删除第1个到第3个元素区间的所有元素
cout<<"v3:"<<endl;
print(v3);
/*运行结果
v3:
大小为:5
0 4 5 6 7
*/
//由结果可知,erase()方法同insert()方法一样,操作的位置都只是迭代器的位置,而不是元素的下标 //要想清空vector(),使用clear()方法一次性删除vector中的所有元素
cout<<"v2:"<<endl;
print(v2);
/*运行结果
v2:
大小为:5
0 0 0 0 0
*/
v2.clear();
if(v2.empty()) cout<<"v2经过使用clear()方法后为空\n";
print(v2);
/*运行结果
v2经过使用clear()方法后为空
大小为:0
*/ //要想将向量中某段迭代器区间元素反向排列,则使用reverse()反向排列算法,需要添加algorithm头文件
cout<<"v3反向排列前:"<<endl;
print(v3);
reverse(v3.begin(),v3.end());//全部反向排列
cout<<"v3反向排列后:"<<endl;
print(v3);
/*运行结果
v3反向排列前:
大小为:5
0 4 5 6 7 v3反向排列后:
大小为:5
7 6 5 4 0
*/ //要想将向量中某段迭代器区间元素进行排序,则使用sort()算法
cout<<"v3升序排列前:"<<endl;
print(v3);
sort(v3.begin(),v3.end());//默认升序排列
cout<<"v3升序排列后:"<<endl;
print(v3);
/*运行结果
v3升序排列前:
大小为:5
7 6 5 4 0 v3升序排列后:
大小为:5
0 4 5 6 7
*/ //自定义排序比较函数,此处降序
cout<<"v3降序排列前:"<<endl;
print(v3);
sort(v3.begin(),v3.end(),mycmpare);
cout<<"v3降序排列后:"<<endl;
print(v3);
/*运行结果
v3降序排列前:
大小为:5
0 4 5 6 7 v3降序排列后:
大小为:5
7 6 5 4 0
*/
} void print(vector <int> v)
{
//cout<<"下标方式访问:"<<endl;
cout<<"大小为:"<<v.size()<<endl;
int i;
for(i=0;i< v.size();i++){
cout<<v[i]<<' ';
}
cout<<endl<<endl; /*cout<<"用迭代器访问:"<<endl;
//定义迭代器变量it,类型与容器元素类型保持一致
vector<int>::iterator it;
for(it=v.begin(); it != v.end(); it++){
cout<<*it<<' ';
}
cout<<endl<<endl;*/
}

C++STL(二)——vector容器的更多相关文章

  1. 带你深入理解STL之Vector容器

    C++内置了数组的类型,在使用数组的时候,必须指定数组的长度,一旦配置了就不能改变了,通常我们的做法是:尽量配置一个大的空间,以免不够用,这样做的缺点是比较浪费空间,预估空间不当会引起很多不便. ST ...

  2. 跟我一起学STL(2)——vector容器详解

    一.引言 在上一个专题中,我们介绍了STL中的六大组件,其中容器组件是大多数人经常使用的,因为STL容器是把运用最广的数据结构实现出来,所以我们写应用程序时运用的比较多.然而容器又可以序列式容器和关联 ...

  3. 【C++】STL,vector容器操作

    C++内置的数组支持容器的机制,但是它不支持容器抽象的语义.要解决此问题我们自己实现这样的类.在标准C++中,用容器向量(vector)实现.容器向量也是一个类模板.标准库vector类型使用需要的头 ...

  4. STL中vector容器实现反转(reverse)

    vector容器中实现可以通过以下两种方式实现: #include "stdafx.h" #include <vector> #include <iostream ...

  5. STL 查找vector容器中的指定对象:find()与find_if()算法

    1 从vector容器中查找指定对象:find()算法 STL的通用算法find()和find_if()可以查找指定对象,参数1,即首iterator指着开始的位置,参数2,即次iterator指着停 ...

  6. STL:vector容器用法详解

    vector类称作向量类,它实现了动态数组,用于元素数量变化的对象数组.像数组一样,vector类也用从0开始的下标表示元素的位置:但和数组不同的是,当vector对象创建后,数组的元素个数会随着ve ...

  7. STL之vector容器详解

    vector 容器 vector是C++标准模版库(STL,Standard Template Library)中的部分内容.之所以认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单的说: ...

  8. (转载)C++STL中vector容器的用法

     vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说vec ...

  9. STL笔记(に)--vector容器

    Vector 1.可变长的动态数组 2.需包含头文件#include<vector> (当然,如果用了万能头文件#include<bits/stdc++.h>则可忽略) 3.支 ...

  10. [转]STL之vector容器详解

    vector 容器 vector是C++标准模版库(STL,Standard Template Library)中的部分内容.之所以认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单的说: ...

随机推荐

  1. Python一键转Jar包,Java调用Python新姿势!

    粉丝朋友们,不知道大家看故事看腻了没(要是没腻可一定留言告诉我^_^),今天这篇文章换换口味,正经的来写写技术文.言归正传,咱们开始吧! 本文结构: 需求背景 进击的Python Java和Pytho ...

  2. 关于PHP命名空间的讨论

    什么是命名空间? 根据php.net官方翻译文档描述,命名空间是这样定义的: 什么是命名空间?从广义上来说,命名空间是一种封装事物的方法. 在PHP中,命名空间用来解决在编写类库或应用程序时创建可重用 ...

  3. java面试汇总一

    第一部分 Java SE基础(1) 1.1 java的8种基本数据类型 装箱  拆箱 1.1.1  8种基本的数据类型 1.1.2装箱  拆箱 自动装箱是 Java 编译器在基本数据类型和对应的对象包 ...

  4. BFC块级格式上下文介绍

    块级格式上下文(Block formatting context) 什么是BFC? 块格式化上下文(block formatting context) 是页面 CSS视觉渲染的一部分.它是用于决定块盒 ...

  5. Java反射之Class类

    接下来的几章,我们谈一谈java的反射机制. 反射就是从一个java类中映射出一个java类或是一个实例.通常在很多框架中都用到反射,比如常用的ssm框架,在配置文件中总是会写到类的全名,框架通过读取 ...

  6. php通过单例模式使一个类只能创建一个对象。

    单例模式也就是一个类只能创建出一个对象 首先你要知道它的基本思想为:三私一公! 何为三私一公?   1(私).防止用户通过构造方法创建对象,因此私有化构造方法. 2(公).创建一个公共静态函数用来进入 ...

  7. Java并发编程学习前期知识下篇

    Java并发编程学习前期知识下篇 通过上一篇<Java并发编程学习前期知识上篇>我们知道了在Java并发中的可见性是什么?volatile的定义以及JMM的定义.我们先来看看几个大厂真实的 ...

  8. MySQL 【教程二】

    MySQL 创建数据表 创建MySQL数据表需要以下信息: 表名 表字段名 定义每个表字段 语法 以下为创建MySQL数据表的SQL通用语法: # CREATE TABLE table_name (c ...

  9. 关于LaTex的安装

    第一次写博客,有点生疏,但是想把具体安装的流程自我的汇总一下,毕竟我总是忘记,万一下一次要用的时候又要弄很久,就当经验吧. 其实是因为这个新型冠状病毒不能出门,也没开学,想找点事情做一做 这个博客不知 ...

  10. 关于BitmapImage EndInit()时报值不在范围内的异常

    值不在预期的范围内.ArgumentException 在 System.Windows.Media.ColorContext.GetColorContextsHelper(GetColorConte ...