vector的介绍
C++ 中的 vector 是一种序列容器,它允许你在运行时动态地插入和删除元素。
vector 是基于数组的数据结构,但它可以自动管理内存,这意味着你不需要手动分配和释放内存。
与 C++ 数组相比,vector 具有更多的灵活性和功能,使其成为 C++ 中常用的数据结构之一。
vector 是 C++ 标准模板库(STL)的一部分,提供了灵活的接口和高效的操作。
vector与数组相比,可以灵活变化空间大小,与灵活存储不同数据类型的值
vector的使用
vector的定义
| (constructor)构造函数声明 | 接口说明 |
|---|---|
| vector()(重点) | 无参构造 |
| vector ( size_type n, const value_type& val = value_type()) | 构造并初始化 n 个 val |
| vector (const vector& x); (重点) | 拷贝构造 |
| vector (InputIterator fifirst, InputIterator last); | 使用迭代器进行初始化构 造 |
cpp
vector<int>v1;//一个类型为int空的vector
vector<int>v2(6, 1);//{1,1,1,1,1,1,}
vector<int>v3 = v2;//上同
vector<int>v5{ 1,1,1,1,1,1, };//上同
vector<int>v4(++v3.begin(), --v3.end());//{1,1,1,1}
vector iterator****的使用
|-----------------------------------------------------------------------------|------------------------------------------------------------------------------|
| iterator的使用 | 接口说明 |
| begin + end (重点) | 获取第一个数据位置的 iterator/const_iterator , 获取最后一个数据的下 一个位置的iterator/const_iterator |
| rbegin + rend | 获取最后一个数据位置的 reverse_iterator ,获取第一个数据前一个位置 的reverse_iterator |
cpp
vector<int>::iterator it = v3.begin();
while (it != v3.end())
{
cout << *it;
it++;
}
vector****空间增长问题
|--------------------------------------------------------------------------------|----------------------|
| 容量空间 | 接口说明 |
| size | 获取数据个数 |
| capacity | 获取容量大小 |
| empty | 判断是否为空 |
| resize | 改变 vector 的 size |
| reserve | 改变 vector 的 capacity |
cpp
vector<int> v1(5, 2);
v1.reserve(3);//capacity仍为5
cout << v1.capacity() << endl;
v1.reserve(20);//空间变为20
cout << v1.capacity() << endl;
vector<int> v1(5, 2);
v1.reserve(10);//空间变为10
cout << v1.capacity() << endl;
v1.resize(4);//size变为4,删除大于3下标的数据
cout << v1.capacity() << endl;
v1.resize(49, 4);//size变为48,且3之后的下标数据用4填充,capacity也会自动扩容
cout << v1.capacity() << endl;
v1.size();//
v1,empty();
由于历史原因,string的reserve与vector的reserve有区别
若当前
capacity小于n,则分配新内存(至少能容纳n个元素),并将原有元素复制 / 移动到新内存,旧内存释放。若capacity已≥n,则什么也不做(不会缩减容量)。而string则在不同的编译器,缩容行为不同
迭代器失效问题
导致操作
扩容
cpp
vector<int> v1{1,2,3,4};
v1.insert(v1.begin() + 2, 40);
//如果此处空间不够,进行扩容,那么原来v1,=,beign()指向的空间就被释放了,
解决办法:
使用相对位置更新
删除
假设此时it指向2,为偶数,删去,3挪到了2的位置,it再指向原来3的位置,如果此时为4,偶数就少删了
cpp
vector<int> v1{1,2,3,45,6,7};
auto it = v1.begin();
while (it != v1.end())
{
if (*it % 2 == 0)
v1.erase(it);
it++;
}
解决
cpp
auto it = v1.begin();
while (it != v1.end())
{
if (*it % 2 == 0)
it = v1.erase(it);//更新it
else
it++;
}
vector的模拟实现
可能遇到的坑
深拷贝
此处不用memcpy进行拷贝的原因是,memcpy是一个一个字节的拷贝,如果拷贝对象为内存管理对象(如:string),就会进行浅拷贝,析构两次,错误
cpp
void reserve(const size_t& n)
{
size_t old_size = size();
T* temp = new T[n];
//std::memcpy(temp, _start, sizeof(T) * size());
for (int i = 0; i < old_size; i++)
_str[i] = temp[i];
delete[]_start;
_start = temp;
//_finish = _start + size();//不可,因为此处在size函数中,statr是已扩容的,而finish则是未扩容的
//使用oldsize
_finish = _start + old_size;
_end_of_storage = temp + n;
}
解决迭代器失效问题
完整实现
cpp
#pragma once
#include <assert.h>
namespace Milestone
{
template <class T>//类模板的声明与定义不能分开写
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
iterator begin()
{
return _start;
}
const iterator begin()const
{
return _start;
}
iterator end()
{
return _finish;
}
const iterator end()const //第一个const修饰返回值不可被修改,第二个const修饰this指针
{
return _finish;
}
void reserve(const size_t& n)
{
size_t old_size = size();
T* temp = new T[n];
//std::memcpy(temp, _start, sizeof(T) * size());
for (int i = 0; i < old_size; i++)
_str[i] = temp[i];
delete[]_start;
_start = temp;
//_finish = _start + size();//不可,因为此处在size函数中,statr是已扩容的,而finish则是未扩容的
//使用oldsize
_finish = _start + old_size;
_end_of_storage = temp + n;
}
size_t size()const//修饰this指针
{
return _finish - _start;
}
size_t capacity()const
{
return _end_of_storage - _start;
}
size_t operator[](const int& n)
{
return *(_start + n);
}
const size_t operator[](const int& n)const
{
return *(_start + n);
}
void push_back(const T& x)
{
if (_finish == _end_of_storage)
{
reserve(capacity() == 0 ? 4 : 2 * sizeof(capacity()));
}
*_finish = x;//是成员函数,有this指针,访问_finish
_finish++;
}
bool empty()
{
return _start == _finish;
}
void pop_back()
{
assert(empty());
--_finish;
}
template<class T>
void print_vector(const vector<T>& v)//打印vector,不改变,用const,再定义一个函数模板,是为了方便多种类型的打印
{
for (auto& e : v)
std::cout << e << " ";
std::cout << std::endl;
//不能从没有实例化的类模板里面取东西,无法确定是类型还是静态成员变量
//class与typename的区别
//加typename确定了是类型
//或者使用auto,这个类型由后面的v.begin()推导
//如果是静态成员变量不用加关键字
//vector<T>::const_iterator it = v.begin();
typename vector<T>::const_iterator it = v.begin();
//auto vector<T>::const_iterator it = v.begin();
/*while (it != v.end())
{
std::cout << *it << " ";
it++;
}
std::cout << std::endl;
for (int i = 0; i < size(); i++)
{
std::cout << v[i] << " ";
}
std::cout << std::endl;*/
}
//void insert(iterator pos,const T&x)//一:在某位置前插入,
iterator insert(iterator pos, const T& x)//一:在某位置前插入,
//为了下面能再对pos修改,返回更新后的pos
{
//迭代器失效:1 类似野指针
//有可能空间不足,出现扩容
if (_finish == _end_of_storage)
{
//使用相对位置更新pos
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : 2 * sizeof(capacity()));
//但此时pos原来指向的空间被释放了,pos就相当于野指针了
pos = _start + len;
}
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end;
--end;
}
*pos = x;
++_finish;
return pos;
}
iterator find(iterator left, iterator right, int x)
{
while (left != right)
{
if (*left == x)
return left;
++left;
}
return left;
}
iterator erase(iterator it)
{
assert(it >= _start);
assert(it < _finish);
iterator end = it;
while (end < _finish - 1)
{
*end = *(end + 1);
end++;
}
--_finish;
return it;
}
void resize(const size_t n, T val = T())
{
//三种情况,size<_size _size<size<capacity size>capacity,后两种归为一种
if (n < size())
{
_finish = _start + n;
}
else
{
reserve(n);
while (_finish < _start + n)
{
*_finish = val;
_finish++;
}
}
}
~vector()
{
delete[]_start;
_start = _finish = _end_of_storage = nullptr;
}
vector()//下面自己定义了拷贝构造,系统就不会走默认构造了,要自己定义
{ }
vector(const vector<T>& v)//拷贝构造
{
reserve(v.size());//提前开好空间,避免频繁扩容
for (auto& e:v)
{
push_back(e);
}
}
void clear()
{
_finish = _start;
}
//深拷贝 传统写法
//vector<T>& operator=( const vector<T>& v)
//{
// if (this != &v)//?
// {
// clear();//清除this指针里面的元素
//
// reserve(v.size());
// for(auto& e : v)
// {
// push_back(e);
// }
// }
// return *this;
// }
//现代写法
/*void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}*/
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
while(first != last)//此处也可以用小于,但只适用于vector,他们在同一块空间,可以比较,但list这些就不行,所以使用!
{
push_back(*first);
++first;
}
//构造函数和类名称一样
}
vector(size_t n, const T &val= T())
{
for (int i = 0; i < n; i++)
{
push_back(val);
}
}
vector(int n, const T &val= T())
{
for (int i = 0; i < n; i++)
{
push_back(val);
}
}
private:
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _end_of_storage = nullptr;
};
void tv1()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
v1.print_vector(v1);//不为const,再定义一个const类型
}
void tv2()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
//v1.push_back(5);
v1.print_vector(v1);
//v1.insert(v1.begin() + 2, 40);//要求左闭右开
//v1.print_vector(v1);
//在某个值前插入数据
int x;
std::cin >> x;
auto p = v1.find(v1.begin(), v1.end(), x);//左闭右开
if (p != v1.end())//防止数据不存在
{
//v1.insert(p, 40);
v1.print_vector(v1);
//(*p) *= 10;
//此处迭代器失效(建议不要访问),因为形参无法改变实参,形参使用引用,也类型不匹配,pos指向位置改变
//要访问的话,更新pos
p = v1.insert(p, 40);
*p *= 10;
v1.print_vector(v1);
}
}
void tv3()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(4);
v1.push_back(5);
v1.print_vector(v1);//不为const,再定义一个const类型
//删除所以偶数
auto it = v1.begin();
while (it != v1.end())
{
if (*it % 2 == 0)
it = v1.erase(it);//更新it
else
it++;
}
v1.print_vector(v1);//不为const,再定义一个const类型
v1.resize(5, 1);
v1.print_vector(v1);//不为const,再定义一个const类型
}
void tv4()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
v1.print_vector(v1);//不为const,再定义一个const类型
vector<int>v2 = v1;
v2.print_vector(v2);//不为const,再定义一个const类型
vector<int>v3;
v3 = v1;
v3.print_vector(v3);
}
void tv5()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
v1.print_vector(v1);//不为const,再定义一个const类型
//迭代器构造
vector<int> v2(v1.begin(), v1.begin() + 4);
v2.print_vector(v2);//不为const,再定义一个const类型
//n 个k
vector<int>v3(5, 1);//此处5 c++默认`是int类型
v3.print_vector(v3);//不为const,再定义一个const类型
vector<int>v4(5);//此处5 c++默认`是int类型
v4.print_vector(v4);//不为const,再定义一个const类型
}
}