优先队列

何为优先队列

在简绍优先队列前,我们先来回顾一下普通队列的特点,即“先进先出(FIFO)"。 

 

而优先队列不再遵循先入先出的原则,而是分为两种情况:

  • 最大优先队列,无论入队顺序,当前最大的元素优先出队。
  • 最小优先队列,无论入队顺序,当前最小的元素优先出队。

比如有一个最大优先队列,它的最大元素是8,那么虽然元素8并不是队首元素,但出队的时候仍然让元素8首先出队:

为了满足优先级队列这一特性,可以使用最大堆或者最小堆。

1.最大堆的堆顶元素是整个堆中的最大元素

2.最小堆的堆顶元素是整个堆中的最小元素

因此,我们可以用最大堆来实现最大优先队列,每一次入队操作就是堆的插入操作,每一次出队操作就是删除堆顶节点。

入队操作:

1.插入新节点5

2.新节点5上浮到合适位置。

出队操作:

1.把原堆顶节点10“出队”

2.最后一个节点1替换到堆顶位置

3.节点1下沉,节点9成为新堆顶

时间复杂度

二叉堆节点上浮和下沉的时间复杂度都是log2n,所以优先队列入队和出队的时间复杂度也是log2n。

最小堆实现


/*优先级队列*/

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<stack>
#include<queue>

const int MAXSIZE = 100;
const int INCSIZE = 2;
template<class Type>
class PriQueue
{
	Type* data;
	int maxsize;//最大容量
	int cursize;//当前容量

	void FilterDown(int begin, int end)//下沉操作  删除
	{
		int i = begin, j = i * 2 + 1;
		Type tmp = data[i];
		while (j <= end)
		{
			if (j < end && data[j] > data[j + 1]) ++j;
			if (tmp <= data[j]) break;
			data[i] = data[j];
			i = j;
			j = i * 2 + 1;
		}
		data[i] = tmp;
	}

	void FilterUp(int begin)//上浮操作   插入
	{
		int j = begin, i = (j - 1) / 2;
		Type tmp = data[j];
		while (j > 0)
		{
			if (data[i] <= tmp) break;
			data[j] = data[i];
			j = i;
			i = (j - 1) / 2;
		}
		data[j] = tmp;
	}

	void Make_Heap()//构建堆时相当于不断进行下沉操作
	{
		int end = cursize - 1;
		int pos = (end - 1) / 2;
		while (pos >= 0)
		{
			FilterDown(pos, end);
			--pos;
		}
	}
public:
	PriQueue() :maxsize(MAXSIZE), cursize(0)//构造函数
	{
		data = new Type[maxsize];
	}

	PriQueue(Type* ar, int n)//调用此构造函数时,说明数据已存在,即要调整元素的位置构造堆
	{
		maxsize = n > MAXSIZE ? n : MAXSIZE;
		cursize = n;
		data = new Type[maxsize];

		for (int i = 0; i < n; ++i)
		{
			data[i] = ar[i];
		}
		Make_Heap();
	}
	~PriQueue()
	{
		delete[]data;
		data = NULL;
		maxsize = 0;
		cursize = 0;
	}

	int GetSize() const { return cursize; }//当前节点个数

	bool IsEmpty() const { return GetSize() == 0; }//判空

	Type& GetFront() //取队顶元素
	{
		return data[0];
	}

	const Type& GetFront() const
	{
		return data[0];
	}

	void pop()//删除队顶元素
	{
		data[0] = data[cursize - 1];
		--cursize;
		FilterDown(0, cursize - 1);
		
	}
	void Push(const Type& x)//入队列
	{
		if (cursize >= maxsize) return;
		data[cursize] = x;
		FilterUp(cursize);
		++cursize;
	}
};

int main()
{
	PriQueue<int> pqu;
	int x;
	while (std::cin >> x, x != -1)
	{
		pqu.Push(x);
	}

	while (!pqu.IsEmpty())
	{
		int x = pqu.GetFront(); pqu.pop();
		std::cout << x <<std:: endl;
	}
	return 0;
}

执行结果: 

最大堆实现


/*优先级队列*/ 
/*小根堆*/

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>

const int MAXSIZE = 100;
const int INCSIZE = 2;
template<class Type>
class PriQueue
{
	Type* data;
	int maxsize;//最大容量
	int cursize;//当前容量
	 
	void FilterDown(int begin, int end)//下沉操作  删除  大根堆
	{ 
		int i = begin, j = i * 2 + 1;//j是左孩子
		Type tmp = data[i];
		while (j <= end)
		{
			if (j < end && data[j] < data[j + 1]) ++j;
			if (tmp >= data[j]) break;
			data[i] = data[j];
			i = j;
			j = i * 2 + 1;
		}
		data[i] = tmp;
	}

	void FilterUp(int begin)//上浮操作   插入  大根堆
	{
		int j = begin, i = (j - 1) / 2;
		Type tmp = data[j];
		while (j > 0)
		{
			if (data[i] >= tmp) break;
			data[j] = data[i];
			j = i;
			i = (j - 1) / 2;
		}
		data[j] = tmp;
	}

	void Make_Heap()//构建堆时相当于不断进行下沉操作
	{
		int end = cursize - 1;
		int pos = (end - 1) / 2;
		while (pos >= 0)
		{
			FilterDown(pos, end);
			--pos;
		}
	}
public:
	PriQueue() :maxsize(MAXSIZE), cursize(0)//构造函数
	{
		data = new Type[maxsize];
	}

	PriQueue(Type* ar, int n)//调用此构造函数时,说明数据已存在,即要调整元素的位置构造堆
	{
		maxsize = n > MAXSIZE ? n : MAXSIZE;
		cursize = n;
		data = new Type[maxsize];

		for (int i = 0; i < n; ++i)
		{
			data[i] = ar[i];
		}
		Make_Heap();
	}
	~PriQueue()
	{
		delete[]data;
		data = NULL;
		maxsize = 0;
		cursize = 0;
	}

	int GetSize() const { return cursize; }//当前节点个数

	bool IsEmpty() const { return GetSize() == 0; }//判空

	Type& GetFront() //取队顶元素
	{
		return data[0];
	}

	const Type& GetFront() const
	{
		return data[0];
	}

	void pop()//删除队顶元素
	{
		data[0] = data[cursize - 1];//最后一个节点补到堆顶
		--cursize;
		FilterDown(0, cursize - 1);//从堆顶开始向下调整
		
	}
	void Push(const Type& x)//入队列
	{
		if (cursize >= maxsize) return;
		data[cursize] = x;
		FilterUp(cursize);//数组的最后一个位置
		++cursize;
	}
};

int main()
{
	PriQueue<int> pqu;
	int x;
	while (std::cin >> x, x != -1)
	{
		pqu.Push(x);
	}

	while (!pqu.IsEmpty())
	{
		int x = pqu.GetFront(); pqu.pop();
		std::cout << x <<std:: endl;
	}
	return 0;
}

 执行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值