C++ STL - 优先级队列及其模拟实现

目录

0. 引言

1. priority_queue 介绍 

1.1 构造函数 

1.2 priority_queue 接口函数使用 

1.3 仿函数 

 1.4 题目练习

 2. priority_queue 模拟实现

2.1基本框架:

2.2 默认构造函数

2.3 基本函数

2.4 堆的向上以及向下调整


0. 引言

优先队列 (priority_queue) 是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。优先队列和堆本质是一样的,以数组形式存储的完全二叉树。

1. priority_queue 介绍 

1.1 构造函数 

我们可以看到有两种构造方式,一个是构造一个空对象,另一个是通过迭代器的区间来构造,默认的构造出的是大堆

priority_queue<int> pq1; //直接构造空对象

接下来我们分别以大堆和小堆的方式来构造对象:

	vector<int> v1 = {3,2,7,6,0,4,1,9,8,5};
	priority_queue<int, vector<int>, less<int>> pq1(v1.begin(), v1.end());
                                    //less-大堆
	while (!pq1.empty())
	{
		cout << pq1.top() << " ";
		pq1.pop();
	}
	cout << endl;

	priority_queue<int, vector<int>, greater<int>> pq2(v1.begin(), v1.end());
                                    //greater-小堆
	while (!pq2.empty())
	{
		cout << pq2.top() << " ";
		pq2.pop();
	}
	cout << endl;

	priority_queue<int> pq3(v1.begin(), v1.end());
                                    //默认大堆
	while (!pq3.empty())
	{
		cout << pq3.top() << " ";
		pq3.pop();
	}
	cout << endl;

因此我们得出: less - 大堆, greater - 小堆。 

1.2 priority_queue 接口函数使用 

接口函数主要包括以下:

函数说明
empty检测优先级队列是否为空,是返回true,否则返回 false
top返回优先级队列中最大(最小元素),即堆顶元
push在优先级队列中插入元素x
pop删除优先级队列中最大(最小)元素,即堆顶元素

1.3 仿函数 

仿函数又名函数对象 function objects 仿函数的主要作用是借助类和运算符重载,做到同一格式兼容所有函数。由于模板将 less 用作大堆,而 greater 用做小堆,是在有点别扭,如果是我们自己实现仿函数的化,肯定会按照习惯来写,less 表示小堆,greater 表示大堆。例如:

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

 1.4 题目练习

优先级队列适合来进行TOPK 以及 排序问题,因为其底层是和堆一模一样的。现在我们一起来看下面这道题:

这题如果不关心时间复杂度,直接利用 sort 排序将会很简单:

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) 
    {
        sort(nums.begin(),nums.end());
        return nums[nums.size()-k];    
    }
};

 当我们使用优先级队列时,时间复杂度会更好:

//大堆
class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) 
    {
    priority_queue<int> pq1(nums.begin(), nums.end());
      for(int i = 0;i < k-1; i++)
      {
            pq1.pop();
      }
       return pq1.top(); 
    }
};
//小堆
class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) 
    {
    priority_queue<int,vector<int>, greater<int>> pq1(nums.begin(), nums.begin()+k);
    for(int i = k ;i < nums.size(); i++)
    {
        if(nums[i] > pq1.top())
        {
            pq1.pop();
            pq1.push(nums[i]);
        }
    }
    return pq1.top(); 
    }  
};

 2. priority_queue 模拟实现

 优先级队列的模拟实现,难点在于堆的 向上和向下调整。

2.1基本框架:

#pragma once

#include <vector>

namespace LHY
{
	//默认底层结构为 vector
	template<class T, class Container = std::vector<T>>
	class priority_queue
	{
	public:
		//构造函数及其他功能
	private:
		Container _con;	//其中的成员变量为底层容器对象
	};
}

2.2 默认构造函数

//默认构造函数
priority_queue()
	:_con()
{}

//迭代器区间构造
template<class InputIterator>
priority_queue(InputIterator first, InputIterator last)
	:_con()
{
	while (first != last)
	{
		push(*first);
		first++;
	}
}

2.3 基本函数

//判断是否为空
bool empty() const
{
	return _con.empty();
}

//优先级队列的大小(有效元素数)
size_t size() const
{
	return _con.size();
}

//堆顶元素(优先级最 高/低 的值)
const T& top() const
{
	return _con.front();
}

2.4 堆的向上以及向下调整

//向上调整
void adjust_up(size_t child)
{
	size_t parent = (child - 1) / 2;

	while (child != 0)
	{
		//父 > 子 此时为大堆,如果不符合,则调整
		if (_con[child] > _con[parent])
		{
			std::swap(_con[child], _con[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
			break;
	}
}
//向下调整
void adjust_down(size_t parent)
{
	size_t child = parent * 2 + 1;	//假设左孩子为 【大孩子 / 小孩子】

	while (child < size())
	{
		//判断右孩子是否比左孩子更符合条件,如果是,则切换为与右孩子进行比较
		if (child + 1 < size() && _con[child + 1] > _con[child])
			child++;

		//父 > 子 此时为大堆,如果不符合,则调整
		if (_con[child] > _con[parent])
		{
			std::swap(_con[child], _con[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
			break;	//满足条件时,一样需要跳出,不再调整
	}
}

 


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

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

相关文章

【测试开发学习历程】认识Python + 安装Python

目录 1 认识 Python 1.1 Python 的起源 1.2 Python的组成 1.2.1 解释器 1.1.2 Python 的设计目标 1.1.3 Python 的设计哲学 1.2 为什么选择 Python 测试人员选择Python的理由 1.3 Python 特点 面向对象的思维方式 1.4 Python 的优缺点 1.4.1 优点 1.4.2 缺点 3. 安…

Unity编辑器功能将AB资源文件生成MD5码

将路径Application.dataPath/ArtRes/AB/PC文件夹下所有的Ab包文件生成MD5吗&#xff0c;通过文件名 文件长度MD5‘|’的格式拼接成字符串写入到资源对比文件abCompareInfo.txt中。 将路径pathFile扥文件生成MD5码

vue项目在本地源码方式启动和打包之后在nginx中代理有什么不同

Vue项目在本地源码方式启动和打包之后在Nginx中代理的主要区别在于开发环境与生产环境的配置、性能优化、安全性和部署流程等方面。以下是一些具体的差异点&#xff1a; 开发环境与生产环境&#xff1a; 本地源码启动通常是在开发环境中&#xff0c;使用Vue CLI的vue-cli-servi…

关于在forEach循环中使用异步,造成forEach里面的函数还未执行完毕,外层的同步已经被执行的问题

使用 原生的 for循环替代forEach循环即可解决问题 1.实例代码&#xff1a; select_Father_comment_sql_res.forEach( (item) > {const Select_FId_children_sql util.format("Select *, \IFNULL(User.UserName,) as CommentUserName, \IFNULL(User.UserName,) as AtU…

【王道训练营】第3题 判断某个年份是不是闰年,如果是闰年,请输出“yes”,否则请输出“no”

文章目录 引言闰年初始代码代码改进改进1&#xff1a;添加提示信息改进2&#xff1a;代码格式改进3&#xff1a;变量命名 其他实现方式使用if-else语句使用函数使用三元操作符 结论 引言 在公历中&#xff0c;闰年的规则如下&#xff1a;如果某个年份能被4整除但不能被100整除…

pycharm使用远程服务器的jupyter环境

1、确保服务器上安装了jupyter,如果没有&#xff0c;执行下面命令安装 pip install jupyter2、启动jupyter notebook服务 jupyter notebook --no-browser --port8888 --ip0.0.0.0 --allow-root表明在服务器的8888 端口上启动 Jupyter Notebook&#xff0c;并允许从任何 IP 地…

qt事件机制学习笔记

实现闹钟功能 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), speecher(new QTextToSpeech(this)) //给语音播报者实例化空间 {ui->setupUi(this); }Widget::~Widget() {delete …

CMake学习笔记(一)一个最简单的CMakeLists嵌套示例

目录 1 mkdir project_macro 2 在project_marco中建立CMakeLists.txt 3 建立专门的src文件夹 4 在src中添加main.cpp和CMakeLists.txt 5 回到project_macro目录&#xff0c;建立build文件夹 6 进入build 文件夹&#xff0c;开始cmake 7 在build文件夹里执行make指令 8 …

Vue.js 安装

1、独立版本 我们可以在 Vue.js 的官网上直接下载 vue.min.js 并用 <script> 标签引入。 2、使用 CDN 方法 以下推荐国外比较稳定的两个 CDN&#xff0c;国内还没发现哪一家比较好&#xff0c;目前还是建议下载到本地。 Staticfile CDN&#xff08;国内&#xff09; :…

uniapp开发H5页面如何打开调试 (vConsole)

前言&#xff1a; H5页面没有微信小程序那样的直接打开调试工具的功能&#xff0c;需要手动安装引用。步骤如下&#xff1a; 一、安装vConsole npm install vconsole 二、引用vConsole 在main.js文件中引入使用 import Vconsole from vconsole let vConsole new Vconsole()…

深度学习的发展历史(深度学习入门、学习指导)

目录 &#x1f3c0;前言 ⚽历史 第一代神经网络&#xff08;1958-1969&#xff09; 第二代神经网络&#xff08;1986-1998&#xff09; 统计学习方法的春天&#xff08;1986-2006&#xff09; 第三代神经网络——DL&#xff08;2006-至今&#xff09; &#x1f3d0;总结…

【MySQL】数据库--库操作

目录 一、创建数据库 二、打开数据库 三、修改数据库 四、显示数据库 五、删除数据库 六、备份与恢复数据库 1.备份&#xff1a; 2.恢复&#xff1a; 一、创建数据库 CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [,create_specification] …] [DEF…

原生数据开发软件 TablePlus for mac

一款非常好用的本地原生数据开发软件&#xff1a;TablePlus激活版。 软件下载&#xff1a;TablePlus for mac v3.11.0激活版 这款优秀的数据库编辑工具支持 MySQL、SQL Server、PostgreSQL 等多种数据库&#xff0c;具备备份、恢复、云同步等功能。它可以帮助您轻松编辑数据库中…

案例分享 | ESP32-C3+智能车库门应用方案 小尺寸低功耗

以前的车库门Opener只能通过墙壁开关或者遥控器来控制开启或关闭&#xff0c;超过一定距离的话无法通过遥控器来操控车库门&#xff0c;也无法随时查看车库门的状态&#xff0c;而启明云端智能车库门方案&#xff0c;可以通过手机APP远程控制车库门&#xff0c;实现远程开关门、…

Cadence——导出BOM清单

首先使用Allegro PCB Designer打开xxx .brd PCB制板文件 如下图&#xff0c;然后点击Tools–>Quick Reports&#xff0c;再选择Bill of Material Report或者Bill of Material Report(Condensed)&#xff0c;这两个的区别就是上面的导出的BOM物料清单中相同的器件是不会合并的…

基于“云”重构“百度云盘”

这一篇文章是和上一篇连着的哟&#xff01; # docker run -p 80:80 -d -v /data/owncloud/:/var/www/html owncloud 一、【安装完成】 二、【打开浏览器】 三、【回到这个熟悉的界面&#xff0c;掉。】 四、【上传文件】 试了可以看哇偶&#xff01;&#xff01;&#xff01…

四年创作,心路历程

四年创作&#xff0c;心路历程 前言初识收获日常憧憬 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 前言 今天打开csdn&#xff0c;发现官方发送了一条私信,原来我已经在计算机这…

分享 | 使用Virtuoso VCPVSR工具基于标准单元的布局布线流程

​ 本节内容 导览 一、准备工作 二、运行VCP前的配置 三、VCP的布局规划 四、VCP的自动摆放 五、VSR的自动绕线 分享使用Virtuoso GXL Custom Digital Placer(VCP) & Space-based Router(VSR)工具进行基于纯数字Standard-Cell布局布线的操作流程。 VCP&VSR演…

TCP(socket 套接字)编程 1

一、TCP套接字编程架构如下 二、相关代码实现 1、服务器端代码 package com.company;import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket;public class Main {public static void main(String[] args) {…

A Novel Negative Sample Generating Method for KnowledgeGraph Embedding

摘要 为了有效地提取知识图中的关系和原因&#xff0c;将实体和关系编码到一个连续的低维语义空间中。在负样本生成阶段&#xff0c;大多数知识图嵌入方法更注重替换头或尾实体以提高训练效率&#xff0c;很少替换关系。这些负样本生成方法对关系预测的贡献不大。本文提出了一…