STL-priority_queue的使用及其模拟实现

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

注意: 默认情况下priority_queue是大堆。

priority_queue的使用

priority_queue的构造函数

模板参数 Compare

在 std::priority_queue 类中,通过模板参数 Compare 来指定用于比较元素的函数对象,从而影响堆的排序方式。Compare 是一个仿函数,它定义了元素之间的比较方式。根据不同的 Compare,优先队列可以变成大堆(最大堆)或小堆(最小堆)。

默认的 std::less<T>(大堆):
std::less 是一个函数对象,它重载了 operator(),用于比较两个元素。它返回一个布尔值,表示是否第一个参数小于第二个参数。在默认情况下,如果不提供 Compare 参数,优先队列使用 std::less 作为比较函数对象,即大堆。这意味着在大堆中,父节点的值总是大于或等于子节点的值。

std::greater<T>(小堆):
std::greater<T> 是另一个函数对象,它重载了 operator(),用于比较两个元素。与 std::less<T> 不同,std::greater<T> 返回一个布尔值,表示第一个参数是否大于第二个参数。如果你将 std::greater<T> 传递给 priority_queue,它将会构造一个小堆。在小堆中,父节点的值总是小于或等于子节点的值。

仿函数

仿函数(Functor)是一种重载了函数调用操作符 operator() 的类对象,使得该对象可以像函数一样被调用。它实际上是一种函数对象,它可以具有自己的成员变量和操作,同时可以在使用上类似于普通函数。

使用仿函数的主要优点之一是可以将函数的行为和状态封装在对象中,从而使代码更具有可读性和可维护性。仿函数可以用于各种情况,包括标准算法、STL容器和其他需要函数式操作的地方。

例如:

// 仿函数/函数对象
template<class T>
class Less
{
public:
    bool operator()(const T& x, const T& y)
    {
        return x < y;
    }
};

empty():检查优先队列是否为空
size():用于获取优先队列中元素的数量
top():获取优先队列的顶部元素(最大或最小元素,取决于堆的类型),但不改变队列的内容
push():用于将新元素添加到优先队列中
emplace():在优先队列中插入一个新元素

pop():将优先队列的顶部元素移除,同时会重新调整堆以维持堆的性质

swap(): 用于交换调用对象和传递的参数 x 之间的内容,将两个优先队列的内容互换,但不会改变它们的比较函数或其他属性

模拟实现priority_queue

// Compare进行比较的仿函数 less->大堆
template<class T>
class Less
{
public:
    bool operator()(const T& x, const T& y)
    {
        return x < y;
    }
};


class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
        : _year(year)
        , _month(month)
        , _day(day)
    {}
    bool operator<(const Date& d)const
    {
        return (_year < d._year) ||
            (_year == d._year && _month < d._month) ||
            (_year == d._year && _month == d._month && _day < d._day);
    }
    bool operator>(const Date& d)const
    {
        return (_year > d._year) ||
            (_year == d._year && _month > d._month) ||
            (_year == d._year && _month == d._month && _day > d._day);
    }
    friend ostream& operator<<(ostream& _cout, const Date& d)
    {
        _cout << d._year << "-" << d._month << "-" << d._day;
        return _cout;
    }
private:
    int _year;
    int _month;
    int _day;
};

//类模板特化
template<>
struct Less<Date*>
{
    bool operator()(const Date* x, const Date* y)
    {
        return *x < *y;
    }
};

// Compare进行比较的仿函数 greater->小堆

template<class T>
class Greater
{
public:
    bool operator()(const T& x, const T& y)
    {
        return x > y;
    }
};
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)
        :_con(first, last)
    {
        // ½¨¶Ñ
        for (int i = (_con.size() - 2) / 2; i >= 0; --i)
        {
            adjust_down(i);
        }
    }

    void adjust_up(int child)
    {
        Compare com;
        int parent = (child - 1) / 2;
        while (child > 0)
        {
            //有名对象
            if (com(_con[parent], _con[child]))
            //匿名对象
            //if (Compare()(_con[parent], _con[child]))
                //if (_con[parent] < _con[child])
            {
                swap(_con[child], _con[parent]);
                child = parent;
                parent = (child - 1) / 2;
            }
            else
            {
                break;
            }
        }
    }

    void adjust_down(int parent)
    {
        Compare com;
        size_t child = parent * 2 + 1;
        while (child < _con.size())
        {
            //if (child + 1 < _con.size() 
            //    //&& _con[child] < _con[child + 1])
            if (child + 1 < _con.size()
                && com(_con[child], _con[child + 1]))
            {
                ++child;
            }

            //if (_con[parent] < _con[child])
            if (com(_con[parent], _con[child]))
            {
                swap(_con[child], _con[parent]);
                parent = child;
                child = parent * 2 + 1;
            }
            else
            {
                break;
            }
        }
    }

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

    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;
};

class PDateLess {
public:
    bool operator()(const Date* p1, const Date* p2) {
        return *p1 < *p2;
    }
};
class PDateGreater{
public:
    bool operator()(const Date* p1, const Date* p2) {
        return *p1 > *p2;
    }
};
void test_priority_queue() {
    priority_queue<int> pq;
    pq.push(1);
    pq.push(2);
    pq.push(3);
    pq.push(4);
    pq.push(1);

    while (!pq.empty()) {
        cout << pq.top() << " ";
        pq.pop();
    }
    cout << endl;
}
void test_priority_queue2()
{
    // 大堆,需要用户在自定义类型中提供<的重载
    priority_queue<Date,vector<Date>,Less<Date>> q1;
    q1.push(Date(2018, 10, 29));
    q1.push(Date(2018, 10, 28));
    q1.push(Date(2018, 10, 30));
    cout << q1.top() << endl;
    priority_queue<Date*, vector<Date*>> q3;
    //priority_queue<Date*, vector<Date*>,PDateLess> q3;
    q3.push(new Date(2018, 10, 29));
    q3.push(new Date(2018, 10, 28));
    q3.push(new Date(2018, 10, 30));
    cout << *(q3.top()) << endl;
    // 如果要创建小堆,需要用户提供>的重载
    priority_queue<Date, vector<Date>, Greater<Date>> q2;
    q2.push(Date(2018, 10, 29));
    q2.push(Date(2018, 10, 28));
    q2.push(Date(2018, 10, 30));
    cout << q2.top() << endl;
}

成员函数的模拟实现

模板类 priority_queue:
这是一个模板类,它代表了一个优先队列的实现。它接受三个模板参数:T(元素类型),Container(底层容器类型,默认为 std::vector<T>),和 Compare(用于比较元素的仿函数,默认为 std::less<T>)

Compare 是一个模板参数,用于进行元素的比较。它是一个仿函数,可以是 std::less<T>(默认)或 std::greater<T>,具体取决于用户提供的优先队列类型。Compare 仿函数用于确定在堆中的元素排序方式,从而决定了是最大堆还是最小堆。在 priority_queue 类的各个成员函数中,通过调用 Compare 仿函数来进行元素的比较,从而实现了插入和调整堆的操作。

构造函数 priority_queue():
这是一个默认构造函数,不需要使用 Compare 仿函数进行比较。

构造函数模板 priority_queue(InputIterator first, InputIterator last):
在构造函数内部,使用 Compare 仿函数来执行比较操作,以确定元素的顺序。在添加元素后,通过调用 adjust_down 函数来构建堆。

成员函数 adjust_up(size_t child):
在上浮操作中,使用 Compare 仿函数执行比较,以确定是否需要交换父子节点的位置,从而保持堆的性质。

成员函数 push(const T& x):
在插入操作中,首先将新元素添加到底层容器 _con,然后通过调用 adjust_up 函数来执行上浮操作,保证新元素位于合适的位置。

成员函数 adjust_down(size_t parent):
在下沉操作中,使用 Compare 仿函数执行比较,以确定是否需要交换父子节点的位置,从而保持堆的性质。

成员函数 pop():
在删除操作中,首先将顶部元素与底层容器的最后一个元素交换,然后通过调用 adjust_down 函数来执行下沉操作,保证堆的性质。

成员函数 const T& top():
通过返回 _con[0],获取优先队列的顶部元素。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/336378.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

车载电子电器架构 —— 智能座舱标准化意义

车载电子电器架构 —— 智能座舱标准化意义 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消…

Python 之微信指数小程序数据抓取

Fiddler安装和设置 安装 Fiddler 安装包可以从这里获取&#xff0c;如果失效了可以自己网上找一个安装。 链接&#xff1a;https://pan.baidu.com/s/10tYQ-uL6HMddkOcIKnWEKQ?pwdd1io 然后就是点击安装就好了&#xff0c;没什么好多说的。 启用HTTPS捕获 进入软件界面&…

数据库设计实例---学习数据库最重要的应用之一

一、引言【可忽略】 在学习“数据库系统概述”这门课程时&#xff0c;我一直很好奇&#xff0c;这样一门必修课&#xff0c;究竟教会了我什么呢&#xff1f; 由于下课后&#xff0c;&#xff0c;没有拓展自己的眼界&#xff0c;上课时又局限于课堂上老师的讲课水平&#xff0c;…

【YOLOv10】2024年5月最新的YOLO系列模型Yolov10(论文阅读笔记) + 完整创新点说明 + 总结

&#x1f680;&#x1f680;&#x1f680; YOLOv10: 实时端到端的目标检测。YOLOv10比最先进的YOLOv9延迟时间更低&#xff0c;测试结果可以与YOLOv9媲美&#xff0c;可能会成为YOLO系列模型部署的“新选择”。 官方论文地址&#xff1a;https://arxiv.org/pdf/2405.14458 官方…

[vue3后台管理二]首页和登录测试

[vue3后台管理二]首页和登录测试 1 修改main.js import ./assets/main.cssimport { createApp } from vue import App from ./App.vue import router from ./router createApp(App).use(router).mount(#app)2 路由创建 import {createRouter, createWebHistory} from vue-ro…

C++ 网络编程

一、Reactor 网络编程模型 reactor 是一个事件处理模型。网络处理:因为用户层并不知道 IO 什么时候就绪,所以将对 IO 的处理转化为对事件的处理。网络模型构成: 非阻塞 IO:操作 IO,如果 IO 未就绪,IO 函数会立刻返回。IO 多路复用:检测多路 IO 是否就绪。工作流程: 注册…

浅谈路由器转发数据包

当路由器转发数据包时&#xff0c;它会经历一系列步骤&#xff0c;包括接收数据包、路由表查询、以及转发数据包。以下是详细的步骤描述&#xff1a; 1. 接收数据包 以太网帧到达端口&#xff1a;当一个以太网帧到达路由器的某个网络接口&#xff08;端口&#xff09;时&#…

Django 做migrations时出错,解决方案

在做migrations的时候&#xff0c;偶尔会出现出错。 在已有数据的表中新增字段时&#xff0c;会弹出下面的信息 运行这个命令时 python manage.py makemigrationsTracking file by folder pattern: migrations It is impossible to add a non-nullable field ‘example’ to …

旧手机翻身成为办公利器——PalmDock的介绍也使用

旧手机有吧&#xff01;&#xff01;&#xff01; 破电脑有吧&#xff01;&#xff01;&#xff01; 那恭喜你&#xff0c;这篇文章可能对你有点用了。 介绍 这是一个旧手机废物利用变成工作利器的软件。可以在 Android 手机上快捷打开 windows 上的文件夹、文件、程序、命…

鸿蒙时间滑动选择器弹窗

例子&#xff1a; Button(打开弹窗).fontSize(14).width(106).height(32).padding({ left: 0, right: 0 }).fontColor(#999).onClick(()>{DatePickerDialog.show({selected:new Date(),onDateAccept:(value)>{AlertDialog.show({ message:JSON.stringify(value) })}})}) …

“Excel+中文编程”衍生新型软件,WPS用户:自家孩子

你知道吗&#xff0c;我们中国人有时候真的挺有创新精神的。 你可能熟悉Excel表格&#xff0c;也可能听说过中文编程&#xff0c;但你有没有脑洞大开&#xff0c;想过如果把这两者结合起来&#xff0c;会碰撞出什么样的火花呢&#xff1f; 别不信&#xff0c;跟着我来看看吧&a…

实时通信的方式——WebRTC

文章目录 基于WebRTC实现音视频通话P2P通信原理如何发现对方&#xff1f; 不同的音视频编解码能力如何沟通&#xff1f;&#xff08;媒体协商SDP&#xff09;如何联系上对方&#xff1f;&#xff08;网络协商&#xff09; 常用的API音视频采集getUserMedia核心对象RTCPeerConne…

raid配置与实战10

一、raid理论 1、raid概述 raid&#xff08;磁盘阵列&#xff09;&#xff1a;是用不同的硬盘分区&#xff0c;组成一个逻辑上的硬盘&#xff0c;高可用&#xff08;冗余&#xff09;。 2、raid级别 2.1、raid0条带化存储 数据分散在多个物理磁盘上的存储方式&#xff0c;…

vue3学习(四)

前言 接上篇学习笔记&#xff0c;分享3个内置组件&#xff1a;动态组件、缓存组件、分发组件基本用法。大家一起通过code的示例&#xff0c;从现象理解,注意再次理解生命周期。 一、code示例 组件A&#xff1a;CompA <script setup> import {onMounted, onUnmounted} f…

linux Inodes满导致数据库宕机

项目经理反馈集群环境中有个节点无法使用了需要支援下&#xff0c;同时发过来截图说明磁盘还是有空的。 登录系统后直接发现问题 orcl2:/home/oracledb2> sqlplus / as sysdba SQL*Plus: Release 11.2.0.4.0 Production on Wed May 29 13:59:21 2024 Copyright (c) 1982,…

民国漫画杂志《时代漫画》第32期.PDF

时代漫画32.PDF: https://url03.ctfile.com/f/1779803-1248635561-0ae98a?p9586 (访问密码: 9586) 《时代漫画》的杂志在1934年诞生了&#xff0c;截止1937年6月战争来临被迫停刊共发行了39期。 ps: 资源来源网络!

类的内存对齐位段位图布隆过滤器哈希切割一致性哈希

文章目录 一、类的内存对齐1.1规则1.2原因 二、位段2.1介绍2.2内存分配问题2.3跨平台问题2.4使用的注意事项 三、位图的应用3.1 给40亿个不重复的无符号整数&#xff0c;找给定的一个数。&#xff08;int的范围可以到达42亿多&#xff09;3.2 给定100亿个整数&#xff0c;设计算…

记录github小程序短视频系统的搭建过程

GitHub - lkmc2/AwesomeVideoWxApp: 《倾心短视频》微信小程序 这个项目按readme中的来可以部署成功&#xff0c;但是会发现图片、视频全是空的&#xff0c;如下图&#xff1a; 修改源代码&#xff0c;更换图片上传与保存地址 大概涉及到这些代码块&#xff0c;进行更改即可。…

Codeforces Round 948 (Div. 2) E. Tensor(思维题-交互)

题目 n(3<n<100)个点的有向图&#xff0c; 图的边的关系未知&#xff0c;但保证以下两点&#xff1a; 1. 只存在j->i&#xff08;i<j&#xff09;的边 2. 对于任意三个点i、j、k&#xff08;i<j<k&#xff09;&#xff0c;要么k可以到达i&#xff0c;要么…

开源数据库同步工具DBSyncer

前言&#xff1a; 这么实用的工具&#xff0c;竟然今天才发现&#xff0c;相见恨晚呀&#xff01;&#xff01;&#xff01;&#xff01; DBSyncer&#xff08;英[dbsɪŋkɜː]&#xff0c;美[dbsɪŋkɜː 简称dbs&#xff09;是一款开源的数据同步中间件&#xff0c;提供M…