堆实现优先队列

本文详细介绍了如何使用堆数据结构来实现优先队列,通过对比链队实现方式,阐述了堆实现在插入和删除操作上的优势。文章深入探讨了利用C++ STL中的vector容器和堆操作函数,如make_heap、push_heap和pop_heap,来构建和维护最大堆,从而高效地处理优先级高的元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

堆实现

为什么要使用堆实现优先队列?
在前面讲了用链队实现优先队列,其思想是插入元素时按普通队列入队,在删除元素(出队)时按优先队列的性质删除.那么就还有一种方式,即插入元素时按优先队列的方式插入,删除时按普通顺序队列的方式删除.那就是用堆实现优先队列!

由于前面已经写过堆的实现,这里不再重复造轮子,读者可以自己改写实现优先队列,我们使用容器适配器.堆的实现

首先我们需要一个容器,vector容器能满足这个需求.vector容器可以看作一个变长数组,可随时增大减小.
使用方法:vector<类型> 标识符

需要用到的方法:
void push_back(const T& x):向量尾部增加一个元素X
void pop_back():删除向量中最后一个元素
iterator begin():返回向量头指针,指向第一个元素
iterator end():返回向量尾指针,指向向量最后一个元素的下一个位置

按最大堆将vector容器中的元素重新组织顺序,需要用到的方法:
make_heap (_RAIter , _RAIter)以堆的形式对容器元素排序,默认生成最大堆.实际上,第一个和第二个参数是迭代器,请看下图:
在这里插入图片描述
这是make_heap的两个重载函数,第二个在下面马上讲到.第一行是模板,里面的RandomAccessItarator是随机存取迭代器的意思.

迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址.

如果不太理解,会用就行了,上面vector容器的操作中begin()和end()正好提供了这两个参数,前者返回第一个元素的迭代器,后者返回最后一个元素的后一个位置的迭代器.

make_heap(_RAIter ,_RAIter,_Compare)_Compare可以自定义,也可以用已经实现的.生成最小堆:greater<>(),生成最大堆less<>(),如果要使用,请加头文件<fuctional>.让一个函数既能接受函数指针,又能接受函数对象,其中一种方法就是使用模板,所以这里的comp参数可以是函数指针,也可以是函数对象,排序的原则:如果第一个参数排在第二个参数前面,返回false,否则返回true.
这里贴出默认的最大堆的代码,可以从中看出排序的原则:

template<>
	struct less<void>
	{	// transparent functor for operator<
	typedef int is_transparent;

	template<class _Ty1,
		class _Ty2>
		constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const
		-> decltype(static_cast<_Ty1&&>(_Left)
			< static_cast<_Ty2&&>(_Right))
		{	// transparently apply operator< to operands
		return (static_cast<_Ty1&&>(_Left)
			< static_cast<_Ty2&&>(_Right));//如果第一个参数排在第二个参数前面,返回false,否则返回true.
		}
	};

如果希望以自定义结构体中某个变量的权重为标准进行最大堆排序,那么就要自定义,这里我们自定义.

push_heap(_RAIter,_RAIter)将第一个元素与最后一个元素交换,然后使交换后(除最后一个元素)仍具有堆的性质,默认为最大堆.
push_heap(_RAIter,_RAIter,_Compare)这里的_Compare同上.
特别注意:如果make_heap()中用的是自己的比较函数,那么pop_heap()的第3个参数也需要是这个函数!

全部代码及测试代码

思路已经在代码中以注释的方式显示.

#include <algorithm>
#include <iostream>
#include <vector>
#include <iterator>

using namespace std;

typedef struct FHeap{
	int data;
	int priority;
}FHeap;

bool myCompare(FHeap* a, FHeap* b) {//以FHeap中的priority的大小为依据排序,生成最大堆
	return a->priority < b->priority;
}

int main(void) {
	vector<FHeap*> h;

	int n;
	cout << "请输入插入元素的个数:";
	cin >> n;
	while (n--) {
		FHeap* e=new FHeap;
		cout << "请输入插入的元素:";
		cin >> e->data;
		cout << "请输入优先级:";
		cin >> e->priority;

		h.push_back(e);//插入元素至末尾
	}
	make_heap(begin(h), end(h), myCompare);//排序

	for (unsigned int i = 0; i < h.size(); i++) {
		cout << "数据:" << h[i]->data << "\t" << "优先级:" << h[i]->priority << endl;
	}

	pop_heap(begin(h), end(h), myCompare);//准备出队,优先级最高的移至队尾
	cout << "出队元素的数据:" << h[h.size() - 1]->data << endl;//打印容器中最后一个元素的数据
	h.pop_back();//出队(删除最后一个元素)

	system("pause");
	return 0;
}

在这里插入图片描述

### 如何用二叉在Python中实现优先队列 #### 方法概述 优先队列是一种特殊的列,其中每个元素都有各自的优先级,高优先级的元素会先于低优先级的元素被取出。为了高效地管理这些优先级关系并减少操作的时间复杂度,通常采用二叉作为底层数据结构[^3]。 #### 实现细节 以下是基于二叉实现优先队列的核心逻辑: 1. **初始化** 创建一个类 `PriorityQueue` 并定义其属性 `heap` 来存储中的元素。初始状态下,该列表为空。 2. **入 (enqueue)** 当有新的元素加入时,将其追加到的末尾,并调用上浮 (`percUp`) 函数调整位置以维持最小性质。具体实现在如下代码片段中有体现[^1]。 3. **出 (dequeue)** 移除具有最高优先级(即根节点处)的元素后,需重新排列剩余部分形成合法的新。这涉及下沉 (`percDown`) 操作。 4. **辅助功能** 包括但不限于比较两个节点大小、交换它们的位置等功能支持上述主要动作完成。 下面是完整的 Python 示例代码展示整个过程: ```python class PriorityQueue: def __init__(self): self.heap = [] def perc_up(self, i): while i // 2 > 0: if self.heap[i] < self.heap[i // 2]: tmp = self.heap[i // 2] self.heap[i // 2] = self.heap[i] self.heap[i] = tmp i //= 2 def enqueue(self, k): self.heap.append(k) self.perc_up(len(self.heap) - 1) def dequeue(self): retval = self.heap[1] self.heap[1] = self.heap[-1] del self.heap[-1] self.perc_down(1) return retval def perc_down(self, i): while i * 2 <= len(self.heap) - 1: mc = self.min_child(i) if self.heap[i] > self.heap[mc]: tmp = self.heap[i] self.heap[i] = self.heap[mc] self.heap[mc] = tmp i = mc def min_child(self, i): if i * 2 + 1 > len(self.heap) - 1: return i * 2 else: if self.heap[i*2] < self.heap[i*2+1]: return i * 2 else: return i * 2 + 1 ``` 此段代码展示了如何构建一个基本版本的支持动态更新的优先队列系统,利用了数组形式表示完全二叉树这一特性简化了许多实际编程工作量的同时也保证了算法效率处于合理范围内。 #### 性能分析 相比传统线性表方式下的 O(n) 插入时间开销以及每次排序带来的额外负担(O(n log n)) ,借助二叉能够显著提升性能至平均情况下的 O(log n) 时间级别。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值