再次面对像栈和队列这样的相当基础的数据结构的学习,应该从多个方面,多维度去学习。
首先,这两个数据结构都是比较常用的,在标准库中都有对应的结构能够直接使用,所以第一个阶段应该是先学习直接来使用,下一个阶段再去探究具体的实现,以及对基本结构的改造!
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
Output
Sample Input
1 2 9 0
Sample Output
1 2 10
此题只使用优先级队列不太能解决问题,解决问题需要两个条件从小到大的排序+无重复,只使用优先级队列可以解决排序,而无重复只能使用自定义逻辑来判断,个人认为使用set能更优雅的解决问题。
下面给出代码,使用set解决问题:
1 #include <iostream> 2 #include <cstdio> 3 #include <set> 4 #include <cmath> 5 6 using namespace std; 7 8 unsigned long result[1500]; 9 10 void getUgly() 11 { 12 set<unsigned long> s; 13 s.insert(2); 14 s.insert(3); 15 s.insert(5); 16 17 int i=0; 18 result[i]=1; 19 unsigned long tmp=0; 20 while(i<1500) 21 { 22 i++; 23 tmp=*(s.begin()); 24 result[i]=tmp; 25 s.erase(tmp); 26 s.insert(tmp*2); 27 s.insert(tmp*3); 28 s.insert(tmp*5); 29 } 30 } 31 32 33 int main() 34 { 35 int n; 36 37 getUgly(); 38 while(cin>>n) 39 { 40 if(n==0) 41 break; 42 43 cout<<result[n-1]<<endl; 44 } 45 return 0; 46 }