C++中STL库函数的基本运用
学了这么长时间的STL库,现在我觉得是有必要对过去的题目和所遇到的问题做一下整理了,以便于之后更好的展开练习:
一、 为什么要用STL库?
1、简单粗暴(省事)。
2、便于解决复杂的问题(在贪心题目中显而易见)。
3、使其思路更加广泛,解决问题的角度更多。
二、 怎么用STL库?
1、设身处地的利用某个函数的特点进行解决问题。(下面会进行介绍各个函数的特点)
2、做好第一点就足够了。
三、 各个函数的特点以及适合解决哪些问题?
1、 vector:
vector的强大之处就在于可以通过它完成建立邻接表,达到存图、存树的效果,之后利用DFS或者BFS的方式进行解决问题。
最短路(包括其优化)中也会用到Vector.
位置的不同也可以通过其进行存储:例如那道字符串的题目。
(一个键对应好几个不同的值时,选择这个会很合适)。
2、 set:
set集合的强大之处莫过于它的去重、排序。
尤其是去重,实在是十分之重要,当然,排序也很重要。
3、 map:
键值对:既一个键对应一个值(若要引用键或者值则需要迭代器)
迭代器:map<int,int>::iterator it;(遍历时也需要)
键:it->first,值:it->second;
Map会根据键的大小进行自动排序,当有相同元素出现时,用数组的方式的话并不会替代之前已经存在的键值,用insert的方式进行插入的时候会替代已经存在的键值。
4、 queue:
利用队列实现BFS是队列的一个强大功能。
单调队列也可以解决某些问题。
5、 stack
单调栈的应用极其广泛。
单调栈适合解决不可排序的一组数,用来简化时间复杂度。
利用某段数的单调性实现其效果。
6、 priority_queue:
优先级队列内部是通过堆进行实现的。
下面会进行详细介绍。
四:各个函数的相关实现及其属性和方法。
Vector:
1.push_back 在数组的最后添加一个数据
2.pop_back 去掉数组的最后一个数据
3.at 得到编号位置的数据
4.begin 得到数组头的指针
5.end 得到数组的最后一个单元+1的指针
6.front 得到数组头的引用
7.back 得到数组的最后一个单元的引用
8.max_size 得到vector最大可以是多大
9.capacity 当前vector分配的大小
10.size 当前使用数据的大小
11.resize 改变当前使用数据的大小,如果它比当前使用的大,者填充默认值
12.reserve 改变当前vecotr所分配空间的大小
13.erase 删除指针指向的数据项
14.clear 清空当前的vector
15.rbegin 将vector反转后的开始指针返回(其实就是原来的end-1)
16.rend 将vector反转构的结束指针返回(其实就是原来的begin-1)
17.empty 判断vector是否为空
18.swap 与另一个vector交换数据
3.2 详细的函数实现功能:其中vector<int> c.
c.clear() 移除容器中所有数据。
c.empty() 判断容器是否为空。
c.erase(pos) 删除pos位置的数据
c.erase(beg,end) 删除[beg,end)区间的数据
c.front() 传回第一个数据。
c.insert(pos,elem) 在pos位置插入一个elem拷贝
c.pop_back() 删除最后一个数据。
c.push_back(elem) 在尾部加入一个数据。
c.resize(num) 重新设置该容器的大小
c.size() 回容器中实际数据的个数。
c.begin() 返回指向容器第一个元素的迭代器
c.end() 返回指向容器最后一个元素的迭代器
set:
begin() 返回set容器的第一个迭代器
end() 返回set容器的最后一个迭代器
clear() 删除set容器中的所有的元素
empty() 判断set容器是否为空
max_size() 返回set容器可能包含的元素最大个数
size() 返回当前set容器中的元素个数
rbegin 返回的值和end()相同
rend() 返回的值和rbegin()相同
判断某个元素是否出现在set集合中的两种方法:
1、COUNT() 用来查找SET中某个某个键值出现的次数。这个函数在SET并不是很实用,因为一个键值在SET只可能出现0或1次,这样就变成了判断某一键值是否在SET出现过了。
示例代码:
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s;
s.insert(1);
s.insert(2);
s.insert(3);
s.insert(1);
cout<<"set 中 1 出现的次数是 :"<<s.count(1)<<endl;
cout<<"set 中 4 出现的次数是 :"<<s.count(4)<<endl;
return 0;
}
2、 FIND() ,返回给定值值得定位器,如果没找到则返回END()。
#include <iostream>
#include <set>
using namespace std;
int main() {
int a[] = {1,2,3};
set<int> s(a,a+3);
set<int>::iterator iter;
if((iter = s.find(2)) != s.end()) {
cout<<*iter<<endl;
}
return 0;
}
#Set中的删除操作:#
1、erase(iterator) ,删除定位器iterator指向的值
2、erase(first,second),删除定位器first和second之间的值
3、erase(key_value),删除键值key_value的值
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s;
set<int>::const_iterator iter;
set<int>::iterator first;
set<int>::iterator second;
for(int i = 1 ; i <= 10 ; ++i) {
s.insert(i);
} //第一种删除
s.erase(s.begin()); //第二种删除
first = s.begin();
second = s.begin();
second++;
second++;
s.erase(first,second); //第三种删除
s.erase(8);
cout<<"删除后 set 中元素是 :";
for(iter = s.begin() ; iter != s.end() ; ++iter) {
cout<<*iter<<" ";
}
cout<<endl;
return 0;
}
二分查找:
lower_bound(key_value) ,返回第一个大于等于key_value的定位器
upper_bound(key_value),返回最后一个大于等于key_value的定位器
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s;
s.insert(1);
s.insert(3);
s.insert(4);
cout<<*s.lower_bound(2)<<endl;
cout<<*s.lower_bound(3)<<endl;
cout<<*s.upper_bound(3)<<endl;
return 0;
}
Map:
begin() 返回指向map头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数
empty() 如果map为空则返回true
end() 返回指向map末尾的迭代
equal_range() 返回特殊条目的迭代器
erase() 删除一个元素
find() 查找一个元素
get_allocator() 返回map的配置器
insert() 插入元素
key_comp() 返回比较元素key的函数
lower_bound() 返回键值>=给定元素的第一个位置
max_size() 返回可以容纳的最大元素个数
rbegin() 返回一个指向map尾部的逆向迭代器
rend() 返回一个指向map头部的逆向迭代器
size() 返回map中元素的个数
swap() 交换两个map
upper_bound() 返回键值>给定元素的第一个位置
value_comp() 返回比较元素value的函数
Queue:
back()返回最后一个元素
empty()如果队列空则返回真
front()返回第一个元素
pop()删除第一个元素
push()在末尾加入一个元素
size()返回队列中元素的个数
访问:
q.front(),即最早被压入队列的元素。
q.back(),即最后被压入队列的元素。
Privority_queue:
入队 q.push();
出队 q.pop();
求队列中元素个数 q.size();
判断队列是否为空 q.empty();若为空返回true,否则返回false
获得首元素 q.top();
返回q的第一个元素 q.top();
返回q的末尾元素 q.back();
优先级里最重要的东西:排序:
默认的优先队列 priority_queue <int> q;排序是由大到小的:
#include<stdio.h>
#include<queue>
using namespace std;
int main()
{
priority_queue<int> q;
int num[5]={19,2,4,3,6};
for(int i=0;i<5;i++)
q.push(num[i]);
for(int i=0;i<5;i++)
{
int temp=q.top();
printf("%d ",temp);
q.pop();
}
return 0;
}
默认的优先队列(结构体,重载小于)
#include<stdio.h>
#include<queue>
using namespace std;
struct node
{
int x,y;
bool operator < (const node & a) const {
return x<a.x;
}
}s;
struct node
{
int x;
int y;
int time;
friend bool operator < (node n1, node n2) // 也可以用友元函数friend
{
return n1.time>n2.time;
}
};
priority_queue <node> q;
int main()
{
printf("读入:\n");
for(int i=0;i<5;i++)
{
scanf("%d%d",&s.x,&s.y);
q.push(s);
}
printf("输出:\n");
while(!q.empty())
{
node temp=q.top();
printf("(%d,%d) ",temp.x,temp.y);
q.pop();
}
return 0;
}
less是从大到小,greater是从小到大:
//升序队列
priority_queue <int,vector<int>,greater<int> > q;
//降序队列
priority_queue <int,vector<int>,less<int> >q;
//greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)
优先级与结构体:
#include <iostream>
#include <queue>
using namespace std;
struct Node{
int x, y;
Node(int a=0, int b=0):
x(a),y(b){}
};
bool operator<(Node a, Node b){//返回true时,说明a的优先级低于b
//x值较大的Node优先级低(x小的Node排在队前)
//x相等时,y大的优先级低(y小的Node排在队前)
if( a.x== b.x ) return a.y< b.y; //优先级队列中的结构体与之前的覆写函数有些许的不同,< 代表从大的先出队
return a.x< b.x;
}
int main(){
priority_queue<Node> q;
for( int i= 0; i< 5; ++i ){
int a,b;
scanf("%d%d",&a,&b);
q.push({a,b});
}
while( !q.empty() ){
cout << q.top().x << ' ' << q.top().y << endl;
q.pop();
}
return 0;
}
Stack:
入栈,如例:s.push(x);
出栈,如例:s.pop();注意,出栈操作只是删除栈顶元素,并不返回该元素。
访问栈顶,如例:s.top()
判断栈空,如例:s.empty() ,当栈空时,返回true。
访问栈中的元素个数,如例:s.size() 。
如果说年轻人未来是一场盛宴的话,那么我首先要有赴宴的资格。