[ACM训练] 算法初级 之 数据结构 之 栈stack+队列queue (基础+进阶+POJ 1338+2442+1442)
2016-10-24 23:15
309 查看
再次面对像栈和队列这样的相当基础的数据结构的学习,应该从多个方面,多维度去学习。
首先,这两个数据结构都是比较常用的,在标准库中都有对应的结构能够直接使用,所以第一个阶段应该是先学习直接来使用,下一个阶段再去探究具体的实现,以及对基本结构的改造!
C++标准库中的基本使用方法:
栈: #include<stack>
定义栈,以如下形式实现: stack<Type> s; 其中Type为数据类型(如 int,float,char等)
常用操作有:
s.push(item); //将item压入栈顶
s.pop(); //删除栈顶的元素,但不会返回
s.top(); //返回栈顶的元素,但不会删除,,,,,,,,,在出栈时需要进行两步,即先top()获得栈顶元素,再pop()删除栈顶元素
s.size(); //返回栈中元素的个数
s.empty(); //检查栈是否为空,如果为空返回true,否则返回false
最基本的用法就是:
stack<int> st;---------------------------------->栈
int first=1;
st.push(first);//入栈1
int second=2;
st.push(second);//入栈2
first=st.top();//first变成了2
st.pop();//出栈
队列:#include<queue>
queue<int> q; //定义一个 int 型的队列 ---------------------------------->队列
q.empty()//如果队列为空返回true,否则返回false
q.size() //返回队列中元素的个数
q.push() //在队尾压入新元素
q.front() //返回队首元素的值,但不删除该元素
q.pop() //删除队列首元素但不返回其值
q.back()//返回队列尾元素的值,但不删除该元素
另外在队列中还有优先队列,priority_queue<.........>---------------------------------->优先队列
要包含头文件:
优先队列支持的操作有:
q.empty() //如果队列为空,则返回true,否则返回false
q.size() //返回队列中元素的个数
q.pop() //删除队首元素,但不返回其值
q.top() //返回具有最高优先级的元素值,但不删除该元素,注意与传统队列的不同以及和栈的相同点
q.push(item) //在基于优先级的适当位置插入新元素
优先队列是我们比较不熟悉的一种结构,下面整体上做一个总结学习:
优先队列是队列的一种,不过它可以按照自定义的一种方式(数据的优先级)来对队列中的数据进行动态的排序,每次的push和pop操作,队列都会动态的调整,以达到我们预期的方式来存储。
例如:我们常用的操作就是对数据排序,优先队列默认的是数据大的优先级高,所以我们无论按照什么顺序push一堆数,最终在队列里总是top出最大的元素。
所以,优先队列在一些定义了权重的地方很有用,priority_queue特别之处在于,允许用户为队列中存储的元素设置优先级。这种队列不是直接将新元素放置在队列尾部,而是放在比它优先级低的元素前面。标准库默认使用<操作符来确定对象之间的优先级关系,所以如果要使用自定义对象,需要重载 < 操作符。
使用上有这么几种类型:
1、默认优先级队列,默认的优先级是按照数据的大小来决定的。默认为最大值优先的。
2、设置的最小值或者最大值优先队列,使用一个比较结构来标识来表明比较的方式,这里的cmp为:
3、采用头文件"functional"内定义的优先级,即greater<int>/less<int>,来标识,除此之外可以不用包含此头文件。
4、或者使用自定义的结构,但结构内需重载操作符<,比如这里的number1和number2:
总结,能直接进行数据大小比较的,就是默认为最大值优先a<b,如果要更改,就是用一个cmp,更改为a>b就变成了最小值优先了,而对于无法直接进行比较的数据结构,就自定义一个<运算符重载,制定一个元素进行比较,默认的按照最大值优先,即x<a.x,若要更改就改成x>a.x即可变成最小值优先。
基本用法就是这个样子,需要从题目中进行锻炼,对于栈和队列基本都比较简单,但是对于优先队列就需要重点去掌握了!!!
针对于优先级队列,有人总结出几点常用的功能:(其实大致就是上面的四种类型的用法)
1、优先队列最基本的功能就是出队时不是按照先进先出的规则,而是按照队列中优先级顺序出队。
知识点:1、一般存放实型类型,可比较大小
2、默认情况下底层以Vector实现
3、默认情况下是大顶堆,也就是大者优先级高,可以自定义优先级比较规则
2、可以将一个存放实型类型的数据结构转化为优先队列,这里跟优先队列的构造函数相关,
使用的是 priority_queue(InputIterator first,InputIterator last)
给出了一个容器的开口和结尾,然后把这个容器内容拷贝到底层实现(默认vector)中去构造出优先队列。
3、可以定义了一个(Node),底层实现以vector实现(第二个参数),优先级为小顶堆(第三个参数)。
前两个参数没什么说的,很好理解,其中第三个参数,默认有三写法:
小顶堆:greater<TYPE>
大顶堆:less<TYPE> --------->需要使用头文件:#include<functional>
如果想自定义优先级而TYPE不是基本类型,而是复杂类型,例如结构体、类对象,则必须重载其中的operator(),即cmp
经典例题:Ugly Numbers http://poj.org/problem?id=1338
Input
Each line of the input contains a postisive integer n (n <= 1500).Input is terminated by a line with n=0.
Output
For each line, output the n’th ugly number .:Don’t deal with the line with n=0.
Sample Input
Sample Output
View Code
拓展:带取最小值的队列
实现一个队列,带有出队(deQueue),入队(enQueue),取最小元素(getMin)三个方法。要保证这三个方法的时间复杂度都尽可能小。
与上面相似,实现为:
没有想好实现方式,先暂时留空。
下面是牛客网关于队列和栈的学习相关总结
首先,这两个数据结构都是比较常用的,在标准库中都有对应的结构能够直接使用,所以第一个阶段应该是先学习直接来使用,下一个阶段再去探究具体的实现,以及对基本结构的改造!
C++标准库中的基本使用方法:
栈: #include<stack>
定义栈,以如下形式实现: stack<Type> s; 其中Type为数据类型(如 int,float,char等)
常用操作有:
s.push(item); //将item压入栈顶
s.pop(); //删除栈顶的元素,但不会返回
s.top(); //返回栈顶的元素,但不会删除,,,,,,,,,在出栈时需要进行两步,即先top()获得栈顶元素,再pop()删除栈顶元素
s.size(); //返回栈中元素的个数
s.empty(); //检查栈是否为空,如果为空返回true,否则返回false
最基本的用法就是:
stack<int> st;---------------------------------->栈
int first=1;
st.push(first);//入栈1
int second=2;
st.push(second);//入栈2
first=st.top();//first变成了2
st.pop();//出栈
队列:#include<queue>
queue<int> q; //定义一个 int 型的队列 ---------------------------------->队列
q.empty()//如果队列为空返回true,否则返回false
q.size() //返回队列中元素的个数
q.push() //在队尾压入新元素
q.front() //返回队首元素的值,但不删除该元素
q.pop() //删除队列首元素但不返回其值
q.back()//返回队列尾元素的值,但不删除该元素
另外在队列中还有优先队列,priority_queue<.........>---------------------------------->优先队列
要包含头文件:
#include<functional> #include<queue>
优先队列支持的操作有:
q.empty() //如果队列为空,则返回true,否则返回false
q.size() //返回队列中元素的个数
q.pop() //删除队首元素,但不返回其值
q.top() //返回具有最高优先级的元素值,但不删除该元素,注意与传统队列的不同以及和栈的相同点
q.push(item) //在基于优先级的适当位置插入新元素
优先队列是我们比较不熟悉的一种结构,下面整体上做一个总结学习:
优先队列是队列的一种,不过它可以按照自定义的一种方式(数据的优先级)来对队列中的数据进行动态的排序,每次的push和pop操作,队列都会动态的调整,以达到我们预期的方式来存储。
例如:我们常用的操作就是对数据排序,优先队列默认的是数据大的优先级高,所以我们无论按照什么顺序push一堆数,最终在队列里总是top出最大的元素。
所以,优先队列在一些定义了权重的地方很有用,priority_queue特别之处在于,允许用户为队列中存储的元素设置优先级。这种队列不是直接将新元素放置在队列尾部,而是放在比它优先级低的元素前面。标准库默认使用<操作符来确定对象之间的优先级关系,所以如果要使用自定义对象,需要重载 < 操作符。
使用上有这么几种类型:
1 priority_queue<int>que;//采用默认优先级构造队列 2 3 priority_queue<int,vector<int>,cmp1>que1;//最小值优先 ,,,,,这里定义底层实现以vector实现 4 priority_queue<int,vector<int>,cmp2>que2;//最大值优先 5 6 priority_queue<int,vector<int>,greater<int> >que3;//最小值优先,另外需注意“>>”会被认为错误, 7 priority_queue<int,vector<int>,less<int> >que4;//最大值优先 8 9 priority_queue<number1>que5; //最小优先级队列 --->针对自定义的数据结构 10 priority_queue<number2>que6; //最大优先级队列
1、默认优先级队列,默认的优先级是按照数据的大小来决定的。默认为最大值优先的。
2、设置的最小值或者最大值优先队列,使用一个比较结构来标识来表明比较的方式,这里的cmp为:
1 struct cmp1 2 { 3 bool operator ()(int &a,int &b) 4 { 5 return a>b;//最小值优先 6 } 7 }; 8 9 struct cmp2 10 { 11 bool operator ()(int &a,int &b) 12 { 13 return a<b;//最大值优先 14 } 15 };
3、采用头文件"functional"内定义的优先级,即greater<int>/less<int>,来标识,除此之外可以不用包含此头文件。
4、或者使用自定义的结构,但结构内需重载操作符<,比如这里的number1和number2:
//自定义数据结构 struct number1 { int x; bool operator < (const number1 &a) const { return x>a.x;//最小值优先 } }; struct number2 { int x; bool operator < (const number2 &a) const { return x<a.x;//最大值优先 } };
总结,能直接进行数据大小比较的,就是默认为最大值优先a<b,如果要更改,就是用一个cmp,更改为a>b就变成了最小值优先了,而对于无法直接进行比较的数据结构,就自定义一个<运算符重载,制定一个元素进行比较,默认的按照最大值优先,即x<a.x,若要更改就改成x>a.x即可变成最小值优先。
基本用法就是这个样子,需要从题目中进行锻炼,对于栈和队列基本都比较简单,但是对于优先队列就需要重点去掌握了!!!
针对于优先级队列,有人总结出几点常用的功能:(其实大致就是上面的四种类型的用法)
1、优先队列最基本的功能就是出队时不是按照先进先出的规则,而是按照队列中优先级顺序出队。
知识点:1、一般存放实型类型,可比较大小
2、默认情况下底层以Vector实现
3、默认情况下是大顶堆,也就是大者优先级高,可以自定义优先级比较规则
1 priority_queue<int> Q; 2 Q.push(2); 3 Q.push(5); 4 Q.push(3); 5 while(!Q.empty()) 6 { 7 cout<<Q.top()<<endl; 8 Q.pop(); 9 }//这样就是一个按照顺序排序的输出
2、可以将一个存放实型类型的数据结构转化为优先队列,这里跟优先队列的构造函数相关,
使用的是 priority_queue(InputIterator first,InputIterator last)
给出了一个容器的开口和结尾,然后把这个容器内容拷贝到底层实现(默认vector)中去构造出优先队列。
1 int a[5]={3,4,5,2,1}; 2 priority_queue<int> Q(a,a+5); 3 while(!Q.empty()) 4 { 5 cout<<Q.top()<<endl; 6 Q.pop(); 7 }
3、可以定义了一个(Node),底层实现以vector实现(第二个参数),优先级为小顶堆(第三个参数)。
前两个参数没什么说的,很好理解,其中第三个参数,默认有三写法:
小顶堆:greater<TYPE>
大顶堆:less<TYPE> --------->需要使用头文件:#include<functional>
如果想自定义优先级而TYPE不是基本类型,而是复杂类型,例如结构体、类对象,则必须重载其中的operator(),即cmp
经典例题:Ugly Numbers http://poj.org/problem?id=1338
Input
Each line of the input contains a postisive integer n (n <= 1500).Input is terminated by a line with n=0.
Output
For each line, output the n’th ugly number .:Don’t deal with the line with n=0.
Sample Input
1 2 9 0
Sample Output
1 2 10
此题只使用优先级队列不太能解决问题,解决问题需要两个条件从小到大的排序+无重复,只使用优先级队列可以解决排序,而无重复只能使用自定义逻辑来判断,个人认为使用set能更优雅的解决问题。 下面给出代码,使用set解决问题:
1 #include <iostream> 2 #include <cstdio> 3 #include <stack> 4 using namespace std; 5 6 template <typename T>//使用模板类T 7 class StackWithMin 8 { 9 public: 10 stack<T> dataStack; 11 stack<T> minStack; 12 13 void push(T t)//入栈,数据栈直接入栈,辅助栈需要比较大小后入栈 14 { 15 dataStack.push(t); 16 if(minStack.size()==0 || t<minStack.top()) 17 minStack.push(t); 18 else 19 minStack.push(minStack.top()); 20 } 21 22 T top() 23 { 24 return dataStack.top(); 25 } 26 27 28 void pop()//出栈时数据栈和辅助栈同时操作即可,仍然设计遵循标准用法 29 { 30 dataStack.pop(); 31 minStack.pop(); 32 } 33 34 T getMin() 35 { 36 return minStack.top(); 37 } 38 }; 39 40 41 int main() 42 { 43 StackWithMin<int> mstack; 44 45 int eles[4] = {3,4,2,5}; 46 for (int i=0;i<4;i++) 47 mstack.push(eles[i]); 48 49 cout<<mstack.getMin()<<endl;//2 50 mstack.pop();//5 51 mstack.pop();//2 52 cout<<mstack.getMin()<<endl;//3 53 mstack.push(1); 54 cout<<mstack.getMin()<<endl;//1 55 56 return 0; 57 }
View Code
拓展:带取最小值的队列
实现一个队列,带有出队(deQueue),入队(enQueue),取最小元素(getMin)三个方法。要保证这三个方法的时间复杂度都尽可能小。
与上面相似,实现为:
没有想好实现方式,先暂时留空。
下面是牛客网关于队列和栈的学习相关总结
相关文章推荐
- 一步一步复习数据结构和算法基础-链式队列
- [ACM训练] 算法初级 之 搜索算法 之 深度优先算法DFS (POJ 2251+2488+3083+3009+1321)
- 数据结构和算法 (二)数据结构基础、线性表、栈和队列、数组和字符串
- 一步一步复习数据结构和算法基础-栈和队列(2)
- HDU 1561 --- 树形dp(摘自ACM算法基础训练教程)
- [ACM训练] 算法初级 之 基本算法 之 枚举(POJ 1753+2965)
- 【数据结构与算法基础】以数组实现的循环队列 / Circular Queue implemented by array
- 算法与数据结构基础6:C++队列的简单实现
- [ACM训练] 算法初级 之 搜索算法 之 广度优先算法BFS (POJ 3278+1426+3126+3087+3414)
- 算法与数据结构基础----表,栈和队列(外加map用法)
- 【Java数据结构学习笔记之三】Java数据结构与算法之队列(Queue)实现
- 一步一步复习数据结构和算法基础-栈和队列(1)
- 算法基础-->链表,堆栈,队列
- 一步一步复习数据结构和算法基础-双链表
- 数据结构之自建算法库——顺序环形队列
- [C++基础]队列<queue>中的常用函数
- 【科普·给学弟看的算法】队列的基础知识和基本运用(1):基本队列与优先队列
- 数据结构14:队列(Queue),“先进先出”的数据结构
- 浅谈算法和数据结构: 十二 无向图相关算法基础
- 数据结构基础(5)--队列和循环队列详解--静态方式