当前位置: 首页 > article >正文

C++:priority_queue(优先级队列)的模拟实现

目录

一、什么是优先级队列

二、优先级队列的定义

三、优先级队列的常用接口

四、模拟实现一个优先级队列

1、posh接口 

2、empty接口、size接口和top接口

3、pop接口

4、构造函数

五、整体代码


一、什么是优先级队列

        首先优先级队列不是队列,C++ 中的优先队列是STL中的派生容器当你往优先级队列里存放数据的时候,它会像堆一样存放数据,将最大的数据或最小的数据放到前面

(至于什么是堆可以看这篇文章->堆的实现)


二、优先级队列的定义

其中:

T 是数据的类型

Container 是容器类型,vector<T> 是容器;

Compare 是作为仿函数容器,决定了是最大的数据还是最小的数据放在前面。


三、优先级队列的常用接口

empty判断优先级队列是否为空(空返回ture,反之返回false)
size返回优先级队列的数据个数
top返回优先级队列第一个数据
push向优先级队列添加数据
pop删除优先级队列中的数据
swap交换两个优先级队列里的数据

四、模拟实现一个优先级队列

        (以大堆为例)

        我们要实现一个优先级队列,最开始要搭建好它的底层。

template <class T, class Container = vector<T>, class Compare = less<T> >
class priority_queue
{
public:

private:
    Container c;
    Compare comp;
};

vector<T> 作为容器(或者其它)构建一个自变c同理用 liss<T>作为容器,构建仿函数comp

因为优先级队列会像堆一样存放数据,所以实现优先级队列基本就是实现一个堆。


1、posh接口 

  • 若我们向一个堆里存放数据后,需要向上调整,所以需要一个向上调整数据的函数 adjust_up()

 (注:在标准库里有adjust_up()函数,但我们是要自己完成一个)

void adjust_up(int child)
{
    int parent = (child - 1) / 2;

    while (child > 0)
    {
        if (c[parent] < c[child])
        {
            swap(c[parent], c[child]);
            child = parent;
            parent = (child - 1) / 2;
        }
        else
            break;
    }
}

但这个代码不够好,(事先说明下面还有一个向下调整函数)若我们想用小堆嘞?总不可能要在类里一个个改它们的比较方式吧,这时候仿函数就该英雄出场了。

if (c[parent] < c[child]) -> if (comp(c[parent], c[child]))

将if中的判断改为函数判断的形式,我们只需在判断函数里修改即可。 

所以push接口可以写成这样↓

void push(const T& x)
{
    c.push_back(x);
    adjust_up(c.size() - 1);
}

2、empty接口、size接口和top接口

因为我们借用了vector作为容器,所以我们可以使用它的接口来代替优先级队列的接口。

bool empty() const
{
    return c.empty();
}

size_t size() const
{
    return c.size();
}

size_t size() const
{
    return c.size();
}

3、pop接口

当我们要删除数据的时候删堆顶的数据,要将堆顶的数据和堆最后的数据互换,然后在利用容器的接口来删除数据。

void pop()
{
    swap(c[0],c[c.size() - 1]);
    c.pop_back();
    adjush_dowm();
}
  • 这里我们需要利用向下调整函数adjust_down()将优先级队列重新排好序。 
void adjush_dowm()
{
    int parent = 0;
    int child = parent * 2 + 1;

    while (child < c.size())
    {
        if (child + 1 < c.size() && comp(c[child], c[child + 1]))
        {
            child++;
        }

        if (comp(c[parent], c[child]))
        {
            swap(c[parent], c[child]);
            child = parent;
            parent = (child - 1) / 2;
        }
        else
            break;
    }
}

 这样我们的优先级队列的大部分接口就实现了。现在我们还差它的构造函数了。


4、构造函数

priority_queue() {};
//利用迭代器来构造优先级队列
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
{
    InputIterator it = first;
    while (it != last)
    {
        push(*it);
        it++;
    }
}

五、整体代码

template <class T, class Container = vector<T>, class Compare = less<T> >
class priority_queue
{
public:
    priority_queue() {};
    template <class InputIterator>
    priority_queue(InputIterator first, InputIterator last)
    {
        InputIterator it = first;
        while (it != last)
        {
            push(*it);
            it++;
        }
    }

    void adjust_up(int child)
    {
        int parent = (child - 1) / 2;

        while (child > 0)
        {
            if (comp(c[parent], c[child]))
            {
                swap(c[parent], c[child]);
                child = parent;
                parent = (child - 1) / 2;
            }
            else
                break;
        }
    }

    void push(const T& x)
    {
        c.push_back(x);
        adjust_up(c.size() - 1);
    }

    bool empty() const
    {
        return c.empty();
    }

    size_t size() const
    {
        return c.size();
    }

    const T& top() const
    {
        return c[0];
    }

    void adjush_dowm()
    {
        int parent = 0;
        int child = parent * 2 + 1;

        while (child < c.size())
        {
            if (child + 1 < c.size() && comp(c[child], c[child + 1]))
            {
                child++;
            }

            if (comp(c[parent], c[child]))
            {
                swap(c[parent], c[child]);
                child = parent;
                parent = (child - 1) / 2;
            }
            else
                break;
        }
    }

    void pop()
    {
        swap(c[0],c[c.size() - 1]);
        c.pop_back();
        adjush_dowm();
    }

    private:
        Container c;
        Compare comp;
    };

http://www.kler.cn/a/300567.html

相关文章:

  • C++第十五讲:异常
  • WPS数据分析000004
  • JSON数据格式的序列化和反序列化jackson针对首字母小学的字段返回序列化后第2个大写字母也变成小写的问题处理
  • 学技术学英文:通过jmeter命令行工具生成聚合报告文件到csv文件
  • Springboot Redisson 分布式锁、缓存、消息队列、布隆过滤器
  • MyBatis(六)关联查询
  • 18070 矩阵行交换或列交换
  • 实时音视频之医疗手术示教技术方案探究
  • DBeaver 连接 MySQL 报错 Public Key Retrieval is not allowed
  • [001-03-007].第26节:分布式锁迭代1->基于setnx命令实现分布式锁:
  • 08-图8 How Long Does It Take(C)
  • Java中的linkedList类及与ArrayList的异同
  • PoS 和 PoW 矿机系统区块链公链开发成本分析
  • 朴素贝叶斯 (Naive Bayes)
  • vue + Element UI table动态合并单元格
  • 前端CSS面试常见题
  • c#中的版本管理和描述
  • 函数的定义
  • Unity3d俯视视角下,通过点击屏幕获取世界坐标是如何实现的
  • windows通过wsl2安装linux系统之Ubuntu,傻瓜式安装
  • C++常用设计模式
  • 数据库视图和索引
  • 【iOS】Masnory的简单学习
  • 【PyQt6 应用程序】在用户登录界面实现密码密文保存复用
  • 若依RuoYi项目环境搭建教程(RuoYi-Vue + RuoYi-Vue3版本)
  • 在Faster Rcnn 中,rpn网络是单独训练的吗