前两个周主要学习了STL的有关知识,对栈、队列和其他函数的简单了解可以使代码更加简洁并且极大的节省时间,下面是对各个知识点的简单总结及心得。
一、零碎知识
- 万能头文件
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);//让cin读取得更快
cin.tie(0);//解除cin和cout的绑定,加快执行效率
return 0;
}
- 宏定义
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define rep(i,a,n) for(int i=a;i<=n;i++) //相当于for循环
#define bp push_back //把push_back换个名字,写起来方便
- 其他
frecpen("in.txt","r",stdin);//输入方式转换为文件格式,当测试数据非常繁琐的时候,改变输入方式
const int inf=0x3f3f3f3f;//无穷大
typedef long long ll;//定义一种类型(此为长整型)
二、字符串(string)
string类型可以直接存储字符串,比字符数组方便,可以直接使用相加和删除等操作
#include <string>
#include<iostream>
using namespace std;
int main()
{
string s,s1,s2;
cin>>s;
getline(输入设备的名称,s);//可以输入空格
s1=s2;//用s2替换s1
s.size();//返回s中字符的个数
s.find();//在s中查找某个字符,并返回其下标
s2<|<=|>|>=|==|!= s1;//判断,返回true或false,按照字典顺序比较
cout<<s;//可以整体一起输出
return 0;
}
三、栈(stack)
栈的插入和删除只能在栈顶进行,所以每次删除的元素都是最后进栈的元素,栈的特征是先进后出,后进先出。
可以对序列实行一种返序操作
#include<iostream>
#include<stack>//头文件
using namespace std;
int main()
{
stack<类型>栈名;//定义栈
s.empty();//判断是否为空
s.size();//返回栈中元素个数
s.top();//返回栈顶元素
s.pop();//移除栈顶元素
s.push();//向栈顶压入元素,元素类型需一致
return 0;
}
四、队列和优先队列
队列,只能在前端(对头)进行删除操作,在后端(队尾)进行插入操作,是一种先进先出的数据结构
优先队列,自动排序的队列,元素被赋予优先级,元素在队尾添加,位权高的被放在第一位,即元素最大值一定在最前面,但不保证其他元素为降序
#include<iostream>
#include<queue>//队列和优先队列的头文件
using namespace std;
int main()
{
//相同之处
q.empty();//判断是否为空
q.size();//返回其中元素个数
q.pop();//删除第一个元素
q.push();//在队尾插入元素,类型需一致
//队列
queue<类型>队列名;//定义
q.front();//返回第一个元素
q.back();//返回队尾元素
//优先队列
priority_queue<类型>队列名;//定义
q.top();//返回队列的第一个元素
return 0;
}
- 非结构体,自动排序
- 结构体,可以通过重载小于号实现,或者重写比较函数cmp
//重载小于号写法
#include<iostream>
#include<queue>
using namespace std;
struct noon
{
int x,y;
bool operator < (const noon & a) const
{
return x<a.x;
}
};
int main()
{
priority_queue<结构体类型>队列名;//定义
return 0;
}
五、动态数组(vector)
vector可以解决越界问题,类似于数组,但是在访问元素的时候更加高效,在末尾添加和删除元素相对高效,功能多种多样。
#include<iostream>
#include<vector>//头文件
using namespace std;
int main()
{
vector<类型>名字;//定义一个向量
v.empty();//判断是否为空
v.size();//返回向量大小
v.clear();//清空向量元素
v.push_back();//将元素插入尾部
v.pop_back();//删除尾端元素
v.front();//返回第一个元素
v.back();//返回最后一个元素
v.insert(位置,数值);// 任意位置插入元素
v.erase();//任意位置删除元素
v.swap();//交换两个向量的元素
sort(v.begin(),v.end());//用sort排序
//遍历元素
for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
cout << *it << endl;
//或者
for (unsigned i = 0; i < vec.size(); i++)
cout << vec.at(i) << endl;//at可以检查是否越界,不用也可以
return 0;
}
六、函数
-
sort(排序,默认为从小到大)
已经用的很熟练了,不再多说了 -
rand (产生随机数,默认每次产生的随机数相同)
#include<iostream>
#include<cstdlib>//rand和srand所需的头文件
using namespace std;
int main()
{
a=rand();//它会返回一个从0到最大随机数的任意整数,最大随机数的大小通常是固定的一个大整数
a=rand()%n+b;//a的值为范围(b,n-1+b)内的随机一个整数,n是整数的范围大小
//另一种写法
a=rand%(x-y+1)+x;//表示x到y之间的数
stand(time(0));//接下来每次产生的随机数不同
return 0;
}
- unique (去重函数)
去除相邻的重复元素,并不是删除,而是移到容器末尾,用时一般先排序
数组和字符串均可用
#include<iostream>
#include<algorithm>//头文件
using namespace std;
int main()
{
//给出一个数组且排序后
int n=unique(第一个成立元素的地址,第一个不成立元素的地址)-第一个成立元素的地址;//得到去重后的元素个数
return 0;
}
- 全排列函数
#include<iostream>
#include<algorithm>//头文件
using namespace std;
int main()
{
//调用全排列函数,可执行则返回true,所无更大或更小则返回false
while(next_permutation(begin,end);//返回按照字典序排列的下一个值较大的组合
while(prev_permutation(begin,end);//返回按照字典序排列的下一个值较小的组合
//如果想产生n!个,也需要先排序
return 0;
}
- 二分查找函数
通常是排好序的序列,实行左闭右开原则
#include<iostream>
using namespace std;
int main()
{
int *a;
//这里的begin是第一个元素的位置,end是最后一个元素的下一个位置
//返回值为bool型
binary_search(begin,end,value); //找到则为真
//返回值为指针类型
lower_bound(begin,end,value);//返回>=value的第一个位置
upper_bound(begin,end,value);//返回>value的第一个位置
return 0;
}
七、set(关联容器,集合)
(默认按照从小到大的顺序排序)
可以随时往容器中插入元素,随时对元素进行快速查找,又可以按某种顺序对元素进行遍历
set与multiset的区别是multiset中的元素可以重复,使用multiset查找重复元素时,找到的是指定的第一个元素
#include<iostream>
#include<set>//头文件
using namespace std;
int main()
{
set/multiset<类型>名字;//定义
//如果想要按照自己的方式排序,可以重载运算符
s.insert(elem);//插入一个元素,并返回这个元素的位置
s.erase(elem);//移除与elem相等的所有元素,并返回删除的个数
s.erase(pos);//移除迭代器pos所指位置上的元素,无返回值
s.clear();//清空
s.find();//查找指定元素
s.count(elem);//返回值为elem的元素的个数
return 0;
}
八、map(关联容器,索引)
根据关键字排序
可以当做数组,比set简便,map中的元素是键值对,即由关键字和值组成一对(pair)
map中的元素是自动按关键字(key)升序排序,所以不能对map用sort函数,并且key值不可以修改
map只允许key与 value一一对应,并且不可以有重复元素; multimap一个key可对应多个value,且可以有重复元素;
#include<iostream>
#include<map>//头文件
using namespace std;
int main()
{
map<类型1,类型2>名字;//定义,且默认以类型1的值由小到大排序
m.size();//返回容器大小
m.empty();//清空容器
m.count(key);//返回键值等于key的元素的个数
m.lower_bound(key);//返回键值等于key的元素的第一个可安插的位置
m.upper_bound(key);//返回键值等于key的元素的个数最后一个可安插的位置
m.erase(key);//移除键值为key的所有元素,返回个数
m.erase(pos);//移除迭代器pos所指位置上的元素
m.find(key);//返回一个迭代器指向键值为key的元素,如果没找到就返回指向map尾部的迭代器。
m[key]=value;//查找的时候没有键值为key的元素,则安插一个键值为key的新元素,实值一般默认为0
//插入元素的三种方法
m.insert(map<类型1,类型2>::值的类型(a,b));//
m.insert(pair<类型1,类型2>(a,b));//
m.insert(make_pair(a,b));//
return 0;
}
小总结
- queue和vector的使用区别:
如果你需要高效的随即存取,而不在乎插入和删除的效率,使用vector
如果你需要随即存取,而且关心两端数据的插入和删除,则应使用deque,占用内存多 - set和vector的区别在于set不包含重复的数据。
- set和map的区别在于set只含有key,而map有一个key和key所对应的value两个元素。
- 只有vector和string可以直接用下标访问
- vector没有find函数,但算法中有此函数直接使用即可
- 栈与队列的相同点:
插入操作都是限定在表尾进行,插入与删除的时间复杂度是相同的,在空间复杂度上两者也一样。
栈与队列的不同点:
1.删除数据元素的位置不同,栈的删除操作在表尾进行,队列的删除操作在表头进行。2.应用场景不同;常见栈的应用场景包括括号问题的求解,表达式的转换和求值,函数调用和递归实现,深度优先搜索遍历等;常见的队列的应用场景包括计算机系统中各种资源的管理,消息缓冲器的管理和广度优先搜索遍历等。
心得
通过近期学习,了解了STL的相关体系,内容繁杂且细节性非常强,有的有相关性,它主要是为了简化代码,提高编程效率而存在的,我最喜欢用是其中一些函数,非常的简洁明了,现在也只是了解了一些皮毛,还是要多写代码来强化记忆