[C++随想录] 优先级队列的模拟实现

news2024/11/18 17:34:48

优先级队列的模拟实现

  • 底层结构
  • 初始化
  • 向下调整 && 向上调整
  • push && pop
  • top && empty && size
  • 源码

底层结构

namespace muyu
{
	template <class T, class Continer = std::vector<T>, class Compare = less<T> >
	class priority_queue
	{

		private:
			Continer _con; // 底层维护的容器
	};
}

在库中, priority_queue是有三个模版参数的,
T — — 控制数据类型
Container — — 容器适配器
Compare — — 仿函数, 控制大小堆的

那么有两个问题:

  1. Container 为啥默认是vector, 而不是 deque呢?
    通过前面数据结构的学习, 我们知道 堆是支持随机访问的, 即支持下标访问, []会用的很频繁的
    list不用说了, 不支持下标访问
    deque虽然支持下标访问, 但 [] 不够极致 ⇐ 需要计算在哪个buff中, 还要计算在该buff数组中的哪个位置上
    而反观vector, 它的[] 就很极致 ⇐ 连续的空间
  2. 仿函数是啥?
    其实, 前面讲 sort时, 提过一下仿函数.
    仿函数就是 仿函数通过重载(), 从而达到类的对象可以像函数一样使用👇👇👇
template<class T>
class Com
{
public:
	bool operator()(const T& x, const T& y)
	{
		return x > y;
	}
};

int main()
{

	Com<int> com; // 类对象

	int a = 5, b = 3;
	bool res = com(a, b);

	cout << res << endl;
}

运行结果:

1


👇👇👇

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<class T>
class Com
{
public:
	bool operator()(const T& x, const T& y)
	{
		return x > y;
	}
};

int main()
{

	Com<Date> com; // 类对象

	Date d1(2023, 7, 20);
	Date d2(2023, 7, 26);

	bool res = com(d1, d2);

	cout << res << endl;

}

运行结果:

0

当然 仿函数 作为 泛型编程, 在后面 模版的特化 中还有很多意想不到的妙用!!
🗨️ 如果上面的传的是 Date*, 那该怎么办?

void test()
{
	muyu::priority_queue<Date*> pq;
	pq.push(new Date(2023, 9, 27));
	pq.push(new Date(2023, 9, 28));
	pq.push(new Date(2023, 9, 29));
	pq.push(new Date(2023, 9, 1));


	while (!pq.empty())
	{
		cout << *pq.top() << " ";
		pq.pop();
	}
	cout << endl;

}

运行结果:

2023-9-1 2023-9-28 2023-9-27 2023-9-29
  • 如果传的的是 Date*, 编译器的 less 会按照地址的大小去比较, 这并不是我们想要的结果
    我们想要的是 日期之间的比较
    由于是 内置类型, 我们又重载不了!!!
    那该怎么办?
    模版的特化就大显身手了👇👇👇
// 普通的按照T来进行比较
template <class T>
class Less
{
public:
	bool operator()(const T& x, const T& y)
	{
		return x < y;
	}
};

// 偏特化 -- 对类型做进一步的限制
template <class T>
class Less<T*>
{
public:
	bool operator()(const T* x, const T* y)
	{
		return *x < *y;
	}
};

特化, 特化, 就是 对此模版做进一步的特殊化处理
如上面的代码, 我们就针对了 指针 做了特殊处理 – --> 按照指针指向的对象来进行比较


初始化

默认初始化咱就不说了, 底层的容器 vector 是自定义类型, 它本身的初始化就够用了
下面, 我们重点讲讲 迭代区间初始化

priority_queue()
{

}

template<class InputIterator>
priority_queue(InputIterator first, InputIterator last)
{
	// 一股脑地倒进来
	while (first != last)
	{
		_con.push_back(*first);
		++first;
	}

	// 建堆
	for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
	{
		AjustDown(i);
	}
}

注意几个点:

  1. 区间是左闭右开的
  2. 向下调整算法的前提条件是 左右子树都是大(小)堆从第一个非叶子节点开始

向下调整 && 向上调整

private:

	void AjustUp(int child)
	{
		Compare com;
		int parent = (child - 1) / 2;
	
		while (child > 0)
		{
			if( com(_con[parent], _con[child]) )
			{
				std::swap(_con[child], _con[parent]);
	
				// 在内部更新child 和 parent
				child = parent;
				parent = (child - 1) / 2;
			}
			else
			{
				break;
			}
		}
	}
	
	void AjustDown(int parent)
	{
		Compare com;
	
		int child = 2 * parent + 1;
	
		while (child < _con.size())
		{
			// 找到孩子中大的那一个
			if (child + 1 < _con.size() &&  com(_con[child], _con[child + 1]) )
			{
				child++;
			}
	
			if ( com(_con[parent], _con[child]))
			{
				std::swap(_con[parent], _con[child]);

				// 在内部更新parent 和 child
				parent = child;
				child = parent * 2 + 1;
			}
			else
			{
					break;
			}
		}
	}
  1. 默认是 大堆 , 即 less, <

push && pop

  1. push
void push(const T& val = T())
{
	_con.push_back(val);

	AjustUp(_con.size() - 1);
}

堆的整体结构并没有发生变化, 即左右子树都是大(小)堆 ⇒ 使用向上调整

  1. pop
    (1) 删除头节点 ⇒ 交换头尾节点, 删除尾节点
    (2) 头节点的 左右子树的堆结构没有发生变化, 但是头节点有问题 ⇒ 从头节点开始向下调整
void pop()
{
	std::swap(_con[0], _con[_con.size() - 1]);
	_con.pop_back();

	AjustDown(0);

}

top && empty && size

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

bool empty() const
{
	return _con.size() == 0;
}

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

源码

# pragma once

#include<vector>

namespace muyu
{
	template <class T, class Continer = std::vector<T>, class Compare = less<T> >
	class priority_queue
	{
	private:

		void AjustUp(int child)
		{
			Compare com;
			int parent = (child - 1) / 2;

			while (child > 0)
			{
				if( com(_con[parent], _con[child]) )
				{
					std::swap(_con[child], _con[parent]);

					// 在内部更新child 和 parent
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void AjustDown(int parent)
		{
			Compare com;

			int child = 2 * parent + 1;

			while (child < _con.size())
			{
				// 找到孩子中大的那一个
				if (child + 1 < _con.size() &&  com(_con[child], _con[child + 1]) )
				{
					child++;
				}

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

		priority_queue()
		{

		}

		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
		{
			// 一股脑地倒进来
			while (first != last)
			{
				_con.push_back(*first);
				++first;
			}

			// 建堆
			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
			{
				AjustDown(i);
			}
		}

		void push(const T& val = T())
		{
			_con.push_back(val);

			AjustUp(_con.size() - 1);
		}

		void pop()
		{
			std::swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();

			AjustDown(0);

		}

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

		bool empty() const
		{
			return _con.size() == 0;
		}

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

	private:
		Continer _con;
	};
}

夫学贵得之于心。求之于心而非也,虽其言之出于孔子,不敢以为是也,而况其未及孔子者乎?求之于心而是也,虽其言出于庸常,不敢以为非也,而况其出于孔子者乎? — — 王阳明

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

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

相关文章

C#停车场管理系统

目录 一、绪论1.1内容简介及意义1.2开发工具及技术介绍 二、总体设计2.1系统总体架构2.2登录模块总体设计2.3主界面模块总体设计2.4停车证管理模块总体设计2.5停车位管理模块总体设计2.6员工管理模块总体设计2.7其他模块总体设计 三、详细设计3.1登录模块设计3.2主界面模块设计…

力扣:119. 杨辉三角 II(Python3)

题目&#xff1a; 给定一个非负索引 rowIndex&#xff0c;返回「杨辉三角」的第 rowIndex 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;力扣&#xff08;LeetCode&#xff09…

【Linux】ping命令详解

目录 一、ping概述 二、Ping用法 三、ping参数详解 四、使用 五、Wireshark抓取ICMP请求应答消息 一、ping概述 ping 命令用于测试与目标主机之间的连接。它向目标主机发送一个ICMP&#xff08;Internet Control Message Protocol&#xff09;Internet控制报文协议回显请求…

fetch前后端通信

fetch 前后端通信&#xff1a;ajax。 4步走&#xff1a; let xhrnew XMLHttpRequest() xhr.open(get,http://xxx) xhr.onreadystatechange xhr.send() 常用库&#xff1a; jQuery -> 回调地狱 axios fetch&#xff1a;网络获取资源 与Ajax的不同&#xff1a; 网络故障或请求…

激光雷达中实现F-P标准具高热稳定性的帕尔贴精密温控解决方案

摘要&#xff1a;法布里-珀罗标准具作为一种具有高温度敏感性的精密干涉分光器件&#xff0c;在具体应用中对热稳定性具有很高的要求&#xff0c;如温度波动不能超过0.01℃&#xff0c;为此本文提出了相应的高精度恒温控制解决方案。解决方案具体针对温度控制精度和温度均匀性控…

指针笔试题(带解析版)

题目2&#xff1a; struct MyStruct {int num;char* pcname;short sdate;char cha[2];short sba[4]; }*p; //结构体大小为32字节 //p0x100000 int main() {p 0x100000;printf("%p\n", p 0x1);//p&#xff1a;结构体指针&#xff0c;1下一个结构体指针&#xff0c;…

JVM-满老师

JVM 前言程序计数器&#xff0c;栈&#xff0c;虚拟机栈&#xff1a;本地方法栈&#xff1a;堆&#xff0c;方法区&#xff1a;堆内存溢出方法区运行时常量池 前言 JVM 可以理解的代码就叫做字节码&#xff08;即扩展名为 .class 的文件&#xff09;&#xff0c;它不面向任何特…

最新AI创作系统/AI绘画系统/ChatGPT系统+H5源码+微信公众号版+支持Prompt应用

一、AI创作系统 SparkAi创作系统是基于国外很火的ChatGPT进行开发的AI智能问答系统和AI绘画系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图…

Easyx图形库趣味编程note3,颜色模型

EasyX的文档中&#xff0c;不只有用大写字母的形式可绘制出的颜色&#xff0c;它支持更加缤纷多彩的颜色供我们使用。 RGB颜色模型 相信大家都知道三原色&#xff0c;小时候我们趴在电视机前&#xff0c;就可以很明显的发现电视上的色彩是由红绿蓝三种色彩构成&#xff0c;有这…

javascript: Sorting Algorithms

// Sorting Algorithms int JavaScript https://www.geeksforgeeks.org/sorting-algorithms/ /** * file Sort.js * 1. Bubble Sort冒泡排序法 * param arry * param nszie */ function BubbleSort(arry, nszie) {var i, j, temp;var swapped;for (i 0; i < nszie - 1; i)…

云原生微服务 第六章 Spring Cloud Netflix Eureka集成OpenFeign组件,实现微服务的远程调用、负载均衡

系列文章目录 第一章 Java线程池技术应用 第二章 CountDownLatch和Semaphone的应用 第三章 Spring Cloud 简介 第四章 Spring Cloud Netflix 之 Eureka 第五章 Spring Cloud Netflix 之 Ribbon 第六章 Spring Cloud 之 OpenFeign 文章目录 系列文章目录前言1、OpenFeign的实现…

httpserver 下载服务器demo 以及libevent版本的 httpserver

实现效果如下&#xff1a; 图片可以直接显示 cpp h 这些可以直接显示 其他的 则是提示是否要下载 单线程 还有bug 代码如下 先放上来 #include "httpserver.h" #include "stdio.h" #include <stdlib.h> #include <arpa/inet.h> #include…

SpringBoot中使用拦截器

拦截器属于MVC中的内容 SpringBoot项目,引入web依赖即可 需要访问的控制器 拦截器第一步实现HandlerInterceptor接口 第二步实现WebMvcConfigurer接口,并重写addInterCeptors()方法,将自定义的拦截器注册 也就是说这里add进去拦截的请求,才会进入到prehandle方法,这里放行的请…

嵌入式Linux应用开发-驱动大全-同步与互斥①

嵌入式Linux应用开发-驱动大全-同步与互斥① 第一章 同步与互斥①1.1 内联汇编1.1.1 C语言实现加法1.1.2 使用汇编函数实现加法1.1.3 内联汇编语法1.1.4 编写内联汇编实现加法1.1.5 earlyclobber的例子 1.2 同步与互斥的失败例子1.2.1 失败例子11.2.2 失败例子21.2.3 失败例子3…

AMD GPU 内核驱动分析(三)-dma-fence 同步工作模型

在Linux Kernel 的AMDGPU驱动实现中&#xff0c;dma-fence扮演着重要角色&#xff0c;AMDGPU的Render/解码操作可能涉及到多个方面同时引用buffer的情况&#xff0c;以渲染/视频解码场景为例&#xff0c;应用将渲染/解码命令写入和GPU共享的BUFFER之后&#xff0c;需要将任务提…

记录UNIAPP打包苹果iOS·APP

用到生成的四个文件:1-1.CSR证书文件、2-2.CER证书文件、3-3.PP文件【证书Profiles文件】、4-4.P12文件【证书私钥】 1. 生成CSR证书文件: 2. 操作苹果后台:Sign In - Applehttps://developer.apple.com/account/resources/certificates/list

高效的开发流程搭建

目录 1. 搭建 AI codebase 环境kaggle的服务器1. 搭建 AI codebase 环境 python 、torch 以及 cuda版本,对AI的影响最大。不同的版本,可能最终计算出的结果会有区别。 硬盘:PCIE转SSD的卡槽,, GPU: 软件源: Anaconda: 一定要放到固态硬盘上。 VS code 的 debug功能…

嵌入式Linux应用开发-驱动大全-同步与互斥④

嵌入式Linux应用开发-驱动大全-同步与互斥④ 第一章 同步与互斥④1.5 自旋锁spinlock的实现1.5.1 自旋锁的内核结构体1.5.2 spinlock在UP系统中的实现1.5.3 spinlock在SMP系统中的实现 1.6 信号量semaphore的实现1.6.1 semaphore的内核结构体1.6.2 down函数的实现1.6.3 up函数的…

关于将对象转成JSON格式的一些问题

1.问题现象&#xff1a; 在ssm项目中&#xff0c;一个controller返回Msg对象&#xff08;自定义Javabean对象&#xff09;&#xff0c;然后利用SpringMVC的ResponseBody注解自动将Msg对象转化成JSON格式&#xff0c;返回给客户端&#xff0c;但是客户端接收到的json字符串只有…

「专题速递」数字人直播带货、传统行业数字化升级、远程协作中的低延时视频、地产物业中的通讯终端...

音视频技术作为企业数字化转型的核心要素之一&#xff0c;已在各行各业展现出广泛的应用和卓越的价值。实时通信、社交互动、高清视频等技术不仅令传统行业焕发新生&#xff0c;还为其在生产、管理、服务提供与维护等各个领域带来了巨大的助力&#xff0c;实现了生产效率和服务…