C++---vector容器

是STL容器中的一种常用的容器,由于其大小(size)可变,常用于数组大小不可知的情况下来替代数组。vector容器与数组十分相似,被称为动态数组。时间复杂度为O(1)。

数组数据通常存储在栈中,vector数据通常存储在堆中。

动态扩展不是在原空间后加入空间,而是寻找更大空间,将数据拷贝新空间,释放新空间。

头文件:#include <vector>

迭代器类似于指针,提供了对象的间接访问,但获取迭代器并不是使用取地址符。如果将指针理解为元素的"地址",那么迭代器可以理解为元素的"位置"。可以使用迭代器访问某个元素,迭代器也能从一个元素移动到另一个元素。

一个迭代器的范围由一对迭代器表示,分别为 beginend 。其中 begin 成员返回指向第一个元素的迭代器;end成员返回容器最后一个元素的下一个位置(one past the end),也就是指向一个根本不存在的尾后位置。

vector初始化

vector<T> v1 创建一个名为v1是元素类型为T的空vector

vector<int> v2 (n): 创建一个vector,元素类型为int,元素个数为n,值默认为0

vector<int> v3 {1,2,3,4,5} vector有5个数,注意花括号

vector<int>v4 (4,1) vector由4个值为1组成

vector<int>v5 (v4) 将v4所有值复制到v5中

vector<int>v6(v3.begin(), v3.end()) 将v3的值从头到尾复制到v6

vector<int>v7(v3.rbegin(), v3.rend()) 将v3的值从尾到头复制到v7

cbegin 和begin()功能相同,在其基础上增加了 const 属性,不能用于修改元素。

cend 和end()功能相同,在其基础上增加了 const 属性,不能用于修改元素。

crbegin 和rbegin()功能相同,在其基础上增加了 const 属性,不能用于修改元素。

crend 和rend()功能相同,在其基础上增加了 const 属性,不能用于修改元素。

vector方法

v2.empty() 判断v2是否为空,为空返回true,否则返回false

v2不为空,返回3

cpp 复制代码
if(v2.empty()) {
    return 2;
}else{
    return 3;
}

元素长度

v2.size() 返回实际v2中的元素个数

cpp 复制代码
int len = v2.size();

v2.capacity()返回v2中可以容纳的元素个数

区分:capacity 当前vector分配的大小,size 当前使用数据的大小

v2.resize()改变v2中的实际元素个数

v2.reserve()增加v2 的容量

访问元素

operator[] 用于从vector中访问指定元素,它接受一个索引并返回指定位置元素的引用。语法:

复制代码
 vector::operator[size_type n];

例如:v2[n] 是v2第n个位置元素的引用,不能用于下标操作添加元素 ,像v2[7]=5是错的。vector容器的下标也是从0开始计数的

vector.at(i)等同于vector[i],访问数组下表的元素,例如:v2.at(2) 返回下标为2的值的元素

两者区别:虽然两者访问元素都不能越界,但是operator不做边界检查,哪怕越界也会返回一个引用(错误的),at会做边界检查,如果越界,会抛出std::out_of_range异常。

cpp 复制代码
cout<<v2[3]<<endl;
cout<<v2.at(3)<<eendl;

v2.front()返回第一个元素

v2.back()返回最后一个元素

v2.data()返回v2第一个元素的指针

元素排序

sort 需要头文件 #include <algorithm>

sort(v2.begin(), v2.end())一种是两个参数,一般为升序(由小到大)

sort(v2.begin(), v2.end(), t),是三个参数,第三个参数可以写排序规则,一般搭配lambda表达式的捕获列表使用

cpp 复制代码
vector<int> a{0,10,9,8,1,5,2,3,6,4,7};
bool cmp(int x,int y){return x>y;}
sort(a.begin(), a.end(),cmp);
//两者等价
sort(a.begin(), a.end(),[](int x, int y){return x > y;});
//原有形式,省略是因为C++可以自动识别函数返回值得数据类型
sort(a.begin(), a.end(),[](int x,int y) -> bool {return x>y;} );

reverse(v2.begin(), v2.end()) 逆序输出

cpp 复制代码
reverse(a.begin(), a.end());  // 原位逆序排列
//结果
7 4 ....9 10 0

unique(v2.begin(), v2.end())将输入序列相邻的重复项"消除",一般搭配sort使用,先排序后消除。

例如,0 0 0 0 3 5 输出后 0 3 5

交换元素

v2.swap() 交换v2 其中的两个元素的所有内容

swap() 函数在头文件 <algorithm><utility> 中都有定义,使用时引入其中一个即可。

v2.assign() 用新元素替换所有内容

添加元素

向 vector 容器中添加元素的唯一方式就是使用它的成员函数,如果不调用成员函数,非成员函数既不能添加也不能删除元素。

v3.push_back(v) 在v3尾端添加一个值为v的元素

cpp 复制代码
v3.push_back(5);
cout<<v3<<endl;
//结果 1,2,3,4,5,5

v2.emplace_back() 在尾部添加一个元素

cpp 复制代码
    vector<int> values{};
    values.emplace_back(1);
    values.emplace_back(2);
    for (int i = 0; i < values.size(); i++) {
        cout << values[i] << " ";
    }
    //结果1 2

两者区别在于底层实现的机制不同。push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);而 emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程。

插入元素

v2.insert(pos,elem)在迭代器 pos 指定的位置之前插入一个新元素elem

|---------------------------------|-----------------------------------------------------------------------------------|
| iterator insert(pos,n,elem) | 在迭代器 pos 指定的位置之前插入 n 个元素 elem,并返回表示第一个新插入元素位置的迭代器。 |
| iterator insert(pos,first,last) | 在迭代器 pos 指定的位置之前,插入其他容器(不仅限于vector)中位于 [first,last) 区域的所有元素,并返回表示第一个新插入元素位置的迭代器。 |
| iterator insert(pos,initlist) | 在迭代器 pos 指定的位置之前,插入初始化列表(用大括号{}括起来的多个元素,中间有逗号隔开)中所有的元素,并返回表示第一个新插入元素位置的迭代器。 |

插入有很多种形式

cpp 复制代码
vector<int> demo{1,2};
//第一种格式用法
demo.insert(demo.begin() + 1, 3);//{1,3,2}
//第二种格式用法
demo.insert(demo.end(), 2, 5);//{1,3,2,5,5}
//可以看出end指的不是数组最后一位,而是最后一位的下一个位置
//第三种格式用法
array<int,3>test{ 7,8,9 };
demo.insert(demo.end(), test.begin(), test.end());//{1,3,2,5,5,7,8,9}
//第四种格式用法
demo.insert(demo.end(), { 10,11 });//{1,3,2,5,5,7,8,9,10,11}

v2.emplace() 指定位置前插入一个新元素,emplace() 每次只能插入一个元素,而不是多个。

cpp 复制代码
vector<int> demo1{1,2};
//emplace() 每次只能插入一个 int 类型元素
demo1.emplace(demo1.begin(), 3);
for (int i = 0; i < demo1.size(); i++) {
    cout << demo1[i] << " ";
}
//结果 3 1 2

emplace与insert比较,emplace效率更高,因为,insert需要将新元素将其生成,再将其拷贝或复制到容器中,emplace是直接在容器指定位置构造元素。

删除元素

cpp 复制代码
v3.pop_back();
//结果 从1 2 3 4 5 5 变为1 2 3 4 5
cpp 复制代码
vector<int>demo{ 1,2,3,4,5 };
auto iter = demo.erase(demo.begin() + 1);//删除元素 2
for (int i = 0; i < demo.size(); i++) {
    cout << demo[i] << " ";
}
//iter迭代器指向元素 3
cout << endl << *iter << endl;

//结果
1 3 4 5
3
cpp 复制代码
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
    vector<int>demo{ 1,2,3,4,5 };
    //交换要删除元素和最后一个元素的位置
    swap(*(std::begin(demo)+1),*(std::end(demo)-1));//等同于 swap(demo[1],demo[4])
   
    //交换位置后的demo容器
    for (int i = 0; i < demo.size(); i++) {
        cout << demo[i] << " ";
    }
    demo.pop_back();
    cout << endl << "size is :" << demo.size() << endl;
    cout << "capacity is :" << demo.capacity() << endl;
    //输出demo 容器中剩余的元素
    for (int i = 0; i < demo.size(); i++) {
        cout << demo[i] << " ";
    }
    return 0;
}
//结果
1 5 3 4 2
size is :4
capacity is :5
1 5 3 4
cpp 复制代码
vector<int> demo{ 1,2,3,4,5 };
//删除 2、3
auto iter = demo.erase(demo.begin()+1, demo.end() - 2);
for (int i = 0; i < demo.size(); i++) {
   cout << demo[i] << " ";
}

//结果
1 4 5
cpp 复制代码
vector<int>demo{ 1,3,3,4,3,5 };
//交换要删除元素和最后一个元素的位置
auto iter = remove(demo.begin(), demo.end(), 3);
//输出剩余的元素
for (auto first = demo.begin(); first < iter;++first) {
    cout << *first << " ";
}
//结果
1 4 5
长度仍为6

注意,在对容器执行完 remove() 函数之后,由于该函数并没有改变容器原来的大小和容量,因此无法使用之前的方法遍历容器,而是需要向程序中那样,借助 remove() 返回的迭代器完成正确的遍历。

remove() 的实现原理是,在遍历容器中的元素时,一旦遇到目标元素,就做上标记,然后继续遍历,直到找到一个非目标元素,即用此元素将最先做标记的位置覆盖掉,同时将此非目标元素所在的位置也做上标记,等待找到新的非目标元素将其覆盖。因此,demo为1 3 3 4 3 5,删除3,得到的结果为 1 4 5 4 3 5

过程:3做标记,3再做标记,4覆盖第一个3,做标记,3再做标记,5覆盖第二个3,做标记。

所以,可以使用 erase() 成员函数删掉这些 "无用" 的元素。

cpp 复制代码
    vector<int>demo{ 1,3,3,4,3,5 };
    //交换要删除元素和最后一个元素的位置
    auto iter = remove(demo.begin(), demo.end(), 3);
    demo.erase(iter, demo.end());
    //输出剩余的元素
    for (int i = 0; i < demo.size();i++) {
        cout << demo[i] << " ";
    }
//结果 1 4 5
长度变为3
cpp 复制代码
    vector<int>demo{ 1,3,3,4,3,5 };
    //交换要删除元素和最后一个元素的位置
    demo.clear();
    cout << "size is :" << demo.size() << endl;
    cout << "capacity is :" << demo.capacity() << endl;
//结果
size is :0
capacity is :6

二维数组

完整版:vector<vector<int>> table(size1, vector<int>(size2, 0)); 行列都给了

名为table的vector容器包含元素为vector的容器。列为size2,行为size1,值为0。

省略版:vector<vector<int>> table; 行列未知

vector<vector<int>> table(5); 行为5,也就是长度

获取二维数组长度

cpp 复制代码
int size_row = table.size();  //获取行数
int size_col = table[0].size();  //获取列数

访问二维数组

cpp 复制代码
for (int i = 0; i < a.size(); i++)
{
	for (int j = 0; j < a[0].size(); j++)//注意如果arr为空不可直接arr[0]
	{
		cout << a[i][j] << endl;
	}
}

https://blog.csdn.net/aruewds/article/details/117375364

C++ STL vector插入元素(insert()和emplace())详解 (biancheng.net)

http://t.csdnimg.cn/Ej3rl

http://t.csdnimg.cn/ebFXf

使用lambda表达式实现sort的自定义排序 - octal_zhihao - 博客园 (cnblogs.com)

相关推荐
A懿轩A1 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
机器视觉知识推荐、就业指导1 小时前
C++设计模式:享元模式 (附文字处理系统中的字符对象案例)
c++
半盏茶香1 小时前
在21世纪的我用C语言探寻世界本质 ——编译和链接(编译环境和运行环境)
c语言·开发语言·c++·算法
Evand J2 小时前
LOS/NLOS环境建模与三维TOA定位,MATLAB仿真程序,可自定义锚点数量和轨迹点长度
开发语言·matlab
LucianaiB2 小时前
探索CSDN博客数据:使用Python爬虫技术
开发语言·爬虫·python
Ronin3052 小时前
11.vector的介绍及模拟实现
开发语言·c++
✿ ༺ ོIT技术༻2 小时前
C++11:新特性&右值引用&移动语义
linux·数据结构·c++
字节高级特工2 小时前
【C++】深入剖析默认成员函数3:拷贝构造函数
c语言·c++
计算机学长大白3 小时前
C中设计不允许继承的类的实现方法是什么?
c语言·开发语言
PieroPc4 小时前
Python 写的 智慧记 进销存 辅助 程序 导入导出 excel 可打印
开发语言·python·excel