【C++】有关栈和队列的模拟实现

本文详细介绍了如何模拟实现C++STL中的stack,queue,和priority_queue,以及它们与deque的关系。着重讲解了适配器的概念,以及如何通过仿函数实现优先级队列的堆操作。同时讨论了deque的特点和适用性。
摘要由CSDN通过智能技术生成

这篇文章将主要介绍stack类、queue类、prioity_queue类的模拟实现,并且简单介绍deque类

stack、queue、prioity_queue都是容器适配器,都不支持迭代器。deque是容器

一、stack

解释什么是适配器:适配就是转换的意思,比如我们可以将vector转换成stack,所以stack就是

容器适配器,stack和queue只是对其他容器的接口进行了包装,从而达到stack和queue的特殊

性质。还有一个问题:STL中stack和queue是通过容器适配转换出来的,不是原生实现的,为什

么要这样做?->复用。并且要知道STL中stack和queue默认使用deque。

进行模拟实现

template<class T, class Container = deque<T>>
class Stack{
public:
    //栈顶插入
    void push(const T& x){_con.push_back(x);}
    //栈顶删除
    void pop(){_con.pop_back();}
    //栈的大小
    size_t size(){return _con.size();}
    //栈是否为空
    bool empty(){return _con.empty();}
    //取出栈顶元素
    T& top(){return _con.back();}
private:
    Container _con;
};

二、queue

进行模拟实现

template<class T, class Container = deque<T>>
class Queue{
public:
    //队尾插入
    void push(const T& x){_con.push_back(x);}
    //队头删除
    void pop(){_con.pop_front();}
    //队列大小
    size_t size(){return _con.size();}
    //队列是否为空
    bool empty(){return _con.empty();}
    //取出队头元素
    T& front(){return _con.front();}
    //取出队尾元素
    T& back(){return _con.back();}
private:
    Container _con;
};

三、prioity_queue

优先级队列,他在<queue>头文件中。普通的queue是先进先出,但是prioity_queue是优先级高

的先出队列。还需要了解到优先级队列的底层就是堆!!!

默认情况下优先级队列是大堆(意味着top()取出的优先级高的数据是大数)

priority_queue<int> pq;

如果想创建小堆,就要将第三个模版参数换成greater<T>,这样top()取出的就是小数

priority_queue<int,vector<int>,greater<int>> pq;

(一)仿函数

1.介绍仿函数

进行模拟实现之前要先了解仿函数:仿函数又叫函数对象。他的目的是让一个类的对象可以像函

数一样去使用。仿函数就是通过重载()【operator()】实现的,这个类就有了类似函数的行为。

注意⚠️:使用STL中的仿函数需要引头文件 #include <functional>

下面是两个仿函数的实现:他俩的功能是比较大于和小于。

template<class T>
struct Less
{
    bool operator()(const T& x1, const T& x2)
    {
        return x1 < x2;
    }
};

template<class T>
struct Greater
{
    bool operator()(const T& x1, const T& x2)
    {
        return x1 > x2;
    }
};

演示使用方法

Less<int> lessFunc;//定义一个对象
cout << lessFunc(1,2) << endl;//使用仿函数
//lessFunc(1,2)《==》 lessFunc.operator()(1,2)

2.sort的使用

(1)排正序

//sort算法默认排升序(仿函数less <)
sort(v.begin(), v.end());

(2)排逆序

//sort算法排降序(需要传greater >)
sort(v.begin(), v.end(), greater<int>());
//greater<int>() -》 匿名对象

(二)模拟实现

因为优先级队列本质上是堆,所以需要向下调整算法(建堆、pop),向上调整算法(push)

template<class T, class Container = vector<T>, class Compare = less<T>>
class Priority_Queue{
public:
    //向上调整算法:传过来要调整的孩子(也就是新插入的数据)把他调整到合适的位置上去
    //默认建大堆
    void AdjustUp(int child)
    {
        Compare com;//定义一个仿函数对象才可以使用仿函数
        int parent = (child - 1) / 2;
        while (child > 0)
        {
            //_con[parent] < _con[child]
            if(com(_con[parent],_con[child]))
            {
                swap(_con[child], _con[parent]);//交换
                child = parent;//迭代
                parent = (child - 1) / 2;
            }
            else
            {
                break;
            }
        }
    }
    //堆中插入
    void push(const T& x)
    {
        //o(logN)
        _con.push_back(x);
        AdjustUp(_con.size()-1);
    }
    
    //向下调整算法
    //默认建大堆
    void AdjustDown(int root)
    {
        Compare com;//定义一个仿函数对象才可以使用仿函数
        int parent = root;
        int child = parent * 2 + 1;
        while (child < _con.size())
        {
            //找左右孩子中大的那一个
            //_con[child] < _con[child+1]
            if(child + 1 < _con.size() && com(_con[child],_con[child+1]))
            {
                child++;
            }
            //建大堆:孩子大就上去(父亲小就下去)
            //_con[parent] < _con[child]
            if(com(_con[parent],_con[child]))
            {
                swap(_con[parent], _con[child]);
                parent = child;
                child = parent * 2 + 1;
            }
            else
            {
                break;
            }
        }
    }
    //删除堆顶元素(优先级高的元素)
    void pop()
    {
        swap(_con[0], _con[_con.size()-1]);
        _con.pop_back();
        //o(logN)
        AdjustDown(0);
    }
    //取出堆顶元素(也就是优先级高的元素)
    T& top(){return _con.front();}
    //优先级队列大小
    size_t size(){return _con.size();}
    //判断优先级队列是否为空
    bool empty(){return _con.empty();}
private:
    Container _con;//用来适配的容器
};

四、deque

双端队列:deque支持头尾o(1)的插入删除,也支持随机访问,也就是说他既有vector的优

点,也有list的优点。看似他好像是一个可以替代vector和list的容器,但是实际呢?

deque随机访问的效率不容乐观(排序效率低),所以他没发替代vector和list。

因为deque的operator[]效率不如vector的operator[],并且deque的迭代器比较复杂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值