STL其他内容解析:关于C++中STL的理解和应用
目录
vector介绍:
vector容器不但能像数组一样对元素进行随机访问,还能在尾部插入元素,是一种简单,高效的容器,完全可以代替数组,vector具有自动管理功能,对于元素的插入和删除,可动态调整所占的内存空间。
vector模版类需要两个模版参数,第一个参数是存储元素的数据类型,第二个参数是存储分配器的类型,其中第二个参数是可选的,如果不给出第二个参数,将使用默认的分配器。
使用要加头文件<vector>。
vector的底层实现:
底层是数组,即将元素保存在一段连续的内存空间中。支持快速随机访问。在尾部之外的位置插入删除元素可能会很慢。
PS:当元素已经占满了预先分配的内存空间,插入新的元素时,开辟一段新的内存空间,大小为之前vector的两倍,再将vector内的元素拷贝到新的内存空间内。
vector的插入删除操作会造成迭代器的失效
vector初始化:
(1)不带参数的构造函数初始化
vector<int> a; //初始化一个size为0的vector
(2)带参数的构造函数初始化
//初始化size,但每个元素值为默认值
vector<int> abc(10); //初始化了10个默认值为0的元素
//初始化size,并且设置初始值
vector<int> cde(10,1); //初始化了10个值为1的元素
(3)通过数组地址初始化
int a[5] = {1,2,3,4,5}; //通过数组a的地址初始化,注意地址是从0到5(左闭右开区间)
vector<int> b(a, a+5);
(4)通过同类型的vector初始化
vector<int> a(5,1); //通过a初始化
vector<int> b(a);
二维vector的初始化:
vector<vector<int> > a(n,vector<int>(m,0)); //n行m列的a初始化为0
存取操作:
定义: vector<类型> 变量名称。 如 vector<int> s;
s[i] // 直接以下标方式访问容器中的元素
s.front() // 返回首元素
s.back() // 返回尾元素
s.push_back(x) // 向表尾插入元素x
s.pop_back() // 删除表尾元素
s.size() // 返回vector大小
s.empty() // 表为空时,返回真,否则返回假
vector用迭代器访问:
s.begin() // 返回指向首元素的随机存取迭代器
s.end() // 返回指向尾元素的下一个位置的随机存取迭代器
s.insert(it, val) // 向迭代器it指向的元素前插入新元素val
s.insert(it, n, val) // 向迭代器it指向的元素前插入n个新元素val
s.erase(it) // 删除由迭代器it所指向的元素 erase函数的返回的是指向被删除元素的下一个元素的迭代器
其他操作:
s.reserve(n) //缓冲空间,使存储空间至少可容纳n个元素
s.resize(n) // 改变序列长度,超出的元素将会全部被删除,如果序列需要扩展(原空间小于n),元素默认值将填满扩展出的空间
s.resize(n, val) // 改变序列长度,超出的元素将会全部被删除,如果序列需要扩展(原空间小于n),val将填满扩展出的空间
s.clear() // 删除容器中的所有元素
s.swap(v) // 将s与另一个vector对象进行交换
// 要注意的是,resize操作和clear操作都是对表的有效元素进行的操作,但并不一定会改变缓冲空间的大小
// 另外,vector还有其他的一些操作,如反转、取反等,不再一一列举
// vector上还定义了序列之间的比较操作运算符(>、<、>=、<=、==、!=),可以按照字典序比较两个序列。
vector作为函数参数传递
- void func(vector<int> x); 传值,需要调用复制构造函数,形参和实参独立的,速度较慢。
- void func(vector<int>* x); 传地址,调用时需要用 x-> 形式,形参和实参一致,速度快,但是使用不习惯,所以更习惯用第三种传引用
- void func(vector<int>& x); 传引用,形参实参一致,速度快,更方便。如果不想修改实参,可以加const修饰:void func(const vector<int>& x);
vector作为函数返回值
如果返回参数较少,可以不用定义vector,直接用 { } 进行返回。
vector<int> func(){
....
if () return {l,r}; //返回l,r两个数
else return {}; //返回空
}
vector的排序
普通的类型
vector<int>v;
sort(v.begin(),v.end(),greater<int>()); //从大到小
sort(v.begin(),v.end(),less<int>()); //从小到大
自定义类型
struct node{
int a;
int b;
};
vector<node>v;
bool cmp(node x,node y){
if(x.a==y.a) return x.b>y.b;
return x.a>y.a;
}
int main(){
....
sort(v.begin(),v.end(),cmp);
....
}
二维vector的排序
如待排序数组为n*2的,按第二个元素的大小排序
bool cmp(vector<int> a,vector<int> b){
if (a[1]>b[1]) return true;
else return false;
}
vector<vector<int>> a;
sort(a.begin(),a.end(),cmp);
自定义排序
sort()函数,默认的是对二维数组按照第一列的大小对每行的数组进行排序。所以可以加上cmp函数用按照任意列对数组进行排序。
【对二维数组排序】
#include<bits/stdc++.h>
using namespace std;
//按照二维数组第一列的大小对每个一维数组升序排序,
//如何第一列相同时,按照第二列大小对每行的数组降序排序
bool cmp(vector<int>&a,vector<int>&b){
if(a[0]!=b[0]) return a[0]<b[0];
else return a[1]>b[1];
}
int main()
{
vector<vector<int> >a(6);
int x;
for(int i=0;i<6;i++){
for(int j=0;j<2;j++){
cin>>x;
a[i].push_back(x);
}
}
cout<<endl;
sort(a.begin(),a.end(),cmp);
for(int i=0;i<6;i++){
for(int j=0;j<2;j++){
cout<<a[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
vector在类中使用:
1.vector在类中定义时,不能直接对其实例化。如下是错误的:
class student{
public:
private:
int sum;
vector<int> score(10);
};
因为编译器认为,score这个vector不属于student这个类,而是属于实例,所以在这里你想定义score的个数是10,是不行的。
解决办法:在构造函数中,定义vector的大小。如下:
class student{
public:
student(){
score=vector<int> (10);
}
private:
int sum;
vector<int> score;
};
2.在类中写cmd函数时,需要声明为static。
因为所有我们在类内定义的非static成员函数在经过编译后隐式的为他们添加了一个this指针参数!变为了:
bool cmp(Solution *this, int a, int b)
而标准库的sort()函数的第三个cmp函数指针参数中并没有这样this指针参数,因此会出现输入的cmp参数和sort()要求的参数不匹配,从而导致了:
error: reference to non-static member function must be called
而我们知道static静态类成员函数是不需要this指针的,因此改为静态成员函数即可通过!