了解vector
1.vector是一个表示可变大小数组的序列容器。
2.vector用连续空间存储元素,这意味着可以使用下标访问它的元素,这和数组很像,但是vector是可以动态改变大小的。
3.vector在其尾部进行增加删除的效率较高,在其他位置操作涉及到挪动数据效率较低。
vector
构造函数
模拟实现
变量
iterator _start=nullptr; // 指向数据块的开始
iterator _finish = nullptr; // 指向有效数据的尾
iterator _endOfStorage = nullptr; // 指向存储容量的尾
构造函数
vector()
:_start(nullptr)
,_finish(nullptr)
,_endOfStorage(nullptr)
{}
vector(int n, const T& value = T())
{
reserve(n);
for (int i = 0; i <n; i++)
{
push_back(value);
}
}
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (last != first)
{
push_back(*first);
++first;
}
}
vector(const vector<T>& v)
{
reserve(v.capacity());
for (auto& e : v)
{
push_back(e);
}
}
迭代器
** iterator的使用 ** | 接口说明 |
---|---|
begin + end | 获取第一个位置的迭代器和最后一个位置的后一个位置的迭代器 |
rbegin + rend | 获取最后一个数据位置的反向迭代器,获取第一个数据前一个位置的反向迭代器 |
模拟实现
typedef T* iterator;
typedef const T* const_iterator;
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin() const
{
return _start;
}
const_iterator end() const
{
return _finish;
}
空间增长问题
我们在使用vector中不断将元素插入到vector中,vector的容量大小会自动改变,编译器为了效率,会一次增加比较大的空间,具体的是多少视编译器而定
其中有两个点需要我们注意
1.reserve会将容器大小扩容到指定的n,但是如果n比现有的容量要小则不会进行任何操作。
2.resize将vector的size改变到指定的大小n,如果现有size比n要大,则会删除超出n的元素,反之会填充指定的元素。
模拟实现
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _endOfStorage - _start;
}
void reserve(size_t n)
{
if (n > capacity())//需要扩容
{
T* tmp = new T[n];
size_t sz = size();
if (_start)
{
for (int i = 0; i < sz; i++)
{
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_endOfStorage = _start + n;
}
}
void resize(size_t n, const T& value = T())
{
if (n < size())
{
_finish = _start + n;
}
else
{
size_t count =n- size();
while (count--)
{
push_back(value);
}
}
}
增删查改
迭代器失效问题,vector的迭代器的底层是一个指针,我们在使用迭代器的时候,如果中途遇到改变底层空间的操作都有可能会引起迭代器失效( resize、reserve、insert、assign、 push_back等 )
vector<int> v{1,2,3,4,5,6};
auto it = v.begin();
// 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容
// v.resize(100, 8);
// 插入元素期间,可能会引起扩容,而导致原空间被释放
// v.insert(v.begin(), 0);
// v.push_back(8);
原因就是上面的操作导致vector扩容,原空间被释放,这个时候it就是指向一段被释放的空间了
删除操作也会导致迭代器失效
int a[] = { 1, 2, 3, 4 };
vector<int> v(a, a + sizeof(a) / sizeof(int));
// 使用find查找3所在位置的iterator
vector<int>::iterator pos = find(v.begin(), v.end(), 3);
// 删除pos位置的数据,导致pos迭代器失效。
v.erase(pos);
cout << *pos << endl; // 此处会导致非法访问
模拟实现
T& operator[](size_t pos)
{
return _start[pos];
}
const T& operator[](size_t pos)const
{
return _start[pos];
}
///modify/
void push_back(const T& x)
{
/*if (size() == capacity())
{
reserve(size() == 0 ? 4 : size() * 2);
}
*_finish = x;
_finish++;*/
insert(end(), x);
}
void pop_back()
{
--_finish;
}
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endOfStorage, v._endOfStorage);
}
iterator insert(iterator pos, const T& x)
{
if (size() == capacity())
{
size_t len = pos - _start;
reserve(size() == 0 ? 4 : size() * 2);
pos = _start + len;
}
iterator it = end() - 1;
while (it >= pos)//挪动数据
{
*(it + 1) = *it;
it--;
}
*pos = x;
_finish++;
return pos;
}
iterator erase(iterator pos)
{
iterator it = pos+1;
while (it!=end())
{
*(it - 1) = *it;
it++;
}
_finish--;
return pos;
}
完整代码
template<class T>
class vector
{
public:
// Vector的迭代器是一个原生指针
typedef T* iterator;
typedef const T* const_iterator;
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin() const
{
return _start;
}
const_iterator end() const
{
return _finish;
}
// construct and destroy
vector()
:_start(nullptr)
,_finish(nullptr)
,_endOfStorage(nullptr)
{}
vector(int n, const T& value = T())
{
reserve(n);
for (int i = 0; i <n; i++)
{
push_back(value);
}
}
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (last != first)
{
push_back(*first);
++first;
}
}
vector(const vector<T>& v)
{
reserve(v.capacity());
for (auto& e : v)
{
push_back(e);
}
}
vector<T>& operator= (vector<T> v)
{
swap(v);
return *this;
}
~vector()
{
delete[] _start;
_start = _finish = _endOfStorage = nullptr;
}
// capacity
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _endOfStorage - _start;
}
void reserve(size_t n)
{
if (n > capacity())//需要扩容
{
T* tmp = new T[n];
size_t sz = size();
if (_start)
{
for (int i = 0; i < sz; i++)
{
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_endOfStorage = _start + n;
}
}
void resize(size_t n, const T& value = T())
{
if (n < size())
{
_finish = _start + n;
}
else
{
size_t count =n- size();
while (count--)
{
push_back(value);
}
}
}
///access///
T& operator[](size_t pos)
{
return _start[pos];
}
const T& operator[](size_t pos)const
{
return _start[pos];
}
///modify/
void push_back(const T& x)
{
/*if (size() == capacity())
{
reserve(size() == 0 ? 4 : size() * 2);
}
*_finish = x;
_finish++;*/
insert(end(), x);
}
void pop_back()
{
--_finish;
}
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endOfStorage, v._endOfStorage);
}
iterator insert(iterator pos, const T& x)
{
if (size() == capacity())
{
size_t len = pos - _start;
reserve(size() == 0 ? 4 : size() * 2);
pos = _start + len;
}
iterator it = end() - 1;
while (it >= pos)//挪动数据
{
*(it + 1) = *it;
it--;
}
*pos = x;
_finish++;
return pos;
}
iterator erase(iterator pos)
{
iterator it = pos+1;
while (it!=end())
{
*(it - 1) = *it;
it++;
}
_finish--;
return pos;
}
private:
iterator _start=nullptr; // 指向数据块的开始
iterator _finish = nullptr; // 指向有效数据的尾
iterator _endOfStorage = nullptr; // 指向存储容量的尾
};