1.vector介绍
vector
是表示可变大小数组的序列容器。就像数组一样,vector
也采用的连续存储空间来存储元素。也就是意味着可以采用下标对
vector
的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
2.vector接口函数的使用
2.1 默认成员函数
vector(); | 无参构造函数 |
vector
(
size_type n, const value_type& val = value_type()
);
| 构造并且初始化n个val |
vector (const vector& x);
| 拷贝构造 |
vector (InputIterator fifirst, InputIterator last);
| 使用迭代器初始化构造 |
vector& operator=(const vector& x); | 赋值重载 |
void vector_test1()
{
//无参构造
vector<int> v1;
//构造并初始化4个5
vector<int> v2(4, 5);
//使用对象st1进行迭代器构造
string st1("hello world");
vector<char> v3(st1.begin(), st1.end());
//使用v2拷贝构造
vector<int> v4(v2);
//赋值重载
vector<int> v5(3, 6);
vector<int> v6;
v6 = v5;
}
打印结果
2.2 vector iterator 的使用
begin() 获取第一个数据位置的 iterator
end() 获取最后一个数据的下一个位置的 iterator
void vector_test2()
{
//iterator begin();//修饰的对象可读可写
//const_iterator begin() const;//只读修饰的对象
string s("you are great!!!");
vector<char> v1(s.begin(), s.end());
vector<char>::iterator it = v1.begin();
while (it != v1.end())
{
cout << *it;
it++;
}
cout << endl;
for (auto e : v1)
{
cout << e;
}
cout << endl;
}
//运行结果
//you are great!!!
//you are great!!!
2.3 vector容量的接口函数
void vector_test3()
{
string s("you are great!!!");
vector<char> v1(s.begin(), s.end());
//size() 判断vector中数据多少
cout << "数据个数: " << v1.size();
cout << endl;
//capacity() 容量大小
cout << "容量大小: " << v1.capacity();
cout << endl;
//empty() 判空 1非空 0空
cout <<"判空:"<< v1.empty();
cout << endl;
//resize() 扩容加初始化
v1.resize(20, 'y');//增容到20,字符串后补y
cout <<"容量大小:"<<v1.capacity() << endl;
for (auto e : v1)
{
cout << e;
}
cout << endl;
v1.resize(10);//容量不变,vector中数据变成10个
cout <<"容量大小:"<< v1.capacity() << endl;
for (auto e : v1)
{
cout << e;
}
cout << endl;
//reserve() 增容
v1.reserve(30);
cout <<"容量大小:"<<v1.capacity();
}
运行结果如下:
2.4 vector的增删查改
push_back | 尾插 |
pop_back | 尾删 |
find |
查找。(注意这个是算法模块实现,不是
vector
的成员接口)
|
insert |
在
position
之前插入
val
|
erase |
删除
position
位置的数据
|
swap |
交换两个
vector
的数据空间
|
operator[ ] |
像数组一样访问
|
void vector_test4()
{
vector<int> v1(2, 5);
//尾插三个数据
v1.push_back(2);
v1.push_back(3);
v1.push_back(6);
//尾删一个数据
v1.pop_back();
for (auto e : v1)
{
cout << e <<" ";
}
cout << endl;
//运行结果:5 5 2 3
InputIterator find(InputIterator first, InputIterator last, const T& val);
找到你要查找的数并返回迭代器
auto pos = find(v1.begin(), v1.end(),3);
在pos位置前面插入val iterator insert (iterator position, const value_type& val);
v1.insert(pos, 9);
for (auto e : v1)
{
cout << e <<" ";
}
cout << endl;
//运行结果:5 5 2 9 3
在pos位置前插入n个val
void insert(iterator position, size_type n, const value_type & val);
在pos位置前插入一段迭代器区间,表示插入一个vector对象的一部分
void insert(iterator position, InputIterator first, InputIterator last);
}
pos = find(v1.begin(), v1.end(), 3);
v1.erase(pos);
for (auto e : v1)
{
cout << e<<" ";
}
cout << endl;
//运行结果:5 5 2 9
vector<int> v2(4, 7);
v1.swap(v2);
for (auto e : v1)
{
cout << e<<" ";
}
cout << endl;
//运行结果:7 7 7 7
//operator[]
for(int i=0;i<v2.size();i++)
{
cout<<v2[i]<<" ";
}
//运行结果:5 5 2 9
3.迭代器失效
迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了
封装
,比如:
vector
的迭代器就是原生态指针
T*
。因此
迭代器失效,实际就是迭代器层对应指针所指向的
空间被销毁了,而使用一块已经被释放的空间
,造成的后果是程序崩溃
(
即
如果继续使用已经失效的迭代器,
程序可能会崩溃
)
。
举俩个例子来加以说明:
一 思想:尾插1,2,3,4四个数据,找到为3数据的下标,然后插入一个数据30,没插入之前 vector对象v1的容量为4,插入之后需要扩容,v1的指针指向了新开辟的空间,之前指针指向的那块区域已经被释放,pos指针指向的是已经释放的空间,所以用pos指针访问和在pos指针前插入数据就是非法访问。
图如下:
![](https://i-blog.csdnimg.cn/blog_migrate/1a5af3880cc37563bdb8714c17e37911.png)
代码如下:
void test_vector5()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
//v1.push_back(5);
auto pos=find(v1.begin(), v1.end(), 3);
if (pos != v1.end())
{
cout << "找到了";
}
v1.insert(pos, 30);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
cout << pos << endl;
v1.insert(pos, 40);
v1.insert(pos, 50);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
二 思想:vector是一段连续的物理空间,删除一个数后,后面的空间会向前移动,这时候如果it++,就会跑到删除这个数地址的后俩位。
思维图:
代码如下:
void test_vector6()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
//v1.push_back(5);
//删除所有偶数
yht::vector<int>::iterator it = v1.begin();
while (it != v1.end())
{
if (*it % 2 == 0)
{
v1.erase(it);
}
else
it++;
}
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
//程序崩溃
4.string底层实现
#include <iostream>
using namespace std;
#include <assert.h>
#include <algorithm>
#include <string>
namespace yht
{
template<class T>
class vector {
public:
typedef T* iterator;
typedef const T* const_iterator;
vector()//构造
:_start(nullptr)
,_finish(nullptr)
,_end_of_storage(nullptr)
{}
template <class InputIterator>
vector(InputIterator first, InputIterator last)
: _start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
while (first != last)
{
push_back(*first);
++first;
}
}
vector(size_t n, const T& val = T())
: _start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
for (size_t i = 0; i < n; i++)
{
push_back(val);
}
}
//拷贝构造 传统写法
/*vector(const vector<T>& v)
{
_start = new T[v.size()];
for (size_t i = 0; i < v.size(); i++)
{
_start[i] = v._start[i];
}
_finish = _end_of_storage = _start + v.size();
}*/
/*vector(const vector<T>& v)
{
_start = new T[v.size()];
_finish = _end_of_storage = _start;
for (int i = 0; i < v.size(); i++)
{
push_back(v._start[i]);
}
}*/
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)
{
vector<T> tmp(v.begin(), v.end());
swap(tmp);
}
//v1=v2;
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
~vector()//析构
{
if (_start)
{
delete[] _start;
_start = _finish = _end_of_storage=nullptr;
}
}
iterator begin()//迭代器
{
return _start;
}
iterator end()
{
return _finish;
}
const iterator begin() const
{
return _start;
}
const iterator end() const
{
return _finish;
}
size_t size() const//数据大小
{
return _finish - _start;
}
size_t capacity() const//容量大小
{
return _end_of_storage - _start;
}
void reserve(size_t n)//提前开空间
{
if (n > capacity())
{
size_t sz = size();
T* tmp = new T[n];
if (_start)
{
memcpy(tmp, _start, sizeof(T) * size());
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_end_of_storage = _start + n;
}
}
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;
}
T& operator[](size_t pos)
{
return _start[pos];
}
iterator insert(iterator pos, const T& x)
{
assert(pos >= _start && pos <= _finish);
if (_finish == _end_of_storage)
{
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
pos = _start + len;
}
T* end = _finish;
while(end>pos)
{
*(end) = *(end - 1);
end--;
}
*pos = x;
_finish++;
return pos;
}
iterator erase(iterator pos)
{
assert(pos < _finish);
T* end = pos + 1;
while (end<_finish)
{
*(end - 1) = *end;
end++;
}
_finish--;
return pos;
}
void resize(size_t n, const T& val = T())
{
if (n > capacity())
{
reserve(n);
}
if (n > size())
{
while (_finish < _start+n)
{
push_back(val);
}
}
else
{
_finish = _start + n;
}
}
private:
T* _start;
T* _finish;
T* _end_of_storage;
};
}