第 K 小数字问题 (优先队列实现)

本文介绍优先队列的基本概念与实现方法,并详细解释如何利用优先队列解决第K小问题。通过示例代码展示如何维护一个大小限定的大根堆,以找到一系列数中的第K小的数值。

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

首先了解优先队列:
可以理解优先队列就是一个含有内部排序的队列,具有队列的一切属性,本质上是通过堆来实现的。

定义语法:
priority_queue<Type, Container, Functional>

Type 是数据类型 (注意:数据元素的类型可以是pair类型)
Container 由数组实现的一些数据结构,如:vector,deque,不可以是List类型,就是存放元素的容器
Functional 是内部排序的方式

当使用的数据类型是基本的内置的数据类型的时候就可以直接传入类型来创建优先队列,默认是大根堆(降序序列)

小根堆 升序序列
priority_queue <int,vector,greater > q;
小根堆 降序序列
priority_queue <int,vector,less > q;

第 K 小问题:
题目:第K小问题题目

思路:
维护一个元素数量上限为K的一个优先队列,按照大根堆的形式进行排序,队列的首元素就是第K小的元素,如果当前元素的数量小于K就不断向其中加入元素,否则,判断当前的队列头部元素与待加入的元素的大小,如果小于对头元素,就直接将当前的对头元素出队,再入队当前的待加入即可。

代码:

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>

#define FAST ios::sync_with_stdio(false)
#define LL long long
#pragma GCC optimize(2)

using namespace std;
int n,m,k;

int main(void)
{
	FAST;
	cin >> n >> m >> k;
	
	priority_queue<int> q;
	
	for(int i = 0;i < n;i++) // 输入n个数据的时候就开始维护长度为k的优先队列
	{
		int x;
		cin >> x;
		
		if(q.size() < k) q.push(x);
		else
		{
			if(x < q.top()) q.pop(),q.push(x);
		}	
	}
	
	for(int i = 0;i < m;i++)
	{
		int t;
		cin >> t;
		
		if(t == 1)
		{
			int x;
			cin >> x;
			
			if(q.size() < k) q.push(x); // 插入元素
			else
			{
				if(x < q.top()) q.pop(),q.push(x);
			}
		}
		else if(t == 2) //询问元素
		{
			if(q.size() >= k)
			cout << q.top() << endl;
			else
			cout << -1 << endl;
		}
	}
	
	return 0;
}

<think>好的,用户现在问的是“列表转优先队列”,我需要先理解他们的需求。用户可能有一个列表,想把它转换成优先队列,也就是堆结构,用来高效地获取最大值或最小值。Python中的优先队列通常用`heapq`模块实现,不过用户可能对具体步骤不太清楚,所以我要详细解释如何转换。 首先,我需要回忆一下`heapq`的基本用法。这个模块提供了堆操作,比如`heapify`可以把列表原地转换为堆,`heappush`和`heappop`来添加和弹出元素。但要注意的是,`heapq`默认实现的是最小堆,如果需要最大堆,得用一些技巧,比如取反数值。 接下来,用户的列表可能有不同的数据类型,比如数字、字符串或者自定义对象。针对不同的情况,处理方法可能不同。特别是自定义对象,可能需要重载比较运算符或者使用元组来包装优先级和对象。 然后,我需要考虑用户可能的错误或误区。比如,直接使用`heapq`的`heapify`后,列表结构变化,但用户可能不知道堆的存储顺序并不是完全有序的。这时候需要解释堆的结构特性,以及为什么弹出操作能保证每次取最小或最大。 还有,用户可能想知道如何维护一个动态的优先队列,比如在转换后如何添加新元素,如何弹出元素,这些操作的时间复杂度是多少。`heapq`的`heappush`和`heappop`都是O(log n)的时间,这对于优先队列来说是很高效的。 另外,Python中的`queue.PriorityQueue`类也是一个选择,它是线程安全的,但内部也是基于`heapq`实现的。如果用户不需要多线程,直接使用`heapq`可能更高效;如果需要线程安全,则推荐`PriorityQueue`。 可能用户的应用场景是什么?比如任务调度,每次处理优先级最高的任务,或者需要频繁获取当前最小/最大值的情况。这时候转换列表为优先队列可以提升效率。 还要注意,当列表元素是自定义对象时,如何处理优先级的问题。比如,如果对象没有自然比较顺序,需要在插入堆之前转换成可以比较的形式,比如元组(优先级,对象),或者在类中定义`__lt__`方法。 最后,总结步骤:导入模块、转换列表(堆化)、操作堆(弹出、推入)、处理不同数据类型的情况。并给出代码示例,让用户能直接参考使用。</think>在 Python 中,将列表转换为优先队列(即堆结构)可通过 `heapq` 模块实现优先队列的特点是**按优先级顺序访问元素**(默认最小堆,即每次弹出最小值)。以下是详细步骤和用法: --- ### 一、基础用法:列表转最小堆 1. **导入模块** ```python import heapq ``` 2. **原地转换列表为堆** `heapq.heapify()` 会将列表转换为堆结构(原地修改列表): ```python nums = [3, 1, 4, 1, 5, 9, 2] heapq.heapify(nums) # 直接修改原列表 → 堆结构 print(nums) # 堆的物理存储顺序可能为 [1, 1, 2, 3, 5, 9, 4] ``` 3. **弹出最小值** 使用 `heappop()` 按优先级顺序弹出元素: ```python while nums: print(heapq.heappop(nums), end=' ') # 输出:1 1 2 3 4 5 9 ``` --- ### 二、实现最大堆 `heapq` 默认是最小堆,若需最大堆,可通过**数值取反**实现: ```python nums = [3, 1, 4, 1, 5] max_heap = [-x for x in nums] # 将所有元素取反 heapq.heapify(max_heap) # 弹出时还原数值 largest = -heapq.heappop(max_heap) # 弹出 5 ``` --- ### 三、动态维护优先队列 1. **添加元素** ```python heapq.heappush(nums, 0) # 添加新元素并保持堆结构 ``` 2. **获取前 N 个极值** ```python heapq.nlargest(3, nums) # 前3大值 → [9, 5, 4] heapq.nsmallest(2, nums) # 前2小值 → [1, 1] ``` --- ### 四、处理复杂数据类型 1. **元组优先级** 若元素是元组,按**第一个元素**作为优先级比较: ```python tasks = [(2, 'taskA'), (1, 'taskB'), (3, 'taskC')] heapq.heapify(tasks) heapq.heappop(tasks) # 弹出 (1, 'taskB') ``` 2. **自定义对象** 需定义 `__lt__` 方法或使用优先级元组包装: ```python class Task: def __init__(self, priority, name): self.priority = priority self.name = name def __lt__(self, other): return self.priority < other.priority # 定义比较规则 heap = [Task(3, '低优先级'), Task(1, '高优先级')] heapq.heapify(heap) ``` --- ### 五、完整示例代码 ```python import heapq # 列表转最小堆 data = [5, 3, 8, 1, 2] heapq.heapify(data) print("堆结构:", data) # 输出可能为 [1, 2, 8, 3, 5] # 动态操作 heapq.heappush(data, 0) print("弹出最小值:", heapq.heappop(data)) # 0 # 最大堆模拟 max_heap = [-x for x in [5, 3, 8, 1, 2]] heapq.heapify(max_heap) print("弹出最大值:", -heapq.heappop(max_heap)) # 8 ``` --- ### 六、注意事项 1. **时间复杂度**: - `heapify()`: $O(n)$ - `heappop()`/`heappush()`: $O(\log n)$ - `nlargest()`/`nsmallest()`: $O(n + k \log n)$($k$ 为返回元素数量) 2. **线程安全**: 若需线程安全优先队列,可使用 `queue.PriorityQueue` 类(内部基于 `heapq`)。 --- 通过灵活使用堆操作,可以高效处理需要动态优先级排序的场景(如任务调度、Top K问题等)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值