本文记录一些常用的stl容器
能力有限,涵盖的应用场景和注意点不一定全,刷题遇到了再补充,当然,真遇到了多半还是靠经验随机应变- -
vector容器
1.定义: vector < typename > v (len , value);
len为v的长度,value为v中元素的初始值,可省略vlaue或(len,value)
2.头文件:#include < vector >
3.相关函数: 以vector < int > v为例(只记录一些常用的,下同)
函数 | 用途 |
---|---|
v.begin() | 返回数组的第一个元素的迭代器 |
v.end() | 返回数组的最后一个元素的下一个元素的迭代器,元素不存在 |
v.rbegin() | 返回数组的最后一个元素的迭代器 |
v.push_back(x) | 数组末尾插入x |
v.erase( v.begin()+i ) | 删除下标为 i 的元素 |
v.at(i) | 访问下标为 i 的元素 |
v[i] | 访问下标为i的元素 |
v.size() | 返回数组长度 |
v.clear() | 删除所有元素 |
v.empty() | 判断是否为空,是则返回true |
代码示例:
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
cout<<*v.begin()<<" "<<*v.end()<<" "<<*v.rbegin()<<endl;
cout<<"数组长:"<<v.size()<<endl;
v.erase(v.begin()+1);
cout<<"数组长:"<<v.size()<<endl;
cout<<v.at(0)<<" "<<v[1]<<endl;
v.clear();
cout<<"数组长:"<<v.size();
return 0;
}
运行结果:
4.应用场景:
1)基本上用到数组就可以用vector平替,操作比静态array灵活,最大缺点就是内存占用比array要大
5.注意点:
1)v.begin()等返回的是指针,要得到值需要用取值符号*,或者直接下标||at访问;
2)删除某一位置的元素前先查看一下是否越界,避免造成程序崩溃
map和unordered_map
1.定义: map < typename , typename > m;
2.头文件:#include < map >
3.相关函数: 以map < string , int > m为例(unordered_map类似)
函数 | 用途 |
---|---|
m[key]=value | 插入键值对{key:value} |
m[key] | 返回key对应的value |
m.begin() | 返回m的第一对键值对的迭代器 |
m.end() | 返回m的最后一个键值对的下一个的迭代器,无指向内容 |
m.rbegin() | 返回m的最后一个键值对的迭代器 |
m.find(key) | 查找键为key的键值对,若没有找到则返回m.end() |
m.erase(key) | 把key对应的那条键值对删去,key存在则返回1,不存在则返回0 |
m[key]->first or m[key]->second | 返回key or 返回key的value |
代码示例:
#include <iostream>
#include <map>
#include <unordered_map>
using namespace std;
int main(){
map<string,int> m;
unordered_map<string,int> um;
cout<<"-----map-----"<<endl;
m["aaa"]=1;
m["bbb"]=5;
m["ddd"]=6;
m["eee"]=7;
for(auto it:m){
cout<<it.first<<" "<<it.second<<endl;
}
cout<<"删除aaa和ccc:"<<m.erase("aaa")<<" "<<m.erase("ccc")<<endl;
cout<<m.begin()->first<<" "<<m.rbegin()->first<<endl;
cout<<"-----unordered_map-----"<<endl;
um["aaa"]=1;
um["bbb"]=5;
um["ddd"]=6;
um["eee"]=7;
for(auto it:um){
cout<<it.first<<" "<<it.second<<endl;
}
return 0;
}
运行结果:
4.应用场景:
1)用于快速找到某一key对应的value;
2)因为map的顺序是key的升序排列,所以题目中如果对排序有一定要求也可以使用;
3)unordered_map是无序的,如果题目对于顺序没有要求,只是快速查找,则unordered_map要更高效;
4)存类似student的结构体时也可以用map,key为学生的唯一id,value为student结构体,这样可以快速找到某一学生对应的信息。
5.注意点:
1)first 和 second 注意 . 和 -> 的使用,不过一般系统会报错提醒;
set和multiset (补:priority_queue
1.定义: set < typename > st;
2.头文件:#include < set >
3.相关函数: 以set < int > st为例(multiset类似)
函数 | 用途 |
---|---|
st.insert(x) | 插入值x |
st.begin() | 返回st的第一个元素的迭代器 |
st.end() | 返回st的最后一个元素的下一个的迭代器,无指向内容 |
st.rbegin() | 返回st的最后一个元素的迭代器 |
st.erase(x) | 若x为值,则删除值为x的元素;若x为迭代器,删除迭代器指向的值 |
st.find(x) | 返回值为x的迭代器,没找到则返回st.end() |
st.lower_bound(x) | 返回第一个大于等于x的迭代器 |
st.upper_bound(x) | 返回最后一个大于等于x的定位器 |
代码示例:
#include <iostream>
#include <set>
using namespace std;
int main(){
set<int> st;
multiset<int> mst;
cout<<"-----set-----"<<endl;
st.insert(11);
st.insert(23);
st.insert(5);
st.insert(5);
for(auto it:st){
cout<<it<<endl;
}
st.erase(5);
cout<<"删除后最小值为:"<<*st.begin()<<endl;
cout<<"-----multiset-----"<<endl;
mst.insert(11);
mst.insert(23);
mst.insert(5);
mst.insert(5);
mst.insert(5);
for(auto it:mst){
cout<<it<<endl;
}
cout<<"第一个大于等于11:"<<*mst.lower_bound(11)<<endl
<<"最后一个大于等于11:"<<*mst.upper_bound(11)<<endl;
mst.erase(mst.begin());
cout<<"迭代器删除,删除一个5后:"<<endl;
for(auto it:mst){
cout<<it<<endl;
}
mst.erase(5);
cout<<"值删除,删除全部5后:"<<endl;
for(auto it:mst){
cout<<it<<endl;
}
return 0;
}
运行结果:
4.应用场景:
1)需要对数据进行排序时使用;
2)快速找第一或最后的某个范围内的数时,lower_bound()和upper_bound()用的是二分,因此更高效
5.注意点:
1)找出第n小的数的时候,不要用set!用也可以但是不如sort排序数组代码块来的容易,经常被这个坑并且屡教不改= =
2)set不允许重复,multiset允许重复,因此要仔细分析题目,到底是需要某个数重复还是不需要;
3)multiset删除的时候注意用法,set删一个就是全删了,multiset删可能需要删一个,也可能需要全删
补++:
priority_queue(补充的简单讲讲)
1.头文件: 在< queue >头文件中,但是因为都涉及到排序因此放在这里一起对比了
2.相关函数: 以priority_queue < int > q为例
函数 | 用途 |
---|---|
q.push(x) | 入队,自动排序,大根堆降序排列 |
q.top() | 返回队首元素,即最大的元素 |
q.pop() | 队首元素出队 |
q.empty() | 判断是否为空,是则返回true |
4.应用场景:
1)仅对最大值(可修改为最小)做改动,对其他元素没有要求
5.注意点:
1)优先队列只能用top访问队首元素,不可以访问其他元素,底层逻辑是大根堆
stack
1.定义: stack < typename > s;
2.头文件:#include < stack >
3.相关函数: 以stack < int > s为例
函数 | 用途 |
---|---|
s.push(x) | 入栈,末位插入x |
s.pop() | 出栈,弹出栈顶元素 |
s.empty() | 判断是否为空,是则返回true |
s.top() | 返回栈顶元素的值 |
代码示例:
#include <iostream>
#include <stack>
using namespace std;
int main(){
stack<int> s;
s.push(1);
s.push(2);
s.push(3);
cout<<s.top()<<endl;
cout<<"弹出栈顶元素:";
while(!s.empty()){
cout<<s.top()<<" ";
s.pop();
}
return 0;
}
运行结果:
4.应用场景:
1)只允许一端出入的类型,典型的比如单调栈类型题
5.注意点:
1)用法比较简单,选定用栈做题后没什么需要注意的,此条待补充。
queue
1.定义: queue < typename > q;
2.头文件:#include < queue >
3.相关函数: 以queue < int > q为例
函数 | 用途 |
---|---|
q.push(x) | 入队,队尾插入x |
q.pop() | 删除队头元素 |
q.front() | 返回队头元素 |
q.back() | 返回队尾元素 |
q.empty() | 判断队伍是否为空,是则返回true |
代码示例:
#include <iostream>
#include <queue>
using namespace std;
int main(){
queue<int> q;
q.push(1);
q.push(2);
q.push(3);
cout<<q.front()<<" "<<q.back()<<endl;
cout<<"出队:";
while(!q.empty()){
cout<<q.front()<<" ";
q.pop();
}
return 0;
}
运行结果:
4.应用场景:
1)先入先出的类型题,做的比较少暂时没遇到多少典型
5.注意点:
1)栈和队列的插入和删除,因为限定了一端所以与其他的稍有不同,但总体来说主要是选定问题,选定用栈或队列解题后其函数用法都比较简单,同栈一样,此条待补充