[C++]priority_queue的介绍及模拟实现

news2025/1/11 19:50:34

目录

priority_queue的介绍及模拟实现::

                                                        priority_queue的介绍

                                                        priority_queue的定义方式

                                                        priority_queue各个接口的使用

                                                        堆的向上调整算法

                                                        堆的向下调整算法

                                                        仿函数

                                                        priority_queue的模拟实现

                                                        反向迭代器的底层原理

                                                        反向迭代器的模拟实现


priority_queue的介绍及模拟实现::

priority_queue的介绍

优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆的向上调整和向下调整算法将vector中的元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。

#include <queue>
int main()
{
	priority_queue<int> pq;
	pq.push(3);
	pq.push(1);
	pq.push(2);
	pq.push(5);
	while (!pq.empty())
	{
		cout << pq.top() << " ";
		pq.pop();
	}
	cout << endl;
	return 0;
}

#include <functional>
#include <queue>
int main()
{
	priority_queue<int,vector<int>,greater<int>> pq;
	pq.push(3);
	pq.push(1);
	pq.push(2);
	pq.push(5);
	while (!pq.empty())
	{
		cout << pq.top() << " ";
		pq.pop();
	}
	cout << endl;
	return 0;
}

priority_queue的定义方式

方式一:使用vector作为底层容器,内部构造大堆结构

priority_queue<int,vector<int>,less<int>> pq1;

方式二:使用vector作为底层容器,内部构造小堆结构

priority_queue<int,vector<int>,greater<int>> pq2;

方式三:不指定底层容器,默认为大堆结构

priority_queue<int> pq3;

priority_queue各个接口的使用

成员函数功能
push插入元素到队尾并调整为堆结构
pop弹出堆顶元素
top访问堆顶元素
size获取队列中有效元素个数
empty判断队列是否为空
swap交换两个队列的内容

priority_queueOJ:数组中第K大的元素

//方法一:建大堆 再popK次
class Solution 
{
public:
	int findKthLargest(vector<int>& nums, int k) 
	{
		priority_queue<int> pq(nums.begin(), nums.end());
		while (--k)
		{
			pq.pop();
		}
		return pq.top();
	}
};
//方法二:建K个数的小堆 和堆顶数据比较
class Solution
{
public:
	int findKthLargest(vector<int>& nums, int k)
	{
		priority_queue<int, vector<int>, greater<int>> pq(nums.begin(), nums.begin() + k);
		for (size_t i = k; i < nums.size(); ++i)
		{
			if (nums[i] > pq.top())
			{
				pq.pop();
				pq.push(nums[i]);
			}
		}
		return pq.top();
	}
};

堆的向上调整算法

思想:

1.将目标结点与父结点进行比较

2.若目标结点的值比父节点的值大,则交换目标结点与其父节点的位置,并将原目标节点的父节点当作新的目标节点继续进行向上调整,若目标节点的值比其父节点的值小,则停止向上调整。

void AdjustUp(vector<int>& v, size_t child)
{
	size_t parent = (child - 1) / 2;
	while (child > 0)
	{
		if (v[child] > v[parent])
		{
			swap(v[child], v[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

堆的向下调整算法

思想:

1.将目标节点与其较大的子节点进行比较

2.若目标节点的值比其较大的子节点的值小,则交换目标节点与其较大的子节点的位置,并将原目标节点的较大子节点当作新的目标节点继续进行向下调整,若目标节点的值比其较大子节点的值大,则停止向下调整。

void AdjustDown(vector<int>& v, int n , size_t parent)
{
	size_t child = 2 * parent + 1;
	while (child < v.size())
	{
		if (child + 1 < n && v[child] < v[child + 1])
		{
			++child;
		}
		if (v[parent] < v[child])
		{
			std::swap(v[child], v[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

仿函数

仿函数的介绍:

namespace wjq
{
	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;
		}
	};
}
int main()
{
	wjq::less<int> lessFunc;
	lessFunc(1, 2);
	return 0;
}

仿函数的使用场景:

bool cmp(int x, int y)
{
	return y > x;
}
void BubbleSort(int* a, int n, bool(*pcom)(int, int))
{
	for (int i = 0; i < n; i++)
	{
		int exchange = 0;
		for (int j = 1; j < n - i; j++)
		{
			if (pcom(a[j - 1] , a[j]))
			{
				std::swap(a[j - 1], a[j]);
				exchange = 1;
			}
		}
		if (exchange == 0)
		{
			break;
		}
	}
}
int main()
{
	int a[] = { 2,3,4,5,6,1,4,9 };
	BubbleSort(a, 8, cmp);
	for (size_t i = 0; i < 8; i++)
	{
		cout << a[i] << " ";
	}
	cout << endl;
	return 0;
}

namespace wjq
{
	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;
		}
	};
}
template<class T,class Compare>
void BubbleSort(T* a, int n, Compare com)
{
	for (int i = 0; i < n; i++)
	{
		int exchange = 0;
		for (int j = 1; j < n - i; j++)
		{
			if (com(a[j], a[j - 1]))
			{
				std::swap(a[j - 1], a[j]);
				exchange = 1;
			}
		}
		if (exchange == 0)
		{
			break;
		}
	}
}
int main()
{
	wjq::less<int> lessFunc;
	int a[] = { 2,3,4,5,6,1,4,9 };
	BubbleSort(a, 8, lessFunc);
	for (size_t i = 0; i < 8; i++)
	{
		cout << a[i] << " ";
	}
	cout << endl;
	return 0;
}

仿函数的特殊使用场景:

如果在priority_queue中放自定义类型的数据,用户需要自己提供>和<的重载

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& out, const Date& d)
	{
		out << d._year << "-" << d._month << "-" << d._day;
		return out;
	}
private:
	int _year;
	int _month;
	int _day;
};
void TestPriorityQueue()
{
	// 大堆,需要用户在自定义类型中提供<的重载
	priority_queue<Date> q1;
	q1.push(Date(2023, 12, 1));
	q1.push(Date(2023, 12, 2));
	q1.push(Date(2023, 11, 30));
	cout << q1.top() << endl;
	// 如果要创建小堆,需要用户提供>的重载
	priority_queue<Date, vector<Date>, greater<Date>> q2;
	q2.push(Date(2023, 12, 1));
	q2.push(Date(2023, 12, 2));
	q2.push(Date(2023, 11, 30));
	cout << q2.top() << endl;
}
int main()
{
	TestPriorityQueue();
	return 0;
}

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& out, const Date& d)
	{
		out << d._year << "-" << d._month << "-" << d._day;
		return out;
	}
private:
	int _year;
	int _month;
	int _day;
};
void TestPriorityQueue()
{
	//大堆
	priority_queue<Date*> q1;
	q1.push(new Date(2023, 12, 1));
	q1.push(new Date(2023, 12, 2));
	q1.push(new Date(2023, 11, 30));
	cout << q1.top() << endl;

	//小堆
	priority_queue<Date*> q2;
	priority_queue<Date*, vector<int>, greater<Date>> q2;
	q2.push(new Date(2023, 12, 1));
	q2.push(new Date(2023, 12, 2));
	q2.push(new Date(2023, 11, 30));
	cout << q2.top() << endl;
}
int main()
{
	TestPriorityQueue();
	return 0;
}

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& out, const Date& d)
	{
		out << d._year << "-" << d._month << "-" << d._day;
		return out;
	}
private:
	int _year;
	int _month;
	int _day;
};
struct PDateLess
{
	bool operator()(const Date* d1, const Date* d2)
	{
		return *d1 < *d2;
	}
};
struct PDateGreater
{
	bool operator()(const Date* d1, const Date* d2)
	{
		return *d1 > *d2;
	}
};
void TestPriorityQueue()
{
	//大堆
	priority_queue<Date*, vector<Date*>, PDateLess> q1;
	q1.push(new Date(2023, 12, 1));
	q1.push(new Date(2023, 12, 2));
	q1.push(new Date(2023, 11, 30));
	cout << *q1.top() << endl;

	//小堆
	priority_queue<Date*, vector<Date*>, PDateGreater> q2;
	q2.push(new Date(2023, 12, 1));
	q2.push(new Date(2023, 12, 2));
	q2.push(new Date(2023, 11, 30));
	cout << *q2.top() << endl;
}
int main()
{
	TestPriorityQueue();
	return 0;
}

priority_queue的模拟实现

namespace wjq
{
	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;
		}
	};
	template <class T, class Container = std::vector<T>, class Compare = less<int>>
	class priority_queue
	{
	private:
		void AdjustUp(size_t child)
		{
			Compare com;//构造一个仿函数对象
			size_t parent = (child - 1) / 2;
			while (child > 0)
			{
				if (com(_con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
		void AdjustDown(size_t parent)
		{
			Compare com;//构造一个仿函数对象
			size_t 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[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
	public:
		//无参构造函数
		priority_queue()
		{
			//默认构造函数即可
		}
		//迭代器区间构造
		template <class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
			:_con(first, last)
		{
			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; --i)
			{
				AdjustDown(i);
			}
		}
		void push(const T& x)
		{
			_con.push_back(x);
			AdjustUp(_con.size() - 1);//从size-1开始调整
		}
		void pop()
		{
			std::swap(_con[0], _con[_con.size() - 1]);//交换首尾数据
			_con.pop_back();//尾删
			AdjustDown(0);
		}
		const T& top() const
		{
			return _con[0];
		}
		bool empty() const
		{
			return _con.empty();
		}
		size_t size()const
		{
			return _con.size();
		}
	private:
		Container _con;
	};
}

反向迭代器的底层原理

反向迭代器的本质就是对正向迭代器的封装,它同样是一个适配器。

STL源码中的反向迭代器的实现:反向迭代器用正向迭代器进行构造。

typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;
reverse_iterator rbegin() 
{ 
	return reverse_iterator(end());
}
reverse_iterator rend() 
{ 
	return reverse_iterator(begin());
}

STL源码中,其实正向迭代器和反向迭代器的位置是对称的。通过图示,rbegin()迭代器是最后一个数据的下一个位置,但是通过rbegin()访问的数据应该是6,这是通过运算符重载operator*()来解决。

template <class Iterator, class Ref, class Ptr>
Ref operator*()
{
    Iterator tmp = _it;
    return *(--tmp);
}

反向迭代器的模拟实现

namespace wjq
{
	template <class Iterator, class Ref, class Ptr>
	class ReverseIterator
	{
	public:
		RevserseIterator(Iterator it)//使用正向迭代器构造反向迭代器
			:_it(it)
		{}
		Ref operator*()
		{
			Iterator tmp = _it;
			return *(--tmp);
		}
		Ptr operator->()
		{
			return &(operator*());
		}
		typedef ReverseIterator<Iterator, Ref, Ptr> Self
		Self& operator++()
		{
			--_it;
			return *this;
		}
		Self& operator--()
		{
			++_it;
			return *this;
		}
		bool operator!=(const Self& s) const
		{
			return _it != s._it;
		}
	private:
		Iterator _it;//底层是传入类型的迭代器
	};
}

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

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

相关文章

4.C转python

1.建立函数: def 函数名(形参): 函数体(记得写缩进) return 返回值(python中可以没有return) 2.调用函数: 函数名(实参) 实参和形参个数相等即可,类型不需要相同 其中接收返回值与C中的差不多 3.如果只是定义而不调用则函数不会执行 4.先定义函数,后调用 5.python中可以…

TikTok医学奇谭:短视频在医学科普中的作用

在数字时代的浪潮中&#xff0c;社交媒体平台的崛起不仅改变了人们的社交方式&#xff0c;也在医学科普领域掀起了一场革命。 作为短视频平台的领军者之一&#xff0c;TikTok通过其独特的形式和广泛的用户群&#xff0c;为医学知识的传播提供了新的可能性。本文将深入探讨TikT…

蓝牙智能电表解决了哪些难题?

提高能源效率已成为当今世界面临的重大挑战之一。在这样的背景下&#xff0c;蓝牙智能电表应运而生。它采用了最新的智能技术&#xff0c;能够通过蓝牙协议实现与移动设备通讯&#xff0c;从而给用户带来更加便捷、高效的服务。那么&#xff0c;蓝牙智能电表解决了哪些难题呢&a…

Vision Pro即将量产之际,苹果还是放不下中国供应链

发布半年后&#xff0c;苹果口中的“革命性新产品”Vision Pro终于有了新消息。 图源&#xff1a;苹果 根据多家消费电子供应链公司核心人士消息&#xff0c;苹果计划于12月正式量产Vision Pro&#xff0c;首批备货40万台左右&#xff0c;2024年的销量目标为100万台&#xff0…

【pytorch】深度学习入门一:pytorch的安装与配置(Windows版)

请支持原创&#xff0c;认准DannisTang&#xff08;tangweixuan1995foxmail.com&#xff09; 文章目录 第〇章 阅读前提示第一章 准备工作第一节 Python下载第二节 Python安装第三节 Python配置第四节 Pycharm下载第五节 Pycharm安装第六节 CUDA的安装 第二章 Anaconda安装与配…

上门服务系统|北京上门服务软件有哪些便利功能?

上门服务软件是一种便捷、高效的服务工具&#xff0c;广泛应用于各种行业领域&#xff0c;包括但不限于家政服务、维修维护、清洁保洁、美甲美发等。预约上门服务系统的崛起改变了传统服务行业的格局。用户不再需要亲自前往实体店面&#xff0c;而是通过几次点击就能享受到各类…

如何生成纯文本的目录树

参考资料&#xff1a; https://ascii-tree-generator.com/ 无需多言&#xff0c;感谢这些前辈的智慧。界面如下&#xff1a;

后仿真 ERROR

后仿真 error ERROR (SFE-23): "input.scs" 252: The instance _57_D32_noxref is referencing an undefined model or subcircuit, parasitic_nwd. Either include the file containing the definition of parasitic_nwd, or define parasitic_nwd before running t…

数组?NO 系Vector啊!

文章目录 前言一、vector的介绍二、vector的使用2.1 vector求容量的用法2.2 vector的增删查改用法2.2.1 尾插2.2.2 尾删2.2.3 头插2.2.4 任意位置删除 2.3 vector的iterator是什么以及失效问题 三、vector的模拟实现3.1 成员变量3.2 成员函数3.2.1 构造函数3.2.2 拷贝构造3.2.3…

docker部署elasticsearch+kibana+head

前言 最近&#xff0c;项目需要使用elasticsearch&#xff0c;所以就想快速安装一个使用&#xff0c;最开始是docker安装了7.10.1版本。 后面计划使用Java开发&#xff0c;发现有 RestHighLevelClient 和 Elasticsearch Java API Client两种客户端连接方式。 然后网上查阅了一…

AI为基,快手新商业图景浮现

监制 | 何玺 排版 | 叶媛 快手新商业图景浮现&#xff01; 11月21日&#xff0c;快手发布了2023年Q3财报。该季度内&#xff0c;快手以超2成营收增长的亮眼业绩&#xff0c;展示出强大的经营韧性。同时其在付费短剧、AI应用等业务上的拓展&#xff0c;则让行业和资本市场看到…

无限移动的风景 css3 动画 鼠标移入暂停

<style>*{margin:0;padding:0;/* box-sizing: border-box; */}ul{list-style: none;}#nav{width:900px;height:100px;border:2px solid rgb(70, 69, 69);margin:100px auto; overflow: hidden;}#nav ul{animation:moving 5s linear infinite;width:200%; /*怎么模拟动画…

RUM增强APP端快照配置全量会话回放与自定义协议网络请求采集功能

一直以来&#xff0c;博睿数据秉承着“让每一款软件运行更完美”的产品理念&#xff0c;注重用户体验和反馈&#xff0c;以持续的技术创新&#xff0c;为广大用户提供轻盈、有序、精准的IT运维一体化智能可观测平台&#xff0c;降低运维成本。 近期&#xff0c;博睿数据根据一…

企业如何做好合规管理?

近年来“合规”作为一个热点话题&#xff0c;频繁出现在公众视野&#xff0c;已然成为企业管理发展的大趋势。国家相继出台的各项合规管理标准预示着我国的企业合规管理正逐步从头部央企向民营企业扩展。因此&#xff0c;各大企业将合规管理作为了企业管理的首要任务。 随着中…

hadoop-3.3.5安装过程

准备资源三台虚拟机&#xff1a; 1&#xff09;准备3台服务器&#xff08;关闭防火墙、静态IP、主机名称&#xff09; 2&#xff09;安装JDK 3&#xff09;配置环境变量 4&#xff09;安装Hadoop 5&#xff09;配置环境变量 安装虚拟机&#xff08;略&#xff09;--1台即…

第二证券:趋势线是画最低点还是收盘价?

趋势线是股票分析中最底子的技术指标之一。趋势线是一种可帮忙股票生意者辨认价格趋势的图形方法。趋势线是可以经过联接恣意两个价格点画出的一条直线。但是&#xff0c;在画出趋势线时&#xff0c;一个常见的问题是&#xff0c;运用最低点还是收盘价来画趋势线&#xff1f;在…

ROS话题消息实时展示在WEB网页上

【使用背景】 最近公司搞了一个室外无人车的项目&#xff0c;需要用到GPS组合惯导&#xff0c;但是这套传感器由于成本控制&#xff0c;它没有提供小程序或是APP之类的数据监测手段&#xff0c;只能通过一个Windows上位机软件去看GPS实时数据&#xff0c;这对于单人外场调试来…

【Skynet 入门实战练习】分布式 ID | 雪花算法 | 缓存设计 | LRU算法 | 数据库

文章目录 前言雪花算法LRU 算法缓存模块数据库测试逻辑 前言 本节实现了 分布式 ID 生成系统&#xff0c;采用雪花算法实现唯一 ID&#xff1b;实现缓存架构&#xff0c;采用 LRU &#xff08;最近最少使用&#xff09;算法。 雪花算法 分布式 ID 生成算法的有很多种&#x…

c#学习相关系列之as和is的相关用法

一、子类和父类的关系 public class Program{static void Main(string[] args){Animal animal new Dog();// Dog dog (Dog)new Animal(); 编译成功&#xff0c;运行报错Dog dog (Dog)animal;Dog dog new Dog();Animal animal dog; //等价于Animal animal new Dog();}}pub…

最新UI酒桌喝酒游戏小程序源码,直接上传源码到开发者端即可,带流量主

源码介绍&#xff1a; 2023最新UI酒桌喝酒游戏小程序源码 娱乐小程序源码 带流量主.修改增加了广告位&#xff0c;直接上传源码到开发者端即可。 通过后改广告代码&#xff0c;然后关闭广告展示提交&#xff0c;通过后打开即可。无广告引流。 流量主版本的&#xff08;配合流…