参加竞赛你至少了解这些常用STL内置函数

 

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 aa<bb;
	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;
}

发布了23 篇原创文章 · 获赞 10 · 访问量 1758

猜你喜欢

转载自blog.csdn.net/weixin_45953673/article/details/104678289