堆排序--优先级队列例题

本文探讨了如何使用优先级队列(堆排序)对几乎有序的数组进行排序。当数组元素移动距离不超过K时,可以利用小根堆先找到最小值,然后逐步加入新元素并取出堆顶元素,实现排序。这种方法尤其适用于元素移动范围较小的情况,有效减少了元素移动次数。

优先级队列其实就是堆排序的意思。

已知一个几乎有序的数组,几乎有序是指,如果把数组排好序的话,每个元素移动的距离不超过K,并且k相对于数组来说比较小。请选择一个合适排序算法针对这个数据进行排序。

分析:如果每个数组移动的距离不超过K,那么数组范围[0,k]内一定存在最小值,因为其他位置的值是不可能移动到数组0位置上的,同理[1,k+1]上存在第二小的值。

那么我们可以利用堆排序,小根堆。

先把[0,k]范围内的元素放到小跟堆中,取出根元素,那么就是这个数组中的最小值,然后再将k+1的元素加入到小根堆中,再取出根元素,就是这个数组中第二小的值。到没有元素可以加的时候,不断的将小根堆中的根元素拿出来就排好序了。

	public static void sortedArrDistanceLessK(int[] arr,int k) {
        //默认为小根堆,PriorityQueue就是优先级队列,也就是堆
		PriorityQueue<Integer> heap = new PriorityQueue<Integer>();
		int index = 0;
		for(;index<Math.min(arr.length, k);index++) {
			heap.add(arr[index]);
            //将【0,k-1】的元素放进去
		}
		int i=0;
		for(;index<arr.length;index++,i++) {
			heap.add(arr[index]);//进一个元素就取出一个范围最小值。
			arr[i] = heap.poll();
			
		}
		while(!heap.isEmpty()) {//最后剩余的元素全部以根元素的形式取出即可
			arr[i++] = heap.poll(); 
		}
		
	}
	

系统给的堆排序只是说更加方便一点,但是只能做到给一个取出一个,要是需要更加复杂的操作的时候就需要手写堆排序了,但是本题中明显不需要。

### 计算机复试中的优先级队列知识点与例题 #### 什么是优先级队列优先级队列是一种特殊的队列,在这种队列中,元素按照其优先级被处理。通常情况下,最高优先级的元素会最先被移除并处理。在实际应用中,优先级队列可以通过多种方式实现,比如堆(Heap)、二叉搜索树(BST)或其他数据结构。 #### 堆与优先级队列的关系 堆是一种常用的实现优先级队列的方式。堆分为最大堆和最小堆两种形式: - **最大堆**:父节点的关键字大于等于子节点的关键字。 - **最小堆**:父节点的关键字小于等于子节点的关键字。 通过维护堆的性质,可以高效地获取当前集合中的最大值或最小值[^1]。 #### 时间复杂度分析 对于基于堆的优先级队列操作,常见的时间复杂度如下: - 插入一个新元素:`O(log n)`。 - 删除具有最高优先级的元素:`O(log n)`。 - 查找具有最高优先级的元素:`O(1)`。 #### 经典例题解析 ##### 题目 1:统计出现频率最高的前 N 个数据 在一个包含大量重复数据的数组中,找到出现次数最多的前 `N` 个数据。 ###### 解法思路 1. 使用哈希表(Hash Map 或者字典)统计每个数据的出现频次。 2. 构建一个小顶堆(Min Heap),大小固定为 `N`,用于存储当前频率最大的 `N` 个数据及其对应频次。 3. 遍历哈希表中的键值对,如果某个数据的频次高于堆顶元素,则替换堆顶元素,并调整堆。 4. 最终输出堆中的所有元素即为所需结果。 ###### 实现代码 ```python import heapq from collections import Counter def top_n_frequent(nums, n): count = Counter(nums) # O(N),构建哈希表 heap = [] for key, freq in count.items(): # O(K * log N),K 是不同元素的数量 if len(heap) < n: heapq.heappush(heap, (freq, key)) elif freq > heap[0][0]: heapq.heapreplace(heap, (freq, key)) result = [(key, freq) for freq, key in sorted(heap, reverse=True)] return result[::-1] # 测试用例 nums = [1, 1, 1, 2, 2, 3] n = 2 print(top_n_frequent(nums, n)) # 输出 [(1, 3), (2, 2)] ``` --- ##### 题目 2:合并 K 个有序链表 给定多个已排序的链表,将其合并成一个新的升序链表。 ###### 解法思路 利用最小堆来辅助解决此问题。每次从堆中弹出当前最小值,并将该值所在链表的下一个结点加入堆中。 ###### 实现代码 ```python class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next def __lt__(self, other): # 定义比较规则以便于放入堆中 return self.val < other.val def merge_k_lists(lists): import heapq dummy = ListNode(-1) current = dummy min_heap = [] for head in lists: # 将每个链表的第一个节点加入堆 if head: heapq.heappush(min_heap, head) while min_heap: # 不断取最小值并更新堆 smallest_node = heapq.heappop(min_heap) current.next = smallest_node current = current.next if smallest_node.next: # 如果还有后续节点则继续加入堆 heapq.heappush(min_heap, smallest_node.next) return dummy.next ``` --- ##### 题目 3:寻找第 k 大的元素 设计一种算法,能够在线性时间内找到未排序数组中的第 k 大元素。 ###### 解法思路 使用大顶堆保存前 k 个小的元素,遍历整个数组后,堆顶即是第 k 大的元素。 ###### 实现代码 ```python def find_kth_largest(nums, k): import heapq heap = nums[:k] heapq.heapify(heap) # 转化为小顶堆 for num in nums[k:]: if num > heap[0]: # 替换堆顶较小的元素 heapq.heapreplace(heap, num) return heap[0] # 测试用例 nums = [3, 2, 1, 5, 6, 4] k = 2 print(find_kth_largest(nums, k)) # 输出 5 ``` --- ### 总结 以上介绍了优先级队列的核心概念以及几个经典的应用场景。掌握这些内容有助于应对计算机复试中的相关问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值