之前练算法很狂热的时候,由于觉得查到的一些容器的总结内容良莠不齐,遂总结了一下算法比赛中可能会用到的一些容器,但是一些不太常见的用法。
- 注释都在代码里,也懒得重新写了,直接看代码吧,非常地干货
- 代码可以直接在编译器里跑,便于测试
//几种常见容器有用但不常见操作
#include<iostream>
#include<string>
#include<vector>
#include<deque>
#include<stack>
#include<queue>
#include<priority_queue>
#include<list>
#include<set>
#include<unordered_set>
#include<multiset>
#include<map>
#include<unordered_map>
#include<multimap>
using namespace std;
const int pos=0;
const size_N=3;
void StringTest()
{
//快速初始化
string str(10,'c'); //10个c
//迭代器初始化实现str的逆转
string rstr(str.rbegin(),str.rend());
//读取一行(包括空格)到string
getline(cin,str);
//字串操作
str.substr(pos,size_n); //pos为字串开始位置(<0时表示从倒数第几个字符开始)
//size_n为字串长度 //返回值也为string类型
str.substr(pos); //默认从pos到末尾
//查找字串
str.find("substr",pos); //从pos开始往后查找第一次出现"substr"的位置
str.rfind("substr",pos); //从pos位置开始倒着查
//查不到的时候返回值为str.npos(其大小随实现改变,有的实现是-1,但这里不是)
//一般用if(str.find(sstr,pos)==str.nops)来处理未找到
//string类型和其他类型之间的转换
int a=123456;
str=to_string(a); //将数字值转换为string
stoi(str);
string::size_type sz;
stoi(str,&sz,2); //从头开始将能转为数字的字符串转换,并将结束位置传到sz
stoi(str,0,2); //从头开始的字串转为10进制数字,第三个参数是将字符串看作几进制
//返回类型看尾巴是什么,还有stol(l),stoul(ul),stoll(ll),stof(float)
//stod(double),stold(long double),其中浮点型无第三个参数几进制
//字符串中间插入字符
str.insert(pos,size_n,'c'); //在pos处插入size_n个'c'
str.insert(pos,"sstr",pos,size_n); //前两个参数同上,后两个是限定sstr的参数
//插入从sstr的pos位置开始的size_n长度的字串
//删除
str.erase(pos); //删除pos到末尾
str.erase(pos,size_n); //删除pos开始的大小为size_n字串
}
void VectorTest()
{
//几种特殊初始化
vector<int> v1={1,2,3}; //列表初始化
int a[]={1,2,3};
vector<int> va(a,a+3); //数组初始化
vector<int> v2(10,1); //10个1
vector<int> v3(10); //大内存要先开辟空空间,否则超过预留的空间将产生很多复制的操作
vector<int> v4[10]; //相当于二维数组
vector<vector<int>> v5; //优于上面的二维数组
//几种常用函数
v1.emplace_back(1); //尾插,也可以用push_back(),但前者效率更高
v1.pop_back(); //尾删
auto it=v1.begin(); //正向迭代器,指向第一个元素,止于v1.end();
auto rit=v1.rbegin(); //反向迭代器,指向最后一个元素,rit++从后往前遍历止于v1.rend();
v1.emplace(it,3); //迭代器指向位置插入也可以用emplace(v1.begin()+index,3);
//相当于insert但是要高效于insert;
v1.erase(it); //删除迭代器位置,也可以erase(v1.begin()+index);
//迭代器指向位置不变,后面元素前移,于是删除后迭代器指向了下一个元素
v1.erase(itb,ite); //删除两个迭代器之间的元素
v1.reserve(size_n); //非初始化时为容器开辟指定空间
//比较
v1==v2;
v1!=v2;
v1>v2; //字典序方式比较两个容器的内容
}
void dequeTest() //双向队列容器
{
//类似于vector,首插和首删操作要优于vector
//一般情况下vector更优,deque仅仅优先选择于大量的首或尾删除操作.
//如果你打算用insert或者有pop_front()的需要,使用deque.
//比vector多的函数
deque<int> d;
d.emplace_front(1);
d.pop_front();
}
void StackTest() //栈:先进后出
{
//初始化
stack<int> s;
//基操
s.emplace(1); //等价于push(),入栈(尾插)
s.top(); //获取栈顶元素其实也就是尾元素
s.pop(); //移除栈顶元素(尾删)
}
void QueueTest() //队列:先进先出
{
//初始化
queue<int> q; //默认应该是deque实现反正不是vector(vector首删比较麻烦)
queue<int,list<int>> q1; //用list实现的queue
queue<int,deque<int>> q2; //用deque实现的queue
//基本操作
q.emplace(1); //等价于push(),尾插
q.front(); //获取头元素
q.back(); //获取尾元素,没想到也能得到尾元素吧,"先进先出"只限制插入和删除
q.pop(); //首删
}
//自定义比较函数
struct zdy{
int x;
bool operator<(const zdy&rhs)const{
return x<rhs.x; //大顶堆
}
};
//重写仿函数
struct cmp{
bool operator()(zdy&a,zdy&b){
return a.x<b.x; //大顶堆
}
};
void Priority_queueTest() //优先队列,具有队列的性质,但内部实现是个堆
{
//可以做到高效获得优先级最高的元素,队首总是自动调节为优先级最高的元素
//基本类型(自带优先级比较函数)初始化
priority_queue<int> pq; //默认为大顶堆
priority_queue<int,vector<int>,greater<int>> pq1; //这样可以获得小顶堆
//对于自定义类型,需自己定义比较函数,或者重写仿函数(见上)
priority_queue<zdy> pq2;
priority_queue<zdy,vector<zdy>,cmp> pq3;
//基操
p.top(); //获取队头元素也就是优先级最高的那个元素
p.emplace(); //等价于push(),插入元素并被排序到合适位置
p.pop(); //删除队头元素
}
void ListTest() //双向链表
{ //底层就是链表的实现
//与向量(vectors)相比,它允许快速的插入和删除,但是随机访问却比较慢.
//初始化
list<int> l; //这样添加int型存的是复制到链表内的数据,并不是地址
list<int*> l1; //这样就是会存的已有变量的地址
//小类型建议直接存数据,因为和地址大小差不多,但是大类型可以存地址节省内存
//访问
l.front(); //返回第一个元素
l.back(); //返回第一个元素
//迭代器
l.begin(); //指向第一个元素
l.end(); //指向最后一个元素之后
l.rbegin(); //指向最后一个元素
l.rend(); //指向第一个元素之前
//正向遍历(从头到尾)
for(auto it=l.begin();it!=l.end();it++)
//反向遍历(从尾至头)
for(auto rit=l.rbegin();rit!=l.rend();rit++)
//插入删除
l.emplace_front(1); //"="push_front()//头插
l.emplace_back(1); //"="push_back()//尾插
l.pop_front(); //头删
l.pop_back(); //尾删
auto it=l.begin();
l.insert(it,1); //迭代器插入
l.erase(it); //使迭代器失效,并返回下一个元素的迭代器 //传入反向迭代器不行
//*因此遍历的时候要注意不要把it直接删除导致进入死循环
l.remove_if(x); //删除指定元素(可多个)
//特殊
l.sort(); //排序 //std::sort()不可以只能用这个
l.unique(); //去重
l.reverse();
}
void SetTest() //集合:元素唯一性,有序性
{ //底层实现为红黑树
//初始化
set<int> s; //自定义类型的话注意要写比较函数
int a[6]={1,3,4,5,6,7};
set<int> s1(a,a+6); //用数组初始化,妙呀测试不用一个个insert了
//迭代器(和list一样)
s.begin(); //指向第一个元素
s.end(); //指向最后一个元素之后
s.rbegin(); //指向最后一个元素
s.rend(); //指向第一个元素之前
//正向遍历(从头到尾)
for(auto it=s.begin();it!=s.end();it++)
//反向遍历(从尾至头)
for(auto rit=s.rbegin();rit!=s.rend();rit++)
//插入删除
s.insert(10); //插入后自动会排序
s.erase(x); //删除指定元素 //找到并删除成功返回值为1,否则为0
s.erase(it); //删除指定迭代器
//it不会失效仍指向原元素,返回值为下一个元素迭代器
//特殊
s.find(x); //查找指定元素成功返回它的迭代器否则返回s.end();
s.count(x); //找到x返回1否则返回0
s.lower_bound(x); //和上面find一样 //和std::low_bound()一样
s.upper_bound(x); //找到比x大一个的并返回迭代器
}
void Unordered_SetTest() //无序集合(set减去排序功能)
{ //底层基于哈希表实现 //不需要排序功能的时候优于set
//咋说呢,存进去是的东西是无序的所以遍历功能基本没啥用
//但是因为是哈希结构,可以快速的查找一个元素是不是在容器内
//初始化(基本和set一样)
unordered_set<int> us;
//*自定义类型需要自己定义hash和qual函数
//插入删除
us.emplace(x); //=insert();//返回值为pair<iterator,bool>类型
//us中已存在x,bool则返回false,否则true,迭代器两种情况都返回指向x的迭代器
us.erase(x); //删除指定元素
//查找
us.find(x); //找到返回x的迭代器,否则返回us.end();
}
void MultiSetTest() //"set减去去重的功能"
{
//底层和set一样都是红黑树(二叉搜索树)
//迭代器:像set一样拥有正反迭代器//反向迭代器不能被erase操作
//删除
multiset<int> ms={1,3,2,3,34,2};
ms.erase(iterator); //删除迭代器指向的位置,返回值为下一个元素的迭代器
ms.erase(x); //删除所有x(x可以有多个)
//统计
ms.count(x); //返回值为容器内x的个数
}
void Unordered_MultiSetTest() //"set减去去重和排序功能"
{
//底层实现是哈希表
//使用场景:可以拿来统计某种值的个数
//初始化
unordered_multiset<int> ums;
//统计
ums.count();
}
void MapTest() //one to one 映射 (key to value)
{
//底层实现是红黑树
//初始化
map<string,int> m;
//插入
m["cjc"]=1; //也可以insert但是这种更方便
//迭代器:拥有正反迭代器
//查找
m.find("key"); //找到对应key返回迭代器,否则返回m.end();
//删除
m.erase("key"); //直接删除对应key的元素
m.erase(iterator); //也可以通过迭代器来删除
}
void Unordered_MapTest() //map减去排序功能
{
//底层实现是哈希表 //查找得很快但是建立哈希表比较耗时间
//用法和map基本相同
}
void MultiMapTest() //map减去去重功能,一个key可以有多个value
{
//实现:红黑树
//应用场景:multimap<寝室,学生> mm可以快速查到同一个寝室的学生
//查找应用
multimap<int,string> mm;
auto bit=mm.lower_bound(627); //找到第一个627位置迭代器
auto eit=mm.upper_bound(627); //找到最后一个627后面的位置的迭代器
for(auto it=bit;it!=eit;it++){
cout<<it->second<<" "; //这样就找到所有627的学生了
}
//统计
mm.count(keyx); //统计key==keyx键值对的总数
//删除
mm.erase(iterator); //只删除迭代器指向的位置
mm.erase(keyx); //删除所有key=keyx的键值对
}
void Unordered_MultiMapTest() //map减去去重和key排序功能
{//实现:哈希表
//应用场景:需要快速查询某个键值的个数一般不用于遍历
//和umset差不多,只是多了一个映射值
}
int main()
{
return 0;
}