内容参考书籍《算法笔记》
1.vector
在一些用普通数组可能会超内存的情况下,可以选择用vector来存储数据,vector可以理解为“长度可以根据需要改变的数组”。并且用vector比较节省空间。
使用vector,需要添加头文件#include<vector> , 而且还得在头文件下面加上using namespace std;
(1). vector的定义
vector<typename> name; //单独定义一个vector ,相当于一维数组name[SIZE]. typename表示数据类型
vector<vector<int> > //如果typename也是一个STL容器,定义的时候记得在>>符号之间加上空格,因为c++11之前标准的编译器会把它视为移位操作。
vector<typename> v[SIZE]; //vector数组的定义,v[0]~v[SIZE - 1]中每一个都是一个vector容器
(2).元素的访问
一般有两种访问方式 :通过下标访问或者通过迭代器访问。
通过下标访问 : 和普通数组一样。
通过迭代器访问 : 迭代器(iterator)可以理解为一种类似指针的东西。其定义是:vector<typename>::iterator it;
这样it就是迭代器,并且可以用*it来访问vector里的元素
如:
for(int i = 0 ; i < 5 ;i ++ ) printf("%d", *(it + i));
(3).vector 的常用函数分析
push_back() //在vector后面添加一个元素,如push_back(x); 时间复杂度是O(1)。
pop_back() //删除vector的尾元素。 时间复杂度是O(1)。
size() //获取vector中元素个数,时间复杂度O(1)。
clear() //清空vector中的所有元素,时间复杂度是O(N),N是vector中元素的个数。
如:
#include<iostream>
using namespace std;
int main(){
vector<int>v;
for(int i = 1 ; i <= 3 ; i++) vi.push_back(i);
vi.clear();
cout << vi.size();
return 0;
}
输出结果:0
insert() // insert(it , x) 用来向vector的任意迭代器it处插入一个元素x,时间复杂度O(N)。
erase() //有两种用法:删除单个元素、删除一个区间内的所有元素。时间复杂度都为O(N)。
erase (it) // 删除迭代器为it处的元素。
erase (first , last) // 删除[first , last)内的所有元素
(4).vector常见用途
1.作为数组
2.用邻接表存储图
例题:http://acm.hdu.edu.cn/showproblem.php?pid=4841
AC代码:
#include<iostream>
#include<vector>
using namespace std;
int n , m ;
vector<int>v;
const int N = 1e6 + 10;
int res[N];
int main(){
while(cin >> n >> m){
memset(res,1,sizeof(res));
v.clear();
for(int i = 0 ; i < 2*n ; i++)
v.push_back(i);
for(int i = 0 ,pos = 0 , num = 2 * n ; i< n ;i++){
pos = (pos + m - 1) % num ;
num --;
res[v[pos]] = 0;
v.erase(v.begin() + pos);
}
for(int i = 0 ; i< 2 * n;i++){
if((i%50 == 0) && (i != 0)) printf("
");
if(res[i]) printf("G");
else printf("B");
}
printf("
");
}
return 0;
}
2.stack
后进先出。#include<stack>并且用using namespace std;
(1)在STL中栈只能通过top()来访问栈顶元素
(2)常用函数
push(x) //将x入栈,时间复杂度O(1)
top() //获得栈顶元素,时间复杂度O(1)
pop() //弹出栈顶元素,时间复杂度O(1)
empty() //检测栈是否为空,返回true为空,返回false为非空,时间复杂度O(1)
size() //返回栈中元素个数,时间复杂度O(1)
(3)常见用途
可以用栈来模拟实现一些递归算法,应用于DFS
例题:http://acm.hdu.edu.cn/showproblem.php?pid=1237
AC代码:
#include<iostream>
#include<stack>
using namespace std;
int n;
char c;
int main(){
scanf("%d",&n);
getchar();
while(n --){
stack<char>s;
while(1){
c = getchar();
if(c==' '||c=='
'||c==EOF){
while(!s.empty()){
printf("%c",s.top());
s.pop();
}
if(c=='
'||c==EOF)break;
printf(" ");
}
else
s.push(c);
}
printf("
");
}
return 0;
}
3.queue 先进先出
(1)在STL中只能通过front()来访问队首元素,或是通过back()来访问队尾元素。
(2)常用函数
push(x) //将x进行入队,时间复杂度为O(1)
front()、 back() //分别获得队首元素和队尾元素,时间复杂度为O(1)
pop() //令队首元素出队,时间复杂度为O(1)
empty() //检测队列是否为空,返回true为空,返回false为非空,时间复杂度O(1)
size() //返回栈中元素个数,时间复杂度O(1)
(3)常见用途
当需要实现BFS时,可以不用自己动手实现一个队列,而是用queue代替。
例题:http://acm.hdu.edu.cn/showproblem.php?pid=1702
#include<iostream>
#include<stack>
#include<queue>
#include<string>
using namespace std;
int t; //次数
int main(){
cin >> t;
while(t --){
stack<int> P;
queue<int> Q;
string s , s1;
int n;
int d;
scanf("%d",&n);
cin >> s ;
if(s == "FIFO"){
for(int i = 0; i<n;i++){
cin >> s1;
if(s1 == "IN"){
scanf("%d",&d);
Q.push(d);
}
if(s1 == "OUT"){
if(Q.empty()) printf("None
");
else{
cout << Q.front() << endl;
Q.pop();
}
}
}
}
if(s == "FILO"){
for(int i = 0; i<n;i++){
cin >> s1;
if(s1 == "IN"){
scanf("%d",&d);
P.push(d);
}
if(s1 == "OUT"){
if(P.empty()) printf("None
");
else{
cout << P.top() << endl;
P.pop();
}
}
}
}
}
return 0 ;
}
4.priority_queue 优先队列
队首元素一定是当前队列中优先级最高的那个。和队列不一样的是优先队列没有front()和back()函数,只能通过top()函数来访问队首元素。
(1)常用函数
push(x) //将x入队,时间复杂度为O(logN),N为当前优先队列中的元素个数。
top() //获得队首元素,时间复杂度O(1)
pop() //令队首元素出队,时间复杂度为O(logN),N为当前优先队列中的元素个数。
empty() //检测优先队列是否为空,返回true则空,返回false则非空,时间复杂度O(1)。
size() //返回队列中元素的个数,时间复杂度O(1)。
(2)priority_queue内元素优先级设置
1.基本数据类型的优先级设置
优先队列对它们的优先级设置一般是数字大的优先级越高。如果是char型,则是字典序最大的。对基本数据类型来说下面两种是等价的:
1.priority_queue<int> q;
2.priority_queue<int , vector<int> , less<int > > q; //less<int>表示数字大的优先级越大,而greater<int>表示数字小的优先级越大。
2.结构体优先级设置
如: struct fruit{
string name;
int price;
friend bool operator < (fruit f1 , fruit f2){
return f1.price < f2.price;
}
}
表示对操作符“<”进行了重载(重载大于号会编译错误,因为从数学上来说只需要重载小于号,即f1 > f2 等价于判断f2 < f1 , 而f1 == f2 等价于判断!(f1 < f2) && !(f2 < f1) )
重载后小于号还是小于号的作用,此时内部就是以价格高的水果优先级高。
同理,如果想以价格低的水果优先级高,只需要把return中的小于号改为大于号,即:
struct fruit{
string name;
int price;
friend bool operator < (fruit f1 , fruit f2){
return f1.price > f2.price; //把小于号重载为大于号
}
}
最后,如果结构体内数据较为庞大,建议使用引用来提高效率,此时比较类的参数中需要加上“const”和“&”如:
struct fruit{
string name;
int price;
friend bool operator < (const fruit &f1 ,const fruit &f2){
return f1.price > f2.price; //把小于号重载为大于号
}
}
3.priority_queue的常见用途
可以解决一些贪心问题,也可以对Dijkstra算法进行优化(因为优先队列的本质是堆)。
有一点需要注意,使用top()函数前,必须要empty()判断队列是否为空,否则可能因为队空而出现错误。
例题:http://acm.hdu.edu.cn/showproblem.php?pid=1873
AC代码:
#include<iostream>
#include<queue>
#include<string>
using namespace std;
struct node{
int id ;
int yxj ;
friend bool operator < (const node &a,const node &b){ //保证B的优先级大于A
if(a.yxj == b.yxj) return a.id > b.id;
return a.yxj < b.yxj;
}
}N[1010];
priority_queue<node> doctor1;
priority_queue<node> doctor2;
priority_queue<node> doctor3;
int main(){
int t , n , i , k;
string s;
while(scanf("%d",&n) != EOF){
k = 1 ;
for( i = 0 ; i < n ;i++){
cin >> s;
if(s == "IN"){
N[i].id = k++;
scanf("%d%d",&t,&N[i].yxj) ;
if(t == 1) doctor1.push(N[i]);
else if(t == 2)doctor2.push(N[i]);
else if(t == 3)doctor3.push(N[i]);
}
else if(s == "OUT"){
scanf("%d",&t);
if(t == 1){
if(doctor1.empty()) cout<<"EMPTY"<<endl;
else{
cout << doctor1.top().id << endl;
doctor1.pop();
}
}
else if(t == 2){
if(doctor2.empty()) cout<<"EMPTY"<<endl;
else{
cout << doctor2.top().id << endl;
doctor2.pop();
}
}
else if(t == 3){
if(doctor3.empty()) cout<<"EMPTY"<<endl;
else{
cout << doctor3.top().id << endl;
doctor3.pop();
}
}
}
}
}
return 0;
}
5.list
链表,高效率地在任意地方删除和插入,常数时间。
常用操作与vector类似。
例题:http://acm.hdu.edu.cn/showproblem.php?pid=1276
AC代码:
#include<iostream>
#include<list>
using namespace std;
int main()
{
int t,n;
cin>>t;
while(t --)
{
cin >> n;
int k = 2;
list<int> l;
list<int>::iterator it;
for (int i = 1; i <= n; ++ i) l.push_back(i);
while(l.size() > 3)
{
int num = 1;
for (it = l.begin();it != l.end();)
{
if(num++ % k == 0) it = l.erase(it); //该试结束后返回的是被删除元素的下一个元素的迭代器
else it++;
}
k == 2?k = 3:k = 2;
}
for (it = l.begin();it != l.end();it++){
if(it != l.begin()) cout<<" ";
cout<<*it;
}
cout<<endl;
}
return 0;
}
6.set
1.set的定义
翻译为集合,是一个内部自动有序且不含重复元素的容器。set自动递增排序且自动去除了重复元素。需要用头文件#include<set> 和using namespace std;
2.元素的访问
set只能通过迭代器iterator访问
3.常用函数
1.insert(x) //将x插入到set中,并自动递增排序和去重,时间复杂度为O(logN)
2.find(value) //返回set中对应值为value的迭代器,时间复杂度O(logN)
3.erase() //同vector 1.s.erase(it) //it为删除元素的迭代器,时间复杂度O(1)
2.s.erase(value) //value是删除元素的值。时间复杂度O(logN)
4.size()
5.clear() //时间复杂度O(N) N为元素个数
例题:http://acm.hdu.edu.cn/showproblem.php?pid=2094
AC代码:
#include <iostream>
#include<set>
using namespace std;
int main()
{
set<string>a,b; //a存比赛人名,b存失败人名
string s1,s2;
int n;
while(cin >> n && n)
{
for (int i = 0; i < n; ++i)
{
cin>>s1>>s2;
a.insert(s1);
a.insert(s2);
b.insert(s2);
}
if (a.size()-b.size()==1) cout<<"Yes"<<endl; //如果参赛人数比失败人数多一,那么比赛有一个人没失败,则必然是冠军
else cout<<"No"<<endl;
a.clear();b.clear();
}
return 0;
}
7.map
map翻译为映射,定义int a[100]数组时,实际上是定义了一个int型到int型的数组,如a[0] = 25,是将0映射到25.
如果要用数组来表示“字符串->页码”这样的对应关系,就可以用到map。
map可以将任何基本类型(包括STL容器)映射到任何基本类型(包括STL容器)。
1.map的定义
需用到#include<map>;和using namespace std;
map<typename1 , typename2> mp; 实现从映射前类型 键(key)到映射后类型 值(value)的映射。
如果是字符串到整形的映射,必须用string而不能用char数组。
2.map容器内元素的访问
1.通过下标访问
和访问普通数组一样,如对一个定义为map<char , int> mp的map来说 ,就可以直接mp['c'] = 20来访问20。键是唯一的。
2.通过迭代器访问
map迭代器的定义: map<typename1 , typename2>::iterator it;
map迭代器是使用方式和其他STL容器不同,因为map的每一对映射都有两个typename,这就决定了必须能通过一个it来同时访问键和值。所以可以用it->first来访问键,it->second来访问值。
map会以键从小到大的顺序自动排序,这点和set一样
3.常用函数
1.find(key) //返回键为key的映射的迭代器,时间复杂度为O(logN).
2.erase()
1.删除单个元素
mp.erase(it),it为需要删除的元素的迭代器,时间复杂度O(1)
mp.erase(key) , key为想要删除的映射的键,时间复杂度O(logN)
2.删除一个区间内的所有元素
mp.erase(first , last),其中first是需要删除区间的歧视迭代器,last是需要删除的区间的末尾迭代器的下一个迭代器,也是左闭右开。时间复杂度O(last - first)
3.size() //映射对数
4.clear() //清空map中的所有元素,时间复杂度O(logN)
例题:http://acm.hdu.edu.cn/showproblem.php?pid=2648
AC代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,m,p;
map<string,int> shop;
while(cin>>n)
{
string s;
for (int i = 0; i < n; ++i) cin>>s;
cin>>m;
while(m--)
{
for (int i = 0; i < n; ++i)
{
cin>>p>>s;
shop[s]+=p;
}
int rank = 1;
map<string,int>::iterator it;
for (it=shop.begin();it != shop.end(); ++it) if(it->second>shop["memory"]) rank++;
cout<<rank<<endl;
}
shop.clear();
}
return 0;
}
8.sort()
排序函数
定义形式
sort(首元素地址(必填),尾元素地址的下一个地址(必填),比较函数(非必填)) //默认为递增排序
比较函数写法:1.基本数据类型的排序 , 例子,实现递减排序。
bool cmp(int a, int b){
return a > b; //可以理解为当a > b时把a放在前面
}
2.结构体数组的排序。
也是写一个比较函数,来规定按怎样的形式排序。
3.容器的排序
和基本数据类型的数组的写法大同小异。
9.next_permutation()
给出一个序列在全排列中的下一个序列。
例题:求全排列
int main(){
int a[3] = {1 , 3 , 2};
sort(a, a+ 3);
do{
for(int i = 0 ; i<3 ; i++){
printf("%d",i);
printf("
");
}
}while(next_permutation(a , a + 3));
return 0;
}
啊啊啊啊啊啊阿,可算写完了,希望对大家有帮助,对自己有帮助!!!