C++STL容器超详介绍
C++stl容器超详介绍
声明
这篇文章属于原创,是从本人的洛谷专栏中搬过来的。转载请经过本人同意,且转载后请注明出处,否则将举报。
引入
线性数据结构 称为container
vector
begin是第一个数据的地址,而end是最后一个数据的下一个地址。
特殊的
for(auto i:a){
cout<<i<<' ';
}
//for range语法
与
for(auto it=a.begin();it!=a.end();it++){
auto i=*it;
cout<<i<<' ';
}
的效果是相同的。
为循环变量值修改会修改原vector的值吗?
在这段代码中,加入i=4,是不会修改原vector a的值的,只会修改i的值。
for(auto i:a){
cout<<i<<' ';
i=4;
}
因为其等价于
for(auto it=a.begin();it!=a.end();it++){
auto i=*it;
cout<<i<<' ';
i=4;
}
但是,当在代码中加入取地址符号&时,会直接影响vector a中的值。
for(auto &i:a){
cout<<i<<' ';
i=4;
}
因为其等价于
for(auto it=a.begin();it!=a.end();it++){
auto &i=*it;//取了*it的地址,修改i时就会直接修改*it
cout<<i<<' ';
i=4;
}
建立vector
有三种
std::vector<int>a;//建立vector a
std::vector<int>a(n);//建立长度为n的vector a
std::vector<int>a(n,i);//建立长度为n,初始值都为i的vector a
嵌套vector
vector中的数据类型也可以嵌套vector
例如,构造一个二维\(n*m\)的vector嵌套,可以用如下代码。
vector<vector<int>>a(n,vector<int>(m));
//等价于 int[n][m];
//定义一个类型为vector的vector,长度为n,初始值都为初始值为m的vector<int>
注意
二维数组是开了一个n*m的内存,而二维vector是开了n个m的内存,n个m在内存中可能不连续。
vector的优点
- vector可以成为局部变量(数据),而数组不可以。
- vector在不规定初始值时默认是0,而数组如果作为局部变量时初始值时随机的,需要耗费 O(\(n^{数组维度}\)) 的时间复杂度来归零。
priority_queue优先队列
建立
std::priority_queue<int>q;
相当于自动排序
注:队列没有指针,不能使用for range遍历队列
大小根堆
priority_queue默认大根堆(从大到小排序)
如果想要改成小根堆可以在建立时加入比较器
std::priority_queue<int,vector<int>,greater<int>>q;
//大根堆的仿函数比较器是less,但是默认是大根堆,所以不常用。
//std::priority_queue<int,vector<int>,less<int>>q;
//像这样就可以建立一个大根堆,不过这样会多此一举,没啥用。
也可以使用构造函数重构,注意需要重载<,且必须重载<,重载其他运算符都无效。
struct node{
int x,y;
bool operator<(const node &o)const{
if(x!=o.x)return x<o.x;// < 是大根堆 > 是小根堆
return y<o.y;
}
node(int x_,int y_):x(x_),y(y_){}
};
std::priority_queue<node>q;
set
关于set
set的本质是二叉平衡树
set的作用
- 维护某个元素是否存在
- 查询大于等于/大于它的最小数字
- 维护本质不同的元素有几个
建立set
std::set<int>s;
set的操作
insert可以往set中插入一个元素,但set的元素不能重复
例如:
s.insert(1);
s.insert(4);
s.insert(2);
s.insert(2);//此时在插入一个2将什么都不会发生,就犹如把这一行给注释掉了。
set有指针,也可以使用for range遍历,输出时默认从小到大(升序)
s.size()s的大小
s.count(x)查询x是否存在,返回1和0
s.erase(x)删除x元素
set中的查找
set中也可以使用查找函数
s.lower_bound和s.upper_bound
具体使用见下文
查找中的技巧
因为没有查找小于的函数,所以我们可以使用查找第一个大于等于前一个数,来查找第一个小于这个数的数。
例如想要在s中查找第一个小于4中的数,可以这样写:(注意,如果使用-1会编译错误,需要直接修改返回值,即--lower_bonud())
cout<<*(--s.lower_bonud(4));
那么同理可得,想要在s中查找第一个小于等于4的数就如下:
cout<<*(--s.upper_bonud(4));
注意
当出现越界是需要处理
auto ret=s.lower_bonud(1);
if(ret==s.begin()){
//do sth.
}
else cout<<*(--s.lower_bound(1));
multiset
multiset其实就是可以有重复元素的set,用法也大致相同。
特殊的用法
见如下代码:
std::multiset<int>s;
s.insert(4);
s.insert(1);
s.insert(2);
s.insert(2);
for(auto i:s){
std::cout<<i<<" ";
}
cout<<'\n';//此时会输出1 2 2 4
s.erase(2);
for(auto i:s){
std::cout<<i<<" ";
}
cout<<'\n';//此时会输出1 4
所以s.erase(x)会删除所有的x,如果要只删掉一个x可以使用s.find(x),它返回的是一个迭代器,可以这样使用:
s.erase(s.find(x));//删除一个x
s.count(x)也有不同,它在multiset中返回的是x的数量,时间复杂度是\(O(log n+返回值大小)\)
bitset
bitset是一个01串。
建立
建立方式很简单,见如下代码。
std::bitset<x>bs;//x必须是一个在编译时确定的量,即常量
函数
s.count();//1的个数
s.all();//是否都是1
s.any();//是否有1
s.none();//是否都是0
s.set(1,1);//等价于s[1]=1;
lower_bound与upper_bound
lower_bound与upper_bound是两个函数
注意函数的返回值是地址(迭代器),输出请加上指针符*
作用
lower_bound可以返回第一个大于等于x的数
upper_bound可以返回第一个大于x的数
例如在vector中使用时可以用如下代码:
std::vector<int>a;
a.push_back(2);a.push_back(3);a.push_back(3);a.push_back(4);
for(int i=0;i<=5;i++){
auto ret=std::lower_bound(a.begin(),a.end(),i);//>=
auto rett=std::upper_bound(a.begin(),a.end(),i);//>
if(ret!=a.end())std::cout<<*ret<<" ";
else std::cout<<"NULL ";
if(rett!=a.end())std::cout<<*rett<<"\n";
else std::cout<<"NULL\n";
//如果没有找到会返回a.end()
}
技巧
可以用返回值减去开始地址得到下标
例如,ret为lower_bound的返回值,那么
*ret=a[ret-a.begin()];
复杂度
O(\(log n\))
min max
//两个数的比较
int a=min(1,2),b=max(1,2);
//多个数的比较
int a=min({1,2,3,4,5}),b=max({1,2,3,4,5});//c++14
//数组中的比较
int a[5]={1,2,5,3,4};
cout<<*max_element(a,a+5)<<'\n';
cout<<*min_element(a,a+5)<<'\n';
//数组中的修改
nth_element(a,a+5,a+3);//将第4(3+1)小的数放在a+3的位置
next_permutation
没啥好说的,全排列。
#include<bits/stdc++.h>
using namespace std;
int main(){
int a[3]={1,2,3};
do{
for(auto i:a)cout<<i<<" ";
cout<<'\n';
}while(next_permutation(a,a+3));
return 0;
}
sort
快速排序和lambda表达式
#include<bits/stdc++.h>
using namespace std;
int main(){
int a[3]={0,1,2};
int b[3]={2,3,1};
//想要按b[a[i]]<b[a[j]]排序
//注意下面一行中[&](int x,int y),如果不加&,就只能访问被排序数组中(a)的元素,不能访问b数组
sort(a,a+3,[&](int x,int y){//lambda表达式
return b[x]<b[y];
});
for(auto i:a)cout<<i<<" ";
return 0;
}
本文来自博客园,作者:S_Z_Xcoco,转载请注明原文链接:https://www.cnblogs.com/SZXcoco/articles/18503205/STL

浙公网安备 33010602011771号