C++ STL之priority_queue的使用及模拟实现

文章目录

  • 1. 介绍
  • 2. priority_queue的使用
  • 3. priority_queue的模拟实现


1. 介绍

英文解释:

在这里插入图片描述

也就是说:

  1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。

  2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。

  3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。

  4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:
    empty():检测容器是否为空
    size():返回容器中有效元素个数
    front():返回容器中第一个元素的引用
    push_back():在容器尾部插入元素
    pop_back():删除容器尾部元素

  5. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。

  6. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。

作图理解:
在这里插入图片描述
关于其底层数据结构可以参照树、二叉树(C语言版)中==二叉树的顺序结构实现==部分的内容,这里重点讲解priority_queue的使用和其在库中的模拟实现。

2. priority_queue的使用

template <class T, class Container = vector<T>, class Compare = less<typename Container::value_type>> class priority_queue;

priority_queue是容器适配器。使用时需实例化其模板参数。

有三个模板参数:

  1. T:表示存储在优先级队列中的元素的类型。
  2. Container:表示用于存储元素的底层容器类型。默认情况下,它使用 vector<T>,但你可以根据需要指定其他容器类型。
  3. Compare:表示用于比较元素优先级的函数对象类型(传参可以用类重载operator()形成的仿函数)。默认情况下,它使用 less<typename Container::value_type>,这将使用元素类型的 < 运算符来进行比较。你也可以提供自定义的比较函数对象。即默认为==大堆==。

用法样例:

class mycomparison
{
    bool reverse;
public:
    mycomparison(const bool& revparam = false)
    {
        reverse = revparam;
    }
    bool operator() (const int& lhs, const int& rhs) const
    {
        if (reverse) return (lhs > rhs);
        else return (lhs < rhs);
    }
};

int main()
{
    int myints[] = { 10,60,50,20 };

    std::priority_queue<int> first;
    std::priority_queue<int> second(myints, myints + 4);
    std::priority_queue<int, std::vector<int>, std::greater<int> >
        third(myints, myints + 4);
    // using mycomparison:
    typedef std::priority_queue<int, std::vector<int>, mycomparison> mypq_type;

    mypq_type fourth;                       // less-than comparison
    mypq_type fifth(mycomparison(true));   // greater-than comparison

    return 0;
}

说明:

  • first 变量是空的 priority_queue 对象,使用默认的 less 比较,是大堆。
  • second 变量包含了四个整数,这四个整数由 myints 定义。默认使用 less 比较,所以为大堆,此时堆顶为60。
  • third 变量包含四个整数,只不过使用了 greater 比较,变成了小堆,此时堆顶为10。
  • fourth 变量是空的 priority_queue 对象,使用自定义的比较方式 mycomparision,此时同样为大堆。
  • fifth 变量是空的 priority_queue 对象,使用自定义的比较方式 mycomparision,同时传参 true 构造改变了operator()的返回值,此时为小堆。

注:这里由于 mycomparison 重载了operator(),所以可以作为仿函数充当形参。具体调用 mycomparison 时的操作,请看模拟实现部分。

接口成员函数

函数名称代码功能说明
emptybool empty() const;返回 priority_queue 是否为空。
sizesize_type size() const;返回 priority_queue 中元素个数。
topconst_reference top() const;返回堆顶元素的引用。
pushvoid push (const value_type& val);
void push (value_type&& val);
向 priority_queue 插入一个新元素 val。
popvoid pop();删除堆顶元素。
swapvoid swap (priority_queue& x) noexcept;用于和另一个容器适配器 x 交换内容。

priority_queue的遍历

#include <iostream>
#include <queue>

int main()
{
    int myints[] = { 10,60,50,20,30,100,200 };
    std::priority_queue<int> myPriorityQueue(myints, myints + sizeof(myints) / sizeof(int));

    // 使用迭代器遍历优先级队列
    std::priority_queue<int> tempQueue = myPriorityQueue; // 创建临时队列用于遍历
    while (!tempQueue.empty())
    {
        std::cout << tempQueue.top() << " ";
        tempQueue.pop();
    }

    return 0;
}

运行结果:

在这里插入图片描述

说明:

首先将其内容复制到一个临时队列 tempQueue 中,使用 top 函数访问临时队列的顶部元素,将其输出,然后使用 pop 函数将其从队列中移除。重复这个过程,直到临时队列为空。

3. priority_queue的模拟实现

#pragma once
#include<vector>

using namespace std;

namespace my_priority_queue
{
    // 大堆
    template<class T>
    struct less
    {
        bool operator()(const T& left, const T& right)
        {
            return left < right;
        }
    };
	
    // 小堆
    template<class T>
    struct greater
    {
        bool operator()(const T& left, const T& right)
        {
            return left > right;
        }
    };

    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)
            :c(first, last)
        {
            for (int i = (c.size() - 1 - 1) / 2; i >= 0; i--)
            {
                adjudge_down(i);
            }
        }

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

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

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

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

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

    private:
        void adjudge_up(size_t child)
        {
            if (child == 0)
                return;
            size_t 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 adjudge_down(size_t parent)
        {
            size_t 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]);
                    parent = child;
                    child = parent * 2 + 1;
                }
                else
                {
                    break;
                }
            }
        }

        Container c;
        Compare comp;
    };
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

伊恩·斯图尔特《改变世界的17个方程》麦克斯韦方程方程笔记

它告诉我们什么&#xff1f; 电和磁并不会随便乱跑。旋转的电场区域会产生垂直于旋转方向的磁场。旋转的磁场区域也会产生垂直于旋转方向的电场&#xff0c;但方向相反。 为什么重要&#xff1f; 这是物理力的第一次重大统一&#xff0c;表明电和磁是密切相关的。 它带来了什么…

数据结构—基础知识(十):树和二叉树(b)

数据结构—基础知识&#xff08;十&#xff09;&#xff1a;树和二叉树(b) 二叉树的定义 二叉树( Binary Tree)是n(n≥0)个结点所构成的集合&#xff0c;它或为空树(n0)&#xff1b;或为非空树&#xff0c;对于非空树T: 有且仅有一个称之为根的结点&#xff1b;根结点以外的…

Oracle错误代码对应原因

Oracle oracle查询列长度太长ORA-01460ORA-01489ORA-01704 oracle查询列长度太长 查询的varchar的列字符串长度超过4000(取决与oracle怎么计算这个字符的长度) 例如&#xff1a; col like ‘%?%’&#xff0c;如果这个like后面的字符串长度超过4000就会报错&#xff0c;其中…

vivado使用注意事项

记得给constrs&#xff08;.xdc&#xff09;限制文件设置为目标文件&#xff08;set as Target Consraint File&#xff09;

计算机网络原理

第一章 认识计算机网络 &#x1f449;计网体系结构 一、计算机网络概述 见x-mind 二、体系结构&参考模型 1.1 分层结构 1.1.1❓❓❓为什么要分层&#xff1f; 发送文件前要完成的工作&#xff1a; 发起通信的计算机必须将数通信的通路进行激活要告诉网络如何识别目的…

springboot120企业级工位管理系统

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的企业级工位管理系统 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 …

vue 解决:Module not found: Error: Can‘t resolve ‘vue-router‘ 的问题

1、问题描述&#xff1a; 其一、报错为&#xff1a; Module not found: Error: Cant resolve vue-router 中文为&#xff1a; 找不到模块&#xff1a;错误&#xff1a;无法解析“vue-router” 其二、问题描述为&#xff1a; 根据报错的中文信息可知&#xff1a;应该是无法…

项目成本估算基准的常见步骤

项目成本估算基准是指在项目启动阶段确定的用于衡量和控制项目成本的基准。 基准成本是项目成本估算的依据&#xff0c;也是后续成本控制和决策的依据。它为管理层提供项目预算投资方案等关键投资依据&#xff0c;决定资源的分配情况&#xff0c;有助于优化资源使用效率&#x…

B-Tree详解及编码实现

一、概念和特性 1、定义 B-Tree是一种平衡的多叉树&#xff0c;适用于外查找多路搜索树&#xff0c;这种数据结构能够保证数据节点查找、顺序访问、插入、删除的动作&#xff0c;其平均时间复杂读控制在O(logN)内;B树为系统大块数据的读写操作做了优化&#xff0c;少定位记录时…

HCIP 交换

拓扑图&IP划分如下&#xff1a; 第一步&#xff0c;配制VLAN LSW1&#xff0c;LSW2&LSW3同理 检测 LSW1 LSW2 测试

最适合家用的洗地机哪个牌子好?清洁力强的洗地机推荐

随着家用市场的不断壮大&#xff0c;洗地机逐渐为人们熟知。众多厂家为提升深度清洁效果投入大量成本和时间&#xff0c;然而消费者在选择洗地机时往往难以判断品质。无线洗地机市场上涌现多个品牌&#xff0c;如何找到性能优越、实惠耐用的机型呢?在了解洗地机时&#xff0c;…

实战内网穿透NPS搭建过程

前提条件 首先你要有个公网IP的服务器&#xff0c;既然是内网穿透&#xff0c;那必然是通过公网IP或者域名访问本地服务。 官网下载地址 https://github.com/ehang-io/nps/releases 服务端 选择linux_amd64_server.tar.gz 客户端 选择windows_amd64_client.tar.gz 服…

列表的创建与删除

Python 中列表可以动态地添加、修改和删除元素&#xff0c;是 Python 编程中不可或缺的一部分。本文将介绍如何使用 Python 创建和删除列表&#xff0c;以及常用的方法和技巧。 创建列表 在 Python 中&#xff0c;我们可以使用一对方括号 [ ] 来创建一个空列表&#xff0c;也可…

UF_UI_select_with_single_dialog()通过单选对话框选择单个对象。对象可以通过光标或输入名称进行选择。对象被突显出来。

int response0;//返回用户操作类型&#xff0c;点了哪一种返回取消或者确定tag_t objtagNULL_TAG;//输出选择对象tag;double cursor[ 3 ];//输出光标位置tag_t view_tagNULL_TAG;//输出视图tag;UF_UI_select_with_single_dialog("请选择一个对象","获取对象类型…

dolphinscheduler节点二次开发需要改动的部分

dolphinscheduler节点二次开发需要改动的部分 前端 在dolphinscheduler-ui/public/images/task-icons/目录下新增两个节点的logo图片&#xff0c;一个为激活状态的一个为非激活状态的&#xff0c;如下。 修改文件dolphinscheduler-ui/src/views/projects/task/constants/task…

CSS高级技巧导读

1&#xff0c;精灵图 1.1 为什么需要精灵图&#xff1f; 目的&#xff1a;为了有效地减少服务器接收和发送请求的次数&#xff0c;提高页面的加载速度 核心原理&#xff1a;将网页中的一些小背景图像整合到一张大图中&#xff0c;这样服务器只需要一次请求就可以了 1.2 精灵…

centos7.9安装redmine5.1.1

前提&#xff1a; 安装mysql并新建数据库--教程太多了此步骤省略&#xff1b; 用sqlyog连上mysql创建数据库redmine&#xff1b; 1.下载redmine-5.1.1.tar.gz&#xff0c;上传到/usr/local/software目录下&#xff1b; 2.解压 cd /usr/local/software tar -zxvf redmine-5.…

JavaScript进阶:WebAPIs重点知识整理2

目录 1 对节点的相关操作 1.1 查找节点 1.1.1 查找节点的父节点 1.1.2 查找节点的子节点 1.1.3 查找节点的兄弟节点 1.2 新增节点&#xff08;先创建&#xff0c;后追加&#xff09; 1.3 克隆节点 1.4 删除节点 2 M 端&#xff08;移动端&#xff09;事件 3 JS清空表…

uniapp使用uni-forms表单校验无效

查看是否写了name属性&#xff0c;且name属性的属性值得和下面v-model绑定的一致&#xff0c;否则校验不生效 官网

C#string字符串相关面试题

C#字符串&#xff08;string&#xff09;是什么类型 C#中的字符串是一种引用类型&#xff0c;属于.NET Framework中的System.String类。在C#中&#xff0c;字符串是不可变的&#xff0c;也就是说&#xff0c;一旦被创建&#xff0c;就不能再被修改。这意味着对于任何字符串的操…