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.mzph.cn/web/18705.shtml

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

相关文章

可选链与空值合并运算符的妙用

可选链&#xff08;Optional Chaining&#xff09;和空值合并运算符&#xff08;Nullish Coalescing Operator&#xff09;是 JavaScript 中的两个新特性&#xff0c;它们可以在处理可能为 null 或 undefined 的值时提供更简洁和安全的代码。 可选链允许我们通过在对象的属性后…

【好书分享第十三期】AI数据处理实战108招:ChatGPT+Excel+VBA

文章目录 一、内容介绍二、内页插图三、作者简介四、前言/序言五、目录 一、内容介绍 《AI数据处理实战108招&#xff1a;ChatGPTExcelVBA》通过7个专题内容、108个实用技巧&#xff0c;讲解了如何运用ChatGPT结合办公软件Excel和VBA代码实现AI办公智能化、高效化。随书附赠了…

NDIS驱动开发-NET_BUFFER体系

网络数据由通过网络发送或接收的数据包组成。 NDIS 提供数据结构来描述和组织此类数据。 NDIS 6.0 及更高版本的主要网络数据结构包括&#xff1a; NET_BUFFERNET_BUFFER LISTNET_BUFFER_LIST_CONTEXT 它们之间的关系如下: 在 NDIS 6.0 及更高版本中&#xff0c; NET_BUFFER …

AI工程师:高薪时代的领跑者

在科技飞速发展的今天&#xff0c;人工智能&#xff08;AI&#xff09;技术正日益成为推动社会进步的关键力量。与此同时&#xff0c;AI领域的人才需求也呈现出井喷之势&#xff0c;其中AI工程师更是成为了各大企业竞相争夺的“香饽饽”。根据最新数据显示&#xff0c;AI工程师…

串口调试助手中文乱码 解决方案

输出乱码 一般&#xff0c;当串口调试助手输出乱码时&#xff0c;可能有以下几个原因&#xff1a; 波特率设置错误&#xff1a;串口通信需要保证发送和接收的设备使用相同的波特率。请检查串口调试助手和目标设备的波特率设置是否一致。 数据位、停止位或校验位设置错误&…

支持向量机、随机森林、K最近邻和逻辑回归-九五小庞

支持向量机&#xff08;Support Vector Machine, SVM&#xff09;、随机森林&#xff08;Random Forest&#xff09;、K最近邻&#xff08;K-Nearest Neighbors, KNN&#xff09;和逻辑回归&#xff08;Logistic Regression&#xff09;是机器学习和统计学习中常用的分类算法。…

【目标解算】相机内外参数详细解读+坐标系转换

一、相机参数介绍 1.1 相机内参矩阵 概念&#xff1a;内参矩阵用于描述相机的内部参数&#xff0c;它包含了相机的焦距、主点坐标和图像的畸变等信息。内参矩阵的形式通常为一个3x3的矩阵&#xff0c;常用表示为K。内参矩阵可以将相机坐标系中的三维点映射到图像平面上的二维…

C++设计模式之策略模式、迭代器模式、适配器模式、工厂模式、超级工厂模式、享元模式、代理模式

文章目录 一、介绍1.毫无价值的使用虚函数例子 二、策略模式1.策略模式2.多重策略与迭代器模式3.不要什么东西都塞一块 三、适配器模式1.跨接口的适配器2.跨接口的适配器 四、工厂模式1.工厂模式2.超级工厂模式3.RAII 自动管理内存4.工厂模式实战 五、享元模式1.享元模式2.代理…

linux安装mysql后,配置mysql,并连接navicat软件

Xshell连接登陆服务器 输入全局命令 mysql -u root -p 回车后&#xff0c;输入密码&#xff0c;不显示输入的密码 注意mysql服务状态&#xff0c;是否运行等 修改配置文件my.cnf&#xff0c;这里没找到就找my.ini&#xff0c;指定有一个是对的 find / -name my.cnf 接下…

GPT-4你了解多少呢

一、引言 在人工智能&#xff08;AI&#xff09;领域&#xff0c;自然语言处理&#xff08;NLP&#xff09;技术一直备受关注。近年来&#xff0c;随着深度学习技术的飞速发展&#xff0c;NLP领域也取得了显著进步。GPT-4&#xff0c;作为OpenAI公司最新发布的自然语言处理模型…

bochs 调试基本指令大全

bochs 调试基本指令大全 功能 指令 举例 在某物理地址设置断点 b addr b 0x90000 运行到断点位置 c c 单步运行&#xff08;遇到函数则进入&#xff09; s s 单步运行&#xff08;遇到函数则跳过&#xff09; n n 继续运行上调指令 回车 回…

liunx进程和计划任务管理

文章目录 一、进程特殊情况 二、查看进程2.1进程查看2.2补充说明 三、进程管理3.1运维的指标五大负载 3.2定时任务、计划任务 一、进程 进程管理 相当于任务管理器 进程就是运行起来的代码 线程&#xff1a;线程相当于复制了进程的部分代码&#xff0c;程序运行起来之后&…

2024-03-23青少年软件编程(Python语言)等考(五级)解析

2024-03-23青少年软件编程(Python语言)等考(五级)解析一、单选题(共25题,共50分) 1.以下代码的输出结果是?( A ) nums = list(range(100, 201)) print(nums[::10]) A.[100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200] B.[100, 101, 102, 103, 104, 105, 106…

京东二面:为什么Netty要造FastThreadLocal?

FastThreadLocal 从字面意义上来看&#xff0c;它是“Fast”“ThreadLocal”的结合体&#xff0c;寓意为快速的 ThreadLocal。那么&#xff0c;问题来了&#xff0c;Netty 为什么要再造一个 FastThreadLocal&#xff1f;FastThreadLocal 运行快的原因是啥&#xff1f;除了快之外…

linnux上安装php zip(ZipArchive)、libzip扩展

安装顺序&#xff1a; 安装zip&#xff08;ZipArchive&#xff09;&#xff0c;需要先安装libzip扩展 安装libzip&#xff0c;需要先安装cmake 按照cmake、libzip、zip的先后顺序安装 下面的命令都是Linux命令 1、安装cmake 确认是否已安装 cmake --version cmake官网 未安装…

项目十 网络服务器搭建及应用

文章目录 Samba1.配置yum源2.安装samba服务和客户端3.添加用户4.修改访问控制权限&#xff0c;使samba指定的目录可以正常访问5.修改samba配置参数6.启动samba服务7.查看samba运行情况8.通过外部服务器访问 I know, i know 地球另一端有你陪我 Samba 1.配置yum源 mkdi…

【Paddle】稀疏计算的使用指南 稀疏ResNet的学习心得 (2) + Paddle3D应用实例稀疏 ResNet代码解读 (1.6w字超详细)

【Paddle】稀疏计算的使用指南 & 稀疏ResNet的学习心得 Paddle3D应用实例稀疏 ResNet代码解读 写在最前面一、稀疏格式简介1. COO&#xff08;Coordinate Format&#xff09;2. CSR&#xff08;Compressed Sparse Row Format&#xff09; 二、Paddle稀疏张量支持1. 创建 C…

SQL刷题笔记day6——转战LeetCode

1 第二高的薪水 ​ 我的代码&#xff1a; SELECT Salary SecondHighestSalary FROM Employee ORDER BY Salary DESC LIMIT 1, 1 我的代码不满足示例2的情况&#xff1a;如果没有第 2 高的薪资&#xff0c;即表里可能只有一条记录&#xff0c;这个解答会被评测为 Wrong Answ…

整理了六个正规靠谱的兼职赚钱软件,适合普通人做的兼职副业~

​随着互联网时代的到来&#xff0c;越来越多的人选择通过互联网赚钱。在这篇文章中&#xff0c;我们将探讨一些可以在网上长期赚钱的方法。 在网络上面其实有很多的赚钱方法&#xff0c;尽管方法很多&#xff0c;但是对于一些网络新手&#xff0c;刚进入互联网圈子不久的伙伴…

智慧校园建设的重要性有哪些

在21世纪的数字化浪潮中&#xff0c;教育领域正经历一场深刻的变革。智慧校园&#xff0c;这一概念如同一股清风&#xff0c;席卷全球的高等教育机构&#xff0c;以其创新的科技应用和教育理念&#xff0c;重塑着学习的未来。面对信息时代的挑战&#xff0c;传统校园模式是否还…