C++STL(五) :priority_queue的模拟实现

C++STL(五) :priority_queue的模拟实现

priority_queue的使用

简介

优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中的元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue,默认情况下priority_queue是大堆

定义方式

  • 使用vector作为底层容器,内部构造大堆结构
priority_queue<int,vector<int>,less<int>> pq;
  • 使用vector作为底层容器,内部构造小堆结构
priority_queue<int,vector<int>,greater<int>> pq;
  • 不指定底层容器和内部需要构造的堆结构,此时默认使用vector作为底层容器,内部默认构造大堆结构
priority_queue<int> pq;

接口函数

成员函数功能
push()插入元素并排序
pop()弹出堆顶元素
top()访问堆顶元素
size()获取队列中元素个数
empty()判断队列是否为空
swap()交换两个队列

priority_queue的实现

堆的向上调整算法

以大根堆为例,该算法思想如下

将目标节点与其父亲节点进行比较:

  • 若目标结点的值比父结点的值大,则交换目标结点与其父结点的位置,并将原目标结点的父结点当作新的目标结点继续进行向上调整
  • 若目标结点的值比其父结点的值小,则停止向上调整,此时该树已经是大堆了

在这里插入图片描述

void AdjustUp(std::vector<int>& v, int child)
{
    //找到父节点
    int parent = (child - 1) / 2;
    while (child > 0)
    {
        if (v[child] > v[parent])
        {
            std::swap(v[child], v[parent]);
            //向上迭代
            child = parent;
            parent = (child - 1) / 2;
        }
        //已经成堆了
        else
            break; 
    }
}

堆的向下调整算法

以大根堆为例,使用堆的向下调整算法必须满足一个前提即待向下调整的结点的左子树和右子树必须都为大根堆;堆的向下调整算法思想如下

将目标结点与其较大的子结点进行比较:

  • 若目标结点的值比其较大的子结点的值小,则交换目标结点与其较大的子结点的位置,并将原目标结点的较大子结点当作新的目标结点继续进行向下调整

  • 若目标结点的值比其较大子结点的值大,则停止向下调整,此时该树已经是大根堆了

在这里插入图片描述

void AdjustDown(std::vector<int>& v, int n, int parent)
{
    //先默认左孩子比右孩子大
    int child = parent * 2 + 1;
    while (child < n)
    {
        //如果右孩子存在且右孩子更大,更新child
        if (child + 1 < n && v[child] < v[child + 1])
            child++;
        if (v[parent] < v[child])
        {
            std::swap(v[child], v[parent]);
            parent = child;
            child = parent * 2 + 1;
        }
        //已经成堆
        else
            break;
    }
}

模拟实现

在学习了堆的向上调整算法与堆的向下调整算法之后,priority_queue的实现就很简单

成员函数实现方法
push()在容器尾部插入元素后进行一次向上调整算法
pop()将容器头部和尾部元素交换,再将尾部元素删除,最后从根结点开始进行一次向下调整算法
#define _CRT_SECURE_NO_WARNINGS 1 
#include <iostream>
#include <vector>

namespace pjy
{
    template<class T>
        struct Less //大根堆
        {
            bool operator()(const T& x, const T& y)
            {
                return x < y;
            }
        };
    template<class T>
        struct Greater //大根堆
        {
            bool operator()(const T& x, const T& y)
            {
                return x > y;
            }
        };
    template<class T, class Container = std::vector<T>, class Compare = Less<T>>
        class priority_queue
        {
            public:
            priority_queue()
            {}
            template<class InputIterator>
                priority_queue(InputIterator first, InputIterator last)
                :_con(first, last)
                {
                    for (int i = (_con.size() - 2) / 2; i >= 0; i++)
                    {
                        adjust_down(i);
                    }
                }
            void adjust_up(size_t child)
            {
                Compare com;
                size_t parent = (child - 1) / 2;
                while (child > 0)
                {
                    if (com(_con[parent], _con[child]))
                    {
                        swap(_con[child], _con[parent]);
                        child = parent;
                        parent = (child - 1) / 2;
                    }
                    else
                    {
                        break;
                    }
                }
            }
            void push(const T& x)
            {
                _con.push_back(x);
                adjust_up(_con.size() - 1);
            }
            void adjust_down(size_t parent)
            {
                Compare com;
                size_t child = parent * 2 + 1;
                while (child < _con.size())
                {

                    if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
                    {
                        child++;
                    }
                    //if (_con[child] > _con[parent])
                    if (com(_con[parent], _con[child]))
                    {
                        swap(_con[child], _con[parent]);
                        parent = child;
                        child = parent * 2 + 1;
                    }
                    else
                    {
                        break;
                    }
                }
            }
            void pop()
            {
                swap(_con[0], _con[_con.size() - 1]);
                _con.pop_back();
                adjust_down(0);
            }
            const T& top()
            {
                return _con[0];
            }
            bool empty()
            {
                return _con.empty();
            }
            size_t size()
            {
                return _con.size();
            }
            private:
            Container _con; //底层容器
            Compare _comp;  //比较方式
        };
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值