在关于算法的竞赛题和面试题里面我们一般不手写数据结构(谁都不想为难自己),更不必怀疑大牛造的轮子,STL就这样成为了我们实现多快好省的利器
STL我们主要得掌握里面线程的数据结构和算法
算法
此时我们的头文件里应有#include<algorithm>#include<bits/stdc++.h>
sort
sort(首地址,末地址):从首地址到末地址前的所有元素(不含末地址对应的元素),时间复杂度为
int a[]={7,8,9,6,2,1};
sort(a+1,a+6);
for(int i=1;i<6;i++) printf("%d ",*(a+i));
// output:1 2 6 8 9(不另外调用排序规则,默认从小到大)
sort(a,a+6,less<int>())
for(int i=1;i<6;i++) printf("%d ",*(a+i));
// output:2 6 7 8 9
sort(a,a+6,greater<int>());
for(int i=1;i<6;i++) printf("%d ",*(a+i));
// output:9 8 7 6 2
struct 结构名
{
bool operator(const <T> &a1,const <T> &a2) const
{
//若a1在a2前面就return true
//否则返回false
}
}
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct Student
{
char name[10];
int id;
double gpa;
};
Student students []={{"Wang",7,98},{"Zhu",8,99},{"Yi",9,100}};
struct StudentRule
{
bool operator() (const Student &s1,const Student &s2) const
{
if(stricmp(s1.name,s2.name)) return true;
return false;
}
};
int main()
{
sort(students,students+3,StudentRule());
for(int i=0;i<3;i++)
printf("%s %d %lf\n",students[i].name,students[i].id,students[i].gpa);
//output:
Yi 9 100.000000
Zhu 8 99.000000
Wang 7 98.000000
return 0;
}
Binary Search
binary-search
binary_search(首地址,末地址,值),查询首地址到末地址前的所有元素是否存在等于值的元素(不含末地址对应的元素),使用之前必须保证该排序的范围所有元素有序,时间复杂度为
int a[]={4,15,7,8,9,3,2};
sort(a,a+7);
printf("%d",binary_search(a,a+7,9));
//output:1
lower_bound
T* lower_bound(首地址,末地址,值)查找从首地址到末地址前的元素下标最小的大于等于值的元素,如果没有则指向末地址
T* lower_bound(首地址,末地址,值,自定义排序规则结构名())查找自定义排序规则中下标最小的排在值后面的元素,如果没有则指向末地址
int a[]={4,15,7,8,9,9,11,3,16};
printf("%d ",sizeof(a)/sizeof(int));//output:9
sort(a,a+9);
printf("%d %d %d ",lower_bound(a,a+8,9)-a,lower_bound(a,a+7,16)-a,lower_bound(a,a+8,16)-a);//output:4 7 8
upper_bound
T* upper_bound(首地址,末地址,值)查找从首地址到末地址前的元素下标最小的大于值的元素,如果没有则指向末地址
T* upper_bound(首地址,末地址,值,自定义排序规则结构名())查找自定义排序规则中下标最小的排在值后面的元素,如果没有则指向末地址
int a[]={4,15,7,8,9,9,11,3,16};
sort(a,a+8);
printf("%d %d ",upper_bound(a,a+8,9)-a,upper_bound(a,a+8,15)-a);//output:6 8
#include<iostream>
#include<algorithm>
using namespace std;
struct Rule
{
bool operator() (const int &a1,const int &a2) const
{
return a1%10<a2%10;
}
};
int main()
{
int a[]={12,5,3,5,98,21,7};
sort(a,a+7,Rule());
for(int i=0;i<7;i++) printf("%d ",a[i]);//output:21 12 3 5 57 98
printf("%d %d ",lower_bound(a,a+7,16,Rule())-a,*lower_bound(a,a+7,16,Rule()));//output:5 7
printf("%d %d ",upper_bound(a,a+7,18,Rule())-a,*lower_bound(a,a+7,18,Rule()));// output:7 0
return 0;
}
数据结构
平衡二叉树
- 面对大量数据,我们需要用到平衡二叉树的数据结构,它能将增加,删除,查找操作的时间复杂度控制在
- 根据前文,好像可以用
sort排序+二分,可是当要增加和删除元素时,就要重新排序,最后时间复杂度为,显然是不可行的(接下来的操作更简单明了) - 此时我们的头文件里应有
#include<set>或#include<map> - 注意该结构中数据的地址都在
[start,end],因此end对应的元素不属于该数据结构,若使用find在该数据集中未找到某元素,则返回end
采用平衡二叉树结构的下列容器均被称为关联容器
set
- 往其中插入元素,可以根据给定规则进行排序,如果没有给定规则则按默认的小到大的顺序排序
- 不能有重复元素,因此可能插入元素不成功
#include<iostream>
#include<set>
using namespace std;
int main()
{
int a[10]={4,15,7,8,9,11,20,3,2,2};
set<int> st;
for(int i=0;i<10;i++) st.insert(a[i]);//插入的是a[i]的copy,即是a[i]的值
for(set<int>::iterator i=st.begin();i!=st.end();i++) printf("%d ",*i);//2 3 4 7 8 9 11 15 20 等价于for(auto it:st) printf("%d ",it);
st.insert(2);
pair<set<int>::iterator,bool> x=st.insert(2);//x.first指向插入元素,x.second表示是否成功插入
cout<<*x.first<<" "<<x.second;//2 0
st.erase(15);
for(auto it:st) printf("%d ",it);//output:2 3 4 7 8 9 11 20
printf("%d",st.end()==st.find(0));//output:1
return 0;
}
multiset
- 操作
set基础上允许出现重复元素
#include<iostream>
#include<set>
using namespace std;
struct Rule
{
bool operator() (const int &a,const int &b) const
{
return a%10<b%10;
}
};
int main()
{
int a[10]={4,15,7,8,9,11,20,3,2,2};
multiset<int,Rule> st;
for(int i=0;i<10;i++) st.insert(a[i]);
for(multiset<int,Rule>::iterator i=st.begin();i!=st.end();i++) printf("%d ",*i); //output:20 11 2 2 3 4 15 7 8 9
auto it=st.find(99);
printf("%d %d ",it==st.end(),*it);//output:0 9(此时find(x)是按照排序规则,找到y既不能排在x前,也不能排在x后)
it=st.find(6);
printf("%d",it==st.end());//output:1(找不到符合规则的位置)
st.clear();
return 0;
}
map
- 容器中的元素都是
pair类型,map<T1(key),T2(value)> mp - 默认情况下容器中的元素按照它们各自元素的
first排序,如果相同则比较second - 可根据元素的
first来查找 - 不允许出现重复的key相同的元素
//统计单词词频
#include<iostream>
#include<map>
#include<set>
#include<cstring>
using namespace std;
struct Word
{
int times;
string wd;
};
struct Rule
{
bool operator() (const Word &a,const Word &b) const
{
if(a.times!=b.times)
return a.times<b.times;
else
return a.wd<b.wd;
}
};
int main()
{
string s;
map<string,int> mp;
set<Word,Rule> st;
while(cin>>s)
{
mp[s]++;
}
/*input:
Guangdong
Guangdong
Guangdong
Winnerway
Winnerway
Champion
*/
for(auto it=mp.begin();it!=mp.end();it++)
{
Word tmp;
tmp.wd=it->first;
tmp.times=it->second;
st.insert(tmp);
}
for(auto it=st.begin();it!=st.end();it++)
cout<<it->wd<<" "<<it->times;
/*
Champion 1
Winnerway 2
Guangdong 3
*/
return 0;
}
multimap
- 在map的基础上允许出现相同
key的pair
制作一个学生成绩登分系统,记录学生name,id,score,可以根据指令进行操作,A:添加学生信息,Q:查询当前比该学生高的最低分,如果没有则输出“nobody”
#include<map>
#include<string>
#include<iostream>
using namespace std;
struct StuInfo
{
int id;
char name[10];
};
int main()
{
multimap<int,StuInfo> mp;
int op;
cin>>op;
while(op--)
{
string s;
cin>>s;
if(s=="A")
{
int score;
StuInfo stu;
cin>>stu.id>>stu.name>>score;
mp.insert(make_pair(score,stu));
}
8
/*input:
A 4 Du 94
A 8 Zhu 98
A 7 Wang 97
A 9 Yi 99
A 11 Zhou 95
A 2 Zhou 95
Q 94
Q 99
*/
else
{
int x;
cin>>x;
auto t=mp.upper_bound(x);
if(t!=mp.end())
{
int v=t->first;
for(auto it=t;it!=mp.end()&&it->first==v;it++)
{
printf("%d %s %d\n",it->second.id,it->second.name,it->first);
/*output:
11 Zhou 95
2 Zhou 95
Nobody
*/
}
}
else printf("Nobody\n");
}
}
return 0;
}