专题5-数据结构 2017-07-13
C++ Primer P329好好研读,stack,queue,priority_queue都是顺序容器适配器adaptor。(接受一种已有的容器类型,使其行为看起来像另一种事物一样)
| stack | 默认基于deque实现,除array和forward_list以外的容器都可以 |
| queue | 默认基于deque实现,可以构造于list和deque之上,但是不能基于vector进行构造 |
| priority_queue | 默认基于vector实现,最大堆max-heap,可以基于vetor和deque,但是不能基于list(需要随机访问能力) |
1、基础知识
1.1、stack栈
| s.pop() | 删除栈顶元素 | O(1) |
| s.push() | 压入元素 | O(1) |
| s.top() | 返回首元素,但是不删除 | O(1) |
| s.swap(stack) | 交换两个栈的内容 |
C++ primer P330
queue模板类的定义在<queue>头文件中。记住队列没有top()函数,使用front(),总是记错。
与stack模板类很相似,queue模板类也需要两个模板参数,一个是元素类型,一个容器类型,元素类型是必要的,容器类型是可选的,默认为deque类型。
定义queue对象的示例代码如下:
queue<int> q1; queue<double> q2;
queue的基本操作有:
| q.push(x) | 入队,将x接到队列的末端 | 时间复杂度是O(1) |
| q.pop() | 出队,弹出队列的第一个元素,注意,并不会返回被弹出元素的值 | 时间复杂度是O(1) |
| q.front() | 访问队首元素,即最早被压入队列的元素 | 时间复杂度是O(1) |
| q.back() | 访问队尾元素,即最后被压入队列的元素 | 时间复杂度是O(1) |
| q.empty() | 判断队列空 | |
| q.size() | 访问队列中的元素个数 |
队列经常用于BFS,之前总结过BFS要利用queue + unordered_map实现,还有就是二叉树的层次遍历。
1.3、priority_queue
主要操作是:pop(),top(),push()。pop,push都是O(logk),top是O(1)的。
左边是队头,右边是队尾,默认是最大堆即返回的top是目前最大的元素,默认是less<>,实现是x < y,因为有个建堆的过程,所以不能以平常的大小来比较。
STL里面容器默认用的是 vector. 比较方式默认用 operator< , 所以如果你把后面俩个参 缺省的话,优先队列就是大顶堆,队头元素最大。
priority_queue利用一个最大堆完成,最大堆是一个以vector表现的完全二叉树,所以缺省情况下它的底部容器是vector。,queue以底部容器完成其所有的工作,具有这种“修改某物接口,形成另一种风貌”之性质者,称为adapter(适配器)。
priority_queue 对于基本类型的使用方法相对简单。他的模板声明带有三个参数,priority_queue<Type, Container, Functional>,Type 为数据类型, Container 为保存数据的容器,Functional 为元素比较方式。
Container 必须是用数组实现的容器,比如 vector, deque 但不能用 list。STL里面默认用的是 vector. 比较方式默认用 operator< , 所以如果你把后面俩个参数缺省的话,优先队列就是大顶堆,队头元素最大。
如果要用到小顶堆,则一般要把模板的三个参数都带进去。
使用方法:
头文件:
声明方式:
1、普通方法:
//通过操作,按照元素从大到小的顺序出队
2、自定义优先级:
struct cmp { bool operator()(int x, int y) { return x > y; } };
{
int x, y;
friend bool operator < (node a, node b)
{
return a.x > b.x; //结构体中,x小的优先级高
}
};
priority_queue<node>q;//定义方法
//在该结构中,y为值, x为优先级。
//通过自定义operator<操作符来比较元素中的优先级。
//在重载”<”时,最好不要重载”>”,可能会发生编译错误
#include <iostream> #include <queue> using namespace std; int main(){ priority_queue<int, vector<int>, greater<int> > q; for( int i= 0; i< 10; ++i ) q.push( rand() ); while( !q.empty() ){ cout << q.top() << endl; q.pop(); } getchar(); return 0; }
**对于自定义类型,则必须自己重载 operator< 或者自己写仿函数**
1)重载 operator<(自己联想一下每次弹出最小元素的queue形式,{3,2,1}所以必须是返回a.x> b.x;)sort默认是小于排序,从大到小排序,所以重载的时候需要operator<。只有自定义类类型才能重写操作符:
bool operator>( Node left, Node right ){ if( left.x== right.x )
return left.y> right.y; return left.x> right.x; }
写仿函数注意有模板的时候才需要greater<int>写这种形式是为了将模板里面的T变为int,如果没用模板,直接写greater。
struct greater{ bool operator() (const int &a, const int &b) { return a > b; } }; //用的时候直接使用geater template<typename T> struct greater{ bool operator() (const T &a, const T &b) { return a > b; } }; //用的时候使用greater<int>,匹配模板
#include <iostream> #include <queue> using namespace std; struct Node{ int x, y; Node( int a= 0, int b= 0 ): x(a), y(b) {} }; bool operator<( Node a, Node b ){ if( a.x== b.x ) return a.y> b.y; return a.x> b.x; } int main(){ priority_queue<Node> q; for( int i= 0; i< 10; ++i ) q.push( Node( rand(), rand() ) ); while( !q.empty() ){ cout << q.top().x << ' ' << q.top().y << endl; q.pop(); } getchar(); return 0; }