vector 是STL中应用最为广泛的一类容器,这里对其重要的特性做一个概括和总结。
- vector的初始化
vector的初始化,见如下代码。
vector<int> v2; // vector with 0 element vector<int> v3(20); // vector with 20 elements whose value is 0 vector<int> v4(20, 5);// vector with 20 elements whose value is 5 vector<int> v5{ 20 }; // vector with 1 element whose value is 20 vector<int> v6(v4); // copy construct function vector<int> v7(v4.begin(), v4.end());//construct function vector<int> v8({ 1,2,3,4,5 });// construct a vector with initialize list vector<int> v9{ 1,2,3,4,5 };// construct a vector with initialize list vector<int> v10 = {1,2,3,4,5};// assignment construct function
- vector的容量和大小
- vector在内存中按照连续方式进行存储,因此初始化vector时会有一个初始的容量(capacity),容量(capacity)类似于一个电梯的最大容纳重量。
- 向vector中添加数据的时候,如果当前元素个数(size)小于容量(capacity),那么就会继续在相应位置插入元素。如果当前元素个数和容量相等,则会对vector的容量进行扩展,一般容量按照当前数据量的2倍方式增长。
- reserve可以对vector的容量进行设置,如果即将设置的容量小于当前容量,则vector的容量不会缩小。而如果设置的值大于当前容量,那么会分配设置的容量。如下代码:
vector<int> v2;
v2.reserve(20);
cout << v2.capacity() << endl; // capacity is set to be 20
v2.reserve(10);
cout << v2.capacity() << endl; // capacity is still 20
- resize函数对vector当前元素个数进行大小设置,resize(n),表示将元素个数设置为n个,如果n小于当前size,则会将超过n的元素截断,只留下n个元素。如果n大于当前size,则将需要添加的元素默认设置为0,如果resize(n,m),则表示将新增元素初始化为m,具体用法如下:
vector<int> values{1,2,3}; // 1 2 3 : size is 3
values.resize(5); // 1 2 3 0 0 : size is 5
values.resize(7,99); // 1 2 3 0 0 99 99 : size is 7
values.resize(6); // 1 2 3 0 0 99 : size is 6
说明:resize(0)并不能将vector中的内存释放,vector的容量不会有任何影响,如果想将vector的capacity设置为0,则有如下办法:
- 方法一:clear和shrink_to_fit
vector<int> v2;
v2.reserve(20); // capacity is set to be 20
v2.clear();
v2.shrink_to_fit(); //clear and shrink_to_fit to set capacity to 0
- 方法二:resize和shrink_to_fit
vector<int> v2;
v2.reserve(20); // capacity is set to be 20
v2.resize(0); // resize to be 0 element
v2.shrink_to_fit();//resize and shrink_to_fit to set capacity to 0
- 方法三: swap方法
vector<int> v2;
v2.reserve(20); // capacity is set to be 20
vector<int> v3; // capacity is 0
swap(v2,v3); // v2's capacity is 0
- vector的元素个数等于当前容量时,vector中再次增加元素时,vector的容量就会增大,一般按照当前已有元素的50%进行扩展,当容量太大而不需要时,可以采用shrink_to_fit()来除去多余的容量以减少内存占用量。
- vector访问元素
- vector可以通过方括号使用索引进行元素访问,也可以通过at(index)方式访问,但是at的访问效率比方括号的访问效率低,这是因为at函数会检查索引越界问题,而方括号不会检查索引是否越界。
- 成员函数front()和back()函数可以返回vector中第一个和最后一个元素的引用,因为返回的是引用,因而可以进行赋值操作。例如:
vector<int> vec{1,2,3,4};
vec.back() = 100; // set last element to 100
vec.front() = 10; // set first element to 10
- 成员函数data()用于返回一个指向数组的指针,它在内部被用来存储元素。
vector<int> values(10,100);
auto pData = values.data();// pData is a pointer point to int*
- vector添加元素
注意:向容器中添加元素的唯一方式是使用它的成员函数。如果不调用成员函数,非成员函数既不能添加也不能删除元素。这意味着容器对象必须通过他所允许的函数去访问,迭代器是不行的。
- 增加元素。可以通过使用容器对象的push_back()和emplace_back()函数在序列的末尾添加一个元素。注意:emplace_back比push_back更加有效率。这是因为emplace_back()的参数正是添加到容器中的对象构造函数所需要的参数。emplace_back用它的参数作为构造函数的参数,在容器中生成对象。
vector<string> vec;
// 生成一个临时string对象,再将临时对象放入vector末尾
vec.push_back("hello world1");
// 直接当做参数传递给末尾string的构造函数,没有产生临时对象这一步骤
vec.emplace_back("hello world2");
string str ("to be or not to be");
// emplace_back()中可以直接传string的构造函数所需要的参数
vec.emplace_back(str,0,18);
插入元素。通过成员函数emplace(),可以在vector序列中插入新的元素。对象会在容器中直接生成,而不是先单独生成对象,然后把它作为参数传入。emplace()的第一个参数是指定对象的插入位置,后面的参数是构造该对象需要的参数,根据vector中存储的对象类型不同,其传入的参数也会不同。
通过成员函数insert()可以在vector中插入一个或者多个元素,第一个参数总是一个指向插入点的const或者non-const迭代器。元素会被迅速插入到第一个参数所指向元素的前面,如果第一个参数是反向迭代器,元素会被插入到迭代器所指向元素的后面。代码示例如下。
vector<string> v2;
v2.emplace_back("second"); // second
string str1 = "first";
v2.emplace(v2.begin(), str1); // first second
string str2 = "third";
v2.emplace(v2.begin() + 1, str2, 0, 5); // first third second
v2.emplace(v2.begin()+1, 4, 'z');
- 插入单个元素,insert第二个参数指定插入的值。insert插入单个元素时有两个重载的版本函数,两个函数第一个参数都是指定插入位置,第二个参数指定插入元素。第一个版本插入元素类型为const T&,第二个版本的类型是T&&——右值引用。右值引用对象是一个临时对象,因此插入过程中被移动插入而不是复制插入。注意:使用同样的参数情况下,调用insert()没有调用emplace()高效。下述调用insert的函数会生成一个临时对象作为传入的第二个参数,但是在emplace()调用中,构造函数用第二个参数直接在容器中生成了字符串对象。如下代码:
vector<string> words {"one","three","eight"};
// iter1 point to elment being inserted
auto iter1 = words.insert (words.begin()+1,"two")// T&& version,one two three eight,
words.emplace(words.begin()+1,"two");// more effective than insert.
string str = "nine";
// iter2 point to elment being inserted
// cosnt T& version,one two three eight nine
auto iter2 = words.insert (words.end(),str);
- 插入元素序列。insert函数可以在某个特定位置前面插入一系列元素。这是emplace函数所不具有的功能。当插入一系列元素时,insert返回第一个插入的元素的位置。
string more[] = {"five","six","seven"};
vector<string> words;
words.insert (words.begin(),begin(more),end(more));
words.insert (words.end(),{"some", "one", "like", "you"});
words.insert (wrods.begin()+1,5,"forward"); // insert 5 "forward"
- vector删除元素
- 使用clear函数将vector中的元素清空,但是capacity并不会释放。
- 使用pop_back()可以删除容器尾部元素。假若要删除vector中某个位置的元素,可以使用swap和最后一个元素交换,然后使用pop_back()删除最后一个元素。代码示例如下。
vector<int> vec = {1,3,5,7,9};
vec.swap(vec.begin()+1,vec.end()-1);
vec.pop_back(); // remove 3
成员函数erase可以用来删除容器中一个或者多个元素,如果只需要删除一个元素,则提供一个迭代器位置即可,删除元素后返回删除元素的下一个位置的迭代器。如果需要删除一定范围内的元素,需要提供两个参数,即删除范围的开始和结束位置。
remove()算法可以删除指定范围内匹配特定值的元素。但是remove()是一个全局函数,不能删除容器中的元素。remove先在vector中寻找要删除的元素,随后将该元素后的所有元素前移,以覆盖该元素,最后将要删除的元素值设置为默认值。需要注意的是,remove()函数不会改变vector的大小和容量,因此为了删除多余的位置,需要配合erase使用。示例代码如下:
vector<string> vec = {"one", "none", "some", "all", "none", "most", "many"};
auto iter = remove(words.begin(),words.end(),"none");
words.erase(iter,words.end());//remove surplus elements