目录
一,vector的模板特性
二,vector基本使用
1. 构造函数
2. operator= 赋值
3. vector——增删
A, 尾插 && 尾删
B,insert
C, erase
4. 访问vector
遍历vector中元素:
法一:数组[]法 || at法
法二:迭代器法
语法糖——for
三,应用
1. 排序
2. vector + string
STL中的vector是一个动态数组容器,它可以存储任意类型的元素。vector的模板构造函数可以通过不同的参数来实现不同的初始化方式。
从STL中就会发现:
vector<int> s1;
vector<double> s2;
vector<char> s3;vector<string> s4 // 数据类型是string类
常见的有:
vector s1; // 设置一个不包含任何元素的空对象
vector s2(3); //设置3个初始值为默认值的vector对象
vector s3(3, 20); // 三个初始值为20的vector对象
// 以及还有迭代器的函数,这里留到讲解vector迭代器再讲
vector s4(s3); // 拷贝构造
结果:
vector s5 = s3; // vector对象之间的赋值
vector中没有头插 && 头删,相应的有insert(插入) && erase(删除)
// 添加数据的值
s1.push_back(10); // 添加一个数据10
s1.push_back(20);
s1.push_back(30);
s1.pop_back(); // 删除尾部元素
s1.pop_back();
vector s1;
s1.push_back(10);
s1.push_back(10);
s1.push_back(30);
s1.push_back(21);
vector::iterator pos = find(s1.begin(), s1.end(), 20);
if (pos != s1.end()) //find()函数如果没有匹配的化会返回最后一个有效数据的下一个位置,
// 没有判断则尾插,不符合判断插入的逻辑。
{
s1.insert(pos, 100); // pos为插入位置的迭代器,100则是插入值
}
for (auto i : s1)
{
cout << i << " ";
}
// 结果是 10 10 30 21
(注意:find()算法函数包含在 algorithm 头文件中)
共两种,一个是删除单个元素,一个则是范围删除,都是通过迭代器进行操作。
v1.erase(v1.begin() + 3); // 删除第三个元素
v1.erase(v1.begin(), v1.end() - 1); // 删除前v1.end() - 1个元素
常见的:
s1[0];
s1[2];
s1.front(); // 返回头元素引用
s1.back(); // 返回尾元素引用
s1.push_back(10);
s1.push_back(20);
s1.push_back(30);
for (int i = 0; i < s1.size(); i++)
{
cout << s1[i] << endl; // s1[i]可换成s1.at(i)后者用的少
// 都是返回数据的引用
}
vector::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
同时,支持迭代器也支持语法糖for,其底层会被替换为迭代器。
挪:
for (auto i : s1)
{
cout << i << endl;
}
其访问结果跟迭代器一模一样。
前面我们了解了vector的使用,学过string类会发现vector没有什么特别新颖的地方。这里我们来做一些小知识点扩展。
这里用到STL中排序算法函数 sort()
如你所见,sort函数通过函数模板实现功能,而其底层使用的是快排算法。
如下:
vector v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(21);
v1.push_back(32);
sort(v1.begin(), v1.end());
for (auto e : v1)
{
cout << e << " ";
}
// 升序:10 20 21 30 32 40
sort函数默认为升序,那如何改为降序呢?
使用第二个重载函数如下:
vector v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(21);
v1.push_back(32);
sort(v1.begin(), v1.end());
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
// 升序:10 20 21 30 32 40
// 库函数中有两个仿函数
less ls; // 默认的升序就是他
greater gt; // 降序
sort(v1.begin(), v1.end(), gt);
for (auto e : v1)
{
cout << e << " ";
}
//降序:40 32 30 21 20 10
当然网络上也有这样的简易写法:
sort(v1.begin(), v1.end(), greater());
而这里用到了匿名对象(less 与 greater是类)。
我们知道vector是泛性编程,那么当数据类型为自定义类型呢? 如:string类时,会有怎样的不同?
代码如下:
vector strv;
string s1 = "张三";
strv.push_back(s1); // 调用拷贝构造
strv.push_back(string("张三")); // 使用了匿名对象,具有临时对象的性质(const string)
// 本质上string使用了拷贝构造,操作还是比较繁琐。
strv.push_back("张三"); // 大部分时候是这样一种写法,使用了string的构造
好,下面我们来用范围for 进行 遍历输出,请看下面代码,是否有不合理的地方?
int main()
{
vector strv;
string s1 = "张三";
strv.push_back(s1); // 调用拷贝构造
strv.push_back(string("张三")); // 使用了匿名对象,具有临时对象的性质(const string)
// 本质上string使用了拷贝构造,操作还是比较繁琐。
strv.push_back("张三"); // 大部分时候是这样一种写法,使用了string的构造
for (auto str : strv)
{
cout << str << endl;
}
return 0;
}
解析:应为 auto& str : strv 。我们知道这次vector容器中的数据是string类,而范围for的功能是将strv中的数据赋值给str, string类赋值给string类这不是拷贝构造吗?那么每次赋值都是深拷贝,性能大浪费,所以应为auto& str : strv(如果严谨一些:不能修改数据,前面用const修饰)
这里有一个使用关于vector的算法题:118. 杨辉三角
从本质来说,下标双括号是调用了两次函数调用。
以上vector常见的用法,如果想要继续了解其他用法,需要查看文档:Reference - C++ Reference (cplusplus.com)
本小节就到这里了,感谢小伙伴的浏览,如果有什么建议,欢迎在评论区评论;如果给小伙伴带来一些收获请留下你的小赞,你的点赞和关注将会成为博主创作的动力。