Vector是序列容器,表示可以改变大小的数组,其本质类似于一个动态顺序表。
就像数组一样,Vector为其元素使用连续的存储位置,这意味着也可以使用指向其元素的常规指针上的偏移量来访问其元素,并且与数组中一样高效。但与数组不同的是,它们的大小可以动态变化,其存储由容器自动处理。
在内部,Vector使用动态分配的数组来存储其元素。当插入新元素时,可能需要重新分配此数组以增加大小,这意味着分配一个新数组并将所有元素移动到该数组。就处理时间而言,这是一项相对费劲的任务,因此,每次向容器中添加元素时,Vector都不会重新分配。相反,Vector容器可以分配一些额外的存储空间来适应可能的增长,因此容器的实际容量可能大于包含其元素所严格需要的存储空间(即其大小)。库可以实现不同的增长策略,以在内存使用和重新分配之间取得平衡,但在任何情况下,重新分配都只能以对数增长的大小间隔进行,这样在向量末尾插入单个元素就可以提供固定的时间复杂度。因此,与数组相比,Vector消耗更多的内存,以换取管理存储和以高效方式动态增长的能力。
与其他动态序列容器(deques、listsandforward_lists)相比,Vector非常有效地访问其元素就像数组一样,并且相对有效地从其末端添加或删除元素。但对于涉及在末尾以外的位置插入或删除元素的操作,它们的性能比其他操作差,并且迭代器和引用的一致性不如list和forward_lists。
#include <vector> //容器vector涉及的头文件
1.vector<int>a //创建一个类型为int的容器a,a的元素默认初始化为0
2.vector<int >b(a) //用容器a创建一个类型为int的容器b
3.vetcor<int>a(100) //创建一个类型为int、拥有100个元素的容器a,其中的元素默认初始化为0
4.vector<int>a(100,1) //创建一个类型为int、拥有100个元素、元素初始值为1的容器a
5.vector<string>a(10,"hello world") //创建一个类型为string、拥有10个元素、元素初始值为字符串"hello world"的容器a
6.vector<string>b(a.begin(),a.end()) //通过迭代器指定容器a的元素来创建一个容器b
本篇博客主要梳理了C++98下vector的基本用法,搭配对vector重要功能的模拟实现,旨在更好地帮助读者理解容器vector(获取更具体的内容,请参考vector - C++ Reference)。
目录
一、vector的基本用法
情景一:
void test_vector1()
{
vector<int> v; //声明一个类型为int的容器v
v.push_back(1); //在容器v后尾插1
v.push_back(2); //在容器v后尾插2
v.push_back(3); //在容器v后尾插3
v.push_back(4); //在容器v后尾插4
//遍历容器v
//通过一般的for循环,结合下标遍历容器v
for (size_t i = 0; i < v.size(); i++) //size()将返回容器v中的有效数据个数
{
cout << v[i] << " "; //1 2 3 4
}
cout << endl;
//通过迭代器遍历容器v
vector<int>::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " "; //1 2 3 4
++it;
}
cout << endl;
//通过范围for遍历容器v
for (auto e : v)
{
cout << e << " "; //1 2 3 4
}
cout << endl;
}
情景二:
void test_vector2()
{
vector<int>v1(10, 1); //声明一个int类型的vector,并初始化为10个1
vector<string>v2(10, "***"); //声明一个string类型的vector,并初始化为10个"***"
//范围for遍历容器v1
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
//范围for遍历容器v2
for (auto e : v2)
{
cout << e << " ";
}
cout << endl;
//声明一个int类型的容器v3,并通过容器v1的迭代器初始化
vector<int> v3(v1.begin(), v1.end());
for (auto e : v3)
{
cout << e << " ";
}
cout << endl;
//vetcor也可以通过其他的容器的迭代器来初始化
string str("hello world");
vector<char> v4(str.begin(), str.end()); //声明一个char类型的容器v4,并通过str的迭代器初始化
for (auto e : v4)
{
cout << e << " ";
}
cout << endl;
//vector还可以通过用数组/指针初始化
int a[] = { 16,2,77,29 };
vector<int> v5(a, a + 4); //声明一个int类型的容器v5,并通过数组/指针初始化
for (auto e : v5)
{
cout << e << " ";
}
cout << endl;
//排序(默认排升序,方式为快速排序)
sort(v5.begin(), v5.end()); //sort()是一个排序算法函数,在头文件#include<algorithm>中
for (auto e : v5)
{
cout << e << " ";
}
cout << endl;
//降序
sort(v5.begin(), v5.end(), greater<int>()); //参数为迭代器和调整序列的仿函数,greater<int>()是一个降序的仿函数
for (auto e : v5)
{
cout << e << " ";
}
cout << endl;
}
情景三:
void test_vector3()
{
vector<char> v1;
v1.resize(10); //为v1开10个数据大小的空间,且用默认值初始化
for (size_t i = 0; i < 10; i++)
{
v1[i] = i; //重载的[]会断言i<v1.size()强制检查越界,故只访问有效数据
}
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
vector<int> v2;
v2.reserve(10); //只改变v2的容量,但不改变有效数据个数以及初始化的值
for (size_t i = 0; i < 10; i++)
{
v2.push_back(i); //在容器v后尾插
}
for (auto e : v2)
{
cout << e << " ";
}
cout << endl;
}
情景四:
void test_vector4()
{
int a[] = { 16,2,77,29,3,33,43,3,2,3,3,2 };
vector<int> v1(a, a + sizeof(a) / sizeof(int)); //利用数组初始化v1
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
// 头插
v1.insert(v1.begin(), 100); //insert可以在指定位置插入指定数据,此处在v1头部插入100
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
// 头删
v1.erase(v1.begin()); //erase()可以删除指定位置的数据,此处删除v1头部的数据
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
// 删除第3个数据
v1.erase(v1.begin() + 2);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
// 删除3,但是不知道3在哪个位置,怎么办?
// 可以通过find()查找3的位置。find()的参数为容器内查找的范围和查找的数据,它会返回数据在容器中第一次出现的位置
//vector<int>::iterator pos = find(v1.begin(), v1.end(), 3);
auto pos = find(v1.begin(), v1.end(), 3); //可以通过auto自动推导类型来简化书写
if (pos != v1.end())
{
v1.erase(pos);
}
// 删除所有的3
// 但这涉及迭代器失效
auto pos = find(v1.begin(), v1.end(), 3);
while (pos != v1.end())
{
v1.erase(pos);
pos = find(v1.begin(), v1.end(), 3);
}
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
// insert或erase以后最好不要使用它们涉及的形参迭代器了,因为它可能失效了,强行使用会造成越界访问
}
情景五:
void TestVectorExpand() //linux下以2倍扩容,vs2019下以1.5倍扩容
{
size_t sz;
vector<int> v;
sz = v.capacity();
cout << "capacity: " << sz << '\n';
cout << "making v grow:\n";
for (int i = 0; i < 100; ++i)
{
v.push_back(i);
if (sz != v.capacity())
{
sz = v.capacity();
cout << "capacity changed: " << sz << '\n';
}
}
}
//打印结果(在vs2019下):
//capacity: 0
//making v grow :
//capacity changed : 1
//capacity changed : 2
//capacity changed : 3
//capacity changed : 4
//capacity changed : 6
//capacity changed : 9
//capacity changed : 13
//capacity changed : 19
//capacity changed : 28
//capacity changed : 42
//capacity changed : 63
//capacity changed : 94
//capacity changed : 141
【Tips】
- vector的声明必须指定容器中数据的类型,可以指定大小和数据内容来初始化,也可以通过其他容器及其迭代器、数组或指针来初始化;
- vector可以通过普通for循环+下标、迭代器、范围for的方式进行访问遍历;
- vetcor的容量可以通过 resize() 和 reserve() 控制;
- vector涉及的增删改查一般有:push_back()、insert()、erase()、find()等;
- 不同平台/环境对vector扩容的方案不同。
二、vector的模拟实现
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace bit
{
template<class T>
class vector
{
public:
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<int> v(10, 1);
//
// vector<int> v(10u, 1);
// vector<string> v1(10, "1111");
vector(size_t n, const T& val = T())
{
resize(n, val);
}
vector(int n, const T& val = T())
{
resize(n, val);
}
// [first, last)
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
vector()
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{}
//深拷贝
vector(const vector<T>& v)
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{
_start = new T[v.capacity()];
//memcpy(_start, v._start, sizeof(T) * v.size());
for (size_t i = 0; i < v.size(); i++)
{
_start[i] = v._start[i];
}
_finish = _start + v.size();
_endofstorage = _start + v.capacity();
}
//vector(const vector<T>& v)
// :_start(nullptr)
// , _finish(nullptr)
// , _endofstorage(nullptr)
//{
// reserve(v.capacity());
// for (auto e : v)
// {
// push_back(e);
// }
//}
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)
{
delete[] _start;
_start = _finish = _endofstorage = nullptr;
}
}
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());
for (size_t i = 0; i < sz; i++)
{
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_endofstorage = _start + n;
}
}
void push_back(const T& x)
{
/*if (_finish == _endofstorage)
{
size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
reserve(newCapacity);
}
*_finish = x;
++_finish;*/
insert(end(), x);
}
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迭代器失效问题
pos = _start + len;//以防pos指向空,变成野指针
}
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;
}
//vector的erase和insert迭代器对象后,不能再访问这个迭代器
//因为迭代器可能失效,访问结果是未定义的
void pop_back()
{
erase(--end());
}
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;
}
}
}
private:
iterator _start;
iterator _finish;
iterator _endofstorage;
};
void print(const vector<int>& v)
{
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}
void test_vector1()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
for (size_t i = 0; i < v1.size(); i++)
{
v1[i]++;
}
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
print(v1);
}
void test_vector2()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
v1.push_back(5);
v1.push_back(5);
v1.push_back(5);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
v1.insert(v1.begin(), 100);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
/*vector<int>::iterator p = v1.begin() + 3;
v1.insert(p, 300);*/
vector<int>::iterator p = v1.begin() + 3;
//v1.insert(p+3, 300);
// insert以后迭代器可能会失效(扩容)
// 记住,insert以后就不要使用这个形参迭代器了,因为他可能失效了
v1.insert(p, 300);
// 高危行为
// *p += 10;
//
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
void test_vector3()
{
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);
v1.push_back(6);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
auto it = v1.begin();
while (it != v1.end())
{
if (*it % 2 == 0)
{
it = v1.erase(it);
}
else
{
++it;
}
}
//v1.erase(v1.begin());
//auto it = v1.begin()+4;
//v1.erase(it);
erase以后,迭代器失效了,不能访问
vs进行强制检查,访问会直接报错
//cout << *it << endl;
//++it;
//cout << *it << endl;
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
void test_vector4()
{
vector<int> v;
v.resize(10, 0);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
int i = 0;
int j = int();
int k = int(1);
}
void test_vector5()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
vector<int> v1(v);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
vector<int> v2;
v2.resize(10, 1);
v1 = v2;
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
void test_vector6()
{
vector<string> v;
v.push_back("111111111111111111");
v.push_back("222222222222222222");
v.push_back("333333333333333333");
v.push_back("444444444444444444");
v.push_back("555555555555555555");
for (auto& e : v)//范围for涉及的自定义类型最好加引用
{
cout << e << " ";
}
cout << endl;
vector<string> v1(v);
for (auto& e : v1)
{
cout << e << " ";
}
cout << endl;
}
void test_vector7()
{
//vector<int> v(10u, 1);
vector<string> v1(10, "1111");
vector<int> v2(10, 1);
}
}