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