C++模拟实现优先级队列(priority_queue)

news2024/10/5 17:25:06

目录

一、 仿函数

1.1仿函数的概念+使用

1.2模拟实现仿函数

二、优先级队列(priority_queue)

2.1 优先级队列概念

2.2 优先级队列使用

2.3 模拟实现优先级队列

2.3.1 优先级队列类框架

2.3.2 模板参数

2.3.3 构造函数

2.3.4 仿函数

2.3.5 adjust_up (堆向上排序)

2.3.6 adjust_down(堆向下排序)

2.3.7 push(尾插数据)

2.3.8 pop(出队头数据)

2.3.9 top(取堆顶)

2.3.A size(容器元素个数)

2.3.B empty(判断容器是否为空)

2.4 优先级队列完整 + 模拟测试

2.4.1 priority_queue.h

2.4.2 test.cpp


一、 仿函数

1.1仿函数的概念+使用

💡仿函数(functor),就是使一个类的使用看上去像一个函数。其实本质就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了

接下来我们要来了解库中两个常用的比较仿函数 less / greater

直接看库代码:

//less
template <class T> struct less : binary_function <T,T,bool> {
  bool operator() (const T& x, const T& y) const {return x<y;}
};

//greater
template <class T> struct greater : binary_function <T,T,bool> {
  bool operator() (const T& x, const T& y) const {return x>y;}
};

它们的本质就是类封装operator()函数,只不过模板参数让它们的比较类型可以灵活化!下面我们来看看它的使用场景控制数据排序是升序还是降序!

#include <iostream>     // std::cout
#include <functional>   // std::greater
#include <algorithm>    // std::sort

int main () {
  int numbers[]={20,40,50,10,30};
  //升序
  sort (numbers, numbers+5, greater<int>());
  for (int i=0; i<5; i++)
    cout << numbers[i] << ' ';
  cout << '\n';
  //降序
  sort (numbers, numbers+5, less<int>());
  for (int i=0; i<5; i++)
    cout << numbers[i] << ' ';
  cout << '\n';
  return 0;
}

代码结果:

结论:less是决定排降序,greater决定是升序

1.2模拟实现仿函数

我们直接看代码:

template<class T>
	class Less
	{
	public:
		bool operator()(const T& left, const T& right)const
		{
			return left > right;
		}
	};
	template<class T>
	class greater
	{
	public:
		bool operator()(const T& left, const T& right)const
		{
			return left < right;
		}
	};

二、优先级队列(priority_queue)

在此之前需要你知道数据结构的堆概念!我写的另一篇博客数据结构的堆介绍了堆!

2.1 优先级队列概念

1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大优先级的。(本质数据排序是数据结构的堆!)
2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。
3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:

函数声明接口说明
priority_queue()/priority_queue(first,
last)
构造一个空的优先级队列
empty( )检测优先级队列是否为空,是返回true,否则返回
false
top( )返回优先级队列中最大(最小元素),即堆顶元素
push(x)在优先级队列中插入元素x
pop()删除优先级队列中最大(最小)元素,即堆顶元素

5. 标准容器类vector和deque满足这些需求默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector
6. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。

2.2 优先级队列使用

#include<vector>
#include<iostream>
#include<queue>
#include<functional>
using namespace std;
int main()
{
	priority_queue<int,vector<int>,greater<int>> pq;
	
    int arr[] = { 9,7,2,6,3,5,1,4,8 };
	for (int i = 0;i < sizeof(arr) / sizeof(arr[0]);i++)
		pq.push(arr[i]);
	while (!pq.empty())
	{
		cout << pq.top() << ' ';
		pq.pop();
	}
	return 0;
}


2.3 模拟实现优先级队列

2.3.1 优先级队列类框架

#pragma once
#include<vector>
#include<iostream>
#include<deque>
using namespace std;
namespace wyz
{
	//仿函数
	template<class T>
	class lesser
	{
	public:
		bool operator()(const T& left, const T right)const
		{
			return left > right;
		}
	};
	template<class T>
	class greater
	{
	public:
		bool operator()(const T& left, const T right)const
		{
			return left < right;
		}
	};

	//优先级队列
	template<class T,class contain=vector<T>,class compare=lesser<T>>
	class priority_queue
	{
	public:
        //默认构造
		priority_queue()
		{}

        //容器迭代器区间构造
		template <class InputIterator>
		priority_queue(InputIterator first, InputIterator last)

        //向上排序
		void adjust_up(size_t child)
	
        //向下排序
		void adjust_down(size_t parent)

		//尾插 + 堆向上排序
		void push(const T& val)
	

		//出堆顶 + 堆向下排序
		void pop()


		//取堆顶
		const T& top()const
		

		//返回容器数据个数
		size_t size()const
	

		//判断容器是否为空
		bool empty()const

	private:
		contain con;//容器
	};
}

2.3.2 模板参数

template<class T,class contain=vector<T>,class compare=lesser<T>>

💡💡三个类型参数分别代表 数据存储类型底层容器类型仿函数决定排序顺序!

我们默认容器时Vector,堆是大堆,即堆顶是最大值!


2.3.3 构造函数

//默认构造
priority_queue()
{}
//容器迭代器区间构造
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
	:con(first, last)//直接迭代器区间构造底层容器
{}

2.3.4 仿函数

💡💡注意两个仿函数各自比较方式!使用的是后注意传给letf、right参数值!

template<class T>
class lesser
{
public:
	bool operator()(const T& left, const T right)const
	{
		return left > right;
	}
};
template<class T>
class greater
{
public:
	bool operator()(const T& left, const T right)const
	{
		return left < right;
	}
};

2.3.5 adjust_up (堆向上排序)

void adjust_up(size_t child)
{
	compare com;
	size_t parent = (child - 1) / 2;
	while (child > 0)
	{
		//Less 建大堆 比较符号是> child>parent匹配符号左右参数
		if (com(con[child], con[parent]))
		{
			swap(con[child], con[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else break;
	}
}

2.3.6 adjust_down(堆向下排序)

void adjust_down(size_t parent)
{
    //别忘记创建仿函数类
	compare com;
	size_t child = parent * 2 + 1;
	while (child < con.size())
	{
		//lesser 建大堆 比较符号>  child+1>child匹配符号左右参数
		if (child + 1 < con.size() && com(con[child + 1], con[child]))
		{
			child = child + 1;
		}
		//lesser 建大堆  比较符号> child>parent匹配符号左右参数
		if (com(con[child], con[parent]))
		{
			swap(con[child], con[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else break;
	}
}

2.3.7 push(尾插数据)

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

2.3.8 pop(出队头数据)

void pop()
{
    //底层是vector,不能直接出头元素,要不然要挪动数据,影响堆整体父子关系
    //我们将首尾元素交换后,再pop尾数据,然后重新向下建堆
	swap(con[0], con[con.size() - 1]);
	con.pop_back();
	adjust_down(0);
}

2.3.9 top(取堆顶)

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

2.3.A size(容器元素个数)

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

2.3.B empty(判断容器是否为空)

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

2.4 优先级队列完整 + 模拟测试

2.4.1 priority_queue.h

#pragma once
#include<vector>
#include<iostream>
#include<deque>
using namespace std;
namespace wyz
{
	//仿函数
	template<class T>
	class lesser
	{
	public:
		bool operator()(const T& left, const T right)const
		{
			return left > right;
		}
	};
	template<class T>
	class greater
	{
	public:
		bool operator()(const T& left, const T right)const
		{
			return left < right;
		}
	};

	//优先级队列
	template<class T,class contain=vector<T>,class compare=lesser<T>>
	class priority_queue
	{
	public:
		priority_queue()
		{}
		template <class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
			:con(first,last)
		{}
		void adjust_up(size_t child)
		{
			compare com;
			size_t parent= (child - 1) / 2;
			while (child > 0)
			{
				//lesser 建大堆 child>parent
				if (com(con[child], con[parent]))
				{
					swap(con[child], con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else break;
			}
		}
		void adjust_down(size_t parent)
		{
			compare com;
			size_t child = parent * 2 + 1;
			while (child < con.size())
			{
				//lesser 建大堆 child+1>child 
				if (child + 1 < con.size() && com(con[child + 1], con[child]))
				{
					child = child + 1;
				}
				//lesser 建大堆 child>parent
				if (com(con[child], con[parent]))
				{
					swap(con[child], con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else break;
			}
		}

		//尾插 + 堆向上排序
		void push(const T& val)
		{
			con.push_back(val);
			adjust_up(con.size()-1);
		}

		//取队头(堆顶) + 堆向下排序
		void pop()
		{
			swap(con[0], con[con.size() - 1]);
			con.pop_back();
			adjust_down(0);
		}

		//取堆顶
		const T& top()const
		{
			return con[0];
		}

		//返回容器数据个数
		size_t size()const
		{
			return con.size();
		}

		//判断容器是否为空
		bool empty()const
		{
			return con.empty();
		}
	private:
		contain con;//容器
	};
}

2.4.2 test.cpp

#include"priority_queue.h"
#include<queue>
#include<functional>
void Test1()
{
	wyz::priority_queue<int, vector<int>, wyz::greater<int>> pq;
	int arr[] = { 9,7,2,6,3,5,1,4,8 };
	for (int i = 0;i < sizeof(arr) / sizeof(arr[0]);i++)
		pq.push(arr[i]);
	cout << "greater优先级队列结果:";
	while (!pq.empty())
	{
		cout << pq.top() << ' ';
		pq.pop();
	}
	cout << endl
}
void Test2()
{
	int arr[] = { 9,7,2,6,3,5,1,4,8 };
	wyz::priority_queue<int, vector<int>, wyz::lesser<int>> pq;
	for (int i = 0;i < sizeof(arr) / sizeof(arr[0]);i++)
		pq.push(arr[i]);
	cout << "lesser优先级队列结果:";
	while (!pq.empty())
	{
		cout << pq.top() << ' ';
		pq.pop();
	}
	cout << endl;
}
int main()
{
	Test1();
	Test2();
	return 0;
}


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

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

相关文章

linux系统中QT里面信号与槽的实现方法

大家好&#xff0c;今天主要来聊一聊&#xff0c;QT中信号与槽的使用方法。 目录 第一&#xff1a;QT中信号与槽简介 第二&#xff1a;如何在项目里创建信号 第三&#xff1a;如何在项目中创建槽 第四&#xff1a;项目中连接信号与槽 第一&#xff1a;QT中信号与槽简介 在学…

遥感图像处理:最小噪声分离变换(Minimum Noise Fraction Rotation,MNF Rotation)

遥感图像处理&#xff1a;最小噪声分离变换&#xff08;Minimum Noise Fraction Rotation&#xff0c;MNF Rotation1.PCA变换2.MNF3.PCA和MNF1.PCA变换 在统计学中&#xff0c;主成分分析PCA是一种简化数据集的技术。它是一个线性变换。这个变换把数据变换到一个新的坐标系统中…

Django使用Celery异步发送短信(Django4.1.3+Celery5.2.7+ubuntu)

首先要下载Celery&#xff0c;直接pip就好 我的redis配置 CACHES {"default": {"BACKEND": "django_redis.cache.RedisCache","LOCATION": "redis://192.168.2.128:6379/0","OPTIONS": {"CLIENT_CLASS"…

自动化测试Seleniums~2

webdriver API 1.如何打开网页以及如何关闭一个浏览器。 package test_20230107;import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver;import static java.lang.Thread.sleep;public class Test {public static void main(String[] args)…

JavaEE多线程-线程的状态和安全问题

目录一、线程中的基本状态二、线程安全问题三、线程安全的标准类四、synchronized 关键字-监视器锁monitor locksynchronized 的特性五、volatile 关键字一、线程中的基本状态 NEW: 安排了工作, 还未开始行动, 就是创建了Thread对象, 但还没有执行start方法(内核里面还没有创建…

SpringSecurity(十一)【跨域】

十一、跨域 简介 跨域问题实际应用开发中的一个非常常见的需求&#xff0c;在 Spring 框架中对于跨域问题的处理方案有好几种&#xff0c;引入了 Spring Security 之后&#xff0c;跨域问题的处理方案又增加了 什么是 CORS CORS&#xff08;Cross-Origin Resource-Sharing&…

联合证券|重磅数据出炉,道指飙涨700点!美股新年首周“开门红”!

美股涨嗨了&#xff01; 当地时间1月6日&#xff0c;最新发布的美国12月非农工作陈述显现&#xff0c;美国工作市场终于呈现降温迹象&#xff0c;过去一年的激进加息成效初显。受此提振&#xff0c;美股三大股指高开高走&#xff0c;彻底改变前几日的跌势。从周k线看&#xff…

PCB结构和谐振(三)

PCB结构和谐振&#xff08;一&#xff09;PCB结构和谐振&#xff08;二&#xff09;仿真研究在本节中&#xff0c;我们首先对玻璃束的随机分布进行了简单的模拟研究。然后我们利用这些实验结论来简化常用的玻璃布3D结构。最后&#xff0c;这种简化的结构用于研究复杂层压板和两…

Java设计模式中原型模式是啥/浅克隆与深克隆又是什么/clone方法怎么回事

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 4.5 原型模式 4.5.1 概述 用已创建实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型对象一样的新对象 4.5.2 结构 抽象原型类&#xff1a;规定具体…

Docker系列 深度使用nextcloud(九) 硬盘挂载

转自我的个人博客https://blognas.hwb0307.com&#xff0c;该文的内容更新仅在个人博客可见。欢迎关注&#xff01; 前言 基于《Docker系列 搭建个人云盘服务nextcloud》&#xff0c;相信无论是在有/无443端口的Linux机子里均可成功安装Nextcloud。值得一提的是&#xff0c;Ne…

02、做点准备工作 osg\openscenegraph源代码下载 C++三维视频融合实战系列(时空克隆)

首先&#xff0c;要有一点C编程基础&#xff0c;熟悉VS2013开发环境。 在开始实践之前&#xff0c;先要搭建号VS2013开发环境。 然后&#xff0c;建议电脑安装windows 10 64位操作系统。 接下来需要在以下地址下载开源代码&#xff1a; 1、osg下载 打开openscenegraph主页…

CSS权威指南(七)视觉格式化

文章目录1.盒模型2.元素的显示方式3.行内元素1.盒模型 不管是什么元素,CSS都假定每个元素会生成一个或多个矩形框,我们称之为元素。各元素框的中心是内容区域&#xff0c;四周有可选的内边距、边框、轮廓和外边距。默认情况下&#xff0c;内容区的背景出现在内边距范围内。外边…

5分钟搞懂用户态,内核态

5分钟搞懂用户态,内核态 1. 什么是用户态,内核态 用户态就是提供应用程序运行的空间&#xff0c;为了使应用程序访问到内核管理的资源例如CPU&#xff0c;内存&#xff0c;I/O。内核必须提供一组通用的访问接口&#xff0c;这些接口就叫系统调用。 用户态&#xff0c;内核态…

进制详解:二进制、八进制和十六进制

进制详解&#xff1a;二进制、八进制和十六进制 背景&#xff08;Contexts&#xff09; 我们平时使用的数字都是由 0~9 共十个数字组成的&#xff0c;例如 1、9、10、297、952 等&#xff0c;一个数字最多能表示九&#xff0c;如果要表示十、十一、二十九、一百等&#xff0c;…

机器学习笔记之深度信念网络(一)背景介绍与模型表示

机器学习笔记之深度信念网络——背景介绍与模型表示引言深度信念网络场景构建深度信念网络的联合概率分布引言 从本节开始&#xff0c;将介绍深度信念网络。 深度信念网络 深度信念网络(Deep Belief Network,DBN)是杰弗里辛顿(Geoffrey Hinton)于2006年提出的模型&#xff0…

Day853.WorkerThread模式 -Java 性能调优实战

WorkerThread模式 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于WorkerThread模式的内容。 Thread-Per-Message 模式&#xff0c;对应到现实世界&#xff0c;其实就是委托代办。这种分工模式如果用 Java Thread 实现&#xff0c;频繁地创建、销毁线程非常影响性能…

场景编程集锦 - 吉米的总统梦想

1. 场景描述 吉米是太平洋岛国一个贫苦家庭的孩子&#xff0c;他的梦想就是当总统&#xff0c;引领国家走向富强之路。 开学的第一堂课上&#xff0c;老师用白色的粉笔在黑板上写下了“我的梦想”&#xff0c;同学们都陷入了思考。大卫的梦想是当一名科学家&#xff0c;用奇思妙…

CSS初级教程(文本)【第六天】

文章目录【1】CSS 文本[字体颜色|背景色]【2】CSS 文本对齐【3】CSS 文字装饰【4】CSS 文本转换[大写或小写]【5】CSS 文字间距【6】CSS 文本阴影【7】所有 CSS 文本属性CSS上回学习链接 CSS初级教程 颜色【第一天】 CSS初级教程 背景【第二天】 CSS初级教程 边框【第三天】 CS…

Windows访问控制 -- SID

Windows访问控制是一个比较大的题目&#xff0c;因此计划用一系列的文章简单谈一下这个。本篇是开篇&#xff0c;介绍SID。 Windows访问控制定义 Windows访问控制的含义可以参考MSDN的描述&#xff1a;Access control refers to security features that control who can acce…

Java集合容器介绍

Java 容器分为 Collection 和 Map 两大类&#xff0c;其下又有很多子类&#xff0c;如下所示&#xff1a; Collection接口&#xff1a;单列数据&#xff0c;定义了存取一组对象的方法的集合 1、List&#xff1a;元素有序(指的是存储时&#xff0c;与存放顺序保持一致)、可重复的…