文章目录
- vector类的介绍
- vector类的常用接口介绍
- 构造相关
- 无参构造
- 迭代器区间构造
- 拷贝构造
- 容量相关的接口
- size
- reserve
- resize
- capacity
- empty
- 数据访问及遍历相关的接口
- operator[]
- begin + end
- rbegin + rend
- 修改数据相关的接口
- push_back
- pop_back
- insert
- erase
- 构造相关
- vector类的模拟实现(含各类接口)
vector类的介绍
vector是STL标准库提供的一个可变大小数组的序列容器的,底层使用的是连续的存储空间,是我们使用STL不可缺少的容器。
vector类的常用接口介绍
构造相关
无参构造:
作用:可以创建一个空的vector对象。
迭代器区间构造:
作用:使用容器的迭代器区间来生成一个vector对象,内容和传参的迭代器内容一样,注意传参是迭代器内的数据类型要相同。
拷贝构造:
作用:用一个已经存在的vector对象来创建一个新的vector对象,内容是相同的。
容量相关的接口
size:
作用:获取vector对象的数据大小。
reserve:
作用:为vector对象申请n个空间,如果n小于原本的大小,则不会进行任何操作,reserve只会扩容,不会缩容。
resize:
作用:将vector对象中是元素个数改为n个,如果n小于当前的元素个数,则会保留前n个元素,超出的部分会被删除,如果n大于当前的元素个数,则会用val填充超出的部分。
capacity:
作用:获取vector对象的容量大小。
empty:
作用:判断vector对象是否为空,如果是返回true,不为空返回false。
数据访问及遍历相关的接口
operator[]:
作用:通过重载了operator[],让我们可以像数组一样用下标的方式去访问数据,并且返回该位置元素的引用,下面是const对象使用的,返回的元素不可以被修改。
begin + end:
begin作用:获取vector对象中第一个元素
的地址
end作用:获取vector对象中最后一个元素的下一个位置
的地址
注意:
1、迭代器是STL中通用的遍历容器方式,迭代器是一种行为像指针一样的类型
,但是迭代器的底层实现是不是指针不确定,具体看容器的底层实现方式,迭代器的使用方式也很像指针,迭代器++
就是访问当前位置的下一个数据,- -(自减)
就是前一个。
2、第二个const接口是提供给const对象调用的,普通的对象和const对象的迭代器是不一样的,不能混淆,因为const迭代器是不允许通过迭代器来修改数据的。
修改数据相关的接口
push_back:
作用:在vector对象的元素尾部插入一个元素。
pop_back:
作用:在vector对象的元素尾部删除一个元素。
insert:
作用:接口1是在某个位置之前插入一个val元素,接口2是在某个位置插入n个val元素,接口3是在某个位置,插入另外一段迭代器区间内的数据。
erase:
作用:接口1是删除某个位置的元素,接口2是删除某段迭代器区间内所有的数据。
vector类的模拟实现(含各类接口)
#include<iostream>
#include<assert.h>
using namespace std;
namespace Lh
{
template <typename T>
class vector
{
public:
typedef T* iterator; //正向迭代器
typedef const T* const_iterator;
//普通迭代器
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
//const 迭代器
const_iterator begin() const
{
return _start;
}
const_iterator end() const
{
return _finish;
}
//无参的构造
vector()
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{}
//迭代器区间构造
template <class InputIterator> //这里要用模板 否则数据的类型只能是自身的类型 被固定了
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
//构造函数
vector(size_t n, const T& val = T())
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
reserve(n);
for (size_t i = 0; i < n; ++i)
{
push_back(val);
}
}
//构造函数 防止优先匹配模板
vector(int n, const T& val = T())
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
reserve(n);
for (int i = 0; i < n; ++i)
{
push_back(val);
}
}
//拷贝构造 传统写法
//vector(const vector<T>& v)
//{
// _start = new T[v.size()]; //这里用size和capacity都可以
// //memcpy(_start, v._start, sizeof(T) * v.size());
// //这里自定义类型不能使用memcpy 内置类型可以 memcpy也是值拷贝
// //如果是自定义类型 又会引发浅拷贝以及析构两次的结果
// for (size_t i = 0; i < v.size(); ++i)
// {
// _start[i] = v._start[i];
// }
// _finish = _start + v.size();
// _end_of_storage = _start + v.size();
//}
//交换函数
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(const vector<T>& v)
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
vector<T> tmp(v.begin(), v.end());
swap(tmp);
}
//容量
size_t capacity() const
{
return _end_of_storage - _start;
}
//Size
size_t size() const
{
return _finish - _start;
}
//头部数据
T& front()
{
assert(size() > 0);
return *_start;
}
T& back()
{
assert(size() > 0);
return *(_finish - 1);
}
//判断vector是否为空
bool empty() const
{
return _finish == nullptr;
}
//operator[]
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
//const operator[]
const T& operator[](size_t pos) const
{
assert(pos < size());
return _start[pos];
}
//尾插
void push_back(const T& x)
{
//空间满了扩容
if (_finish == _end_of_storage)
{
reserve(capacity() == 0 ? 4 : capacity() * 2);
}
*_finish = x;
++_finish;
}
//尾删
void pop_back()
{
assert(_finish > _start);
--_finish;
}
//任意位置插入数据
iterator insert(iterator pos, const T& x)
{
assert(pos >= _start && pos <= _finish);
if (_finish == _end_of_storage) //检查容量
{
size_t len = pos - _start; //防止迭代器失效 记录下pos到begin位置的距离
reserve(capacity() == 0 ? 4 : capacity() * 2); //扩容后会更换空间 导致pos失效
pos = _start + len; //更新下pos
}
iterator end = _finish - 1;
while (end >= pos) //挪动数据
{
*(end + 1) = *end;
--end;
}
*pos = x;
++_finish;
return pos; //STL规定insert返回新插入位置的迭代器
}
//任意位置删除数据
iterator erase(iterator pos) //stl 规定erase返回删除位置下一个位置迭代器
{
assert(pos >= _start && pos < _finish);
iterator begin = pos + 1;
while (begin < _finish) //挪动数据
{
*(begin - 1) = *begin;
++begin;
}
--_finish;
return pos; //STL规定erase返回插入位置的迭代器
}
//扩容
void reserve(size_t n)
{
if (n > capacity()) //超过了原有容量才扩容
{
iterator tmp = new T[n];
size_t sz = size();
if (_start)
{
//memcpy(tmp, _start, sizeof(T) * sz);
//这里自定义类型不能使用memcpy 内置类型可以 memcpy也是值拷贝
//如果是自定义类型 又会引发浅拷贝以及析构两次的结果
for (size_t i = 0; i < sz; ++i)
{
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_end_of_storage = _start + n;
}
}
//
void resize(size_t n, const T& val = T())
{
//n > 原来空间
if (n > capacity())
{
reserve(n);
}
//n > 原来数据
if (n > size())
{
//添加数据
while (_finish < _start + n)
{
*_finish = val;
++_finish;
}
}
else
{
_finish = _start + n;
}
}
//赋值重载 现代写法 利用传值传参产生临时对象 来和this 进行交换 传值不会影响实参
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
//析构
~vector()
{
delete[] _start;
_start = nullptr;
_finish = _end_of_storage = nullptr;
}
private:
iterator _start;
iterator _finish;
iterator _end_of_storage;
};