Standard Template Library 标准模板库
使用其中算法需要 #include<algorithm>
一、sort
a为数组a[]
T为元素类型
n1,n2都是int类型的表达式,可包含变量sort(a+n1,a+n2);
将数组中下标范围为[n1,n2)的元素从小到大排序sort(a+n1,a+n2,greater<T>()) ;
将数组中下标范围为[n1,n2)的元素从大到小排序sort(a+n1,a+n2,Rule());
Rule为排序规则结构名
将T类型的数组中下标范围为[n1,n2)的元素按照自定义的排序规则排序
排序规则结构的定义方式:
1)
用例:对数组a前10个元素排序
sort(a,a+10,Rule());
struct Rule{
bool operator()(const T & a1,const T & a2) const
{
return ;
}
} ;
struct Rule1{ //按从大到小排序
bool operator()(const int & a1,const int & a2) const
{
return a1>a2;
}
} ;
struct Rule2{ //按个位数从小到大排序
bool operator()(const int & a1,const int & a2) const
{
return a1%10 < a2%10;
}
} ;
2)
用例:对数组a前10个元素排序
sort(a,a+10,Rule);
bool Rule( 参数列表 )
{
return ;
}
bool Rule(int x,int y) //从大到小排序
{
return x>y;
}
bool cmp(int a,int b) //按照正整数各位数字和从小到大排序
{
int suma=0,sumb=0;
while(a)
{
suma+=a%10;
a/=10;
}
while(b)
{
sumb+=b%10;
b/=10;
}
if(suma==sumb)
return a<b;
else
return suma<sumb;
}
用法代码呈现:
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double EPSILON=1e-6;
double num[105];
bool cmp(double a,double b)
{
double da=fabs(a-round(a));
double db=fabs(b-round(b));
if(fabs(da-db)<EPSILON)
return a<b;
return da<db;
}
int main()
{
int N;
scanf("%d",&N);
for(int i=0;i<N;++i)
scanf("%lf",&num[i]);
sort(num,num+N,cmp);
for(int i=0;i<N;++i)
{
if(i!=N-1)
printf("%lf ",num[i]);
else
printf("%lf\n",num[i]);
}
return 0;
}
二、二分查找法
binary_search、lower_bound、upper_bound
find(x):在排序容器中找一个元素y,“x必须在y前面”和“y必须在x前面”都不成立
find(x):在排序容器中找一个元素y,“x必须在y前面”和“y必须在x前面”都不成立
find(x):在排序容器中找一个元素y,“x必须在y前面”和“y必须在x前面”都不成立a为数组a[]
T为元素类型
n1,n2都是int类型的表达式,可包含变量
number为要查找的数
Rule为自定义排序规则
binary_search(a+n1,a+n2,number)
在从小到大排好序的基本类型数组上进行二分查找
在下标范围为[n1,n2)的数组中查找“等于”number的元素
返回值为true或false
binary_search(a+n1,a+n2,number,Rule())
在用自定义排序规则排好序的,元素为任意的T类型数组上进行二分查找
在下标范围为[n1,n2)的数组中查找“等于”number的元素
返回值为true或false
lower_bound(a+n1,a+n2,number)
T *lower_bound(a+n1,a+n2,number)
在对元素类型为T的从小到大排好序的基本类型的数组中进行查找
返回指针T *p
*p是查找区间里下标最小的,大于等于“number”的元素。如果找不到,p指向下标为n2的元素
lower_bound(a+n1,a+n2,number,Rule())
T *lower_bound(a+n1,a+n2,number,Rule())
在元素类型任意的T类型、按照自定义排序规则排好序的数组中进行查找
返回指针T *p
*p是查找区间里下标最小的,按自定义排序规则,可以排在“number”后面的的元素。如果找不到,p指向下标为n2的元素
upper_bound(a+n1,a+n2,number)
T *upper_bound(a+n1,a+n2,number)
在对元素类型为T的从小到大排好序的基本类型的数组中进行查找
返回指针T *p
*p是查找区间里下标最小的,大于“number”的元素。如果找不到,p指向下标为n2的元素
upper_bound(a+n1,a+n2,number,Rule())
T *upper_bound(a+n1,a+n2,number,Rule())
在元素类型任意的T类型、按照自定义排序规则排好序的数组中进行查找
返回指针T *p
*p是查找区间里下标最小的,按自定义排序规则,必须排在“number”后面的的元素。如果找不到,p指向下标为n2的元素
三、排序容器:multiset、set
注意,在C++中遍历set是从小到大遍历的,也就是说set会帮我们排序
set经常会配合结构体来使用。set是需要经过排序的。系统自带的数据类型有默认的比较大小的规则,而我们自定义的结构体,系统是不知道这个结构体比较大小的方式,所以我们需要用一种方式来告诉系统如何比较这个结构体的大小。其中一种方法叫做运算符重载,我们需要重新定义小于号。
用法代码呈现:
/*
find(x):在排序容器中找一个元素y,“x必须在y前面”和“y必须在x前面”都不成立
find(x):在排序容器中找一个元素y,“x必须在y前面”和“y必须在x前面”都不成立
find(x):在排序容器中找一个元素y,“x必须在y前面”和“y必须在x前面”都不成立
*/
#include<iostream>
#include<cstring>
#include<set> //使用multiset和set需要此头文件
using namespace std;
int main()
{
multiset<int> st; //multiset中可以有重复元素
int a[10]={1,14,12,13,7,13,21,19,8,8};
for(int i=0;i<10;++i)
st.insert(a[i]); //插入的是a[i]的复制品
multiset<int>::iterator i;
/*
multiset<T>::iterator p;
迭代器,近似于指针,可用于指向multiset中的元素。
访问multiset中的元素要通过迭代器
multiset上的迭代器可++,--,用==和!=比较,不可比大小,加减整数、相减。
*/
for(i=st.begin();i!=st.end();++i)
cout<<*i<<",";
/*
multiset<T> st;
st.begin()返回值类型为multiset<T>::iterator,是指向st中头一个元素的迭代器
st.end()返回值类型为multiset<T>::iterator,是指向st中最后一个元素后面的迭代器
*/
cout<<endl;
i=st.find(22); //查找返回值为迭代器
if(i==st.end()) //找不到返回值为end()
cout<<"not found"<<endl;
st.insert(22);
i=st.find(22);
if(i==st.end())
cout<<"not found"<<endl;
else
cout<<"found:"<<*i<<endl; //找到返回指向找到元素的迭代器
i=st.lower_bound(13);
/*
1,7,8,8,12,13, 13,14,19,21
返回最靠后的迭代器it,使得[begin(),it)中的元素都在13前面
*/
cout<<*i<<endl; //输出13
i=st.upper_bound(8);
/*
1,7,8,8, 12,13,13,14,19,21
返回最靠前的迭代器it,使得[it,end())中的元素都在8后面
*/
cout<<*i<<endl; //输出12
st.erase(i); //删除迭代器i指向的元素,即12
for(i=st.begin();i!=st.end();++i)
cout<<*i<<",";
cout<<endl;
return 0;
}
#include<iostream>
#include<cstring>
#include<set>
using namespace std;
//自定义排序规则的multiset用法
struct Rule1
{
bool operator()(const int & a,const int & b) const
{
return (a%10)<(b%10);
}
};
int main()
{
multiset<int,greater<int> > st; //排序规则为从大到小
int a[10]={1,14,12,13,7,13,21,19,8,8};
for(int i=0;i<10;++i)
st.insert(a[i]);
multiset<int,greater<int> >::iterator i;
for(i=st.begin();i!=st.end();++i)
cout<<*i<<",";
cout<<endl;
multiset<int,Rule1> st2; //个位数小的排前面
for(int i=0;i<10;++i)
st2.insert(a[i]);
multiset<int,Rule1>::iterator p;
for(p=st2.begin();p!=st2.end();++p)
cout<<*p<<",";
cout<<endl;
p=st2.find(133);
cout<<*p<<endl; //输出13
return 0;
}
#include<iostream>
#include<cstring>
#include<set>
using namespacec std;
int main()
{
set<int> st;
int a[10]={1,2,3,8,7,7,5,6,8,12};
for(int i=0;i<10;++i)
st.insert(a[i]);
cout<<st.size()<<endl; //输出8
set<int>::interator i;
for(i=st.begin();i!=st.end();++i)
cout<<*i<<","; //输出1,2,3,5,6,7,8,12,
cout<<endl;
pair<set<int>::iterator,bool> result=st.insert(2);
/*
pair<T1,T2>类型等价于
struct{
TI first;
T2 second;
};
pair<set<int>::iterator,bool>等价于
struct{
set<int>::iterator first;
bool second;
};
*/
if(!result.second) //插入不成功,迭代器指向与要插入元素相同的元素
cout<<*result.first<<"already exists"<<endl;
else
cout<<*reslut.first<<"instered."<<endl;
return 0;
}
例题:蒜头君破案
问题描述:
最近某地连续发生了多起盗窃案件,根据监控和路人提供的线索得知,这是一个犯罪团伙.并且还知道这个犯罪团伙中每个人的身高、体重、年龄。
警察想知道这个犯罪团伙中的每个人是不是本市的(如果本市有这个特征的人就视为是本市的)。
但本市人口太多,又不能一个一个排查,警察又急需这条信息来缩小范围,所以誓察特来找到聪明的你来帮忙解决这个棘手的问题。
输入格式:
第一行将会输入两个数字n、m。n代表本市的人口数目,m 代表犯罪团伙的数量。
后面n行每行有3个数字代表本市每个人的身高、体重、年龄。
然后会有m行每行有3个数字代表犯罪团伙每个人的身高、体重、年龄。
#include<iostream>
#include<set>
using namespace std;
struct People{
int height;
int weight;
int age;
People(int _height,int _weight,int _age)
{
height=_height;
weight=_weight;
age=_age;
}
};
struct Rule{
bool operator()(const People & a1,const People & a2)const
{
if(a1.height!=a2.height)
return a1.height>a2.height;
else if(a1.weight!=a2.height)
return a1.weight>a2.weight;
else
return a1.age>a2.age;
}
};
set<People,Rule> s;
int main()
{
int n,m;
int height,weight,age;
cin>>n>>m;
for(int i=0;i<n;++i)
{
cin>>height>>weight>>age;
s.insert(People(height,weight,age));
}
for(int i=0;i<m;++i)
{
cin>>height>>weight>>age;
if(s.count(People(height,weight,age)))
cout<<"yes"<<endl;
else
cout<<"no"<<endl;
}
return 0;
}
四、排序容器:multimap、map
用法代码呈现:
/*
multimap
multimap容器中的元素,都是pair形式的
multimap<T1,T2> mp;
mp中的元素都是如下类型:
struct
{
T1 first; //关键字
T2 second; //值
};
multimap中的元素按照first排序,并可以按照first进行查找
*/
/*
一个学生成绩录入和查询系统 ,接受以下两种输入:
Add name id score
Query score
查询输出已有记录中分数比score低的最高分获得者的信息
如果有多个学生满足条件,输出学号最大的学生的信息
*/
#include<iostream>
#include<map>
#include<cstring>
using namespace std;
struct StudentInfo{
int id;
char name[20];
};
struct Student{
int score;
StudentInfo info;
};
typedef multimap<int,StudentInfo> MAP_STD;
int main()
{
MAP_STD mp;
Student st;
char cmd[20];
while(cin>>cmd)
{
if(cmd[0]=='A')
{
cin>>st.info.name>>st.info.id>>st.score;
mp.insert(make_pair(st.score,st.info));
/*
make_pair生成一个pair<int,StudentInfo>变量
其first等于st.score,second等于st.info
*/
}
else if(cmd[0]=='Q')
{
int score;
cin>>score;
MAP_STD::iterator p=mp.lower_bound(score);
//查找分数比score低的最高分
//[begin(),p)范围中每一个元素都是比score低的分数 ,p指向的元素分数不会比score低
if(p!=mp.begin())
{
--p;
score=p->first; //比要查询分数低的最高分
MAP_STD::iterator maxp=p;
int maxID=p->second.id;
for(;p!=mp.begin()&&p->first==score;--p) //遍历所有成绩和score相等的学生
{
if(p->second.id>maxID)
{
maxp=p;
maxID=p->second.id;
}
}
if(p->first==score)
//如果上面的循环是因为p==mp.begin()而终止,则p指向的元素还要处理
{
if(p->second.id>maxID)
{
maxp=p;
maxID=p->second.id;
}
}
cout<<maxp->second.name<<" "<<maxp->second.id<<" "<<maxp->first<<endl;
}//if(p!=mp.begin())
else
cout<<"Nobody"<<endl;
//lower_bound的结果就是begin,说明没人分数比查询分数低
}//else if(cmd[0]=='Q')
}//while(cin>>cmd)
return 0;
}
/*
map
map中不能有关键字重复的元素 重复:A和B都可以排在前面
可以使用[],下标为关键字,返回值为first和关键字相同的元素的second
插入元素可能失败
*/
#include<iostream>
#include<map>
#include<string>
using namespace std;
struct Student{
string name;
int score;
};
Student students[5]={{"jack",89},{"tom",74},{"cindy",87},{"alysa",87},{"micheal",98}};
typedef map<string,int> MP;
int main()
{
MP mp;
for(int i=0;i<5;++i)
mp.insert(make_pair(students[i].name,students[i].score));
cout<<mp["jack"]<<endl; //输出89
mp["jack"]=60; //修改名为“jack”的元素的second
for(MP::iterator i=mp.begin();i!=mp.end();++i)
cout<<"("<<i->first<<","<<i->second<<") ";
cout<<endl;
Student st;
st.name="jack";
st.score=99;
pair<MP::iterator,bool> p=mp.insert(make_pair(st.name,st.score));
if(p.second)
cout<<"("<<p.first->first<<","<<p.first->second<<") inserted"<<endl;
else
cout<<"insertion failed"<<endl;
mp["harry"]=78; //插入一元素,其first为"harry",然后将其second改为78
MP::iterator q=mp.find("harry");
cout<<"("<<q->first<<","<<q->second<<")"<<endl;
return 0;
}
/*
输入大量单词,每个单词一行,不超过20个字符,没有空格。
按出现次数从多到少输出这些单词及其出现次数
出现次数相同的,字典序靠前的在前面
*/
#include<iostream>
#include<map>
#include<set>
#include<string>
using namespace std;
struct Word{
int times;
string wd;
};
struct Rule{
bool operator()(const Word & w1,const Word & w2)const
{
if(w1.times!=w2.times)
return w1.times>w2.times;
else
return w1.wd<w2.wd;
}
};
int main()
{
string s;
set<Word,Rule> st;
map<string,int> mp;
while(cin>>s)
++mp[s]; //mp[]返回元素second
for(map<string,int>::iterator i=mp.begin();i!=mp.end();++i)
{
Word tmp;
tmp.wd=i->first;
tmp.times=i->second;
st.insert(tmp);
}
for(set<Word,Rule>::iterator i=st.begin();i!=st.end();++i)
cout<<i->wd<<" "<<i->times<<endl;
return 0;
}
map又二维的用法:二维的map不仅可以map套map,还能map套set:
五、queue
queue的头文件:#include<queue>
queue的基本操作:
1.入队:如q.push(x):将x元素接到队列的末端;
2.出队:如q.pop() 弹出队列的第一个元素,并不会返回元素的值;
3,访问队首元素:如q.front()
4,访问队尾元素:如q.back();
5,访问队中的元素个数:如q.size();
6.判断队列是否为空:q.empty()
六、vector
动态数组(不定长数组)vector:数组的长度根据需要动态改变
vector的头文件#include<vector>vector<T> vec 定义了一个名为vec的存储T类型数据的动态数组 初始时vec是空的
C++通过push_back()方法在数组最后面插入一个新的元素 vec.push_back();
C++通过pop_back()方法删除动态数组的最后一个元素 vec.pop_back();
C++通过clear()方法清空vector,但并不会清空开的内存 vec.clear();
C++通过 vector<int> v;
vector<int>().swap(v); 清空vector的内存vector<T> vec(a1,a2);
通过一个构造函数快速建立一个动态数组。(构造函数:在定义一个对象的时候给它赋予初始值)
上面的代码,调用构造函数,a1为初始的动态数组的长度,a2为初始数组中每个元素的值,如果不传入a2,那么初始的值都是0二维动态数组
vector< vector<int> > vec2;
二维动态数组的每一维的长度都可以不一样。
借助构造函数,快速构造一个n行m列的动态数组,每个元素的初始值是0:vector< vector<int> > vec2(n,vector<int>(m,0));
用例代码展示:
锯齿矩阵是指每一行包含的元素个数不同的矩阵
读入若干对整数(x,y),表示在第x行的末尾加上一个元素y。
输出最终的锯齿数组。初始时矩阵为空。
输入格式:
第一行输入两个整数n,m(1<=n,m<=10000),n表示锯齿数组的行数,m表示插入的元素总数
接下来一共m行,每行两个整数x,y(1<=x<=n,0<=y<=10000)
#include<iostream>
#include<vector>
using namespace std;
vector<int> mat[10005];
int main()
{
int n,m,x,y;
cin>>n>>m;
for(int i=0;i<m;++i)
{
cin>>x>>y;
mat[x].push_back(y);
}
for(int i=1;i<=n;++i)
{
for(int j=0;j<mat[i].size();++j)
{
if(j!=mat[i].size()-1)
cout<<mat[i][j]<<" ";
else
cout<<mat[i][j]<<endl;
}
cout<<endl;
}
return 0;
}