1. vector容器
1.1 容器特性
顺序序列 :顺序容器中的元素按照严格的线性顺序排序,可以通过元素在序列中的位置访问对应的元素。
动态数组 :支持对序列中的任意元素进行快速直接访问,甚至可以通过指针算述进行该操作,操供了在序列末尾相对快速地添加/删除元素的操作。
能够感知内存分配 :容器使用一个内存分配器对象来动态地处理它的存储需求。
1.2 vector容器的初始化
直接初始化 :vector<int> vec{1,2,3};//一维容器
; vector<vector<int>> vec{ {1,2,3},{4,5,6} };//二维容器
赋值初始化 :vector<int> vec1(5, 1);//带参数构造vec1;vector<int>vec2(vec1);//拷贝构造
迭代器初始化 :在这种迭代器范围拷贝时,不要求容器类型相同,而且新容器和原容器的元素类型也可以不同,只要能够将要拷贝的元素转换成要初始化的容器元素即可 。例如:int a[5] = { 1,2,3,4,5 };vector<int> c(a, a + 5);//数组迭代器初始化
;vector<int> c2(c1.begin(),c1.begin()+5);//vector容器迭代器初始化;
不带参数的构造函数 :vector<int> vec;//初始化一个空的vector,元素个数size()为0
带参数的构造函数 :vector<int> vec(10);//初始化size,但每个元素值为默认值
;vector<int> vec(10,1);//初始化size,并且设置初始值
1.3 访问元素
数组下标访问 :cout<<vec[i]<<endl;//或者 cout<<vec.at(i)<<endl;
,后者如果index越界,抛出out_of_range,这是两者的区别。
使用迭代器 : vector<int>::iterator it;
for(it=vec.begin();it!=vec.end();it++) cout<<*it<<endl;
容器的首元素迭代器 :vec.front();
容器的尾后迭代器 :vec.back();
查找元素是否存在该元素 :find(vec.begin(),vec.end(),value);
在vec.begin()(包括)开始到vec.end()(不包括)中开始查找是否有value的元素,若存在,则返回位置。
查找元素值为value在容器的个数 :int num=count(vec.begin(),vec.end(),value);
查找符合条件的元素个数 :
bool cmp ( Student s) {
return 90 < s. score;
}
int num= count_if ( vec. begin ( ) , vec. end ( ) , cmp) ;
1.4 插入元素
在末尾添加元素 :vec.push_back(val);
向容器迭代器插入单个元素 :vec.insert(vec.begin()+pos,x);
向容器迭代器插入n个相同元素 :vec.insert(vec.begin()+post,n,x);
向容器迭代器插入一段其他容器的元素 :vec.insert(vec.begin()+pos,vec1.begin()+beginpos,vec1.begin()+endpos);
1.5 删除元素
删除容器最后的元素 :vec.pop_back();
删除容器迭代器指向的元素 :vec.erase(vec.begin()+pos);
删除容器中[first,last)中元素 :vec.erase(first,last);
清空容器 :vec.clear();
vector.clear()的真正作用是:把size设置成0,但是capacity不变。
注意 :如果是删除指定位置的元素时,返回值是一个迭代器,指向删除元素的下一个位置 ;如果是删除某范围内的元素时,返回值也是一个迭代器,指向最后删除元素的下一个位置 。
1.6 容器迭代器
返回向量头指针 ,指向第一个元素:vec.begin()
返回向量尾指针 ,指向向量最后一个元素的下一个位置:vec.end();
反向迭代器 ,指向最后一个元素:vec.rbegin();
反向迭代器 ,指向第一个元素之前的位置:vec.rend();
翻转容器 :reverse(vec.begin(),vec.end());
容器排序 :sort(vec.begin(),vec.end();
删除元素 :vec.erase(remove(vec.begin(),vec.end(),value),vec.end());
,查找得到第一个元素的位置,然后从此位置开始遍历容器,将后面的元素依次前移,跳过与value相同的元素,即所有与value相同的元素均被覆盖,而其他元素都依次向前移动。
指向首元素指针 :int *x=vec.data();
链接例题 在C++11中,vector 增加了data()的用法,它返回内置vecotr所指的数组内存的第一个元素的指针 。 int *p = myvec.data();则p指向myvector的第一个元素指针,而++p;则p指向了myvector的第二个指针,也即p[0]为myvector的第二个元素,则p[2]指向myvector的第四个元素 。
常量迭代器 :vec.cbegin();vec.cend();
cbegin和cend是不管是对象本身是不是常量,换回值都是const_iterator.
常量反向迭代器 :vec.crbegin();vec.crend();
1.7 容器的大小与判断
返回值为容器大小 :vec.size();
。
重新指定有效元素的个数 :vec.resize(10);
指定容器有效容器为10个元素,此时vec.size()=10。将vec的现有元素个数调至10个,多则删少则补,其值随机。同时vec.resize(10,2);
是将a的现有元素个数调至10个,多则删少则补,其值为2。
返回值为目前容器能存数据的个数 :vec.capacity();
当创建空容器时, 容量(capacity)为 0;当用完时,增加原容量的 1/2 。capacity 一般大于size的原因是为了避免每次增加数据时都要重新分配内存 ,所以一般会生成一个较大的空间,以便随后的数据插入。注意,每次当容器的内存不够用的时候,需要扩大容器的存储,指的就是capacity 。
指定容器预留空间,即能存储数据的个数 :vec.reserve(100);
指定容器能够容纳100个单位,此时vec.capacity()=100。不过这一过程是只增不减 的,如果n小于当前capacity,否则reserve(n)无效。
下面,我们顺便说一下capacity()的大小的问题: vector<T>
默认构造函数 此时:capacity = 0 ,使用构造函数vector(n, value)指定capacity 此时:capacity = n 。 string (basic_string<char> )
默认构造函数 此时:capacity =15 指定了初始字符串的,此时:capacity = 大于字符串长度且等于n*15-1 ; basic_string<wchar_t>
//不常用,默认构造函数 此时:capacity = 7 指定了初始字符串的 此时:capacity = 大于字符串长度且等于n*8-1 ;。在上面,我们说到vec.reserve(n)过程是只增不减的,所以无法通过reserve()来收缩空间 。因此,当我们需要收缩内存空间的时候,可以使用下面方法:首先新建一个vector/string,然后往新建的vector/string填充原容器的内容,最后将原容器的变量名指向新的容器。代码如下:
vector< int > v ( 10 , 5 ) ;
v. reserve ( 20 ) ;
vector< int > ( v) . swap ( v) ;
用不完的内存可以请求归还 :在C++11新标准中当内存用不完的时候,可以请求系统归还内存。最后,使得 vec.capacity()==vec.size()。语法如下:vec.shrink_to_fit();
这里和上面的收缩空间本质是一样的,只不过这里skrink_to_fit(收缩到合适)是利用系统提供的库函数来实现。
判断容器是否为空 :vec.empty();
1.8 其他函数
assign函数 :将区间[first,last)的元素赋值到当前的vector容器中,或者赋n个值为x的元素到vector容器中,这个容器会清除掉vector以前的内容 。 vec2.assign(vec1.begin(), vec1.end());
或者vec.assign(n,x);
。还有,该函数允许从一个不同但相容 的类型赋值,或者从容器的一个子序列赋值。例如:
list< string> newstyle;
vector< const char * > oldstyle;
newstyle= oldstyle;
newstyle. assign ( oldstyle. cbegin ( ) , oldstyle. cend ( ) ) ;
list< string> list1 ( 1 ) ;
list1. assign ( 10 , "hello" ) ;
swap函数 :swap操作交换两个容器内容的操作很快,因为元素本身并没有交换 ,swap只是交换两个容器的内部数据结构,例如:vec1.swap(vec2);
。元素不会移动的事实,除了stirng外,指向容器的迭代器、引用和指针在swap操作之后都不会失效 。它们仍指向swap操作之前所指向的那些元素。但是在swap操作之后,这些元素已经属于不同的容器 。
copy函数 :把vec1中的从vec1.begin()(包括它)到vec1.end()(不包括它)的元素复制到vec2中,从vec2.begin()+1的位置(包括它)开始复制,覆盖掉原有元素copy(vec1.begin(),vec1.end(),vec2.begin()+1);
关系运算符 :每个容器都支持相等运算符(==或者!=);除了无序关联器外的所有容器都支持关系运算符(>,>=,<,<=),关系运算符左右两边的运算对象必须是相同类型,且必须保存相同类型元素。
1.9 emplace操作
新标准引进了三个新成员,emplace_front,emplace,emplace_back
,这些操作构造而不是拷贝元素,也就是当我们调用一个emplace成员函数时,则是将参数传递给元素类型的构造函数 。例如:
c. emplace_back ( "012" , 25 , 12.0 ) ;
c. push_back ( "012" , 25 , 12.0 ) ;
c