优先级队列的实现

什么是优先级队列

优先级队列是一种特殊的数据结构,它类似于队列或栈,但是每个元素都关联有一个优先级或权重。在优先级队列中,元素的出队顺序不是简单地按照它们进入队列的先后顺序(先进先出,FIFO),而是根据元素的优先级来决定。具有最高优先级的元素最先出队,如果两个元素具有相同的优先级,则按照它们在队列中的顺序出队。
通俗来说,假设我们传入队列的是整形数据,那么他会按照数据的从小到大还是从大到小的出队顺序存放在队列中这就是优先级队列

仿函数

这里要提到一个概念叫仿函数

仿函数是一个可以像函数一样调用的对象。简单来说,仿函数是一种具有operator()成员函数的对象,使得该对象可以像普通函数一样使用调用操作符(),他是重载operator()括号实现的,我们来举个例子

下面是个比较大小的仿函数例子

cpp 复制代码
 template<class type>
  class less
 {
 public:
	bool operator()(const type& x, const type& y)
	{
		return x < y;
	}
};

这里我们利用这个比较大小的仿函数,就可以像函数那样调用,就像这样

cpp 复制代码
int main()
{
  less li;
  if(li(1,2))
  {
  cout<<"y比x大"<<endl;
  }
  else
 {
 cout<<"x比y大"<<endl;
 }
  return 0;
  }

在举个形象的例子

c 复制代码
# include<iostream>
# include<string>
using namespace std;
template<class type>
class _cout
{
public:
	void operator()(const type& input)
	{
		cout << input << endl;
	}
};
int main()
{
	_cout<string> print;
	print("hello,word");
	return 0;
}

有了以上仿函数的介绍之后,就可以开始说我们的优先级队列了

优先级队列的实现

优先级队列的实质上就是用堆来创建队列,按照堆排序的思想来对输入到队列里面的数据进行处理,按照升序建大堆,降序建小堆的思想进行创建,所以这里需要两个堆排序里面关键的函数**adjustdown(向下调整)adjustup(向上调整)**还需要我们上面提到的仿函数,这里仿函数的作用就是我们不用去改代码中的大于还是小于,直接在创建对象的时候提供模板参数就来作为创建大堆还是小堆的依据,非常方便

下面是仿函数

cpp 复制代码
 template<class type>
  class less
 {
 public:
	bool operator()(const type& x, const type& y)
	{
		return x < y;
	}
};

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

接下来是建堆算法

cpp 复制代码
	template<class type,class contier = vector<type>,class compre = less<type>>
	class priorityqueue
	{
	public:
		void adjustup(size_t child)
		{
			compre 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;
				}
			}
		}
		void adjustdown(size_t parent)
		{
			compre com;
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				//        x        <        y 
				if (child + 1 < _con.size() && com(_con[child], _con[child+1]))
				{
					child++;
				}
				//        x        <        y 
				if (com(_con[parent], _con[child]))
				{ 
					swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
void push(const type& input)
{
	_con.push_back(input);
	adjustup(_con.size() - 1);
}
void pop()
{
	swap(_con[0], _con[_con.size() - 1]);
	_con.pop_back();
	adjustdown(0);
}

这里需要结合这4个函数一起看,push就是插入数据,插入完之后,我们这里的默认容器是vector,然后我们调用向上建堆算法,从数组最后一位开始(所以这里的size()-1)vector下标是从零开始的存放10个数就是占用0-9个位置,假设我们插入1,9,2,10,3我们来画图看看是怎么调堆的
这就是向上建堆的过程,也是我们push数据的过程

接下来说一说pop,出队列

这里需先出对顶数据在把第一个数据和最后一个数据进行交换

在向下调整堆

因为是建的大堆,把最大的数据给pop掉了之后,采用向下调整算法,第二大的数据就会出现在堆顶

在一直执行这个操作,最后的出队顺序就是从大到小的顺序

t1是创建的对象
出队列代码

cpp 复制代码
	void test()
	{
		priorityqueue<int,vector<int>,less<int>> t1;
		t1.push(1);
		t1.push(9);
		t1.push(2);
		t1.push(10);
		t1.push(3);

		while (!t1.is_empty())
		{
			cout << t1.top() << " ";
			t1.pop();
	   }
	}

最后还有剩下的这些小函数关于返回大小,容器空没有,取到堆顶的数据

cpp 复制代码
		size_t size()
		{
			return _con.size();
		}
		bool is_empty()
		{
			return _con.empty();
		}
		const type& top()
		{
			return _con[0];
		}

源码

cpp 复制代码
#pragma once
# include<vector>
# include<iostream>
using namespace std;
namespace thr
{ 
 template<class type>
  class less
 {
 public:
	bool operator()(const type& x, const type& y)
	{
		return x < y;
	}
};

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

	template<class type,class contier = vector<type>,class compre = less<type>>
	class priorityqueue
	{
	public:
		void adjustup(size_t child)
		{
			compre com;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				  //        x        <        y 
				if (com(_con[parent],_con[child]))
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
		void adjustdown(size_t parent)
		{
			compre com;
			size_t child = parent * 2 + 1;
			while (child < _con.size())
			{
				//        x        <        y 
				if (child + 1 < _con.size() && com(_con[child], _con[child+1]))
				{
					child++;
				}
				//        x        <        y 
				if (com(_con[parent], _con[child]))
				{ 
					swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		void push(const type& input)
		{
			_con.push_back(input);
			adjustup(_con.size() - 1);
		}
		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjustdown(0);
		}
		size_t size()
		{
			return _con.size();
		}
		bool is_empty()
		{
			return _con.empty();
		}
		const type& top()
		{
			return _con[0];
		}
	private:
		contier _con;
	};
	void test()
	{
		priorityqueue<int,vector<int>,less<int>> t1;
		t1.push(1);
		t1.push(9);
		t1.push(2);
		t1.push(10);
		t1.push(3);

		while (!t1.is_empty())
		{
			cout << t1.top() << " ";
			t1.pop();
	   }
	}
}
相关推荐
anlog5 分钟前
C#在自定义事件里传递数据
开发语言·c#·自定义事件
奶香臭豆腐18 分钟前
C++ —— 模板类具体化
开发语言·c++·学习
晚夜微雨问海棠呀25 分钟前
长沙景区数据分析项目实现
开发语言·python·信息可视化
graceyun26 分钟前
C语言初阶习题【9】数9的个数
c语言·开发语言
波音彬要多做1 小时前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
Swift社区1 小时前
Excel 列名称转换问题 Swift 解答
开发语言·excel·swift
一道微光1 小时前
Mac的M2芯片运行lightgbm报错,其他python包可用,x86_x64架构运行
开发语言·python·macos
矛取矛求1 小时前
QT的前景与互联网岗位发展
开发语言·qt
Leventure_轩先生1 小时前
[WASAPI]从Qt MultipleMedia来看WASAPI
开发语言·qt
向宇it2 小时前
【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
开发语言·unity·c#·游戏引擎