栈、队列与优先队列
新学了一下紫书上的三个例题(=。=自己完全不会编啊),
主要讲栈、队列与优先队列。
1.栈
栈是一种符合“后进先出”规则的数据结构,有PUSH和POP两种操作,其中PUSH把元素压如“栈顶”,而pop从栈顶把元素弹出。
头文件<stack>
;
定义:stack<int> s
声明了一个栈,
栈的操作函数:
入栈s.push()
出栈s.pop()
取栈顶元素s.top()
相关题目:UVA12096-5.5-集合栈计算机
链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=835&page=show_problem&problem=3248
这个题就是各种栈操作,不过放入栈的是集合。
=。=集合套集合
题目分析:
首先是要学习两个函数:
(1).set_union (first, first+5, second, second+5, v.begin());
作用:将多个集合合并成没有交集的集合。
大概就是求两个集合的“并集减去交集”
函数元素:集合A首地址,尾地址
集合B首地址,尾地址
(2).set_intersection()
作用:实现求集合A,B交集。
函数元素:集合A首地址,尾地址
集合B首地址,尾地址
然后是整体这个题的思路:
一个很重要的地方就是给集合进行标记:
typedef set<int> Set //小技巧,减少需要输入的代码=。=
map<Set,int> IDcache;
vector<Set> Setchache;
int ID (Set x)
{
if(IDcache.count(x))
return IDcache[x];
Setcache.push_back(x);
return IDcache[x]=Setchache.size()-1;
}
这便是给集合进行标记的函数,主函数传入一个集合,首先判断这个集合是否标过了,通过IDcache.count(x)
进行查找,如果已经被标记,返回这个集合的标记数字,如果没有,将这个集合加入vector容器,并加入一个标记,并返回这个标记。
代码通使用映射map使得每个集合都可以有对应的标记。
然后书上用了一个很好玩的东西,宏定义来减少重复代码(=。=我怎么就想不到呢)
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin()
这样就可以不用写长长的代码了。
然后是主函数
int main()
{
int n;
cin>>n;
while(n--)
{
int m;
cin>>m;
for(int i=0;i<m;i++)
{
string op;
cin>>op;
if(op[0]=='P') s.push(ID(Set()));
else if(op[0]=='D') s.push(s.top());
else
{
Set x1=Setcache[s.top()];s.pop();
Set x2=Setcache[s.top()];s.pop();
Set x;
if(op[0]=='U') set_union(ALL(x1),ALL(x2),INS(x));
if(op[0]=='I') set_intersection(ALL(x1),ALL(x2),INS(x));
if(op[0]=='A') {x=x2;x.insert(ID(x1));}
s.push(ID(x));
}
cout<<Setcache[s.top()].size()<<endl;
}
cout<<"***"<<endl;
}
return 0;
}
主要就是熟悉栈的操作,可惜我现在还是迷迷糊糊的。=、=
2.队列与优先队列
队列是符合“先进先出”规则(就像食堂排队一样)的一种数据结构,
而优先队列有些特殊,不止是先进先出,而且还有优先级。
头文件:<queue>
队列的操作函数:
queue<int> q;
q.push(x);//加入队列
int t=q.front();//返回队首元素,但是不弹出队列
q.pop();//首元素弹出队列
在STL的库里面,还有对于优先队列的模板(大概是叫模板?)
声明方式:priority_queue<int> q
这是一个“越小的整数优先级越低的优先队列”。
由于出队元素并不是先进队的元素,所以取将要出队元素的办法由queue的front()变成了top()。
自定义类型也可以组成优先队列,但必须为每个元素定义一个优先级。这个优先级并需要一个确定的数字,只需要能比较大小就可以。
就像是C/C++里面的sort函数自定义一个排序方式一样。
priority_queue<int,vector<int>,cmp> pq
struct cmp
{
bool operator() (const int a,const int b) const
{
return a%10>b%10 //a的优先级比b小时返回TRUE
}
};
对于上面的那个Strut,我感觉又像是前面自己定义加法运算,依然不是很懂,有空补一蛤。
当然,对于常见的优先队列,STL提供了更为简单的定义方法。
越小的整数优先级越大的优先队列 可以写成
priority_queue<int,vector<int>,greater<int> > q;
注意最后两个> 符号不要写一起,以免被编译器认为是 “>>”运算符
相关题目:
UVA540-5.6-团体队列
链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=835&page=show_problem&problem=481
题目大意就是几个团体进行排队,新来排队的人如果发现前面有自己的队友,可以直接插到最后一个队友后面。
题目分析:
这个题用一个主队列加一个数组队列,主队列里面是插入团体,数组队列是每个队列代表一个团体,每当来一个人,如果主队列里面有队友(即数组队列里面对应团体不为空),那在数组队列对应团体里面加入这个人,如果没有队友,那在数组队列对应团体里面加入这个人,再将这个团体加入队列里面。
给出代码:
贴一位其他博主大大写的代码:
http://blog.csdn.net/a197p/article/details/43408927
UVA136-5.7-丑数(Ugly Number)
链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=835&page=show_problem&problem=72
求第1500个丑数,丑数即为不能被2,3,5以外的素整除的数(1也是丑数)。
题目分析:
算是优先队列的练习题了,用一个整数越小优先级越大的数存丑数,用一个map集合来存素数(利用集合的唯一性),利用count函数在集合里面查重,不重的话放到集合和队列里面,不断往队列里面放数取数就好了。
给出代码:
直接贴一下紫书上的代码好了(=。=作者大佬写的代码都好整洁)
#include<iostream>
#include<vector>
#include<queue>
#include<set>
using namespace std;
typedef long long LL;
const int coeff[3]= {2,3,5};
int main()
{
priority_queue<LL,vector<LL>,greater<LL> > pq;
set<LL> s;
pq.push(1);
s.insert(1);
for(int i=1;; i++)
{
LL x=pq.top();
pq.pop();
if(i==1500)
{
cout<<"The 1500'th ugly number is "<<x<<".\n";
break;
}
for(int j=0; j<3; j++)
{
LL x2=x*coeff[j];
if(!s.count(x2))
{
s.insert(x2);
pq.push(x2);
}
}
}
return 0;
}
最后再膜拜一下这个代码 0。0
总结:
栈和队列是两种比较相似的数据结构,一个符合先进后出,一个符合先进先出。在STL库里面都预有这两种结构,分别是stack和queue。这两种结构理解起来很简单,但是关键是如何用这两种结构,将其用到实际当中去,估计还需要以后的反复练习。