【C++】priority_queue模拟实现+仿函数+反向迭代器

news2024/11/24 22:51:50

priority_queue模拟实现+仿函数+反向迭代器

  • 1.priority_quyue
    • 1.1priority_queue的使用
    • 1.2priority_queue模拟实现
      • 1.2.1无参构造+一段区间构造
      • 1.2.2push
      • 1.2.3pop
      • 1.2.4empty
      • 1.2.5size
      • 1.2.6top
  • 2.仿函数
    • 2.1什么是仿函数
    • 2.2增加仿函数的priority_queue模拟实现完整代码
  • 3.反向迭代器
    • 3.1list反向迭代器
    • 3.2vector反向迭代器

自我名言只有努力,才能追逐梦想,只有努力,才不会欺骗自己。在这里插入图片描述
喜欢的点赞,收藏,关注一下把!在这里插入图片描述

1.priority_quyue

priority_queue文档介绍

  1. 优先队列也和栈,队列一样是一种容器适配器,容器适配器即将特定容器类封装作为其底层容器类。
  2. 优先级底层是堆,而堆又是一个完全二叉树,因此可以选用vector和dequeue来作为特定的容器,dequeue头插头删效率高,但是随机访问效率低一些。因此选择vector作为特定的容器更为合适。
  3. 优先级队列默认是一个大堆
  4. 优先级队列规定优先级高的先出。

在这里插入图片描述

priority_queue默认是一个大堆,这是由第三个参数less仿函数)所控制的,虽然less明面意思是小于,但是默认是一个大堆,默认大的优先级较高,大的先出。greater(仿函数),明面意思是大于,但是默认是一个小堆,默认小的优先级比较高,小的先出。

这里先不介绍仿函数,直接用就可以了,下面再详细讲。

1.1priority_queue的使用

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

在这里插入图片描述

注意缺省值不能隔着传。

在这里插入图片描述

写一道题来熟悉接口。
215. 数组中的第K个最大元素

在这里插入图片描述
在数据结构的学过堆,并且这里问题提供两个思路

思路一:
堆排序
时间复杂度:O(N*log2N)

思路二:
拿N个元素建立一个大堆,然后popK-1次,这样top拿的就是第K个最大的元素。
时间复杂度:建堆O(N),调整堆O(Klog2N) ----> O(N+Klog2N)

思路三:
拿K个元素建立一个小堆,再将N-K个元素与堆顶元素比较,大于堆顶元素就入堆,最后堆顶元素就是就是第K个大的元素。
时间复杂度:O(K+(N-K)*log2K) ----->O(N)

这里给出第三个思路的代码。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        //前k个建小堆
        priority_queue<int,vector<int>,greater<int>> pq(nums.begin(),nums.begin()+k);

        //N-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.2priority_queue模拟实现

关于这的一些向上调整算法和向下调整算法再堆的实现,画图和代码分析建堆,堆排序,时间复杂度以及TOP-K问题里都有详细介绍,这里不在细说了。

1.2.1无参构造+一段区间构造

//大堆
template<class T, class Container = vector<T>>
class priority_queue
{
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 adjustdown(int parent)
	{
		int minchild = parent * 2 + 1;
		while (minchild < _con.size())
		{
			if (minchild + 1 < _con.size() && _con[minchild + 1] > _con[minchild])
			{
				minchild++;
			}

			if (_con[minchild] > _con[parent])
			{
				swap(_con[minchild], _con[parent]);
				parent = minchild;
				minchild = parent * 2 + 1;
			}
			else
			{
				break;
			}
		}
	}

private:
	Container _con;
};

1.2.2push

//向上调整法
void adjustup(int child)
	{
		int parent = (child - 1) / 2;
		while (child > 0)
		{
			if (_con[child] > _con[parent])
			{
				swap(_con[child], _con[parent]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
			{
				break;
			}
		}
	}
	
void push(const T& val)
{
	_con.push_back(val);
}

1.2.3pop

void pop()
{
	assert(!empty());
	swap(_con[0], _con[_con.size() - 1]);
	_con.pop_back();
	adjustdown(0);
	
}

1.2.4empty

bool empty()
{
	return _con.empty();
}

1.2.5size

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

1.2.6top

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

这里还是和库里有些区别,我们写第三个参数,仿函数,下面我们来介绍它,并且在完善我们的代码。

2.仿函数

2.1什么是仿函数

仿函数其实是一个类的对象,也可以说是函数对象,因为这个类的对象可以像函数一样使用。

仿函数类别有很多种,今天主要介绍less和greater(比大小仿函数 )。

还记得C语言给我们提供了一个qsort函数,这个函数用到了函数指针。
这个函数指针指向一个比大小的函数。

C++既然包容C了,为什么不直接用这个函数指针呢?
C++主要觉得函数指针太麻烦了。因此引入了仿函数。

拿冒泡排序为例。

下面是普通的冒泡排序,如果排升序>,降序<,但是这都不能由使用者来决定,只能由写这个排序的人才能决定。这样给用户的体验感不好,自己不能控制。如果自己能够控制排序的方式就好了,所以这里可以写个比大小的仿函数。

void Bubblesort(int* a,int n)
{
	for (int i = 0; i < n - 1; ++i)
	{
		int flag = 1;
		for (int j = 0; j < n - i - 1; ++j)
		{
			if (a[j] > a[j+1])
			{
				swap(a[j], a[j + 1]);
				flag = 0;
			}
		}
		if (flag == 1)
		{
			break;
		}
	}
}

仿函数

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

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

这样看起来为什么一个类的对象可以叫做函数对象了,这个对象可以像函数一样调用。

less<int> lessfunc;
greater<int> greaterfunc
lessfunc(0, 1);
greaterfunc(0,1)
//这里是运算符重载  lessfunc.operator()(0,1)

现在将冒泡排序写成一个函数模板,这样就可以自己控制升序还是降序了。

template<class T,class Compare>
void Bubblesort(T* a,int n,Compare _com)
{
	for (int i = 0; i < n - 1; ++i)
	{
		int flag = 1;
		for (int j = 0; j < n - i - 1; ++j)
		{
			//升序
			//if (a[j] > a[j+1])
			if (_com(a[j],a[j+1]))
			{
				swap(a[j], a[j + 1]);
				flag = 0;
			}
		}
		if (flag == 1)
		{
			break;
		}
	}
}
int main()
{	
	int a[] = { 4,1,2,5,7,3,9,0,6,8 };
	Bubblesort(a, sizeof(a) / sizeof(a[0]), bit::greater<int>());

	return 0;
}

2.2增加仿函数的priority_queue模拟实现完整代码

#include<iostream>
#include<queue>
#include<vector>
#include<assert.h>
#include<algorithm>
using namespace std;


namespace bit
{

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

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

	//大堆
	//template<class T, class Container = vector<T>>
	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)
			:_con(first, last)
		{
			//向下调整法建堆
			for (int i =( _con.size() - 1 - 1) / 2; i >= 0; --i)
			{		
				adjustdown(i);
			}
		}

		void adjustdown(int parent)
		{
			Compare _com;
			int minchild = parent * 2 + 1;
			while (minchild < _con.size())
			{
				
				//if (minchild + 1 < _con.size() && _con[minchild + 1] > _con[minchild])
				if (minchild + 1 < _con.size() && _com(_con[minchild],_con[minchild+1]))
				{
					minchild++;
				}

				//if (_con[minchild] > _con[parent])
				if (_com(_con[parent],_con[minchild]))
				{
					swap(_con[minchild], _con[parent]);
					parent = minchild;
					minchild = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}

		void adjustup(int child)
		{
			Compare _com;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				
				//if (_con[child] > _con[parent])
				if (_com(_con[parent],_con[child]))
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

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

		void pop() 
		{
			assert(!empty());
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();

			adjustdown(0);
		}

		bool empty()
		{
			return _con.empty();
		}

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

		const T& top()
		{
			assert(!empty());
			return _con[0];
		}
	private:
		Container _con;
	};
}

3.反向迭代器

在前面vector和list模拟实现,我们只实现了正向迭代器和const正向迭代器,没有去实现反向迭代器。

这是因为反向迭代器也是一个容器适配器
给我一个正向迭代器我可以适配出反向迭代器。
给我一个const正向迭代器我可以适配出const反向迭代器。

也就是我们复用现有的来帮我们实现所需要的。

在这里插入图片描述

3.1list反向迭代器

复用iterator创造reverse_iterator,因此把iterator传过去。
在这里插入图片描述

template<class iterator,class Ref ,class Ptr>
class Reverseiterator
{
public:

//构造
	Reverseiterator(iterator It)
		:_it(It)
	{}

private:
	iterator _it;
};

在这里插入图片描述

//++rit
	self& operator++()
	{
		--it;
		return *this;
	}

	//rit++
	self operator++(int)
	{
		iterator tmp(*this);
		--it;
		return tmp;
	}

	//--rit
	self& opeartor--()
	{
		++it;
		return *this;
	}

	//rit--
	self operator--(int)
	{
		iterator tmp(*this);
		++it;
		return tmp;
	}

在这里插入图片描述

Ref operator*()
	{
		iterator tmp = _it;
		//先--,在解引用
		return *(--tmp);
	}
	
//针对自定义类型
Ptr operator->()
{
	return &(operator*());
}

完整代码

template<class iterator,class Ref ,class Ptr>
class Reverseiterator
{
	typedef Reverseiterator<iterator, Ref, Ptr> self;
public:
	Reverseiterator(iterator It)
		:_it(It)
	{}

	Ref operator*()
	{
		iterator tmp = _it;
		return *(--tmp);
	}

	Ptr operator->()
	{
		return &(operator*());
	}

	//++rit
	self& operator++()
	{
		--_it;
		return *this;
	}

	//rit++
	self operator++(int)
	{
		iterator tmp(*this);
		--_it;
		return tmp;
	}

	//--rit
	self& operator--()
	{
		++_it;
		return *this;
	}

	//rit--
	self operator--(int)
	{
		iterator tmp(*this);
		++_it;
		return tmp;
	}

	bool operator!=(const self& s)
	{
		return _it != s._it;
	}

private:
	iterator _it;
};




reverse_iterator rbegin()
	{
		return reverse_iterator(end());
	}

reverse_iterator rend()
{
	return reverse_iterator(begin());
}

3.2vector反向迭代器

我们的思路和list的反向迭代器一样,把上面代码复用给vector,就实现了vector的反向迭代器。
在这里插入图片描述

在这里插入图片描述

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

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

相关文章

私有云:【13】用户授权及访问

私有云&#xff1a;【13】用户授权及访问 1、AD域中为云桌面用户2、用户授权及访问3、本地物理机访问云桌面 1、AD域中为云桌面用户 创建用户 密码永不过期&#xff0c;自行选择设置 完成 2、用户授权及访问 添加授权 添加 - 搜索名称【刚创建的dev_01用户】 选择dev_01用户…

MinIO 高性能分布式存储最新版单机与分布式部署

文章目录 一、概述二、单机部署&#xff08;单主机&#xff0c;多硬盘模式&#xff09;1&#xff09;磁盘初始化2&#xff09;创建服务启动用户并设置磁盘属主3&#xff09;下载 minio 安装包4&#xff09;修改配置5&#xff09;配置 systemctl 启动6&#xff09;客户端工具 mc…

拜耳阵列(Bayer Pattern)和解马赛克简介

拜尔阵列 典型的图像传感器&#xff08;例如我们在数码相机中使用的图像传感器&#xff0c;主要有CCD, CMOS&#xff09;由许多单独的光电传感器组成&#xff0c;所有这些传感器都会捕获光线。这些光电传感器本身能够捕获光的强度&#xff0c;但不能捕获其波长&#xff08;颜色…

BUUCTF_练[PASECA2019]honey_shop

[PASECA2019]honey_shop 文章目录 [PASECA2019]honey_shop掌握知识解题思路关键paylaod 掌握知识 页面信息收集&#xff0c;根据下载的图片找到下载链接&#xff0c;确定url的参数进行利用&#xff1b;session字段的解密和解密&#xff0c;session伪造的考点。 解题思路 打开…

科技驱动教育!将名师智慧资产固定在系统中

文章目录 每日一句正能量前言未来教育教育趋势一、在线教育&#xff1a;打破时间和空间的限制二、混合式学习&#xff1a;结合线上和线下的优势三、项目式学习&#xff1a;以问题为导向&#xff0c;以项目为载体 科技驱动教育模式在线教育人工智能教育虚拟现实/增强现实教育游戏…

电子器件 二极管

二极管主要是利用其单向导电性&#xff0c;通常用于整流、检波、限幅、元件保护等&#xff0c;在数字电路中常作为开关元件。 一、常用二极管类型 高频二极管 1N4148 等 肖特基二极管 SS14 SS34 SS54 等 快恢复二极管&#xff08;FRD&#xff09; 可以用快恢复二极管代替肖特…

Redis 原理缓存过期、一致性hash、雪崩、穿透、并发、布隆、缓存更新策略、缓存数据库一致性

redis过期策略 redis的过期策略可以通过配置文件进行配置 一、定期删除 redis会把设置了过期时间的key放在单独的字典中&#xff0c;定时遍历来删除到期的key。 1&#xff09;.每100ms从过期字典中 随机挑选20个&#xff0c;把其中过期的key删除&#xff1b; 2&#xff09;.…

TELUS Ventures(泰勒斯)

TELUS Ventures&#xff08;泰勒斯&#xff09;高峰论坛于2023年10月28日在南京第5站正式开幕。该论坛是由泰勒斯风险投资公司主办的一项重要活动&#xff0c;旨在促进创新和创业精神的发展 。 这次高峰论坛将汇集来自全球各地的创业者、投资者和行业专家&#xff0c;共同探讨…

51单片机-点阵屏led

代码配置 这样就能选择每一列哪个亮了 进行位选&#xff0c;段清零&#xff0c;这样就不会影响多列同时了 实现动画 1、使用文字摸提取文件&#xff0c;提取图案的16进制表示数组 offest作为偏移量&#xff0c;count作为计时。count10,偏移量加1&#xff0c;就相当于得到下一…

Docker:命令

Docker&#xff1a;命令 1. 创建MySQL的命令解读2. 基础命令3. 案例 查看DockerHub&#xff0c;拉取Nginx镜像&#xff0c;创建并运行Nginx容器4. 命令别名附录 1. 创建MySQL的命令解读 docker run :创建并运行一个容器&#xff0c;-d 是让容器在后台运行--name:给容器起一个名…

Mac 版 WPS 接入 WPS AI,支持内容创作、修改文章、提炼重点等功能

导读近日消息&#xff0c;“WPS 办公助手”公众号发文宣布&#xff0c;Mac 版 WPS 现已接入 WPS AI&#xff0c;将带来内容生成、内容修改、辅助阅读等功能。 汇总 Mac 版 WPS 接入 WPS AI 之后&#xff0c;在文字、PDF 方面的功能如下&#xff1a; 一键生成文章大纲、讲话稿、…

震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)

注&#xff1a;以下我写的所有方法都在我的一个类中&#xff0c;类已经添加好Controller注解 1、返回静态页面 现在前后端分离&#xff0c;基本不再由后端来返回前端的静态页面&#xff0c;但此处还是分享一下用法&#xff0c;以防万一 如果想要返回静态页面&#xff0c;对应…

PySide6 编写的仪表盘

PySide6 编写的仪表盘 本代码原链接&#xff1a;https://www.cnblogs.com/wangmantou/p/11662779.html 1、使用了PySide6替换了PyQt5, 2、if i % self._scaleMainNum is 0: 替换成了 if i % self.scaleMainNum 0: 3、app.exec() 替换成了 app.exec() 效果如下&#xff1a; …

数据结构───链表

花费一个周时间学完了链表&#xff08;的一部分&#xff09;&#xff0c;简单总结一下。 链表的学习离不开画图&#xff0c;将其抽象成一种逻辑模型&#xff0c;可以减少思考时间&#xff0c;方便理解。 链表大致分为8种结构&#xff0c;自己学习并实现了两种结构&#xff0c;也…

Spring Cloud 之RabbitMQ的学习【详细】

服务通信 分布式系统通信两种方式&#xff1a; 直接远程调用&#xff08;同步&#xff09;借助第三方间接通信&#xff08;异步&#xff09; 同步通讯的问题 Feign就属于同步通讯。存在的如下问题 耦合度高&#xff0c;每次添加新的模块就要修改原有模块的代码性能下降&am…

私有云:【8】VCenter安装Connection服务

私有云&#xff1a;【8】VCenter安装Connection服务 1、安装Connection服务 服务器创建好后配置IP&#xff0c;加入域以及添加域管理员cloudadmin&#xff0c;可参考安装sqlserver部分 1、安装Connection服务 使用cloudadmin用户登录Connection服务器 将connection安装包复制到…

导入的xls文件,数字和日期都是文本格式,到df3都正常,但df4报错,什么原因?...

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 脱我战时袍&#xff0c;著我旧时裳。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python最强王者交流群【斌】问了一个Pandas数据处理的问题&…

云闪付app拉新更新政策啦

云闪付app拉新一手平台 “聚量推客” 目前平台有3个云闪付的版本 1.云闪付高价版 2.云闪付京东版 3.云闪付普通版 普通版和最老的版本是一样的&#xff0c;高价办和京东版都是依托京东进行完成 云闪付拉新是什么&#xff1f;在拉新市场受各个地推人员和网推人员的追捧&am…

3D RPG Course | Core 学习日记一:初识URP

前言 最近开始学习Unity中文课堂M_Studio&#xff08;麦大&#xff09;的3D RPG Course&#xff0c;学习一下3D RPG游戏核心功能的实现&#xff0c;第一课我们学习到的是地图场景的编辑&#xff0c;其中涉及到了URP渲染。 我们首先进入Unity资源商店把地图素材和人物素材导入好…

提高微星笔记本Linux下散热性能,MSI-EC 驱动新补丁发布

导读近日消息&#xff0c;今年早些时候&#xff0c;Linux 6.4 中添加了 MSI-EC 驱动程序&#xff0c;允许对 Linux 系统微星笔记本电脑进行更多控制。 MSI-EC 驱动程序近日迎来新补丁&#xff0c;为微星笔记本带来 Cooler Boost 功能。该功能允许提高笔记本电脑的风扇转速&…