备战蓝桥杯从STL库开始—最简单的几个常用容器
1、STL库的介绍
学习C/C++语言的基础很简单,但是写写算法的能力不是人人都具备的,本人蒟蒻一枚,时常感觉算法的概念原理都懂,但就是写不出来东西,于是发现了一个“百宝箱”——STL(Standard Template Library,标准模板库)
一般分为algorithm(算法)、container(容器)和iterator(迭代器)三类。模板库内容主要包含了一些常用的算法如快速排序、简单查找等,当然还包括了一些常用的数据结构,如可变长数组、链表、字典等。
一般以它的高效著称。注解:打比赛return 0少不了!!!
2、基础知识
-
快速排序sort
sort排序是学习STL必须要知道的,内部算法结构是快速排序,不懂的同学可以先去了解一下快排的原理,毕竟手打快排也有可能在比赛场上需要。
#include<iostream> #include<algorithm> #include<cstdlib> using namespace std; int main(){ int a[10]; for(int i=0;i<10;i++){ a[i]=rand()%100;//存入十个随机数 } for(int i=0;i<10;i++){ cout<<a[i]<<" "; } cout<<endl; sort(a+0,a+10);//默认是从小到大排序 //其中第一个参数 代表数组的起始一个元素的位置,第二个参数代表数组最后一个元素的起始位置 //只要你愿意,你可以只排序一部分的数据试一试。 for(int i=0;i<10;i++){ cout<<a[i]<<" "; } //排序结果 }
那么如何从大到小排序呢?
其实sort方法有内置好的方法让你从大到小排序,在这里,我们讲一下如何自己写一个方法从大到小排序。
#include<iostream> #include<algorithm> #include<cstdlib> using namespace std; bool cmp(int x,int y){//这里的参数一定要是你排序类型的参数 return x>y;//从大到小排序 } int main(){ int a[10]; for(int i=0;i<10;i++){ a[i]=rand()%100;//存入十个随机数 } for(int i=0;i<10;i++){ cout<<a[i]<<" "; } cout<<endl; sort(a+0,a+10,cmp);//默认是从小到大排序 //其中第一个参数 代表数组的起始一个元素的位置,第二个参数代表数组最后一个元素的起始位置 //只要你愿意,你可以只排序一部分的数据试一试。 for(int i=0;i<10;i++){ cout<<a[i]<<" "; } //排序结果 }
![在这里插入图片描述](https://img-blog.csdnimg.cn/202104090001127.png)
一般sort排序是针对字典序进行排序,所以当你是字符串数组的时候也是可以进行排序的,这一点大家可以自行尝试。同时还支持double类型的排序,也可以尝试一下。
针对结构体数据也可以使用sort进行排序,我们以输入学生成绩进行排序为例子,每个学生都有3门课的成绩:语文、数学、英语。先按总分从高到低排序,如果两个同学总分相同,再按语文成绩从高到低排序,如果两个同学总分和语文成绩都相同,那么规定学号小的同学排在前面。
#include<iostream> #include<algorithm> using namespace std; int n; struct stu{ int num;//学号 int c,m,e;//三科成绩 int sum;//总分 }student[310];//定义学生的结构体类型 bool cmp(stu a,stu b){ if(a.sum>b.sum){ return a.sum>b.sum; }else if(a.sum<b.sum){ return 0; }else{ if(a.c>b.c){ return a.c>b.c; }else if(a.c<b.c){ return 0; }else{ return a.num < b.num; } } } int main(){ cin >> n; for(int i=1;i<=n;i++){ student[i].num=i; cin>>student[i].c>>student[i].m>>student[i].e; student[i].sum=student[i].c+student[i].m+student[i].e; } sort(student+1,student+n+1,cmp); for(int i=1;i<=5;i++) cout<<student[i].num<<' '<<student[i].sum<<endl; return 0; }
-
vector 向量容器
vector 向量容器是一种简单高效的容器,在尾端插入和删除元素,算法时间为O(1),其他元素插入和删除时间为O(n)。vector可动态调整所占用的内存空间。
在此之前导入**#include**
vector,T代表类型,类似于你定义数组的类型一样。
也被称为动态数组,当你做题目的时候如果遇到数组空间大小不确定的情况下,可以考虑使用它,同样也很高效,首先要了解它常用的几种方法。
-
如何存数据?
#include<iostream> #include<vector> using namespace std; int main(){ vector < int > v ; v.push_back(30); //此时是从尾端插入新元素 v.push_back(23); v.push_back(11); return 0; }
-
如何取数据
-
采取数组的方式读取数据
#include<iostream> #include<vector> using namespace std; int main(){ vector < int > v ; v.push_back(30); //此时是从尾端插入新元素 v.push_back(23); v.push_back(11); for(int i = 0 ; i < v.size() ; i++ ){ cout<<v[i]<<' '; } return 0; }
-
采取迭代器的方式读取数据
#include<iostream> #include<vector> using namespace std; int main(){ int j ; vector < int > v ; v.push_back (11) ; //尾插入新元素 v.push_back (23) ; // v.clear () ; //清空全部元素 v.push_back (30) ; v.push_back(1); v.push_back(16); v.insert ( v.begin() + 3 , 41 ) ; //插入41在第3个元素的后面 //一定要去动手验证一下结果 v.insert ( v.begin(), 15 ) ; //插入15为首元素 v.insert ( v.end(), 12 ) ; //插入12为末元素 v.erase ( v.begin() + 2) ; //删除第三个元素 v.erase ( v.begin() , v.begin() + 2 ) ; //删除前三个元素 //迭代器访问 vector < int > :: iterator i ; for( i=v.begin(),j=0;i!=v.end();i++,j++ ){//从头到尾来进行扫描 cout<<"v["<<j<<"]="<< *i <<endl;//*号必不可少 } swap(v[1],v[3]); //交换元素 for( i = v.begin() , j = 0 ; i != v.end() ; i++ , j++ ){ cout<<" v[ "<<j<<" ]= "<<*i<<endl; }//审查元素 cout<<v.empty()<<endl; //判断是否为空 cout<<v.size()<<endl; //元素实际个数 cout<<v.max_size()<<endl; //可容纳的最大元素个数 cout<<v.capacity()<<endl; //当前可容纳的最大元素个数 cout<<v.front()<<endl; //首元素引用 cout<<v.back()<<endl; //末元素引用 v.pop_back(); //删除末尾的一个元素 v.reserve(30); //调整数据空间大小 cout<<v.capacity()<<endl; vector < int > :: reverse_iterator re ; //反向迭代器 for( re = v.rbegin() ; re != v.rend() ; re++ ){ //转置方法 cout<<*ri<<endl; } return 0; }
-
-
结构体容器
#include<iostream> #include<vector> using namespace std; struct stu{ int x; int y; }; int main() { int j ; vector <stu> v1 ; //声明结构体容器 vector <stu> v2 ; struct stu a1={1,2}; struct stu a2={2,3}; struct stu a3={4,5} ; v1.push_back( a ); v1.push_back( b ); v1.push_back( c ); //压入数据 v2.push_back( c ); v2.push_back( b ); v2.push_back( a ); //读取出数据 for(int i=0; i<v1.size(); i++ ){ cout<<v1[i].x<<' '<<v1[i].y<<'\n'; } for(inti=0; i<v2.size(); i++ ){ cout<<v2[i].x<<' '<<v2[i].y<<'\n'; } swap(v1,v2); //两结构体元素交换 for(int i=0; i<v1.size(); i++ ){ cout<<v1[i].x<<' '<<v1[i].y<<'\n'; } for(inti=0; i<v2.size(); i++ ){ cout<<v2[i].x<<' '<<v2[i].y<<'\n'; } return 0; }
更多的vector 的使用,还得到实际的场景中去实际操作。
-
-
set容器
set集合容器使用一种红黑树的平均二叉检索树,不会将重复键值插入,检索使用二叉树的中序遍历,因此可以将元素从小到大排列出来。同时保证数据不重复,可以理解为集合中元素不重复一样
使用时注意包含头文件**#include**
1.set容器的常用操作
s.begin() 返回set容器的第一个元素 s.end() 返回set容器的最后一个元素 s.clear() 删除set容器中的所有的元素 s.empty() 判断set容器是否为空 s.insert() 插入一个元素 s.erase() 删除一个元素 s.size() 返回当前set容器中的元素个数
2.set容器的创建
#include <iostream> #include <set> using namespace std; int main(){ set<int> s; }
3.set容器的操作
//插入操作 #include <iostream> #include <set> using namespace std; int main(){ set<int >s; int cnt = 1; s.insert(1); s.insert(2); s.insert(5); for(set<int>::iterator it = s.begin(); it!= s.end(); it++) cout << *it << " "; s.insert(2); //set只允许用一个值出现一次,要插入相同元素请用multiset for(set<int>::iterator it = s.begin(); it!= s.end(); it++) cout << *it << " "; int a[4] = {11,12,13,14}; s.insert(a,a+4); //将区间[a, a+4]里的元素插入容器 for(set<int>::iterator it = s.begin(); it!= s.end(); it++) cout << *it << " "; return 0; } //删除操作 //s.erase() //删除一个元素 #include <iostream> #include <set> using namespace std; set<int >s; int main(){ int cnt = 1; for(int i = 1; i < 11; i++){ s.insert(i); } setprint(cnt++); s.erase(9); //根据元素删除 for(set<int>::iterator it = s.begin(); it!= s.end(); it++) cout << *it << " "; set<int>::iterator ita = s.begin(); set<int>::iterator itb = s.begin(); s.erase(ita); //删除迭代器指向位置的元素 for(set<int>::iterator it = s.begin(); it!= s.end(); it++) cout << *it << " "; ita = s.begin(); itb = s.begin(); itb++;itb++; s.erase(ita,itb); //删除区间[ita,itb)的元素 for(set<int>::iterator it = s.begin(); it!= s.end(); it++) cout << *it << " "; s.clear(); return 0; } //查找操作 //s.find() 查找一个元素,如果容器中不存在该元素,返回值等于s.end() #include <iostream> #include <set> using namespace std; set<int >s; int main(){ int cnt = 1; s.insert(1); s.insert(2); s.insert(5); for(set<int>::iterator it = s.begin(); it!= s.end(); it++) cout << *it << " "; if(s.find(2) != s.end()) cout << "2 is existent" << endl; else cout << "2 is non-existent" << endl; if(s.find(3) == s.end()) cout << "3 is non-existent" << endl; else cout << "2 is existent" << endl; return 0; } //判断元素是否在set中 & 判断set是否为空 #include <iostream> #include <set> #include <functional> using namespace std; int main(){ set<int > s; if(s.empty()) cout << "容器为空" << endl; s.insert(1); if(!s.empty()) cout << "容器不为空" << endl; if(s.count(1)) cout << "1在容器中" << endl; if(!s.count(2)) cout << "2不在容器中" << endl; return 0; } //自定义比较函数 #include <iostream> #include <set> #include <functional> using namespace std; struct cmp{ bool operator () (const int &a, const int &b){ return a > b; } }; set<int, cmp>s; //自定义排序函数构造set int main(){ s.insert(1); s.insert(2); s.insert(6); for(set<int,cmp>::iterator it = s.begin(); it!= s.end(); it++) cout << *it << " "; return 0; }
-
stack容器
stack,俗称为“栈”。可以先去了解一下栈结构再来看看。
由于栈是后进后出的数据结构,因此STL中的stack中只能通过top()来访问栈顶元素。用来模拟实现一些递归。(防止程序对栈内存的限制而导致程序运行错误)
一般来说,程序的栈内存空间很小,若用普通的函数来递归,一旦层数过深,则会导致程序运行崩溃。用栈来模拟递归算法的实现,则可以避免这一方面的问题.
导入前加入头文件#include
-
常见操作
empty:判断堆栈元素是否为空,true表示栈元素为空; pop:移除栈顶元素; push:栈顶添加元素; top:返回栈顶元素; size:返回栈中元素数目;
-
具体实现
#include<iostream> #include<stack> using namespace std; int main(){ stack<int> st; if(st.empty()==true){//输出Empty printf("Empty\n"); }else{ printf("Not Empty\n"); } for(int i = 1; i < 5; i++){ st.push(i); } printf("%d\n",st.top);//top()取栈顶元素,输出为5 printf("%d\n",st.size()); for(int i = 1; i < 5; i++){ st.pop(i); } printf("%d\n",st.top);//top()取栈顶元素,输出为5 printf%d\n",st.size()); }
-
-
queue容器
queue与stack模版非常类似,queue模版也需要定义两个模版参数,一个是元素类型,一个是容器类型,元素类型是必要的,容器类型是可选的,默认为dqueue类型。
队列的知识建议百度搜一下就懂了,提前知道什么是队列再看。
queue<int> q1; queue<double> q2;
-
基本操作
入队,如例:q.push(x); 将x 接到队列的末端。 出队,如例:q.pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。 访问队首元素,如例:q.front(),即最早被压入队列的元素。 访问队尾元素,如例:q.back(),即最后被压入队列的元素。 判断队列空,如例:q.empty(),当队列空时,返回true。 访问队列中的元素个数,如例:q.size()
-
具体实现
#include <cstdlib> #include <iostream> #include <queue> using namespace std; int main() { int e,n,m; queue<int> q1; for(int i=0;i<10;i++) q1.push(i); if(!q1.empty()) cout<<"dui lie bu kong\n"; n=q1.size(); cout<<n<<endl; m=q1.back(); cout<<m<<endl; for(int j=0;j<n;j++) { e=q1.front(); cout<<e<<" "; q1.pop(); } cout<<endl; if(q1.empty()) cout<<"dui lie bu kong\n"; system("PAUSE"); return 0; }
队列中还有很多知识,其中最重要的是优先队列,这个要花一些时间去理解,往后再说,同时利用优先队列做的题目也不再少数,很多都是搜索方面的题目,下一次一起拿一些题目一起单独聊聊优先队列和大小堆的知识点
-