发布时间:2024-05-05 15:01
各位小伙伴们,大家好!我是bug。今天我们来谈谈vector的相关内容:
(代码可能会有一点问题,请各位老铁指正 )
Vector: vector是C++标准模板库中的部分内容。它是动态增长的对象数组,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。
vector的常用接口:
construct(构造函数) | 用法 |
---|---|
vector() | 无参构造函数 |
vector(size_type n, const value_type& val = value_type()) | 构造初始化n个val |
vector (const vector& x); | 拷贝构造 |
vector (InputIterator first, InputIterator last); | 迭代器初始化构造 |
遍历操作 | 用法 |
---|---|
operator[] | 数组 |
begin | 获取第一个数据位置的iterator/const_iterator |
end | 获取最后一个数据的下一个位置的iterator/const_iterator |
rbegin | 获取最后一个数据位置的reverse_iterator |
rend | 获取第一个数据前一个位置的reverse_iterator |
操作空间/容量 | 用法 |
---|---|
size | 获取数据个数 |
capacity | 获取容量大小 |
empty | 判断是否为空 |
resize | 改变vector的size |
reserve | 改变vector的capacity |
修改操作 | 用法 |
---|---|
push_back | 尾插 |
pop_back | 尾删 |
insert | 在position之前插入数据 |
erase | 删除position位置的数据 |
swap | 交换两个vector的数据空间 |
vector创建对象的方式有很多,比如:
使用默认构造函数
使用带参构造函数
使用拷贝构造函数
使用赋值运算符重载
使用迭代器区间进行构造
创建匿名对象
代码⬇️ ⬇️:
//有参数构造
vector<int> v1(5, 4);
//无参数构造
vector<int> v2;
//拷贝构造
vector<int> v3(v1);
//迭代器区间进行构造
vector<int> v4(v1.begin(), v1.end());
//赋值运算符重载
vector<int> v5 = v1;
//匿名对象
vector<int>();
string有三种遍历的方式:
通过[]的重载像数组一样遍历。
通过迭代器进行遍历。
通过范围for进行的遍历
代码⬇️ ⬇️:
//遍历,和string类似,这里就不详细演示了
vector<int> v(4, 5);
//[]重载
for (size_t i = 0; i < v.size(); i++)
{
cout << v[i] << \" \";
}
cout << endl;
//迭代器
vector<int>::iterator it = v.begin();
while (it != v.end())
{
cout << *it << \" \";
it++;
}
cout << endl;
//范围for
for (auto e : v)
{
cout << e << \" \";
}
cout << endl;
注意❗️ ❗️
(1)[]的重载有const和非const版本的。
(2)迭代器有const和非const版本的,C98中直接将begin、end进行重载。在C11中为了区别const和非const迭代器,引入了cbegin和cend。(和begin、end的const版本就名字不同)
(3)范围for的本质是迭代器,程序运行过程中,编译器会把范围for替换成迭代器进行操作。同时范围for是通过赋值的方式进行遍历(将数据赋给变量),如果要修改,就要使用引用。
测试代码⬇️ ⬇️:
vector<int> v(4, 5);
//打印容量
cout << v.capacity() << endl;
v.reserve(3);
cout << v.capacity() << endl;
v.reserve(8);
cout << v.capacity() << endl;
//只能扩容,和string一样
v.resize(2);
//打印容量
cout << v.capacity() << endl;
//遍历
auto it = v.begin();
while (it != v.end())
{
cout << *it << \" \";
it++;
}
cout << endl;
v.resize(12, 0);
//要重新对it赋值,因为扩容之后迭代器begin发生了改变
//这里的begin是原生指针
it = v.begin();
//打印容量
cout << v.capacity() << endl;
while (it != v.end())
{
cout << *it << \" \";
it++;
}
cout << endl;
迭代器失效有两种情况:
1.、会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、push_back等。
2、erase删除数据
解决方法:对it重新赋值。
这里我们来仔细谈谈迭代器失效:
在vector的类中,我们并没有实现find函数,我们使用的是算法里面的查找函数,当我们使用insert进行插入、或者使用erase删除等操作时,都需要找到数据的位置然后进行相应的操作。
但是会有这几种情况发生:
(1)使用insert等接口时,底层空间发生了改变。
从底层的角度我们不难发现,以扩容为例,过程大致分为这么几个步骤:
这个时候我们之前使用的find函数返回的指针仍然指向之前的那片空间(被释放掉了),即这个指针就是野指针了。
在vector中,为了解决这个问题,采取了返回iterator的方式。即通过insert返回新的指针,指向之前查找的那个数字。
(2)使用erase时,我们要进行连续删除。
举个栗子:删除vector对象中所存储的奇数:
这个代码有什么问题吗?⬇️ ⬇️(vs上编不过)
#include
#include
using std::cin;
using std::cout;
using std::endl;
using std::vector;
int main()
{
vector<int> v(4, 5);
auto it = std::find(v.begin(), v.end(), 5);
while (it != v.end())
{
v.erase(it);
it++;
}
cout << endl;
return 0;
}
如图分析:
在上图这情况下,结果看起来是没有什么问题,但是如果是下面这种呢?
即每次删除一个奇数数据后,会跳过一个数据同时判断下一个数据是否是奇数。当发生极端情况,即最后一个数据是奇数,被删除后,it发生了自增操作,就会直接越过end,然后不断的循环越界。(迭代器就失效了)
所以为了避免这种情况,我们同样采用了返回iterator的形式,通过返回一个修正值来避免迭代器失效。
代码⬇️ ⬇️:
#include
#include
using std::cin;
using std::cout;
using std::endl;
using std::vector;
int main()
{
vector<int> v(4, 5);
auto it = std::find(v.begin(), v.end(), 5);
while (it != v.end())
{
//通过接收erase返回后的修正值防止迭代器失效
it = v.erase(it);
it++;
}
cout << endl;
return 0;
}
总结:解决迭代器失效的方法就是重新对it进行赋值操作。
这里我们来实现一个简易的vector⬇️ ⬇️:
typedef _Tp* iterator;
typedef const _Tp* const_iterator;
//构造函数
vector()
vector(size_t n, const _Tp& val = _Tp())
vector(const vector& v1)
vector(InputIterator start, InputIterator finish)
void swap(vector& v)
vector& operator=(const vector& v1)
//遍历操作
_Tp& operator[](size_t i)
const _Tp& operator[](size_t i)const
iterator begin() const
iterator end() const
const_iterator cbegin()const
const_iterator cend()const
//扩容操作
void reserve(size_t n)
void resize(size_t n, _Tp val = _Tp())
//增删操作
void push_back(const _Tp& t)
void pop_back(size_t n)
iterator insert(iterator pos, const _Tp& val)
iterator insert(iterator pos, size_t n, const _Tp& val)
iterator erase(iterator pos)
iterator erase(iterator start, iterator finish)
//其他
void clear()
bool empty()
完整代码⬇️ ⬇️:
#include
#include
#include
using std::cin;
using std::cout;
using std::endl;
using std::istream;
using std::ostream;
namespace lz
{
template<class _Tp>
class vector
{
public:
//迭代器
typedef _Tp* iterator;
typedef const _Tp* const_iterator;
iterator begin() const { return _start; }
iterator end() const { return _finish; }
const_iterator cbegin()const { return _start; }
const_iterator cend()const { return _finish; }
typedef _Tp* InputIterator;
size_t size()const { return _finish - _start; }
size_t capacity()const { return _end_of_storage - _start; }
// 构造函数
vector(InputIterator start, InputIterator finish)
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
while (start != finish)
{
push_back(*start);
start++;
}
}
vector(size_t n, const _Tp& val = _Tp())
:_start(new _Tp[n])
, _finish(_start + n)
, _end_of_storage(_finish)
{
auto it = begin();
while (it != _finish)
{
*it = val;
it++;
}
}
vector()
: _start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{}
// 析构函数
~vector()
{
delete[]_start;
_start = _finish = nullptr;
_end_of_storage = nullptr;
}
// 拷贝构造函数
vector(const vector& v1)
{
reserve(v1.capacity());
for (size_t i = 0; i < v1.size(); i++)
{
*(_start + i) = *(v1._start + i);
}
_finish = _start + v1.size();
}
// 赋值运算符重载
vector& operator=(const vector& v1)
{
vector<_Tp> tmp(v1);
swap(tmp);
return *this;
}
// []重载
_Tp& operator[](size_t i)
{
return _start[i];
}
const _Tp& operator[](size_t i)const
{
return _start[i];
}
// 交换函数swap
void swap(vector& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
// 扩容 reserve
void reserve(size_t n)
{
size_t sz = size();
if (n > capacity())
{
_Tp* tmp = new _Tp[n];
if (!empty())//判断是否为空
{
for (size_t i = 0; i < sz; i++)
{
tmp[i] = _start[i];
}
}
delete[]_start;
_start = tmp;
_finish = _start + sz;
_end_of_storage = _start + n;
}
}
// 扩容+初始化 resize
void resize(size_t n, _Tp val = _Tp())
{
if (n < size())
{
_finish = _start + n;
}
else if (n > size())
{
if (n > capacity())
{
reserve(n);
}
for (size_t i = size(); i < n; i++)
{
*(_start + i) = val;
}
_finish = _start + n;
}
}
// 尾插 push_back单个数据
void push_back(const _Tp& t)
{
if (_end_of_storage == _finish)
{
size_t new_capacity = (capacity() == 0 ? 4 : capacity() * 2);
reserve(new_capacity);
}
*_finish = t;
_finish++;
}
// 插入 insert单个数据
iterator insert(iterator pos, const _Tp& val)
{
assert(pos >= _start && pos <= _finish);
size_t sz = _finish - pos;
if (_finish == _end_of_storage)
{
size_t new_capacity = (capacity() == 0 ? 4 : capacity() * 2);
reserve(new_capacity);
pos = _finish - sz;
}
for (iterator it = _finish; it >= pos; it--)
{
*it = *(it - 1);
}
_finish++;
*pos = val;
return pos + 1;
}
//插入insert多个数据
iterator insert(iterator pos, size_t n, const _Tp& val)
{
assert(pos >= _start && pos <= _finish);
size_t sz = _finish - pos;
if (_end_of_storage <= pos + n)
{
size_t new_capacity = n + _end_of_storage - pos;
reserve(new_capacity);
pos = _finish - sz;
}
iterator it = pos;
for (iterator i = pos; i < n + pos; i++)
{
it = insert(it, val);
}
return pos + n;
}
// 尾删 pop_back单个数据
void pop_back(size_t n)
{
if (!empty())
{
if (n > size())
{
n = size();
}
_finish -= n;
}
}
// 删除 erase(单个数据)
iterator erase(iterator pos)
{
assert(pos >= _start && pos < _finish);
iterator it = pos;
while (it != _finish)
{
it++;
*(it - 1) = *it;
}
//防止为空时,_finish跑到_start前面了
if (!empty())
_finish--;
return pos - 1;
}
//删除一个迭代器区间数据
iterator erase(iterator start, iterator finish)
{
assert(start >= _start && _finish >= finish);
size_t sz = finish - start;
size_t it = sz;
while (it)
{
start = erase(start);
it--;
}
return finish - sz;
}
//清理
void clear()
{
_finish = _start;
}
// 判空 empty
bool empty()
{
return _start == _finish;
}
private:
iterator _start;
iterator _finish;
iterator _end_of_storage;
};
}
void Test1()//构造函数
{
lz::vector<int> v1(4, 5);
lz::vector<int> v2;
lz::vector<int> v3(v1);
lz::vector<int> v4 = v3;
lz::vector<int> v5(v4.begin(), v4.end());
//lz::vector();
for (auto e : v5)
{
cout << e << \" \";
}
cout << endl;
}
void Test2()//erase
{
lz::vector<int> v(3, 5);
auto it1 = std::find(v.begin(), v.end(), 5);
while (it1 != v.end())
{
it1 = v.erase(it1);
it1++;
}
auto it2 = v.begin();
while (it2 != v.end())
{
cout << *it2 << \" \";
it2++;
}
cout << endl;
}
void Test3()//push_back+insert
{
lz::vector<int> v1;
lz::vector<int> v2(3, 1);
v1.push_back(4);
v1.push_back(5);
v1.push_back(6);
v1.push_back(7);
//打印容量
cout << \"capacity = \" << v1.capacity() << endl;
auto it = v1.begin();
while (it != v1.end())
{
cout << *it << \" \";
it++;
}
cout << endl;
auto tmp1 = std::find(v1.begin(), v1.end(), 4);
tmp1 = v1.insert(tmp1, 1);
//打印容量
cout << \"capacity = \"<< v1.capacity() << endl;
v1.insert(tmp1, 2);
it = v1.begin();
while (it != v1.end())
{
cout << *it << \" \";
it++;
}
cout << endl;
}
void Test4()//reserve+resize
{
lz::vector<int> v1(3, 5);
v1.reserve(3);
cout << \"capacity = \" << v1.capacity() << endl;
v1.reserve(8);
cout << \"capacity = \" << v1.capacity() << endl;
v1.resize(4);//默认初始值
cout << \"capacity = \" << v1.capacity() << endl;//容量不变
auto it = v1.begin();
while (it != v1.end())
{
cout << *it << \" \";
it++;
}
cout << endl;
v1.resize(20, 9);
cout << \"capacity = \" << v1.capacity() << endl;
it = v1.begin();//对it进行重新赋值
while (it != v1.end())
{
cout << *it << \" \";
it++;
}
cout << endl;
}
void Test5()//clear+empty
{
lz::vector<int> v;
//判空
cout << v.empty() << endl;
//插入数据
v.push_back(4);
v.push_back(4);
v.push_back(4);
v.push_back(4);
for (auto e : v)
{
cout << e << \" \";
}
cout << endl;
v.clear();
//容量不变
cout << \"capacity = \" << v.capacity() << endl;
//清除数据后,不打印
for (auto e : v)
{
cout << e << \" \";
}
cout << endl;
}
int main()
{
Test5();
return 0;
}