C++ 容器适配器 stack/queue/priority_queue

容器适配器 stack

stack 栈适配器是一种单端开口的容器,实际上该容器模拟的就是栈存储结构,即无论是向里存数据还是从中取数据,都只能从这一个开口实现操作。

由于 stack 适配器以模板类 stack<T,Container=deque<T>>(其中 T 为存储元素的类型,Container 表示底层容器的类型)的形式位于<stack>头文件中,并定义在 std 命名空间里。

作为stack容器适配器的基础容器,其必须提供 empty()、size()、back()、push_back()、pop_back() 这 5 个成员函数,符合条件的序列式容器有vector、deque 和 list 。

声明与创建
#include <stack>
using namespace std;

stack<int> s;//创建空栈
stack<int, list<int> > s;//创建使用list基础容器的栈

list<int> values {1, 2, 3};
stack<int,list<int>> my_stack (values); //从其他基础容器中构造(需要该容器的类型和 stack 底层使用的基础容器类型相同即可)
//者复制构造
常用方法
s.empty();//栈为空时返回true
s.size();//返回栈中元素个数
s.top();//返回栈顶与元素的引用
s.push(ele);//将一个元素进栈
s.pop();//出栈
s.swap(s1);//交换两个栈的元素,需要注意的是,进行互换的 2 个 stack 适配器中存储的元素类型以及底层采用的基础容器类型,都必须相同

容器适配器 queue

queue 容器适配器有 2 个开口,其中一个开口专门用来输入数据,另一个专门用来输出数据。这种存储结构最大的特点是,最先进入 queue 的元素,也可以最先从 queue 中出来,即用此容器适配器存储数据具有“先进先出(简称 “FIFO” )”的特点,因此 queue 又称为队列适配器。

queue 容器适配器以模板类 queue<T,Container=deque<T>>(其中 T 为存储元素的类型,Container 表示底层容器的类型)的形式位于<queue>头文件中,并定义在 std 命名空间里。

作为 queue 容器适配器的基础容器,其必须提供 front()、back()、push_back()、pop_front()、empty() 和 size() 这几个成员函数,符合条件的序列式容器仅有 deque 和 list。

声明与创建
#include<queue>
using namespace std;

queue<int> q;

qeque<int> values{1,2,3};
queue<int> my_queue(values);//使用基础容器初始化 queue 适配器,由于 my_queue 底层采用的是 deque 容器,和 values 类型一致,且存储的也都是 int 类型元素,因此可以用 values 对 my_queue 进行初始化。
常用函数
q.empty();
q.size();

q.front();
q.back();

q.push(ele);
q.emplace(ele);
q.pop();

q.swap(q2);

容器适配器 priority_queue

priority_queue 容器适配器模拟的也是队列这种存储结构,即使用此容器适配器存储元素只能“从一端进(称为队尾),从另一端出(称为队头)”,且每次只能访问 priority_queue 中位于队头的元素。

但是,priority_queue 容器适配器中元素的存和取,遵循的并不是 “First in,First out”(先入先出)原则,而是“First in,Largest/Smallest out”原则。

priority_queue 容器适配器为了保证每次从队头移除的都是当前优先级最高的元素,每当有新元素进入,它都会根据既定的排序规则找到优先级最高的元素,并将其移动到队列的队头;同样,当 priority_queue 从队头移除出一个元素之后,它也会再找到当前优先级最高的元素,并将其移动到队头。

基于 priority_queue 的这种特性,因此该容器适配器有被称为优先级队列。

priority_queue 容器适配器“First in,Largest out”的特性,和它底层采用堆结构存储数据是分不开的。

STL中,priority_queue 容器适配器的定义如下:

template <typename T,        
        typename Container=std::vector<T>,        
        typename Compare=std::less<T> > 
class priority_queue{    
    //......
}

可以看到,priority_queue 容器适配器模板类最多可以传入 3 个参数,它们各自的含义如下:

  • typename T:指定存储元素的具体类型;

  • typename Container:指定 priority_queue 底层使用的基础容器,默认使用 vector 容器。

    作为 priority_queue 容器适配器的底层容器,其必须包含 empty()、size()、front()、push_back()、pop_back() 这几个成员函数,STL序列式容器中只有 vector 和 deque 容器符合条件。

  • typename Compare:指定容器中评定元素优先级所遵循的排序规则,默认使用std::less<T>按照元素值从大到小进行排序 (大根堆);还可以使用std::greater<T>按照元素值从小到大排序 (小根堆),但更多情况下是使用自定义的排序规则。

    为什么 less 对应大根堆?
    我们可以看到,less 对应大根堆,这是因为优先级队列中底层使用 vector 容器,出堆时会先将头部元素和尾部元素交换,然后再将尾部元素出堆,如果数据元素不出堆,我们会发现 vector 中所存储的元素的大小顺序就是 less 的顺序(从小到大),由于元素是从末尾出堆,所以最终从大到小的顺序。

声明与创建
#include <queue>
using namespace std;

priority_queue<int> values;

//使用普通数组
int values[]{4,1,3,2};
priority_queue<int>copy_values(values,values+4);//{4,2,3,1}
//使用序列式容器
array<int,4>values{ 4,1,3,2 };
priority_queue<int>copy_values(values.begin(),values.end());//{4,2,3,1}
常用函数
pq.empty();
pq.size();

pq.top();
pq.push();
pq.pop();
pq.emplace();

pq.swap(pq2);

使用自定义数据类型
//自定义数据类型之二
struct Node{
    int x,y;
    Node(int a=0, int b=0):
            x(a), y(b) {}
};
//重写仿函数
struct cmp1{
    bool operator()(Node a, Node b){
        //x大的Node优先级高,小根堆
        if(a.x == b.x)
            return a.y > b.y;
        return a.x > b.x;
    }
};
//重载比较运算符
bool operator< (Node a, Node b) {//对应于less函数
    //x值较小的Node优先级高,大根堆
    if(a.x == b.x)
        return a.y < b.y;
    return a.x < b.x;
}
bool operator> (Node a, Node b){//对应于greater函数
    //x值较大的Node优先级高,小根堆
    if( a.x == b.x )
        return a.y > b.y;
    return a.x > b.x;
}
int test_pq3(){
    priority_queue<Node, vector<Node>, less<>> p1;
    priority_queue<Node, vector<Node>, greater<>> p2;
    priority_queue<Node, vector<Node>, cmp1> p3;
    for(int i=0; i<5; ++i) {
        int x = rand()%10;
        int y = rand()%10;
        p1.push(Node(x, y));
        p2.push(Node(x, y));
        p3.push(Node(x, y));
    }


    while(!p1.empty()){
        cout<< "(" << p1.top().x << ", " << p1.top().y << ")    ";
        p1.pop();
    }
    cout << endl;
    while(!p2.empty()){
        cout<< "(" << p2.top().x << ", " << p2.top().y << ")    ";
        p2.pop();
    }
    cout << endl;
    while(!p3.empty()){
        cout<< "(" << p3.top().x << ", " << p3.top().y << ")    ";
        p3.pop();
    }
    cout << endl;
    return 0;
}
/*
(9, 4)    (8, 8)    (4, 0)    (2, 4)    (1, 7)
(1, 7)    (2, 4)    (4, 0)    (8, 8)    (9, 4)
(1, 7)    (2, 4)    (4, 0)    (8, 8)    (9, 4)
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值