Vector
一. 什么是vector
vector的介绍
C++是一门广泛应用于计算机程序设计的编程语言,而vector则是C++中非常常用的一个容器。下面将详细介绍C++ vector的特性和使用方法。
1.1 vector的本质
vector是C++ STL(标准模板库)中的一个动态数组容器,可以在程序运行时动态地定义和改变其大小。与传统数组相比,vector的最大优势就是内存管理的自动化,让开发者不必过多关注内存的分配和释放问题。
1.2 vector的特点
(1)向量大小可变:由于vector是动态数组,所以其大小是可变的,可以通过push_back、insert、erase等操作实现动态调整数组大小。
(2)连续存储:不像链表那样需要额外的指针来建立节点间的联系,vector的元素都是连续存储的,这也使得它的访问速度比链表更快。
(3)支持随机访问:由于vector的元素是连续存储的,所以我们可以使用下标随机访问其中的元素,这也是vector的另一个优点。
(4)内存管理自动化:vector容器对内存进行了自动管理,对于开发者而言,不必再去手动分配内存空间或者释放内存空间。
1.3 vector的优缺点
优点:
1.采用连续的地址存储元素, 自然就支持下标的随机访问, 因此 访问元素的效率 更加高效。
2.在尾部插入删除等行为不需要挪动数据,效率也较高。
缺点:
1.空间不足扩容时,可能造成空间的浪费。(看下面的解释)
2.在除尾部外 进行数据的插入删除操作时,会依次挪动数据,效率极为低下。
vector的基本使用方法
1.定义方式
构造函数声明 | 接口说明 |
---|---|
vector() (重点) | 无参构造 |
vector (size_type n, const value_type& val = value_type()) | 构造并初始化n个val |
vector (const vector& x); (重点) | 拷贝构造 |
vector (InputIterator first, InputIterator last); | 使用迭代器进行初始化构造 |
(1). 定义任意类型的空vector
vector<int> v1;
vector<char> v2;
vector<string> v3;
(2). 定义一个任意类型的vector,并用n个val来初始化vector
vector<int> v4(8, 3);// 用8个3来初始化vector
(3). 定义一个任意类型的vector,并用迭代器区间来初始化vector
vector<int> v5(v4.begin(), v4.end());// 用v4的迭代器区间来初始化v5
string s("hello world");
vector<char> v6(s.begin(), s.end());// 用s的迭代器区间来初始化v6
2.遍历方式
(1). 下标访问
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
vector<int> v(10, 6);
for (size_t i = 0; i < v.size(); i++)
{
v[i] += i;
cout << v[i] << " ";
}
cout << endl;
return 0;
}
(2). 迭代器循环访问
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
vector<int> v(10, 8);
vector<int>::iterator it = v.begin();
while (it != v.end())
{
(*it)++;
cout << *it << " ";
}
cout << endl;
return 0;
}
3.构建多维数组
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
vector<vector<int>> v;
v.resize(5);// 开辟5行空间
for (size_t i = 0; i < 5; i++)
{
v[i].resize(10);// 开辟10列空间
}
// 至此,5行10列的二维数组初始化完毕
// 向二维数组写入
for (size_t i = 0; i < v.size(); i++)
{
for (size_t j = 0; j < v[i].size(); j++)
{
v[i][j] = i*j;
}
}
// 打印二维数组
for (size_t i = 0; i < v.size(); i++)
{
for (size_t j = 0; j < v[i].size(); j++)
{
cout << v[i][j] << " ";
}
cout << endl;
}
return 0;
}
resize与reserve的区别
reserve
void test()
{
vector<int> v;
//开好100个元素的空间
v.reserve(100);
//用[]插入10个元素
for (size_t i = 0;i < 10;++i)
{
v[i] = i;
}
}
resize
void test()
{
vector<int> v;
//开好10个元素的空间
v.resize(10);
//用[]插入10个元素
for (size_t i = 0;i < 10;++i)
{
v[i] = i;
}
for (auto ret : v)
{
cout << ret << " ";
}
cout << endl;
}
我们用reserve仅仅只是开辟了100个空间,但是size==0,当我们要为数组赋值元素就可以用resize初始化好元素个数在进行赋值。
二. vector的插入方式
push_back
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v(1, 0);
for (auto x : v)
{
cout << x << " ";
}
cout << endl;
v.push_back(1);
v.push_back(2);
v.push_back(3);
for (auto x : v)
{
cout << x << " ";
}
cout << endl;
return 0;
}
insert
void test()
{
vector<int> v;
v.push_back(0);
v.push_back(0);
v.push_back(0);
//头插
v.insert(v.begin(), 1);
v.insert(v.begin(), 2);
//尾插
v.insert(v.end(), 2);
v.insert(v.end(), 3);
//中间插入(将其理解为指针的用法)
v.insert(v.begin() + 3, 6);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}
assign
将原来空间中的内容清空,再将你输入的内容插入到你的空间中去
1.正常代换
void test()
{
vector<Date> v;
v.reserve(10);
v.push_back(1);
v.push_back(1);
v.push_back(1);
v.push_back(1);
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "修改之前的长度为:" << endl;
cout << v.size() << endl;
cout << "修改之前的容量为:" << endl;
cout << v.capacity() << endl;
vector<Date> v1;
v1.push_back(2);
v1.push_back(2);
v1.push_back(2);
v1.push_back(2);
v1.push_back(2);
vector<Date>::iterator it1 = v1.begin();
v.assign(it1,v1.end());
cout << "修改之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "修改之后的长度为:" << endl;
cout << v.size() << endl;
cout << "修改之后的容量为:" << endl;
cout << v.capacity() << endl;
}
2.批量代换
void test()
{
vector<Date> v;
v.reserve(10);
v.push_back(1);
v.push_back(1);
v.push_back(1);
v.push_back(1);
v.push_back(1);
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "修改之前的长度为:" << endl;
cout << v.size() << endl;
cout << "修改之前的容量为:" << endl;
cout << v.capacity() << endl;
vector<Date> v1;
v.assign(3, 2);
cout << "修改之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "修改之后的长度为:" << endl;
cout << v.size() << endl;
cout << "修改之后的容量为:" << endl;
cout << v.capacity() << endl;
}
三. vector的删除方式
pop_back
实现尾删,这个删除就是将vector中的最后一个数据删除
void test()
{
vector<Date> v;
v.reserve(10);
v.push_back(1);
v.push_back(2);
v.push_back(3);
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "修改之前的长度为:" << endl;
cout << v.size() << endl;
cout << "修改之前的容量为:" << endl;
cout << v.capacity() << endl;
v.pop_back();
cout << "使用pop_back之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
}
erase
pop_back的功能是将尾部的数据删除,并且使用一次只能删除一个数据,而erase函数则可以做到在vector对象中的任意位置删除指定元素或者删除一段区间的元素
void test()
{
vector<Date> v;
v.reserve(10);
v.push_back(1);
v.push_back(2);
v.push_back(3);
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
vector<Date>::iterator it1 = v.begin();
v.erase(it1+1,v.end()-1);
cout << "修改之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
}
clear
clear函数是将全部的数据删除
void test()
{
vector<Date> v;
v.reserve(10);
v.push_back(1);
v.push_back(2);
v.push_back(3);
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "修改之前的长度为:" << endl;
cout << v.size() << endl;
cout << "修改之前的容量为:" << endl;
cout << v.capacity() << endl;
v.clear();
cout << "修改之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
cout << "修改之后的长度为:" << endl;
cout << v.size() << endl;
cout << "修改之后的容量为:" << endl;
cout << v.capacity() << endl;
}
四. vector内容的调用
size
这个函数的作用是查看当前对象含有的元素个数
void test()
{
vector<Date> v;
v.reserve(10);
v.push_back(1);
v.push_back(2);
v.push_back(3);
cout << "该对象的长度为:" << endl;
cout << v.size() << endl;
}
empty
该函数的作用是查看该对象的内容是否为空,如果为空返回1,非空返回0
void test()
{
vector<Date> v;
v.reserve(10);
v.push_back(1);
v.push_back(2);
v.push_back(3);
cout << "该对象是否为空:";
cout << v.empty();
}
operator[ ]
因为vector存储数据的方式是在一段连续的空间进行存储,所以在vector中我们将操作符[ ]进行了重载,使其[ ]可以像数组那样通过下标来获取对应的元素和修改对应的元素
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(6);
for (int i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
cout << endl;
return 0;
}
at
这个函数的作用和operator[ ]的作用是一样的,唯一的区别就在于对于不合法的下标at会抛异常不会报错而[ ]会报错
void test()
{
vector<Date> v;
v.reserve(10);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
cout << "修改之前的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
v.at(1) = 2;
v.at(2) = 3;
v.at(3) = 4;
cout << "修改之后的内容为:" << endl;
for (auto ch : v)
{
ch.print();
}
}
front
该函数的作用就是返回vector中的第一个元素,我们可以根据这个函数来修改和打印对应的数据。
back
该函数的作用就是返回vector中的最后一个元素,我们可以根据这个函数来修改和打印对应的数据。
capacity
该函数作用是查看该对象的容量
void test()
{
vector<Date> v;
v.reserve(10);
v.push_back(1);
v.push_back(2);
v.push_back(3);
cout << "该对象的容量为:" << endl;
cout << v.capacity() << endl;
}
五. vector中的其他函数
find
返回值是指向第一个匹配元素的迭代器。如果没有找到匹配的元素,则返回指向 vector 容器末尾的迭代器(end())。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vec = { 1, 2, 3, 4, 5, 6 };
// 查找元素
auto iter = find(vec.begin(), vec.end(), 3);
if (iter != vec.end())
{
cout << "元素找到,并位于 vector 的第 " << iter - vec.begin() << " 个位置上。" << endl;
}
else
{
cout << "未能找到指定元素。" << endl;
}
return 0;
}
swap
swap() 通过引用传递另一个 vector 容器,并且不返回任何值。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vec1 = { 1, 2, 3 };
vector<int> vec2 = { 4, 5, 6 };
//交换前
cout << "Before swapping:\n";
cout << "vec1: ";
for (auto it : vec1)
{
cout << it << " ";
}
cout << "\nvec2: ";
for (auto it : vec2)
{
cout << it << " ";
}
cout << endl;
vec1.swap(vec2);
//交换后
cout << "After swapping:\n";
cout << "vec1: ";
for (auto it : vec1)
{
cout << it << " ";
}
cout << "\nvec2: ";
for (auto it : vec2)
{
cout << it << " ";
}
cout << endl;
return 0;
}
六. 迭代器失效问题
在vector中,当对其进行添加、删除操作时,迭代器可能会失效,因为vector会动态地重新分配存储空间,导致原有元素在内存中的位置发生变化.此时我们更新一下迭代器就可以了.