vector< T>向量容器
头文件:#include<vector>
特点:可以动态调整所占用的内存空间,擅长在尾部插入/删除元素。
创建一个vector
std::vector<int> int_vec;//创建一个int类型的vector容器
std::vector<double> double_vec{0.2,4.2,3.99};//初始化时指定初始值及元素个数
std::vector<char> char_vec(5);//创建具有5个char类型元素的vector容器,默认值为0
std::vector<int> temp(10,2);//创建具有10个int类型元素且默认值为2的vector容器
std::vector<int> temp2(temp);//通过其他的容器来创建自己的vector容器
注意:采用std::vector<int> temp(10,2);
创建vecotr容器时,两个参数既可以是常量,也可以是变量。
vector成员函数
下面我们通过实例来简单介绍下vector成员函数的作用:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
std::vector<int> int_vec{1,9,8,8,0,3,2,1};
for (int i = 0; i < int_vec.size(); i++)//利用size()成员函数遍历vector容器
{//size():返回容器元素个数
cout<<int_vec[i]<<" ";//像普通数组一样访问容器元素
}
cout<<endl;
cout<<"push a 25 at last!"<<endl;
int_vec.push_back(25);//push_back():在序列的尾部添加一个元素
//也可以使用emplace_back()成员函数,与push_back作用一样,但前者更快。
vector<int>::iterator iter;
for (auto iter = int_vec.begin(); iter != int_vec.end(); iter++)//通过begin()和end()成员函数遍历vector容器
{//begin():返回指向容器中第一个元素的迭代器
//end():返回指向容器最后一个元素所在位置后一个位置的迭代器
cout<<*iter<<" ";
}
cout<<endl;
cout<<"pop 3 elem at last"<<endl;
for (int i = 0; i < 3; i++)
{
cout<<"the elem which is poped is :"<<int_vec.back()<<endl;
//back():返回最后一个元素的引用
int_vec.pop_back();
//pop_back():移出序列尾部的元素
}
cout<<"now the vector's size is : "<<int_vec.size()<<endl;
cout<<"we change the size to nowsize * 2"<<endl;
int_vec.resize(int_vec.size()*2);//resize():改变实际元素的个数。
int * ptr = int_vec.data();//data():返回指向容器中第一个元素的指针。
for (int i = 0; i < int_vec.size(); i=i+2)
{
cout<<*(ptr+i)<<" ";
}
cout<<endl;
vector<int> temp{1,1,0};
int_vec.swap(temp);//swap():交换两个容器的所有元素
for (int i = 0; i < int_vec.size(); i++)
{
cout<<int_vec.at(i)<<" ";//at():使用经过边界检查的索引访问元素。越界会抛出异常哦~
}
cout<<endl;
getchar();
return 0;
}
输出:
1 9 8 8 0 3 2 1
push a 25 at last!
1 9 8 8 0 3 2 1 25
pop 3 elem at last
the elem which is poped is :25
the elem which is poped is :1
the elem which is poped is :2
now the vector's size is : 6
we change the size to nowsize * 2
1 8 0 0 0 0
1 1 0
vector<T>
的常用成员函数及其作用已经在上述程序注释。我们可以发现,其中大部分内容包括了array<T,N>
中的成员函数,且作用相似,如 begin() 指向首元素,end() 指向尾元素后面的一个位置。
注意事项:
- vector容器包括了成员函数 swap() 之外,还有一个 std::swap(x,y) 非成员函数,但注意两者必须是存储相同类型的元素。
- vector容器的 swap() 成员函数交换了两个容器内的数据,也改变了其 size 大小。
- vector容器可以初始化为空的容器,因为其长度可变,但是在初始化空的vector容器时,不能使用迭代器,因为对于空的 vector 容器来说,其 begin() 和 end() 都指向的是同一个位置。此时如果想初始化,可以通过调用push_back() 或 resize() 函数来初始化。
#include<iostream>
#include<vector>
using namespace std;
int main(){
vector<int> val;
for(auto iter = val.begin(); iter != val.end(); iter++)
{//没有输出
*iter = 1;
cout<<*iter<<" ";
}
cout<<"**************"<<endl;
val.resize(10);//改变vector容器大小
for(auto iter = val.begin(); iter != val.end(); iter++)
{
*iter = 1;
cout<<*iter<<" ";
}
getchar();
return 0;
}
输出:
**************
1 1 1 1 1 1 1 1 1 1
- 如果想增加容器的容量,还可以使用成员函数 reserve() 达成目的,但是申请了更多内存的同时,容器中元素的存放地址会发生改变(可以说是找了一块儿新的内存存储区来存储)
#include<iostream>
#include<vector>
using namespace std;
int main(){
vector<int> val{1,2,4,5};
cout<<"old address : "<<val.data()<<endl;
val.reserve(10);
cout<<"new address : "<<val.data()<<endl;
for (auto i = val.begin(); i != val.end(); i++)
{
cout<<*i<<" ";
}
cout<<endl;
cout<<"the val's size is : "<<val.size()<<endl;
vector<int> temp{1,2,3,4};
temp.resize(10);
for (auto iter = temp.begin(); iter != temp.end(); iter++)
{
cout<<*iter<<" ";
}
cout<<endl;
cout<<"the temp's size is : "<<temp.size()<<endl;
getchar();
return 0;
}
输出:
old address : 0xef4320
new address : 0xef4360
1 2 4 5
the val's size is : 4
1 2 3 4 0 0 0 0 0 0
the temp's size is : 10
可见调用 reserve() 后改变了地址,并且遍历后只显示了4个元素,这是因为 reserve() 开辟出来的空间并不代表就都是有效空间,只有 size() 的大小才是有效空间。
注意:如果你调用 reserve(n) ,其中 n 小于原本的容量,则这个函数什么作用都没有。
具体的 reserve() 和 resize() 之间的区别可以看看这几篇文章
http://c.biancheng.net/view/6770.html
插入操作 insert() 和 emplace() 详解
insert() 函数的功能是在 vector 容器的指定位置插入一个或多个元素。
具体用法 (4中插入方法) 如下:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> vec{1,2,3,4,5,6};
vector<int>::iterator iter;
vec.insert(vec.begin()+2,10);//在第begin()+2 (3)个位置前插入int型元素 10
for (auto&& val : vec)
{
cout<<val<<" ";
}
cout<<endl;
vec.insert(vec.end()-1,3,9);//在最后一个元素之前插入 3 个int型元素 9
for (auto&& val : vec)
{
cout<<val<<" ";
}
cout<<endl;
vec.insert(vec.begin()+3,{10,9,8,7});//在第4个元素之前插入列表{10,9,8,7}
for (auto&& val : vec)
{
cout<<val<<" ";
}
cout<<endl;
vector<int> add{9,9,6};
vec.insert(vec.end(),add.begin(),add.end());//在最后插入整个vector容器add
for (auto&& val : vec)
{
cout<<val<<" ";
}
cout<<endl;
getchar();
return 0;
}
输出:
1 2 10 3 4 5 6
1 2 10 3 4 5 9 9 9 6
1 2 10 10 9 8 7 3 4 5 9 9 9 6
1 2 10 10 9 8 7 3 4 5 9 9 9 6 9 9 6
emplace() 函数也是在指定位置前插入元素,不过每次只能插入一个元素,而不是多个。
当然其也比 insert() 函数效率高一些。
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v{1,2,3};
v.emplace(v.begin(),0);
for(auto && val : v)
{
cout<<val<<" ";
}
cout<<endl;
getchar();
return 0;
}
输出:
0 1 2 3
删除操作pop_back()、erase()、remove()和clear() 详解
还是先上代码看看:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
vector<int> v{1,9,9,9,0,6,0,2};
cout<<"test pop_back()"<<endl;
cout<<"size is : "<<v.size()<<endl;
cout<<"capacity is : "<<v.capacity()<<endl;
cout<<"pop last one : "<<v.back()<<endl;
v.pop_back();
cout<<"size is : "<<v.size()<<endl;
cout<<"capacity is : "<<v.capacity()<<endl<<endl;
//此时v{1,9,9,9,0,6,0}
cout<<"test erase()"<<endl;
auto iter = v.erase(v.begin()+2);//删除指定位置元素,返回一个指向删除元素所在位置下一个位置的迭代器。
for(auto i = iter; i != v.end(); i++ )//从迭代器后开始遍历
{
cout<<*i<<" ";
}
cout<<endl;
cout<<"size is : "<<v.size()<<endl;
cout<<"capacity is : "<<v.capacity()<<endl<<endl;
//此时v{1,9,9,0,6,0}
cout<<"test another erase()"<<endl;
iter = v.erase(v.begin(),v.begin()+3);//删除[first,last)区域的元素,并返回指向此区域之后一个位置的迭代器
for(auto i = iter; i != v.end(); i++ )
{
cout<<*i<<" ";
}
cout<<endl;
cout<<"size is : "<<v.size()<<endl;
cout<<"capacity is : "<<v.capacity()<<endl<<endl;
//此时v{0,6,0}
cout<<"test remove()"<<endl;
iter = remove(v.begin(),v.end(),0);//删除指定区域内元素为 0 的所有元素
for(auto i = v.begin();i != iter;i++)
{
cout<<*i<<" ";
}
cout<<endl;
for(auto i = v.begin(); i != v.end() ; i++)
{
cout<<*i<<" ";
}
cout<<endl;
cout<<"size is : "<<v.size()<<endl;
cout<<"capacity is : "<<v.capacity()<<endl<<endl;
//此时v{6,6,0}
cout<<"test clear()"<<endl;
v.clear();//删除容器中所有的元素
cout<<endl;
cout<<"size is : "<<v.size()<<endl;
cout<<"capacity is : "<<v.capacity()<<endl<<endl;
getchar();
return 0;
}
输出:
test pop_back()
size is : 8
capacity is : 8
pop last one : 2
size is : 7
capacity is : 8
test erase()
9 0 6 0
size is : 6
capacity is : 8
test another erase()
0 6 0
size is : 3
capacity is : 8
test remove()
6
6 6 0
size is : 3
capacity is : 8
test clear()
size is : 0
capacity is : 8
pop_back(),函数用法很简单,即删除 vector 容器中最后一个元素,该容器的大小(size)会减 1,但容量不会改变。
erase(pos),删除 vector 容器中 pos 迭代器指定位置处的元素,并返回指向被删除元素下一个位置元素的迭代器。该容器的大小(size)会减 1,但容量(capacity)不会发生改变。
erase(pos1,pos2),删除 vector 容器中 [pos1,pos2) 的元素,并返回指向被删除区域下一个位置元素的迭代器。该容器的大小(size)会减 pos2-pos1,但容量(capacity)不会发生改变。
remove(),删除容器中所有和指定元素值相等的元素,并返回指向最后一个元素下一个位置的迭代器。值得一提的是,调用该函数不会改变容器的大小和容量。
- 注意:我们看输出可以发现通过remove() 删除元素后,大小没变,且对容器进行遍历后输出为
6 6 0
,这是为什么呢?这是因为remove() 的实现原理是,在遍历容器中的元素时,一旦遇到目标元素,就做上标记,然后继续遍历,直到找到一个非目标元素,即用此元素将最先做标记的位置覆盖掉(即用 第二个6 覆盖了最初的 0,但原来的 6 没有背覆盖,最后一个 0因为后面没有元素了也不会背覆盖),同时将此非目标元素所在的位置也做上标记,等待找到新的非目标元素将其覆盖。
clear(),删除 vector 容器中所有的元素,使其变成空的 vector 容器。该函数会改变 vector 的大小(变为 0),但不是改变其容量。