专题5-数据结构 2017-07-13

C++ Primer P329好好研读,stack,queue,priority_queue都是顺序容器适配器adaptor。接受一种已有的容器类型,使其行为看起来像另一种事物一样)

适配器的底层容器(array和forward_list都不行)
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) 交换两个栈的内容  

1.2、队列queue:


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< , 所以如果你把后面俩个参数缺省的话,优先队列就是大顶堆,队头元素最大。

    如果要用到小顶堆,则一般要把模板的三个参数都带进去。

使用方法:

头文件:

#include <queue>

声明方式:

1、普通方法:

priority_queue<int>q;
//通过操作,按照元素从大到小的顺序出队

2、自定义优先级:

struct cmp  
{  
    bool operator()(int x, int y)  
    {  
        return x > y;  
    }  
}; 

 

 
//其中,第二个参数为容器类型。第三个参数为比较函数。
结构体声明方式:
struct node
{
      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;
}
重载operator<形式代码示例

相关文章: