【C++初阶】:优先队列(仿函数)

文章介绍了优先队列的基本使用,包括其底层的数组模拟堆结构和常用成员函数。接着,展示了如何使用模板参数进行模拟实现,提供了调整堆的上下调整方法。最后,讨论了仿函数的概念,并解释了如何通过仿函数改变优先队列的存储顺序。
摘要由CSDN通过智能技术生成

一.基本使用

优先队列的底层默认是使用vector构造的,也就是使用数组模拟(二叉树)堆。并且默认是按大堆存放数据(也就是父节点>子节点,左节点>右节点)。

在这里插入图片描述

优先队列的成员函数不多,常用的就是empty,size,top,pop,push。

在这里插入图片描述

简单使用

首先优先队列常使用区间初始化和无参初始化。

在这里插入图片描述

可以使用push插入数据,注意因为优先队列是使用数组模拟堆,所以不能直接遍历。只能通过不断访问顶部数据,再不断弹出顶部数据进行间接遍历。

在这里插入图片描述

在这里插入图片描述

二.模拟实现

这里使用了模板参数(template<class T,class Container=vector>),一共有两个参数,第一个T用来适配不同类型的数据(例如int,string或者自定义类型),第二个参数默认是vector,也就是底层默认是用vector实现优先队列,当然也可以使用list等等(这里与库里保持一致)。

#include<vector>

namespace mine
{
	template<class T,class Container=vector<T>>
	class priority_queue
	{
	private:
		//向下调整
		void AdjustDown(int parent)
		{
			int child = parent * 2 + 1;
			while (child < _con.size())
			{
				if (child + 1 < _con.size() &&  _con[child]< _con[child + 1])
				{
					child++;
				}
				if (_con[parent]<_con[child])
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}	
			}
		}

		//向上调整
		void AdjustUp(int child)
		{
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				if (_con[parent] <_con[child])
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
	public:
		//无参构造
		priority_queue()
		{}
		//区间构造
		template<class InputLterater>
		priority_queue(InputLterater first,InputLterater last)
		{
			while (first != last)
			{
				_con.push_back(*first);
				first++;
			}

			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
			{
				AdjustDown(i);
			}
		}
		//弹出顶部数据
		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			AdjustDown(0);
		}
		//插入数据
		void push(const T&x)
		{
			_con.push_back(x);
			AdjustUp(_con.size() - 1);
		}
		//访问顶部数据
		const T& top()
		{
			return _con[0];
		}
		//数组大小
		size_t size()
		{
			return _con.size();
		}
		//是否为空
		bool empty()
		{
			return _con.empty();
		}

	private:
		Container _con;
	};

}

测试

#include<iostream>
using namespace std;

#include"priority_queue.h"


int main()
{
	int a[9] = { 4,8,1,9,6,7,2,5,5};
	mine::priority_queue<int> v(a,a+9);//使用区间初始化


	mine::priority_queue<int> vv;//无参初始化
	vv.push(5);
	vv.push(2);
	vv.push(7);
	vv.push(11);
	while (!vv.empty())
	{
		cout << vv.top() << ' ';
		vv.pop();
	}
	return 0;
}

三.仿函数

1.优先队列里的使用

在库里除了T,Container两个模板参数外,还有一个Compare参数,这是一个仿函数用来改变存储顺序(默认是less,也就是大堆,可以改成greater,也就是小堆)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.概念

仿函数的底层实际很简单,就是一个类里面重载了一个括号()运算符。

在这里插入图片描述

在这里插入图片描述

仿函数的本质就是一个类的对象可以像函数一样使用。

3.模拟

由于less,greater本质都是类,库里有实现,所以就可以直接使用。

#include<vector>

namespace mine
{
	template<class T,class Container=vector<T>,class Compare=less<T>>
	class priority_queue
	{
	private:
		//向下调整
		void AdjustDown(int parent)
		{
			Compare com;
			int child = parent * 2 + 1;
			while (child < _con.size())
			{
				if (com(child + 1, _con.size()) && com( _con[child], _con[child + 1]))
				{
					child++;
				}
				if (com(_con[parent],_con[child]))
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}	
			}
		}

		//向上调整
		void AdjustUp(int child)
		{
			Compare com;
			int 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;
				}
			}
		}
	public:
		//无参构造
		priority_queue()
		{}
		//区间构造
		template<class InputLterater>
		priority_queue(InputLterater first,InputLterater last)
		{
			while (first != last)
			{
				_con.push_back(*first);
				first++;
			}

			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
			{
				AdjustDown(i);
			}
		}
		//弹出顶部数据
		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			AdjustDown(0);
		}
		//插入数据
		void push(const T&x)
		{
			_con.push_back(x);
			AdjustUp(_con.size() - 1);
		}
		//访问顶部数据
		const T& top()
		{
			return _con[0];
		}
		//数组大小
		size_t size()
		{
			return _con.size();
		}
		//是否为空
		bool empty()
		{
			return _con.empty();
		}

	private:
		Container _con;
	};

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咸蛋挞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值