目录
vector
vector即向量,可理解为“长度根据需要而自动改变的数组”
数组跟vector的区别在于:数组是静态分配空间,一旦分配了空间的大小,就不可以再改变了;
而vector是动态分配内存,随着元素的不断插入,它会按照自身的一套机制不断扩充自身的容量, vector容器的容量增长是按照容器现有容量的一倍进行增长。 先另外复制2倍的vector空间,此时vector占有的空间是原来的三倍,再删除原来1倍的vector空间。空间复杂度增大。
vector基本操作
#include <vector>
vector<int> vec;
几种初始化
vector<int> vec;
vector<int> a(10,1);//定义具有10个整型元素的向量,且给出的每个元素初值为1
vector<int> vec(a);//用已有vector数据a来初始化vec
vector<int> vec(a.begin(),a.begin()+2);
vector<int> vec{1,3,5};//常用在vector类型数据的返回,如:return vector<int> {1,2}
vector<int> vec={1,3,5};
vec.push_back();//尾端插入
vec.pop_back();//尾端弹出
vec.size();//vector内实际数据的个数
vec.capacity();//vector被重新分配内存前,可容纳数据的多少,即vector的容量
vec.clear();//清空vector内的数据,但不会释放内存
sort(vec.begin(),vec.end(),comp);//排序函数,comp可以是函数或函数对象
reverse(vec.begin(),vec.end());//反转函数,将vec内的元素倒序放置
//如(1,4,5,3) 变为 (3,5,4,1)
vector的front()和back()函数
vector<int> vec{1,3,4,5};
cout<<vec.front()<<endl;//返回第一个元素的值 1
cout<<vec.end()<<endl;//返回最后一个元素的值 5
vector中元素的删除
vec.erase(vec.begin()+i);//删除下标为i的元素
vec.erase(vec.begin()+i,vec.begin()+j);//删除下标为i到j的元素
TIPS:
调用erase函数时,会返回一个iterator ,指向删除元素的下一个元素。即后面的元素会自动向前补位。所以在用for循环删除元素时,迭代器不用++指向下一个元素,erase()执行后,自动返回一个迭代器指向下一个元素。
vector返回最后一个元素
vector中的end()函数 返回一个迭代器,它指向容器的最后一个元素的下一个位置,即指向的是最后的结束符,所以不能用end()来返回最后一个元素。
vector<int> vec;
方法一:
vector<T>::iterator it = vec.end()-sizeof(int);
int result= *it;
方法二:
vec.back();
方法三:
* vec.rbegin();
assign函数
void assign(const_iterator first,const_iterator last) 相当于将vector数组中已有的一段拷贝复制给调用者,但是要注意,拷贝复制过来的不包括迭代器const_iterator last所表示的值,当然此函数也可以vector数组自己对自己调用。
vector<int> a1={1,2,3,4,5,6};
vector<int> a2;
a2.assign(a1.begin(),a1.begin()+5);//a2={1,2,3,4,5}
a2.assign(a2.begin()+1,a2.begin()+3);//a2={2,3}
vector与find函数 count函数
不同于map(map有find方法),vector本身是没有find这一方法,其find是依靠algorithm来实现的
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
vec.push_back(5);
vec.push_back(6);
vector<int>::iterator it = find(vec.begin(), vec.end(), 6);
count(vec.begin(),vec.end(),target)//count函数
vector指定位置元素的插入:
iterator insert( iterator loc, const TYPE &val );
在指定位置loc前插入值为val的元素,返回指向这个元素的迭代器
void insert( iterator loc, size_type num, const TYPE &val );
在指定位置loc前插入num个值为val的元素
void insert( iterator loc, input_iterator start, input_iterator end );
在指定位置loc前插入区间[start, end)的所有元素
示例
//创建一个vector,置入字母表的前十个字符
vector <char> alphaVector;
for( int i=0; i < 10; i++ )
alphaVector.push_back( i + 65 );
//插入四个C到vector中
vector <char>::iterator theIterator = alphaVector.begin();
alphaVector.insert( theIterator, 4, 'C' );
//显示vector的内容
for( theIterator = alphaVector.begin();
theIterator != alphaVector.end(); theIterator++ )
cout < < *theIterator;
这段代码将显示:
CCCCABCDEFGHIJ
swap()函数
vector<int> vec_1;
vector<int> vec_2;
swap(vec_1[i],vec_1[j]);//互换vec_1中下标为i,j的两处数据
swap(vec_1[i],vec_2[j]);//互换vec_1中下标为i和vec_2中下标为j的数据
vec_1.swap(vec_2);//将两个vector的大小以及数据直接互换 可以用来释放空闲空间
vector执行clear()函数后内存的变化:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector <int >a;
cout << a.empty() << endl;//输出 1 代表该vector此时是空
a.push_back(1);
a.push_back(2);
cout << a[0] << " " << a[1] << endl;//输出1 2
cout << a.empty() << endl;//输出 0 代表该vector此时非空
cout << a.size() << endl;//输出2
cout << a.capacity() << endl;//输出2
cout << "***************" << endl;
//a[0]=NULL;a[1]=NULL; 这是赋值为0,并不清空数据,也不释放内存。
a.clear();
cout << a[0] << " " << a[1] << endl;//仍然输出1 2,因为没有释放内存,
//所以输出该地址的内容仍然与之前一样
cout << a.empty() << endl;//输出1 代表该vector此时已经为空
cout << a.size() << endl;//输出0,代表当前容器内存储元素个数是0,与.empty()类似,
//都告诉我们当前容器是空的意思
cout << a.capacity() << endl;//输出2,代表当前该vector在重新分配存储空间前
//所能容纳的元素数量并没有改变
cout << "***************" << endl;
/*
下面这五行说明,.pop_back()与.clear()起到了相同的作用,都是清空数据,
但是没有释放内存
while(!a.empty()){
a.pop_back();
}
cout<<a.empty()<<endl;//输出 1 代表该vector此时已经为空
cout<<a[0]<<" "<<a[1]<<endl;//仍然输出为 1 2,因为没有释放内存,
//所以输出该地址的内容仍然与之前一样
*/
a.push_back(4);
cout << a[0] << " " << a[1] << " " << a[2] << endl;//输出 4 2 0
//尽管没有释放内存,但是已经认为该vector已经被清空,所以再push_back();时,a[0]被覆盖。
cout << a.size() << endl;//输出1,代表当前容器内存储元素个数是1,
//就是刚刚push_back();装进去的数起到的作用
cout << a.capacity() << endl;//此时仍然输出2
cout << "***************" << endl;
vector构建二维数组
放代码:
//二维向量的定义
vector< vector<int> > b(10, vector<int>(5,0)); //创建一个10*5的int型二维向量b,初始值为0
vector< vector<int> > b(5)//创建一个二维向量,只知道有5个int型vector,
//但每个vector所含元素个数未知
vector< vector<int> > b;//创建一个未知大小的int型二维向量b,
vector< vector< card > > cards( m, vector< card >(n,card)); //card为自定义结构体或类
vector< vector<int> > temp(b.begin(),b.end());//用已有的二维数组来初始化
int size_row = vec.size(); //获取行数
int size_col = vec[0].size(); //获取列数
vector二维数组 排序函数sort()的使用
默认排序:按每一个vector数组第一个元素进行由小到大排序
自定义排序函数 (目标:对 二维vector<vector> points中最后一个元素进行排序)
static bool cmp(const vector<int>& a,const vector<int>& b){
return a.back()<b.back();
}
sort(points.begin(),points.end(),cmp);
Lambda 函数
sort( points.begin(),points.end(),
[](vector<int>a, vector<int>b){return a.back()<b.back();} );
//速度比方法1稍慢
// return a[0]<b[0] 实现二维数组中第一个关键字的排序
sort(people.begin(),people.end(),[](vector<int>&a,vector<int>&b){
return a[0]>b[0] || (a[0] == b[0] && a[1] < b[1]);} );
//对于二维数组vector 按第一个元素由大到小排序,如果遇到第一个元素相等的情况,
//按第二个元素由小到大排序
resize()和reserve()函数的区别
见代码:
#include "iostream"
#include<vector>
using namespace std;
void printresult(vector<int> &vec){
for (int i = 0; i < vec.size(); i++)
cout << vec[i];
cout <<endl<< "size" << vec.size() << endl;
cout << "capacity" << vec.capacity() << endl;
}
int main(){
vector<int> vec(6, 1);
printresult(vec);
vec.resize(5, 3);
printresult(vec);
vec.resize(7, 2);
printresult(vec);
vec.resize(10);
printresult(vec);
vec.reserve(12);
printresult(vec);
vec.reserve(15);
printresult(vec);
return 0;
}
输出结果如下
111111
size6 //vector<int> vec(6,1)构建vector类型数据
capacity6
————————————
11111
size5 //执行resize(5,3)之后,vector的长度变成了5,容量大小没有变
capacity6
————————————
1111122
size7 //执行resize(7,2)之后,vector扩容,长度为7,容量变为9,这与vector内存的
capacity9 //分配机制有关,vector的动态内存分配是一段一段的分配的
————————————
1111122000
size10 //同理,执行完resize(10)后,默认扩容数据为0,长度为10,容量为13
capacity13
————————————
1111122000
size10 //执行reserve(12),因为原来vector容量大于12,所以容量不变
capacity13
————————————
1111122000
size10 //执行reserve(15),长度不变,容量变为15
capacity15
vector遍历元素的新写法:
for(declaration : expression)
statement
expression部分是一个序列,可以是用花括号括起来的初始值列表,数组,vector,string等类型的对象,这些类型的特点是拥有能返回迭代器的begin和end成员。
declaration定义一个变量,序列expression中的每个元素都要能转换成该变量的类型,采用auto类型说明符来确保类型相容。每次迭代,declaration部分的变量会被初始化为expression部分的下一个元素值。vector的遍历如下:
vector< TheType > vec;
for (auto num : vec)
{
cout<<num;
}
//相当于
for(int i=0;;i<vec.size();i++) {
cout<<vec[i];
}
如果想在遍历时对vec内的元素进行修改,则需要把declaration定义为引用类型
for (auto & num : vec)
{
cout<<num++;
}
vector之反向迭代器
对反向迭代器的自加操作,相当于对该迭代器前移。
反向迭代器之间能够进行加或减的操作,但不能对反向迭代器和迭代器进行加减操作。
vector<int> vec = { 1,2,3,4,5 };
vector<int>::reverse_iterator it;
it = find(vec.rbegin(), vec.rend(), 4);
//直接写成auto it=find(vec.rbegin(), vec.rend(), 4)也可
cout << *it << endl;//输出4
cout << *(it+1) << endl;//输出3
cout << *(it-1) << endl;//输出5
vector与list的对比
- vector是连续存储结构:vector是可以实现动态增长的对象数组,支持对数组高效率的访问和在数组尾端的删除和插入操作,在中间和头部删除和插入相对不易,需要挪动大量的数据。它与数组最大的区别就是vector不需程序员自己去考虑容量问题,库里面本身已经实现了容量的动态增长,而数组需要程序员手动写入扩容函数进形扩容。
- list是非连续存储结构:list是一个双链表结构,支持对链表的双向遍历。每个节点包括三个信息:元素本身,指向前一个元素的节点(prev)和指向下一个元素的节点(next)。因此list可以高效率的对数据元素任意位置进行访问和插入删除等操作。由于涉及对额外指针的维护,所以开销比较大
- vector的随机访问效率高,但在插入和删除时(不包括尾部)需要挪动数据,不易操作。
- List的访问要遍历整个链表,它的随机访问效率低。但对数据的插入和删除操作等都比较方便,改变指针的指向即可。
vector与数组的区别:
1、内存中的位置
C++中数组为内置的数据类型,存放在栈中,其内存的分配和释放完全由系统自动完成;vector,存放在堆中,由STL库中程序负责内存的分配和释放,使用方便。
2、大小能否变化
数组的大小在初始化后就固定不变,而vector可以通过push_back或pop等操作进行动态扩容。
3、初始化
数组不能将数组的内容拷贝给其他数组作为初始值,也不能用数组为其他数组赋值;而向量可以。
4、执行效率
数组>vector向量。主要原因是vector的扩容过程要消耗大量的时间。