STL概念
STL(Standard Template Library)是C++的标准模板库,竞赛中很多常用的数据结构算法在STL中都有。STL包含容器(contaniner),迭代器(interator),空间配置器(allocator),配接器(adapter),算法(algorithm),仿函数(function)6个部分。
顺序式容器
顺序式容器包括:vector,list,deque,queue,priority_queue,stack等。
vector:动态数组,从末尾能快速插入与删除,直接访问任何元素。
list:双链表,从任何地方快速插入与删除。
deque:双向队列,从前面或后面快速插入与删除,直接访问任何元素。
queue:队列,先进先出。
priority_queue:优先队列,最高优先级元素总是第一个出列。
stack:栈,后进先出。
Vector
vector是STL的动态数组,在运行时能根据需要改变数组大小。内存空间是连续的。
1.定义
2.常用操作
3.运用
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int main()
{
int n,m;
vector<int>table;
while(~scanf("%d %d",&n,&m))
{
table.clear();//清空数据
for(int i=0;i<2*n;i++)
{
table.push_back(i);//初始化,编号
}
int pos=0;
for(int i=0;i<n;i++)
{
pos=(pos+m-1)%table.size();//圆桌是个环,取余处理
table.erase(table.begin()+pos);//赶走坏人,table人数减1
}
int j=0;
for(int i=0;i<2*n;i++)
{
if(!(i%50)&&i)//50个字母一行
printf("\n");
if(j<table.size()&&i==table[j])//赶走坏人之后,编号和原来一样的是留下来的好人
{
j++;
printf("G");
}
else
printf("B");
}
printf("\n\n");
}
return 0;
}
stack(栈)
特点“先进后出”
头文件:#include< stack >
1.相关操作
2.运用
方法一:
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int main()
{
int n;
char ch;
scanf("%d",&n);
getchar();
while(n--)
{
stack<char>s;
while(true)
{
ch=getchar();//一次读入一个字符
if(ch==' '||ch=='\n'||ch=='\0')
{
while(!s.empty())
{
printf("%c",s.top());//输出栈顶
s.pop();//清除栈顶
}
if(ch=='\n'||ch=='\0')
break;
printf(" ");
}
else
{
s.push(ch);//入栈
}
}
printf("\n");
}
return 0;
}
方法二:
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
string str;
string s="";
int main()
{
int n;
while(~scanf("%d",&n))
{
getchar();
while(n--)
{
getline(cin,str);//输入需要注意,因为输入的字符串有空格
for(int i=0;i<str.length();i++)
{
//这里犯了个错误,就是把'\0'用成了'\n',使用'\n',会出现死循环
while(str[i]!=' '&&str[i]!='\0')
{
s+=str[i];
i++;
}
//翻转字符串
reverse(s.begin(),s.end());
cout<<s;
s="";//重新初始化
if(str[i]==' ')//最后一个字符串不需要输出空格
printf(" ");
}
printf("\n");
}
}
return 0;
}
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int main()
{
double n,m;
char c;
stack<double>s;
while(~scanf("%lf",&n))
{
c=getchar();
if(c=='\n'&&n==0)
break;
s.push(n);
scanf("%c",&c);
while(~scanf("%lf",&n))
{
//c等于*或者/的时候,先取出栈顶,再将后面一个数字与栈顶元素进行*或者/,
//然后再入栈
if(c=='*')
{
m=s.top();
m*=n;
s.pop();
s.push(m);
}
if(c=='/')
{
m=s.top();
m/=n;
s.pop();
s.push(m);
}
//+直接入栈
if(c=='+')
{
s.push(n);
}
//-是将符号一起入栈,即将"负数"入栈
if(c=='-')
{
s.push(0-n);
}
if(getchar()=='\n')
{
break;
}
c=getchar();
}
double sum=0;
while(!s.empty())//判断栈是否为空
{
sum+=s.top();//取栈顶元素
s.pop();//删除栈顶元素
}
printf("%.2lf\n",sum);
}
return 0;
}
queue(队列)
特点 “先进先出”
头文件:#include< queue>
1.相关操作
2.运用
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
string str,str1;
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
queue<int>q;
stack<int>s;
int m,temp;
cin>>m>>str;
for(int i=0;i<m;i++)
{
if(str=="FIFO")//队列
{
cin>>str1;
if(str1=="IN")
{
cin>>temp;
q.push(temp);//放进队列
}
if(str1=="OUT")
{
if(q.empty())
printf("None\n");
else
{
printf("%d\n",q.front());//出队列
q.pop();
}
}
}
else//栈
{
cin>>str1;
if(str1=="IN")//入栈
{
cin>>temp;
s.push(temp);
}
if(str1=="OUT")
{
if(s.empty())
printf("None\n");
else
{
printf("%d\n",s.top());//出栈
s.pop();
}
}
}
}
}
return 0;
}
priority_queue(优先队列)
以某种排序准则(默认为less)管理队列中的元素
头文件:#include< queue>
优先队列:优先级最高的先出队
队列和排序的完美结合,不仅可以存储数据,还可以将这些数据按照设定的规则进行排序。每次push和pop操作,优先队列都会动态调整,把优先级最高的元素放在前面。
priority_queue< int,vector< int>,less< int> >q; 完整的名称(从大到小)
priority_queue< int,vector< int>,greater< int>>q;(从小到大)
q.push(e) 根据元素的优先级将元素置入队列
q.top() 返回优先队列头部最大的元素的引用,但不移除
q. pop() 从栈中移除最大元素,但不返回
q.empty() 队列是否为空
//实现按照结构体中x,从大到小排序
/*struct node
{
int x,y;
bool operator < (const node&a)const
{
return x<a.x;
}
};
priority_queue<node>q;
//node是一个结构体
//结构体里重载了'<'小于符号
*/
//样例
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
struct node
{
int x,y;
bool operator < (const node&a)const
{
return x<a.x;
}
}k;
priority_queue<node>q;//从大到小
//priority_queue<node,vector<node>,greater<node> >q;从小到大
int main()
{
k.x=10,k.y=100;q.push(k);
k.x=12,k.y=100;q.push(k);
k.x=4,k.y=160;q.push(k);
k.x=5,k.y=10;q.push(k);
k.x=56,k.y=140;q.push(k);
while(!q.empty())
{
node m=q.top();
q.pop();
printf("(%d %d)\n",m.x,m.y);
}
return 0;
}
2.运用
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
struct node
{
int b;//优先级
int id;
bool operator < (const node & t2)const
{
if(b!=t2.b)
return b<t2.b;
return id>t2.id;
}
};
string str;
int main()
{
int n;
while(~scanf("%d",&n))
{
priority_queue<node>q[4];
int id=1;
node temp;
for(int i=0;i<n;i++)
{
cin>>str;
if(str=="IN")
{
int a,b;//a是看医生的序列,b是优先级
scanf("%d %d",&a,&b);
temp.b=b;
temp.id=id;
id++;
q[a].push(temp);
}
else
{
if(str=="OUT")
{
int a;
scanf("%d",&a);
if(q[a].empty())
{
printf("EMPTY\n");
}
else
{
printf("%d\n",q[a].top().id);
q[a].pop();
}
}
}
}
}
return 0;
}
List(链表)
双向链表,它的内存空间不必连续,通过指针来进行数据的访问,高效率地在任意地方删除和插入,插入和删除操作是常数时间。
list和vector的优缺点正好相反,它们的应用场景不同:
1.vector:插入和删除操作少,随机访问元素频繁。
2.list:插入和删除频繁,随机访问较少。
1.迭代器
//所有容器都提供两种迭代器
1.container::iterator 以“读/写”模式遍历元素2.container::const_iterator 以“只读”模式遍历元素
//迭代器分类
1、双向迭代器
可以双向行进,以递增运算前进或以递减运算后退,可以用==和!=比较
list、set和map提供双向迭代器
2.随机存取迭代器
除了具备双向迭代器的所有属性,还具备随机访问能力。
可以对迭代器增加或减少一个偏移量,处理迭代器之间的距离或者使用< 和 >之类的关系运算符比较两个迭代器。
vector、deque和string提供随机存取迭代器
stack、queue、priority_queue不支持迭代器
2.迭代器相关函数
3迭代器定义及使用
容器<类型>::iterator it;
//正序遍历
for(it=a.begin());a!=a.end();it++)
cout<<*it<<endl;
//逆序遍历
for(it=a.rbegin();it!=rend();it++)
cout<<*it<<endl;
4.运用
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int main()
{
int t,n;
cin>>t;
while(t--)
{
cin>>n;
int k=2;
list<int> mylist;
list<int>::iterator it;
for(int i=1;i<=n;i++)
mylist.push_back(i);
while(mylist.size()>3)
{
int num=1;
for(it=mylist.begin();it!=mylist.end();num++)
{
if(num%k==0)
it=mylist.erase(it);
else
it++;
}
k==2?k=3:k=2;//1至2报数,1至3报数
}
for(it=mylist.begin();it!=mylist.end();it++)
{
if(it==mylist.begin())//格式处理,最后一个数据后面不能有空格
cout<<*it;
else
cout<<" "<<*it;
/* if(it!=mylist.begin())
cout<<" ";
cout<<*it;
*/
}
printf("\n");
}
return 0;
}
关联式容器
包括set、multiset、 map、multimap等。
set:集合,快速查找,不允许重复值。
multiset:快速查找,允许重复值。
map:一对多映射,基于关键字快速查找,不允许重复值。
multimap:一对多映射,基于关键字快速查找,允许重复值。
set(集合)
用二叉搜索树实现,集合中的每个元素只出现一次,且是排好序的。访问元素的时间复杂度是O(logn)的。
1.相关操作
2.运用
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
ll a[1005];
set<ll>s;
set<ll>::iterator it;
int main()
{
int n;
while(~scanf("%d",&n))
{
s.clear();
for(int i=0;i<n;i++)
cin>>a[i];
//scanf("%l64d",&a[i]);使用这个在hdu上没有过
//scanf("%lld",&a[i]);这个ac了
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
s.insert(a[i]+a[j]);//元素一次相加
}
}
ll sum=0;
for(it=s.begin();it!=s.end();it++)
{
sum+=*it;
}
cout<<sum<<endl;
}
return 0;
}
Map
使用平衡二叉树管理元素。
元素包含两部分(key,value),key和value可以是任意类型。
头文件:#include< map>
根据元素的key自动对元素排序,因此根据元素的key进行定位很快,但根据元素的value定位很慢。
不能直接改变元素的key,可以铜鼓operator[]直接存取元素值。
map中不允许key相同的元素。
count(key) 返回“键值等于key”的元素个数
find(key) 返回“键值等于key”的第一个元素,找不到返回end
1.Map赋值方法
第一种:用insert函数插入pair数据
map<int,string>stu;
stu.insert(pair<int,string>(1,"one"));
stu.insert(pair<int,string>(2,"two"));
stu.insert(pair<int,string>(3,"three"));
map<int,string>::iterator it;
for(it=stu.begin();it!=stu.end();it++)
cout<<it->first<<" "<<it->second<<endl;
第二种:用数组方式插入数据
//Map[key]=value
stu[1]="one";
stu[2]="two";
stu[3]="three";
2.运用
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
string str;
int main()
{
int n,day,price;
map<string,int>shop;
while(cin>>n)
{
for(int i=1;i<=n;i++)
cin>>str;//输入商店名字
cin>>day;
while(day--)
{
for(int i=1;i<=n;i++)
{
cin>>price>>str;
shop[str]+=price;//用map直接操作商店,加上价格
}
int rank1=1;
map<string,int>::iterator it;
for(it=shop.begin();it!=shop.end();it++)
{
if(it->second>shop["memory"])//比较价格
rank1++;
}
cout<<rank1<<endl;
}
shop.clear();
}
return 0;
}