vector
是一个可改变数组大小的序列容器vector
和数组一样采取连续的空间存放数据,可以使用方括号访问vector的元素,和数组一样高效。但是vector的大小可以动态增长,而数组不行vector
内部使用一个动态分配的数组存放数据。当插入新元素时,数组会按需重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将所有元素移动到这个数组中。这是一个比较耗时间的策略,因此每当插入一个新元素时,vector并不会每次重新分配大小。n
个val
初始化vector
,每一个元素的值都是val
[First, Last)
中的元素一次初始化vector
的每一个元素vector
void test1()
{
string str("hello world");
vector<int> v1; //vector是一个类模板,显示模板实例化int
vector<int> v2(3, 1); //填充构造,3个1初始化v2;
vector<char> v3(str.begin(), str.end());
//范围构造
vector<int> v4(v2); //拷贝构造
for (auto e : v1)
{
cout << e; //输出为空
}
cout << endl;
for (auto e : v2)
{
cout << e << " "; //1 1 1
}
cout << endl;
for (auto e : v3)
{
cout << e; //hello world
}
cout << endl;
for (auto e : v4)
{
cout << e << " "; //1 1 1
}
cout << endl;
}
vector
的内容替换当前vector
的值vector
demo:
// vector assignment
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> foo (3,0);
std::vector<int> bar (5,0);
bar = foo;
foo = std::vector<int>();
std::cout << "Size of foo: " << int(foo.size()) << '\n';//Size of foo: 0
std::cout << "Size of bar: " << int(bar.size()) << '\n';//Size of bar: 3
return 0;
}
与string
一样,vector
是数据连续存储
的容器,因此迭代器是指针。
vector
中最后一个元素的下一个位置
的迭代器。demo:
// vector::begin/end
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector;
for (int i=1; i<=5; i++) myvector.push_back(i);
std::cout << "myvector contains:";
for (std::vector<int>::iterator it = myvector.begin() ; it != myvector.end(); ++it)
std::cout << ' ' << *it; //1 2 3 4 5
std::cout << '\n';
return 0;
}
vector
中最后一个元素
的反向迭代器
vector
中第一个元素
的反向迭代器
。demo:
// vector::rbegin/rend
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector (5); // 5 default-constructed ints
std::vector<int>::reverse_iterator rit = myvector.rbegin();
int i=0;
for (rit = myvector.rbegin(); rit!= myvector.rend(); ++rit)
*rit = ++i;
std::cout << "myvector contains:";
for (std::vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it)
std::cout << ' ' << *it; //5 4 3 2 1
std::cout << '\n';
return 0;
}
vector
的有效数据
个数size_type
,等同于size_t
demo:
// vector::size
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myints;
std::cout << "0. size: " << myints.size() << '\n';
for (int i=0; i<10; i++) myints.push_back(i);
std::cout << "1. size: " << myints.size() << '\n';
myints.insert (myints.end(),10,100);
std::cout << "2. size: " << myints.size() << '\n';
myints.pop_back();
std::cout << "3. size: " << myints.size() << '\n';
return 0;
}
output:
0. size: 0
1. size: 10
2. size: 20
3. size: 19
vector
的有效元素个数
n
个,删除超出的元素(是否会异地缩容取决编译器)capacity
==n
,再用val
填充剩下的空间val
填充capacity-size
个空间vector
有效元素个数demo:
// resizing vector
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector;
// set some initial content:
for (int i=1;i<10;i++) myvector.push_back(i);
myvector.resize(5);
myvector.resize(8,100);
myvector.resize(12);
std::cout << "myvector contains:";
for (int i=0;i<myvector.size();i++)
std::cout << ' ' << myvector[i];
std::cout << '\n';
return 0;
}
output:
myvector contains: 1 2 3 4 5 100 100 100 0 0 0 0
vector
的容量(最大存储有效元素的个数)size_t
类型demo:
// comparing size, capacity and max_size
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector;
// set some content in the vector:
for (int i=0; i<100; i++) myvector.push_back(i);
std::cout << "size: " << (int) myvector.size() << '\n';
std::cout << "capacity: " << (int) myvector.capacity() << '\n';
std::cout << "max_size: " << (int) myvector.max_size() << '\n';
return 0;
}
output:
size: 100
capacity: 128
max_size: 1073741823
vector
是否为空(有效数据个数为0)size
==0返回ture
,否则返回 false
demo:
// vector::empty
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector;
int sum (0);
for (int i=1;i<=10;i++) myvector.push_back(i);
while (!myvector.empty())
{
sum += myvector.back();
myvector.pop_back();
}
std::cout << "total: " << sum << '\n';
return 0;
}
output:
total = 55;
vector
的capacity
,使得capacity
最少容纳n个数据
n
>capacity
时,扩容至capacity==n
,将原空间数据挪动到扩容后的新空间。n
<capacity
时,不做处理。reserve
不会影响size
vector
最小的容量,实际capacity
可能会大于n
,类型为size_t
demo:
// vector::reserve
#include <iostream>
#include <vector>
int main ()
{
std::vector<int>::size_type sz;
std::vector<int> foo;
sz = foo.capacity();
std::cout << "making foo grow:\n";
for (int i=0; i<100; ++i) {
foo.push_back(i);
if (sz!=foo.capacity()) {
sz = foo.capacity();
std::cout << "capacity changed: " << sz << '\n';
}
}
std::vector<int> bar;
sz = bar.capacity();
bar.reserve(100); // this is the only difference with foo above
std::cout << "making bar grow:\n";
for (int i=0; i<100; ++i) {
bar.push_back(i);
if (sz!=bar.capacity()) {
sz = bar.capacity();
std::cout << "capacity changed: " << sz << '\n';
}
}
return 0;
}
output:
making foo grow:
capacity changed: 1
capacity changed: 2
capacity changed: 4
capacity changed: 8
capacity changed: 16
capacity changed: 32
capacity changed: 64
capacity changed: 128
making bar grow:
capacity changed: 100
可以看见,如果提前reserve一段空间,可以减少扩容和数据拷贝的次数从而提高效率。
注意:
不同的编译器对vector扩容机制不同,在VS下扩容后是扩容前空间的1.5倍,g++下是2倍
capacity
以适应其尺寸,函数可能会realloc
,但是对size
无影响。capacity
>size
。demo:
// vector::shrink_to_fit
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector (100);
std::cout << "1. capacity of myvector: " << myvector.capacity() << '\n';
myvector.resize(10);
std::cout << "2. capacity of myvector: " << myvector.capacity() << '\n';
myvector.shrink_to_fit();
std::cout << "3. capacity of myvector: " << myvector.capacity() << '\n';
return 0;
}
output:
1. capacity of myvector: 100
2. capacity of myvector: 100
3. capacity of myvector: 10
vector::at
具有相同功能,不同的是 vector::at
进行了边界检查,并通过抛出 out_of_range
异常来指示请求的位置是否超出范围。size_t
const vector
,返回常引用
,否则返回引用
demo:
// vector::operator[]
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector (10); // 10 zero-initialized elements
std::vector<int>::size_type sz = myvector.size();
// assign some values:
for (unsigned i=0; i<sz; i++) myvector[i]=i;
// reverse vector using operator[]:
for (unsigned i=0; i<sz/2; i++)
{
int temp;
temp = myvector[sz-1-i];
myvector[sz-1-i]=myvector[i];
myvector[i]=temp;
}
std::cout << "myvector contains:";
for (unsigned i=0; i<sz; i++)
std::cout << ' ' << myvector[i];
std::cout << '\n';
return 0;
}
output:
myvector contains: 9 8 7 6 5 4 3 2 1 0
vector
用于内部存储数据的数组的指针。因为vector
数据是连续存储的,所以可以通过data偏移量
访问vector
中的数据,例如v.data()[1]==v[1]vector
只读,指针指向的类型是const_value_type
,否则指针指向的类型是value_type
demo:
// vector::data
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector (5);
int* p = myvector.data();
*p = 10;
++p;
*p = 20;
p[2] = 100;
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i];
std::cout << '\n';
return 0;
}
output:
myvector contains: 10 20 0 100 0
vector
原本的内容,并合适地修改size
。当且仅当新的容器大小大于当前vector
时,数组会realloc
first
和last
是其他容器的迭代器,first
是序列的初始位置,last
是序列的结束位置,将[first,last)
中的值分配给vector
,这些值包括first
不包括last
。n
是vector
的size
大小,类型为size_t
,用n
个val
填充vector
demo:
// vector assign
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> first;
std::vector<int> second;
std::vector<int> third;
first.assign (7,100); // 7 ints with a value of 100
std::vector<int>::iterator it;
it=first.begin()+1;
second.assign (it,first.end()-1); // the 5 central values of first
int myints[] = {1776,7,4};
third.assign (myints,myints+3); // assigning from array.
std::cout << "Size of first: " << int (first.size()) << '\n';
std::cout << "Size of second: " << int (second.size()) << '\n';
std::cout << "Size of third: " << int (third.size()) << '\n';
return 0;
}
output:
Size of first: 7
Size of second: 5
Size of third: 3
val
值插入到vector
尾部。尾插后size
会增加1个大小,当且仅当增加后的size>capacity时,分配的存储空间会realloc
。realloc
,那么realloc
的时间与vector
的size
成线性函数。realloc
,那么所有的迭代器,指针,引用都会失效,否则只有end_iterator
是失效的,其他的迭代器,指针引用都和调用前指向相同。realloc
,所有的元素都会被复制到新分配的空间中。demo:
// vector::push_back
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector;
int myint;
std::cout << "Please enter some integers (enter 0 to end):\n";
do {
std::cin >> myint;
myvector.push_back (myint);
} while (myint);
std::cout << "myvector stores " << int(myvector.size()) << " numbers.\n";
return 0;
}
vector
中最后一个元素,size
大小减一。pop_back
后,任何指向被删除元素的迭代器,指针,引用都失效demo:
// vector::pop_back
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector;
int sum (0);
myvector.push_back (100);
myvector.push_back (200);
myvector.push_back (300);
while (!myvector.empty())
{
sum+=myvector.back();
myvector.pop_back();
}
std::cout << "The elements of myvector add up to " << sum << '\n';
return 0;
}
output:
The elements of myvector add up to 600
功能:通过在指定位置的元素之前插入新元素来扩展vector
,从而通过插入元素的数量有效地增加容器大小。当新的size>capacity时,分配的空间会realloc
。
参数:
iterator
是一个成员类型,定义为指向元素的random_access_iterator
类型。size_t
[first,last)
范围内的元素副本将插入到position
位置(以相同的顺序)。范围包括first
不包括last
。first
和last
都是vector::iterator
类型。返回值:返回一个指向新插入的第一个元素迭代器,返回值类型为vector::iterator
注意:
时间复杂度:与插入的元素数量(复制/移动构造)加上位置后的元素数量(移动)成线性关系。若不是在vector末尾插入元素,效率通常不会很高 O ( n ) O(n) O(n)
迭代器失效:如果内存分配发生realloc
,那么所有的迭代器,指针,引用都会失效;否则只有指向position
之后的迭代器,指针,引用会失效,指向position
之前的迭代器,指针,引用不会失效。
demo:
// inserting into a vector
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector (3,100);
std::vector<int>::iterator it;
it = myvector.begin();
it = myvector.insert ( it , 200 );
myvector.insert (it,2,300);
//After reallocation, "it" no longer valid, get a new one:
it = myvector.begin();
std::vector<int> anothervector (2,400);
myvector.insert (it+2,anothervector.begin(),anothervector.end());
int myarray [] = { 501,502,503 };
myvector.insert (myvector.begin(), myarray, myarray+3);
std::cout << "myvector contains:";
for (it=myvector.begin(); it<myvector.end(); it++)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
output:
myvector contains: 501 502 503 300 300 400 400 200 100 100 100
vector
中删除单个元素或删除一段迭代器区间。size
大小减一。vector
中需要被删除的元素。vector::iterator
和vector::const_iterator
都是成员类型,也是random_access_iterator
。vector
的区间,包括[first,last)
中的所有元素,即包括first
不包括last
。first
和last
都是vector::iterator
类型,即random_access_iterator
。position
(或 first
)及以后元素的迭代器、指针和引用将失效,而指向 position
(或 first
)之前元素的所有迭代器、指针和引用将保证继续指向调用前所指向的相同元素。demo:
/ erasing from vector
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector;
// set some values (from 1 to 10)
for (int i=1; i<=10; i++) myvector.push_back(i);
// erase the 6th element
myvector.erase (myvector.begin()+5);
// erase the first 3 elements:
myvector.erase (myvector.begin(),myvector.begin()+3);
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i];
std::cout << '\n';
return 0;
}
output:
myvector contains: 4 5 7 8 9 10
vector
的内容交换当前vector
的内容,两个vector
的类型相同,size
可能不同vector
引用x
,x
与当前vector
具有相同类型。swap
是通过非成员库函数swap
实现的vector
的 bool
特化为此函数提供了额外的重载vector<bool>::swapdemo:
// swap vectors
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> foo (3,100); // three ints with a value of 100
std::vector<int> bar (5,200); // five ints with a value of 200
foo.swap(bar);
std::cout << "foo contains:";
for (unsigned i=0; i<foo.size(); i++)
std::cout << ' ' << foo[i];
std::cout << '\n';
std::cout << "bar contains:";
for (unsigned i=0; i<bar.size(); i++)
std::cout << ' ' << bar[i];
std::cout << '\n';
return 0;
}
output:
foo contains: 200 200 200 200 200
bar contains: 100 100 100
(clear)[https://cplusplus.com/reference/vector/vector/clear/]
vector
中的所有元素,让size=0。realloc
,也不能保证capacity
会改变。强制清空capacity
可以通过使用swap函数vector<T>().swap(x)
。size
大小线性相关vector
中的所有迭代器都失效demo:
// clearing vectors
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector;
myvector.push_back (100);
myvector.push_back (200);
myvector.push_back (300);
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); i++)
std::cout << ' ' << myvector[i];
std::cout << '\n';
myvector.clear();
myvector.push_back (1101);
myvector.push_back (2202);
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); i++)
std::cout << ' ' << myvector[i];
std::cout << '\n';
return 0;
}
output:
myvector contains: 100 200 300
myvector contains: 1101 2202
T* _start:指向存储空间的起始位置
T* _finish:指向最后一个有效数据的下一个位置
T* _end_of_storage:指向最后一个有效存储空间的下一个位置
iterator:T*的重定义。
const_iterator:const T*的重定义。
注意:
深拷贝
的问题~ template<typename T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
vector() //default构造函数
{
_start = _finish = _end_of_storage = nullptr;
}
vector(int sz, const T& val = T())
{ //fill构造函数,sz的类型为int让编译器区分构造vector<int>(3,1)类型时调用的是fill构造而不是range构造
//为vector申请sz个空间
_finish = _start = new T[sz];
//fill构造时,_end_of_storage和_finish指向同个位置
_end_of_storage = _start + sz;
//这里也可以*_finish++ = val;
for (size_t i = 0; i < sz; i++)
{
push_back(val);
}
}
vector(const vector<T>& v)
{ //拷贝构造函数
//v的size
int sz = v._finish - v._start;
//v的capacity
int capacity = v._end_of_storage - v._start;
_start = new T[capacity];
//注意:这里依次让v的每个元素赋值给*this,当*this类似于string类型时赋值可以调用string的深拷贝
//不能简单的使用memcpy,memcpy是浅拷贝
for (size_t i = 0; i < sz; i++)
{
_start[i] = v._start[i];
}
//更新_finish和_end_of_storage
_finish = _start + sz;
_end_of_storage = _start + capacity;
}
//range构造函数
template<typename InputerIterator>
vector(InputerIterator first, InputerIterator last)
{
//数据区间为[first,last)
while (first != last)
{ //等效于*_finish++ = *first++;
push_back(*first++);
//first++;
}
}
~vector()
{ //new的空间delete,防止MemoryLeak
delete[] _start;
_start = _finish = _end_of_storage = nullptr;
}
测试结果:
注意:当vector类型为string等,考虑深拷贝
问题
//赋值重载函数
vector<T>& operator=(const vector<T>& v)
{
int sz = v._finish - v._start;
int capacity = v._end_of_storage - v._start;
//start指向sz个空间
_start = new T[sz];
for (size_t i = 0; i < sz; i++)
{ //使用赋值考虑深拷贝的问题
*_finish++ = v[i];
}
//更新_end_of_storage
_end_of_storage = _start + capacity;
return *this;
}
测试结果:
//迭代器
iterator begin()
{
return _start;
}
const_iterator begin() const
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator end() const
{
return _finish;
}
测试结果:
注意:
深拷贝
问题 rsize_t capacity() const
{
return _end_of_storage - _start; //_end_of_storage和_start之间是存储空间
}
rsize_t size() const
{
return _finish - _start; //_finish和_start之间是有效元素
}
void reserve(size_t n) //预先开辟n个空间
{
size_t cap = capacity();
size_t sz = size();
if (n > cap) //当且仅当n大于当前容量扩容
{
T* tmp = new T[n];
//拷贝元数据到新空间,数据拷贝时需要注意深拷贝问题,使用赋值而不用memcpy
for (size_t i = 0; i < sz; i++)
{
tmp[i] = _start[i];
}
delete[] _start; //释放原数据空间
//更新_start _finish _end_of_storage
_start = tmp;
_finish = _start + sz;
_end_of_storage = _start + cap;
}
}
void resize(size_t sz, T val = T())
{
size_t _sz = _finish - _start;
size_t _capacity = _end_of_storage - _start;
if (sz < _sz) //情况1.sz小于当前size,直接缩小当前size,capacity不变
{
_finish -= sz;
}
else if (sz <= _capacity) //情况2.size<sz<capacity,直接在剩下的存储空间中插入capacity-
{
while (_sz < sz)
{
push_back(val);
_sz++;
}
}
else //情况3.sz>capacity,先扩容,在插入sz-size个val
{
reserve(sz);
while (_sz < sz)
{
push_back(val);
}
}
}
测试结果:
注意:
/*访问*/
T& operator[](size_t pos)
{
assert(0 <= pos && pos < _finish - _start);
return *(_start + pos);
}
const T& operator[](size_t pos) const
{
assert(0 <= pos && pos < _finish - _start);
return *(_start + pos);
}
T front()
{
return *_start;
}
const T front() const
{
return *_start;
}
T back()
{
return *_finish;
}
const T back() const
{
return *_finish;
}
/*修改类*/
void push_back(const T& val)
{
size_t sz = _finish - _start;
size_t ca = _end_of_storage - _start;
if (ca == sz)
{
reserve(ca == 0 ? 4 : 2 * ca);
}
*_finish = val;
_finish++;
//insert(end(), val);
}
void pop_back()
{
assert(_finish - _start >= 1);
_finish--;
//erase(end() - 1);
}
iterator insert(iterator pos, const T& val)//返回值用于更新扩容前指向pos处的迭代器
{
int sz = _finish - _start;
int capacity = _end_of_storage - _start;
int gap = pos - _start; //记录扩容前_start和pos的相对位置
if (_finish == _end_of_storage) //扩容
{
//2倍扩容
reserve(capacity == 0 ? 4 : 2*capacity);
//此时_start _finish _end_of_storage已经是扩容后的位置了
pos = _start + gap;//修正pos
}
/*挪动数据*/
iterator end = _finish;
while (end > pos)
{
*end = *(end - 1);
end--;
}
*pos = val;
_finish++;
return pos;
}
template<class Inputiterator>
iterator insert(iterator pos, Inputiterator first, Inputiterator last)
{
int num = last - first; //要插入的个数
int sz = _finish - _start;
int capacity = _end_of_storage - _start;
int gap = pos - _start; //_start和pos的相对位置
//当前容量不够插入需要扩容
if (sz + num > capacity)
{
reserve(sz + num);
_finish = _end_of_storage;
pos = _start + gap;
iterator after = pos + num;
iterator before = pos;
while (after < _end_of_storage)
{
*after++ = *before++;
}
while (first < last)
{
*pos++ = *first++;
}
_finish = _end_of_storage;
}
//当前容量够插入
else
{
iterator after = pos + num;
iterator before = pos;
while (before < _finish)
{
*after++ = *before++;
}
while (first < last)
{
*pos++ = *first++;
}
_finish = after;
}
return pos;
}
iterator erase(iterator pos)
{
assert(pos >= _start); //删除元素位置介于[first,last)
assert(pos < _finish);
iterator begin = pos; //pos后面的元素往前挪
while (begin < _finish - 1)
{
*begin = *(begin + 1);
begin++;
}
_finish--;
return pos;
}
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
void clear()
{
_finish = _start; //size=0
}
测试结果: