优先级队列的实现

什么是优先级队列

优先级队列是一种特殊的数据结构,它类似于队列或栈,但是每个元素都关联有一个优先级或权重。在优先级队列中,元素的出队顺序不是简单地按照它们进入队列的先后顺序(先进先出,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();
	   }
	}
}
相关推荐
2501_903238651 分钟前
Java 9模块开发:Eclipse实战指南
java·开发语言·eclipse·个人开发
ahardstone2 分钟前
【CS61A 2024秋】Python入门课,全过程记录P5(Week8 Inheritance开始,更新于2025/2/2)
开发语言·python
阿豪学编程18 分钟前
c++ string类 +底层模拟实现
开发语言·c++
沈韶珺1 小时前
Visual Basic语言的云计算
开发语言·后端·golang
沈韶珺1 小时前
Perl语言的函数实现
开发语言·后端·golang
嘻嘻哈哈的zl2 小时前
初级数据结构:栈和队列
c语言·开发语言·数据结构
wjs20242 小时前
MySQL 插入数据指南
开发语言
美味小鱼2 小时前
Rust 所有权特性详解
开发语言·后端·rust
Bluesonli2 小时前
第 1 天:UE5 C++ 开发环境搭建,全流程指南
开发语言·c++·ue5·虚幻·unreal engine
中游鱼2 小时前
C# 数组和列表的基本知识及 LINQ 查询
c#·linq·数组·数据处理·list数列