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知识点 - 获取当前系统主机名、用户名、用户目录。

    代码示例: import socket, getpass, os # 获取当前系统主机名 host_name = socket.gethostname() # 获取当前系统用户名 user_name ...

  2. C++常数优化

    #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC target("avx") #pragma GCC opti ...

  3. Vuex的理解以及它的辅助函数

    理解:vue中的“单向数据流”,这里借用官网的图示: Vue是单向数据流,v-model只是语法糖而已.单向数据流就是:数据总是[向下传递]从父级组件传递给子组件,只能单向绑定.子组件内部不能直接修改 ...

  4. 2020 还不会泡 Github 你就落伍了

    前言 回想起两年前缸接触 GitHub 那会儿,就发现网上完全搜不到一篇关于 github 使用的文章,虽然自己倒腾几下慢慢的也就上手了,但毕竟花费了不少时间. 时间对每个人都是宝贵的,一直很好奇 G ...

  5. axios请求拦截器

    import axios from 'axios';   // 创建axios实例   let service = null;   if (process.env.NODE_ENV === 'deve ...

  6. [BUG]微信小程序生成小程序码"小程序页面路径不存在,请重新输入"

    描述 小程序页面线上能打开. 微信官方 获取小程序页面小程序码 页面 ,输入 小程序页面路径,提示 "小程序页面路径不存在,请重新输入". 使用微信复制小程序路径方法, 也是同样的 ...

  7. javaScript 基础知识汇总 (十二)

    1.属性的标志和描述符 属性的标志 对象属性除value外还有三个特殊属性,即标志 writable ----如果为true,则可以修改,否则它只是只读的. enumerable ----如果为tru ...

  8. Python可以用中文命名

    Python中文命名 命名规则数字.字母.下划线 环境 python 3.7.3 x64 win10 现象 Python在命名的地方都是可以用中文命名 如: 变量 中文下划线无法被识别 打出中文下划线 ...

  9. gradle管理的Springboot使用JSP详解

    大家知道现在的springboot默认经不支持jsp了,但是还是可以用的,需要加一些配置. 我使用的springboot是用gradle构造的,现在跟着我一步步来吧! 一,新建一个springBoot ...

  10. Linux - top命令监控列表的详细解析

    统计信息区(系统资源信息区) 前五行,即列表上方的五行 第一行:输出系统任务队列信息 18:46:38:系统当前时间 up 2days 1:54:系统开机后到现在的总运行时间 1 user:当前登录用 ...