文章目录
vector简介
- vector是表示可变大小数组的序列容器。
- 与数组类似,vector也采用的连续存储空间来存储元素。可以采用下标对vector的元素进行访问。
- vector的大小是可以动态改变的,而且它的大小会被容器自动处理。
- 当vector需要重新分配大小时,其做法是,分配一个新的数组,然后将全部元素移到这个数组当中,并释放原来的数组空间。
- vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因此存储空间比实际需要的存储空间一般更大。不同的库采用不同的策略权衡空间的使用和重新分配,以至于在末尾插入一个元素的时候是在常数的时间复杂度完成的。
- 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。
vector默认成员函数的使用
构造一个某类型的空容器。也就是实例化vector
vector<int> v1; //构造int类型的空容器
构造一个含有n个val的某类型容器。
vector<int> v2(10, 2); //构造含有10个2的int类型容器
拷贝构造某类型容器的复制品。
vector<int> v3(v2); //拷贝构造int类型的v2容器的复制品
使用迭代器拷贝构造某一段内容。
vector<int> v4(v2.begin(), v2.end()); //使用迭代器拷贝构造v2容器的某一段内容
注意:该方式也可用于拷贝其他容器的某一段内容。
string s("hello world");
vector<char> v5(s.begin(), s.end()); //拷贝构造string对象的某一段内容
vector的扩容问题
reserve和resize
通过reserse函数改变容器的最大容量,resize函数改变容器中的有效元素个数。
reserve:
1、当所给值大于容器当前的capacity时,将capacity扩大到该值。
2、当所给值小于容器当前的capacity时,什么也不做。
resize:
1、当所给值大于容器当前的size时,将size扩大到该值,扩大的元素为第二个所给值,若未给出,则默认为0。
2、当所给值小于容器当前的size时,将size缩小到该值。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v(10, 2);
cout << v.size() << endl; //10
cout << v.capacity() << endl; //10
v.reserve(20); //改变容器的capacity为20,size不变
cout << v.size() << endl; //10
cout << v.capacity() << endl; //20
v.resize(15); //改变容器的size为15
cout << v.size() << endl; //15
cout << v.capacity() << endl; //20
return 0;
}
vector的修改与访问
push_back
对容器进行尾插
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v;
v.push_back(1); //尾插元素1
v.push_back(2); //尾插元素2
v.push_back(3); //尾插元素3
v.push_back(4); //尾插元素4
return 0;
}
find与insert
find:在所给的容器中查找给定的一个值,并返回其下标
insert:在所给迭代器位置插入一个或多个元素
一般find都是与insert配合使用
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> v1;
v1.push_back(1); //尾插元素1
v1.push_back(2); //尾插元素2
v1.push_back(3); //尾插元素3
v1.push_back(4); //尾插元素4
vector<int>::iterator pos = find(v1.begin(), v1.end(), 3);//在v1对象中查找3的位置
//pos==v1.end()则说明没有找到,find函数会自动返回最后一个元素的地址
if (pos!=v1.end())
{
v1.insert(pos, 30);
}
return 0;
}
sort
给vector中的数据排序
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
int main()
{
vector<int> v1;
v1.push_back(1); //尾插元素1
v1.push_back(2); //尾插元素2
v1.push_back(3); //尾插元素3
v1.push_back(4); //尾插元素4
//排序 默认排升序
sort(v1.begin(), v1.end());
//降序
less<int> ls;
greater<int> gt;
sort(v1.begin(), v1.end(),gt);
//greater一般都是直接使用匿名对象来传参
sort(v1.begin(), v1.end(), greater<int>());
return 0;
}
元素访问
通过“下标+[ ]”对容器当中的元素进行访问
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
for (size_t i = 0; i < 4; i++)
{
v1[i]++;
}
for (size_t i = 0; i < 4; i++)
{
cout << v1[i] << " ";
}
cout << endl;
return 0;
}
vector的迭代器
begin和end
通过begin函数可以得到容器中第一个元素的正向迭代器,通过end函数可以得到容器中最后一个元素的后一个位置的正向迭代器。
正向迭代器:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v(10, 2);
//正向迭代器遍历容器
vector<int>::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
cout << endl;
return 0;
}
rbegin和rend
通过rbegin函数可以得到容器中最后一个元素的反向迭代器,通过rend函数可以得到容器中第一个元素的前一个位置的反向迭代器。
反向迭代器:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v(10, 2);
//反向迭代器遍历容器
vector<int>::reverse_iterator rit = v.rbegin();
while (rit != v.rend())
{
cout << *rit << " ";
rit++;
}
cout << endl;
return 0;
}
vector迭代器失效问题
insert导致的迭代器失效
1,扩容导致的野指针
正确写法:
iterator insert(iterator pos, const T& x)
{
assert(pos >= _start);
assert(pos <= _finish);
if (_finish == _end_of_storage)
{
//注意迭代器失效问题
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
pos = _start + len;//更新pos
}
iterator end = _finish - 1;
while (end>=pos)
{
*(end + 1) = *end;
end--;
}
*pos = x;
++_finish;
return pos;
}
2,pos总是指向同一个数导致的野指针
正确写法:
void test1()
{
lhj::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
auto it = v.begin();
while (it!=v.end())
{
if (*it % 2 == 0)
{
//插入后,it指向插入前的那个位置,只是内容改变为插入的数
it=v.insert(it,*it*2);
//若为偶数,则it需要移动两次
++it;
++it;
}
else
{
++it;
}
}
}
erase导致的迭代器失效
正确写法:
void test1()
{
lhj::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(4);
auto it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
{
it=v.erase(it);
}
else
{
it++;
}
}
}
总结:
使用insert/erase时,不要直接访问pos,一定要先更新pos再使用,否则会出现迭代器失效问题。