C++ —— 优先级队列(priority queue)的模拟实现

目录

杂谈

vector和list的区别

1. 优先级队列的定义

2. 优先级队列的模拟实现

3. 仿函数


链接:

priority_queue - C++ Reference (cplusplus.com)icon-default.png?t=O83Ahttps://legacy.cplusplus.com/reference/queue/priority_queue/?kw=priority_queue


杂谈

vector和list的区别

在这种情况下诞生了一个缝合怪:deque

 

但是依旧有缺陷 


1. 优先级队列的定义

队列是一种先进先出的数据类型。元素的入队都只能从队尾进入,出队时从队列头部出去

*

优先级队列不能先进先出,更像是数据类型中的“”,也就是数组

优先级队列每次出队的元素是队列中优先级最高的那个元素,默认大的值优先级高,如果想要小的值优先级高可以使用仿函数,而不是队首的元素,也就是每次出队,都是将当前队列中最大的那个元素出队


2. 优先级队列的模拟实现

假设父节点在数组中的下标为i,那么:

                                                        1.左孩子在数组中的下标为:2*i+1 

                                                        2.右孩子在数组中的下标为:2*i+2

假设孩子在数组中的下标为i,那么:

                                                        父在数组中的下标为:(i - 1)/ 2

在这里不区分左孩子和右孩子,因为除以会向下取整

#pragma once
//优先级队列:默认大的值优先级高,如果想要小的值优先级高可以使用仿函数
//底层是堆
namespace bit
{
	template<class T, class Container = vector<T>>
	class priority_queue
	{
	public:
		//堆的向上调整
		void AdjustUp(size_t child)
		{
			//孩子/2找到父节点
			int parent = (child - 1) / 2;
			//孩子大于0就进入/继续
			while (child > 0)
			{
				//如果孩子小于父亲
				if (_con[parent] < _con[child])
				{
					swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		//向下调整
		void AdjustDown(size_t parent)
		{
			// 先假设左孩子小
			int child = parent * 2 + 1;

			// child >= n说明孩子不存在,调整到叶子了
			while (child < 0)
			{
				//找到大的子结点 
				if (child + 1 < _con.size() && _con[child] < _con[child + 1])
				{
					child++;
				}
				//if (_con[child] > _con[parent]) 大堆
				//孩子小于父亲
				if (_con[child] < _con[parent])//小堆
				{
					swap(_con[child], _con[parent]);
					parent = child;
					//继续算左孩子
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}



			void push(const T & x)
			{
				//插入数据之前已经是一个堆了,那么数据就要
				_con.push_back(x);

				//从堆底向上调整
				AdjustUp(_con.size() - 1);
			}

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

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

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

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

		private:
			Container _con;
		};
	}


3. 仿函数

仿函数的本质是一个类,使用到了仿函数来重载 operator(),以达到改变大/小堆的功能,他的对象可以像函数一样使用

// 仿函数:本质是一个类,这个类重载operator(),他的对象可以像函数一样使用
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;
	}
};
#pragma once
//优先级队列:默认大的值优先级高,如果想要小的值优先级高可以使用仿函数
//底层是堆
namespace bit
{
	template<class T, class Container = vector<T>>
	class priority_queue
	{
	public:
		//堆的向上调整
		void AdjustUp(size_t child)
		{
			Compare com;
			//孩子/2找到父节点
			int parent = (child - 1) / 2;
			//孩子大于0就进入/继续
			while (child > 0)
			{
				//如果孩子小于父亲
				//if (_con[parent] < _con[child])
				//将大的值移向堆顶,建大堆
				if (com(_con[child], _con[parent]))
				{
					swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		//向下调整
		void AdjustDown(size_t parent)
		{
			Compare com;
			// 先假设左孩子小
			int child = parent * 2 + 1;

			// child >= n说明孩子不存在,调整到叶子了
			while (child < 0)
			{
				//找到大的子结点 
				//if (child + 1 < _con.size() && _con[child] < _con[child + 1])
				if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
				{
					child++;
				}
				//if (_con[child] > _con[parent]) 大堆
				//孩子小于父亲
				//if (_con[child] < _con[parent])//小堆
				if (com(_con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
					parent = child;
					//继续算左孩子
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}



			void push(const T & x)
			{
				//插入数据之前已经是一个堆了,那么数据就要
				_con.push_back(x);

				//从堆底向上调整
				AdjustUp(_con.size() - 1);
			}

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

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

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

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

		private:
			Container _con;
		};
	}

感谢观看~

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值