目录
七、vector
(一)vector的介绍及使用
1、介绍
2、使用
1)定义
编辑 2)迭代器使用
3)vector 空间增长问题
注意
4)vector增删查改
3、迭代器失效
(二)vector的模拟实现
1、浅拷贝问题
2、代码
vector是序列容器,表示可以改变大小的数组,也就是顺序表。
(constructor) 构造函数声明
|
接口说明 |
vector(); | 无参构造 |
vector(size_type n,const value_type& val = value_type()); | 构造并初始化n个val |
vector(const vector& x); | 拷贝构造 |
vector (InputIterator first, InputIterator last);
|
使用迭代器进行初始化构造 |
vector
迭代器传参也可以传string的迭代器
int main()
{
vector v1();
vector v2(10,3);
vector v3(v2);
vector v4(v2.begin(),v2.end());
string s = "hello";
vector v5(s.begin(),s.end());
cout << "v2 :";
for (int i = 0; i < v2.size(); i++)
{
cout << v2[i] << " ";
}
cout << endl;
cout << "————————————————" << endl;
cout << "v3 :";
vector ::iterator it = v3.begin();
while (it != v3.end())
{
cout << *it << " ";
it++;
}
cout << endl;
cout << "————————————————" << endl;
cout << "v4 :";
for (auto e : v4)
{
cout << e << " ";
}
cout << endl;
cout << "————————————————" << endl;
cout << "v5 :";
for (auto e : v5)
{
cout << e << " ";
}
cout << endl;
cout << "————————————————" << endl;
return 0;
}
当然,这只是些常见的构造,还有一些其他的,这里就不再举例
和string迭代器一样
之前上边的代码也使用了迭代器进行遍历
cout << "v3 :";
vector ::iterator it = v3.begin();
while (it != v3.end())
{
cout << *it << " ";
it++;
}
cout << endl;
cout << "————————————————" << endl;
cout << "v4 :";
for (auto e : v4)
{
cout << e << " ";
}
cout << endl;
cout << "————————————————" << endl;
函数名称 | 作用 |
size | 获取数据个数 |
capacity | 获取容量大小 |
empty | 判断是否为空 |
resize | 改变vector的size |
reserve | 改变vector的capacity |
void func2()
{
vector v = { 1,2,3,4,5,6 };
cout << "size: " << v.size() << endl;
cout << "capacity: " << v.capacity() << endl;
cout << "empty: " << v.empty() << endl;
cout << "————————————————" << endl;
v.resize(10);
cout << "size: " << v.size() << endl;
cout << "capacity: " << v.capacity() << endl;
cout << "————————————————" << endl;
v.reserve(12);
cout << "size: " << v.size() << endl;
cout << "capacity: " << v.capacity() << endl;
}
函数名称 | 作用 |
push_back | 尾插 |
pop_back | 尾删 |
find(不在vector中) | 查找 |
insert |
在 position 之前插入 val
|
erase |
删除 position 位置的数据
|
swap | 交换 |
operator[] | 访问 |
在学数据结构的时候,我们自己写顺序表有头插头删,但是vector没有直接提供它们,因为效率太低,不希望我们使用,但是我们可以用insert和erase来实现头插头删,但是能不用就不用,效率太低了。
void func3()
{
vector v = { 1,2,3 };
auto e = find(v.begin(), v.end(), 2);
cout << *e << endl;
cout << "————————————————" << endl;
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
cout << "————————————————" << endl;
v.push_back(4);
v.push_back(5);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
cout << "————————————————" << endl;
v.pop_back();
for (int i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
cout << endl;
cout << "————————————————" << endl;
v.insert(v.begin() + 1, 600);
v.insert(v.begin() + 3, 600);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
cout << "————————————————" << endl;
v.erase(v.begin() + 1);
v.erase(v.begin() + 2);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
cout << "————————————————" << endl;
vector tmp = { 100,200,300 };
cout << "v: ";
for (auto e : v)
{
cout << e << " ";
}
cout << endl<<"tmp: ";
for (auto e : tmp)
{
cout << e << " ";
}
cout << endl;
cout << "————————————————" << endl;
swap(v, tmp);
cout << "v: ";
for (auto e : v)
{
cout << e << " ";
}
cout << endl<<"tmp: ";
for (auto e : tmp)
{
cout << e << " ";
}
cout << endl;
cout << "————————————————" << endl;
}
值得注意的是reserve,当我们只扩容,然后去访问新扩容的位置时,你会发现↓
void func4()
{
vector v = { 1,2,3 };
cout << "size: " << v.size() << endl;
cout << "capacity: " << v.capacity() << endl;
cout << "————————————————" << endl;
v.reserve(10);
cout << "size: " << v.size() << endl;
cout << "capacity: " << v.capacity() << endl;
cout << "————————————————" << endl;
cout << v[8] << endl;
}
因为vector中的[]重载只允许0~size-1范围内,超出该范围会有断言
如果非要这么访问,我们就要用resize
void func4()
{
vector v = { 1,2,3 };
cout << "size: " << v.size() << endl;
cout << "capacity: " << v.capacity() << endl;
cout << "————————————————" << endl;
//v.reserve(10); //size = 3 , capacity = 10;
v.resize(10); //size = 10 , capacity = 10;
cout << "size: " << v.size() << endl;
cout << "capacity: " << v.capacity() << endl;
cout << "————————————————" << endl;
cout << v[8] << endl;
}
find是不在vector中写入的,而是在算法库中,在任何地方都可以使用,它是个模版
比如我需要在“2”的前面加个“100”,但是我不知道2是在哪个位置
vector v = { 1,2,3 };
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
auto i = find(v.begin(), v.end(), 2);
v.insert(i, 100);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
函数名称 | 作用 |
clear | 清空 |
shrink_to_fit | 将空间缩短至size |
注意,clear只是清空数据,空间大小不变
void func5()
{
vector v = { 1,2,3,4,5 };
cout << "size: " << v.size() << endl;
cout << "capacity: " << v.capacity() << endl;
cout << "————————————————" << endl;
v.clear();
cout << "size: " << v.size() << endl;
cout << "capacity: " << v.capacity() << endl;
cout << "————————————————" << endl;
v.shrink_to_fit();
cout << "size: " << v.size() << endl;
cout << "capacity: " << v.capacity() << endl;
cout << "————————————————" << endl;
}
以上就是vector常用的函数,当然vector还有很多,这里不再举例
有兴趣的,可以去官网查看 https://legacy.cplusplus.com/
失效一:
iterator insert(iterator pos, const T& x)
{
assert(pos <= _finish);
assert(pos >= _start);
if (_finish == _endOfStorage)
{
reserve(capacity() == 0 ? 4 : 2 * capacity());
}
iterator a = _finish - 1;
while (a >= pos)
{
*(a+1) = *a;
a--;
}
_finish++;
*pos = x;
return pos;
}
当我们模拟实现vector的insert函数时,我们这样写代码会发现,当需要扩容时,会产生随机数
这就是因为迭代器失效了
当扩容时是异地扩容,地址会改变,但是pos的值却没变,所以我们需要更新pos值
iterator insert(iterator pos, const T& x)
{
assert(pos <= _finish);
assert(pos >= _start);
if (_finish == _endOfStorage)
{
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : 2 * capacity());
pos = _start + len;
}
iterator a = _finish - 1;
while (a >= pos)
{
*(a+1) = *a;
a--;
}
_finish++;
*pos = x;
return pos;
}
失效二:
vector::const_iterator it = v.begin();
v.insert(v.begin() + 1, 10);
while (it != v.end())
{
cout << *it << " ";
it++;
}
cout << endl;
形参只是实参的一份临时拷贝,改变形参直接不会形象实参
失效三:
iterator erase(iterator pos)
{
assert(pos >= _start);
assert(pos < _finish);
iterator it = pos + 1;
while (it < _finish)
{
*(it - 1) = *it;
++it;
}
--_finish;
return pos;
}
vector v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(6);
v.push_back(7);
vector::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
cout << endl;
it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
{
v.erase(it);
}
it++;
}
it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
这个代码是可以正常运行的
vector v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(6);
v.push_back(7);
v.push_back(8);
vector::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
cout << endl;
it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
{
v.erase(it);
}
it++;
}
it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
以及当偶数在一起时
vector v;
v.push_back(1);
v.push_back(2);
v.push_back(2);
v.push_back(4);
v.push_back(5);
v.push_back(6);
v.push_back(7);
vector::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
cout << endl;
it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
{
v.erase(it);
}
it++;
}
it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
所以我们需要利用erase的返回值对it进行更新
vector v;
v.push_back(1);
v.push_back(2);
v.push_back(2);
v.push_back(4);
v.push_back(5);
v.push_back(6);
v.push_back(7);
v.push_back(8);
vector::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
cout << endl;
it = v.begin();
while (it != v.end())
{
if (*it % 2 == 0)
{
it = v.erase(it);/
}
else
it++;/
}
it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
所以,insert和erase都会涉及迭代器失效问题,要注意!
当vector的每一个元素为string时
vector()
:_start(nullptr)
,_finish(nullptr)
,_endOfStorage(nullptr)
{}
~vector()
{
delete[] _start;
_start = _finish = _endOfStorage = nullptr;
}
void reserve(size_t n)
{
if(n > capacity())
{
T* tmp = new T[n];
int sz = size();
if (_start != nullptr)
{
memcpy(tmp, _start, sizeof(T) * sz);
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_endOfStorage = _start + n;
}
}
void push_back(const T& x)
{
if (_finish == _endOfStorage)
{
reserve(capacity() == 0 ? 4 : 2 * capacity());
}
*_finish = x;
_finish++;
}
vector v;
v.push_back("111111111111111111");
v.push_back("111111111111111111");
v.push_back("111111111111111111");
v.push_back("111111111111111111");
vector::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
}
没有什么问题 ,但当插入第五个元素,需要扩容时
vector v;
v.push_back("111111111111111111");
v.push_back("111111111111111111");
v.push_back("111111111111111111");
v.push_back("111111111111111111");
v.push_back("111111111111111111");
vector::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
it++;
}
}
发生了问题,这是为什么呢?
刚开完空间是这样的
memcpy后是这样的
delete后是把_start释放掉,但是它的里面是自定义类型,就会调用自定义类型的析构函数,把_str释放掉,所以原来的信息也会变为随机值
也就是浅拷贝问题,memcpy是浅拷贝,我们需要的是深拷贝,所以memcpy不能在这里使用
void reserve(size_t n)
{
if(n > capacity())
{
T* tmp = new T[n];
int sz = size();
if (_start != nullptr)
{
//memcpy(tmp, _start, sizeof(T) * sz);
for (size_t i = 0; i < sz; i++)
{
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_endOfStorage = _start + n;
}
}
代码仅供参考
#include
#include
using namespace std;
namespace YM
{
template
class vector
{
public:
// Vector的迭代器是一个原生指针
typedef T* iterator;
typedef const T* const_iterator;
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator cbegin() const
{
return _finish;
}
const_iterator cend() const
{
return _start;
}
// construct and destroy
vector()
:_start(nullptr)
,_finish(nullptr)
,_endOfStorage(nullptr)
{}
vector(int n, const T& value = T())
: _start(nullptr)
, _finish(nullptr)
, _endOfStorage(nullptr)
{
reserve(n);
for (size_t i = 0; i < n; i++)
{
push_back(value);
}
}
template
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
first++;
}
}
vector(const vector& v)
: _start(nullptr)
, _finish(nullptr)
, _endOfStorage(nullptr)
{
reserve(v.capacity());
iterator it = begin();
const_iterator vit = v.cbegin();
while (vit != v.cend())
{
*it++ = *vit++;
}
_finish = it;
}
vector& operator= (vector v)
{
swap(v);
return *this;
}
~vector()
{
delete[] _start;
_start = _finish = _endOfStorage = nullptr;
}
void reserve(size_t n)
{
if(n > capacity())
{
T* tmp = new T[n];
int sz = size();
if (_start != nullptr)
{
//memcpy(tmp, _start, sizeof(T) * sz);
for (size_t 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 > capacity())
{
reserve(n);
while (_finish < _start + n)
{
*_finish = value;
_finish++;
}
}
else
{
_finish = _start + n;
}
}
///access///
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos)const
{
assert(pos < size());
return _start[pos];
}
///modify/
void push_back(const T& x)
{
if (_finish == _endOfStorage)
{
reserve(capacity() == 0 ? 4 : 2 * capacity());
}
*_finish = x;
_finish++;
}
void pop_back()
{
assert(_finish > _start);
if (_start + 1 == _finish)
{
delete[] _start;
_start = _finish = _endOfStorage = nullptr;
}
else
{
_finish--;
}
}
void swap(vector& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endOfStorage, v._endOfStorage);
}
iterator insert(iterator pos, const T& x)
{
assert(pos <= _finish);
assert(pos >= _start);
if (_finish == _endOfStorage)
{
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : 2 * capacity());
pos = _start + len;
}
iterator a = _finish - 1;
while (a >= pos)
{
*(a+1) = *a;
a--;
}
_finish++;
*pos = x;
return pos;
}
iterator erase(iterator pos)
{
assert(pos < _finish);
assert(pos >= _start);
iterator a = pos+1;
while (a < _finish)
{
*(a-1) = *a;
a++;
}
_finish--;
return pos;
}
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _endOfStorage - _start;
}
private:
iterator _start; // 指向数据块的开始
iterator _finish; // 指向有效数据的尾
iterator _endOfStorage; // 指向存储容量的尾
};
}