一、vector的初步认识
基础概念:vector是c++标准库(STL)的序列容器,支持动态调整大小,底层通过连续的内存实现。类似于动态数组。
- vector需要包含头文件
- vector随机访问效率高(O(1)),尾部插入/删除效率高(O(1)),中间/头部的操作效率低(O(n))
二、vector的相关使用
创建与初始化
int main()
{
vector<int> v1;//无参构造
vector<int> v2(10);//10个元素,默认值为0
vector<int> v3(10, 20);//10个元素,值为20
vector<int> v4(v3);//拷贝构造
vector<int> v5 = { 0,1,3 };//列表初始化
return 0;
}
插入元素
- push_back
int main()
{
vector<int> v1(3,6);//三个元素,值均为6
v1.push_back(9);//尾部插入一个元素9
for (auto a : v1)
{
cout << a << " ";
}cout << endl;
return 0;
}
-
insert
int main()
{
vector<int> v1(3, 6);//三个元素,值均为6
for (auto a : v1)
{
cout << a << " ";
}cout << endl;
//插入单个元素,在v1.begin()位置之前插入元素,插入后,返回新插入元素的迭代器
vector<int>::iterator it = v1.insert(v1.begin(), 5);
for (auto a : v1)
{
cout << a << " ";
}cout << endl;
return 0;
}
int main()
{
vector<int> v1 = { 1,2,3 };
for (auto a : v1)
{
cout << a << " ";
}cout << endl;
//插入多个相同的元素,在v1.begin()+1位置之前插入元素,插入后,返回第一个新插入元素的迭代器
vector<int>::iterator it = v1.insert(v1.begin()+1, 2,9);//插入两个9
for (auto a : v1)
{
cout << a << " ";
}cout << endl;
return 0;
}
int main()
{
//插入迭代器范围元素,返回值指向第一个新插入的元素的迭代器
vector<int> src = { 2, 3 };
vector<int> dest = { 1, 4 };
//在dest.begin() + 1前插入,src.begin(), src.end()的元素,end指向最后一个元素的下一个位置
dest.insert(dest.begin() + 1, src.begin(), src.end());
// dest 变为 {1, 2, 3, 4}
return 0;
}
int main()
{
//插入一个初始化列表元素,返回值指向第一个新插入的元素
vector<int> v = { 1, 5 };
v.insert(v.begin() + 1, { 2, 3, 4 }); // v 变为 {1, 2, 3, 4, 5}
return 0;
}
删除元素
-
pop_back
int main() { vector<int> v1 = { 1,2,3 }; v1.pop_back();//删除尾部元素 for (auto a : v1) { cout << a << " "; }cout << endl; return 0; }
-
erase
int main() { vector<int> v = { 1,2,3,4,5,6 }; //删除单个元素,返回一个新的迭代器,指向被删除元素的下一个位置 v.erase(v.begin()); for (auto a : v) { cout << a << " "; }cout << endl; return 0; } int main() { vector<int> v = { 1,2,3,4,5,6 }; auto first = v.begin() + 1;//指向第二个元素 auto last = v.begin() + 5;//指向第五个元素 //删除范围元素,删除第二个到第四个元素 v.erase(first, last);//左闭右开,[first,last) for (auto a : v) { cout << a << " "; }cout << endl; return 0; }
-
clear
清空所有元素,使size()为0,但保留capacity()不变,不会释放底层内存
int main() { vector<int> v = { 1,2,3,4,5,6 }; cout << v.size() << endl; cout << v.capacity() << endl; for (auto a : v) { cout << a << " "; }cout << endl; v.clear(); cout << v.size() << endl; cout << v.capacity() << endl; for (auto a : v) { cout << a << " "; }cout << endl; return 0; }
容量管理
-
size
int main() { vector<int> v = { 0,1,2 }; size_t n = v.size();//返回容器中实际存储元素的数量 cout << n << endl; return 0; }
-
max_size
int main() { vector<int> v = { 0,1,2 }; size_t n = v.size();//返回容器中元素的大小 size_t m = v.max_size(); //返回vector中理论能存储的最大元素数量,由系统本身决定,不可修改,即使有足够内存,也可能因内存碎片化,无法达到 cout << n << endl; cout << m << endl; return 0; }
-
resize()
resize调整容器元素数量。当n小于size,删除尾部多余的元素,使size的大小为n,但不改变底层空间的大小(capacity);当n大于size,会自动扩容,使size的大小为n,扩大capacity,尾部添加默认值0,也可以自己手动修改默认值
int main() { vector<int> v = { 1,2,3 }; cout << v.size() << " " << v.capacity() << endl; v.resize(1);//n<size cout << v.size() << " " << v.capacity() << endl; for (auto a : v) { cout << a << " "; }cout << endl; return 0; } int main() { vector<int> v = { 1,2,3 }; cout << v.size() << " " << v.capacity() << endl; v.resize(6);//n>size cout << v.size() << " " << v.capacity() << endl; for (auto a : v) { cout << a << " "; }cout << endl; return 0; } int main() { vector<int> v = { 1,2,3 }; cout << v.size() << " " << v.capacity() << endl; v.resize(6, 9);//n>size,将默认值修改为9 cout << v.size() << " " << v.capacity() << endl; for (auto a : v) { cout << a << " "; }cout << endl; return 0; }
-
capacity
int main() { vector<int> v = { 1,2,3 }; size_t n = v.capacity();//返回当前分配的内存空间的大小,可能等于size,也可能大于size size_t m = v.size(); cout << n << " "<<m<<endl; return 0; }
-
reserve(n)
reserve用于预分配内存,不改变元素的数量size,仅改变底层容量capacity。当n<=capacity不会有任何操作,只有当n>capacity,才会分配新内存,可以避免多次重复扩容
int main() { vector<int> v(10); cout << v.size() << " " << v.capacity() << endl; v.reserve(2);//n<capacity cout << v.size() << " " << v.capacity() << endl; return 0; } int main() { vector<int> v(10); cout << v.size() << " " << v.capacity() << endl; v.reserve(20);//n>capacity cout << v.size() << " " << v.capacity() << endl; return 0; }
-
empty
判断容器是否为空,size为0,就返回true,否则就返回false
int main() { vector<int> v; cout << v.empty() << endl; v.push_back(1); cout << v.empty() << endl; v.clear(); cout << v.empty() << endl; return 0; }
-
shrink_to_fit
缩减内存,但不一定使内存变为size()
int main() { vector<int> v(1); v.resize(100); cout << v.capacity() <<" "<< v.size() << endl; v.clear(); cout << v.capacity() <<" "<< v.size() << endl; v.shrink_to_fit(); cout << v.capacity() <<" "<< v.size() << endl; }
访问元素
-
operator[]
int main() { vector<int> v = { 1,2,3,4 }; cout << v[0] << endl;//通过索引访问,不检查是否越界 v[0] = 100; cout << v[0] << endl;//修改元素 //cout << v[10] << endl;//越界访问,抛异常 return 0; }
-
at()
它在访问时会进行边界检查,在越界时会抛出异常,但效率比operayor[]低,返回元素的引用
int main() { vector<int> vec = {10, 20, 30}; cout << vec.at(1); // 输出 20 // 修改元素 vec.at(2) = 99; // 越界访问(触发异常) try { int x = vec.at(5); // 索引5超出size()=3 } catch (const std::out_of_range& e) { std::cerr << "错误: " << e.what() << "\n"; // 输出异常信息 } return 0; }
-
front()与back()
int main() { vector<int> v = { 1,2,3 }; cout << v.front() << endl;//返回第一个元素的引用 cout << v.back() << endl; v.front() = 9;//修改front元素 cout << v.front() << endl; v.clear(); //cout << v.front() << endl;//容器为空,数据错误 return 0; }
迭代器
-
begin()与end()
begin()用于获取指向容器第一个元素的迭代器,若容器为空,则begin()==end();end()用于获取指向容器末尾之后位置的迭代器。
int main() { vector<int> v = { 9,8,7,6,5,4,3,5 }; for (auto it = v.begin(); it != v.end(); it++)//遍历容器 { cout << *it << " "; }cout << endl; sort(v.begin(), v.end());//算法排序 for (auto it = v.begin(); it != v.end(); it++) { cout << *it << " "; }cout << endl; return 0; }
-
rbegin()与rend()
逆向迭代器,rbegin()指向最后一个元素的逆向迭代器,rend()指向第一个元素之前的位置的逆向迭代器,若容器为空则rbegin()==rend()。
int main() { vector<int> v = { 9,8,7,6,5,4,3,2,1 }; for (auto it = v.rbegin(); it != v.rend(); it++)//遍历容器,逆向迭代器的++会向容器的头部移动 { cout << *it << " "; }cout << endl; sort(v.rbegin(), v.rend());//算法排序 for (auto it = v.begin(); it != v.end(); it++) { cout << *it << " "; }cout << endl; return 0; }
-
cbegin()与cend()
只允许读,不允许修改的迭代器,若在只读不写的情况下,使用它更加安全
三、vector的简单实现
namespace mystl
{
template<class T>
class vector
{
typedef T* iterator;
typedef const T* const_iterator;
public:
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin()const
{
return begin();
}
const_iterator end()const
{
return _finish;
}
vector(size_t n, const T& val = T())
{
return resize(n, val);
}
template<class InputIterator>
vector(InputIterator first,InputIterator last)
{
while (first != last)
{
push_back(*first);
first++;
}
}
vector(const vector<T>& v)
:_start(nullptr), _finish(nullptr), _endofstorage(nullptr)
{
reserve(v.capacity());
for (auto a : v)
{
push_back(a);
}
}
vector(const vector<T>& v)
{
_start = new[v.capacity()];
for (size_t i = 0; i < v.size(); i++)
{
_start[i] = v._start[i];
}
_finish = _start + v.size();
_endofstorage = _start + v.capacity();
}
void swap(vector<T>& v)
{
std::swap(_start.v._start);
std::swap(_finish, v._finish);
std::swap(_endofstorage, v._endofstorage);
}
vector<T>& operator=(vector<T>& v)
{
swap(v);
return *this;
}
~vector()
{
if (_start)
{
_start = _finish = _endofstorage = nullptr;
}
}
void reserve(size_t n)
{
if (n > capacity())
{
size_t sz = size();
T* tmp = new T[n];
if (_start)
{
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& val = T())
{
if (n < size())
{
_finish = _start + n;
}
else
{
reserve(n);
while (_finish != (_start + n))
{
*_finish = val;
_finish++;
}
}
}
void push_back(const T& x)
{
if (_finish == _endofstorage)
{
size_t newcapacity = capacity() == 0 ? 4 : capacity() *= 2;
reserve(newcapacity);
}
*_finish = x;
++_finish;
}
void pop_back()
{
erase(--end());
}
size_t capacity()const
{
return _endofstorage - _start;
}
size_t size()const
{
return _finish - _start;
}
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos)const
{
assert(pos < size());
return _start[pos];
}
iterator insert(iterator pos, const T& x)
{
assert(pos >= _start && pos <= _finish);
if (_finish == _endofstorage)
{
size_t len = pos - _start;
size_t newcapacity = capacity() == 0 ? 4 : capacity() *= 2;
reserve(newcapacity);
pos = _start + len;
}
iterator end = _finish - 1;
while (end > pos)
{
*end + 1 = *end;
--end;
}
*pos = x;
_finish++;
return pos;
}
iterator erase(iterator pos)
{
assert(pos >= _start && pos < _finish);
iterator it = pos + 1;
while (it != _finish)
{
*it - 1 = *it;
++it;
}
_finish--;
return pos;
}
private:
iterator _start = nullptr;//指向数据块的开始
iterator _finish = nullptr;//指向有效数据的结尾
iterator _endofstorage = nullptr;//指向存储容量的结尾
};
}