目录
前言
学习完string,我们再来看vector(向量)——可变大小数组的序列容器,其实本质就是顺序表,可以是任意类型,如char、int、string、vector等等。
本节学习vector的常用接口。
标准库中的vector类
alloctor是内存池,C++为了提高内存申请效率而设计的,有缺省值,如果对C++的设计不满意,可以自己传参修改
一、构造函数
构造函数声明 | 接口说明 |
vector()(重点) | 无参构造 |
vector (size_type n, const value_type& val = value_type()) | 构造并初始化n个val |
vector (const vector& x)((重点) | 拷贝构造 |
vector (Inputlterator first, Inputlterator last) | 使用迭代器进行初始化构造 |
vector<int> v1(10, 1);
//例一:
vector<string> v2(10, "***");
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
for (auto e : v2)
{
cout << e << " ";
}
cout << endl;
// 自己类型的迭代器
vector<int> v3(v1.begin(), v1.end());
for (auto e : v3)
{
cout << e << " ";
}
cout << endl;
//例四:
string str("hello world");
vector<char> v4(str.begin(), str.end());
for (auto e : v4)
{
cout << e << " ";
}
cout << endl;
//例五:
int a[] = { 16,2,77,29 };
vector<int> v5(a, a+4);
for (auto e : v5)
{
cout << e << " ";
}
cout << endl;
二、空间问题
容量空间 | 接口说明 |
size | 获取数据个数 |
capacity | 获取容量大小 |
empty | 判断是否为空 |
resize | 改变vector的size和capacity |
reserve | 改变vector的capacity |
reserve && resize
预留容量空间,是为了提高扩容效率,避免多次扩容空间。
我们来看下面一段代码:
vector<int> v;
v.reserve(10);
for (size_t i = 0; i < 10; i ++ )
{
v[i] = i;
}
运行后发现越界,这是错误写法,因为[ ] 重载函数内会判断i是否小于size,是以size为标准的,所以不能插入到size与capacity之间的空间中
所以,如果想访问这之间的空间,我们需要使用resize函数,将size与capacity同时更新
vector<int> v;
v.resize(10);
for (size_t i = 0; i < 10; i ++ )
{
v[i] = i;
}
三、vector增删查改
vector增删查改 | 接口说明 |
push_back | 尾插 |
pop_back | 尾删 |
find | 查找(在算法模块,不是vector的成员接口) |
insert | 在pos之前插入val |
erase | 删除pos位置的数据 |
swap | 交换两个vector的数据空间 |
operator[ ] | 像数组一样访问 |
举例:
int a[] = { 16,2,77,29,3,33,43,3,2,3,3,2 };
vector<int> v1(a, a + sizeof(a)/sizeof(int));
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
// 头删
v1.erase(v1.begin());
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
// 头插
v1.insert(v1.begin(), 100);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
// 删除第3个数据
v1.erase(v1.begin()+2);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
// 删除3,但是不知道3在哪个位置,怎么办?
//vector<int>::iterator pos = find(v1.begin(), v1.end(), 3);
auto pos = find(v1.begin(), v1.end(), 3);
/*if (pos != v1.end())
{
v1.erase(pos);
}*/
如果要删除所有值为x的元素,要怎么做呢?
如果将上面的代码使用循环,每次再从pos + 1处find,最后会涉及迭代器失效问题,出现错误。这个问题,我们后面再来解决。
// 删除所有的3 -- 涉及迭代器失效!后面解决 while(pos != v1.end()) { v1.erase(pos); //pos = find(pos+1, v1.end(), 3); pos = find(v1.begin(), v1.end(), 3); }
四、如何扩容
我们来看在vs和Linus中扩容情况:
void TestVectorExpand()
{
size_t sz;
vector<int> v;
sz = v.capacity();
cout << "making v grow:\n";
for (int i = 0; i < 100; ++i)
{
v.push_back(i);
if (sz != v.capacity())
{
sz = v.capacity();
cout << "capacity changed: " << sz << '\n';
}
}
}
大致为1.5倍扩容,而在Linus上,为2倍扩容
五、例题
如何理解 vector<vector<int>> ?
我们可以分析vector<int>
数组a的类型是int* ,a数组内的每个元素类型是int
那么类比来看vector<vector<int>>
此时数组a的类型变为 vector<int> *,是一个vector的指针类型(是一个对象数组),数组内的每个元素类型是vector<int> ,每个元素都有各自的数组a、siza、capacity。
所以,vector<vector<int>> 就是二维数组,数组的长度可以不一致。
对于二维的vector,可以使用v[ i ][ j ]来访问数据,它的原理是:第一个v[ i ]表示v.operator[]( i ),返回的值类型是vector<int>&,而第二个[ ],表示的是v[ i ].operator[]( j ),返回的值类型是int。
学习了vector的使用,我们来做一个例题,充分使用vector
例题1:
https://leetcode.cn/problems/letter-combinations-of-a-phone-number/description/
class Solution {
public:
string a[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
public:
//多路递归
void Combinations(const string& digits, int level, string str, vector<string>& v)
{
if (level == digits.size())
{
v.push_back(str);
return;
}
//取每一层对应映射的字母
int num = digits[level] - '0';
string tmp(a[num]);
for (int i = 0; i < tmp.size(); ++ i)
{
//注意:我们没有改变str的值,不是+=,我们只是在或面加了一个字母
//所以递归回溯后,不需要还原
Combinations(digits, level + 1, str + tmp[i], v);
}
}
//全排列
vector<string> letterCombinations(string digits)
{
vector<string> res;
if (digits.size() == 0)
return res;
Combinations(digits, 0, "", res);
return res;
}
};
具体理解,可以自己画递归展开图
六、算法
1. sort
- 参数传迭代器 (string、vector等都可使用 sort 进行排序)
- 默认升序,如果想排为降序,使用仿函数匿名对象即可
- 实现的算法 :快排
int a[] = { 16,2,77,29 };
vector<int> v5(a, a+4);
for (auto e : v5)
{
cout << e << " ";
}
cout << endl;
// 升序 <
// less
sort(v5.begin(), v5.end());
//sort(v5.rbegin(), v5.rend());
for (auto e : v5)
{
cout << e << " ";
}
cout << endl;
// 降序 >
//greater<int> gt;
//sort(v5.begin(), v5.end(), gt);
//greater<int>() 匿名对象
sort(v5.begin(), v5.end(), greater<int>());
for (auto e : v5)
{
cout << e << " ";
}
cout << endl;
总结
本节初步了解vector类的使用方法,具体更多的接口概念与定义在网站内查询。
vector - C++ Reference (cplusplus.com)
下节课,我们将模拟实现vector
最后,如果小帅的本文哪里有错误,还请大家指出,请在评论区留言(ps:抱大佬的腿),新手创作,实属不易,如果满意,还请给个免费的赞,三连也不是不可以(流口水幻想)嘿!那我们下期再见喽,拜拜!