对于给定的n个元素的数组a[1..n],要求从中找出第k小的元素。 【输入样例】 a={20, 43, 32, 67 ,48, 89, 36, 47, 15} k=3 【输出样例】 32
时间: 2024-05-06 12:20:29 浏览: 7
一、暴力方法
最简单的方法是直接对数组进行排序,然后输出第k个元素。时间复杂度为 $O(n\log n)$。
二、快速选择
快速选择(Quickselect)是基于快速排序的一种算法,它可以在平均 $O(n)$ 的时间复杂度内找出第k小的元素。
快速排序的思想是通过每次选择一个枢轴元素(pivot)将数组分为左右两部分,左边的元素都小于等于pivot,右边的元素都大于等于pivot。然后对左右两部分分别递归进行快速排序。
快速选择的思想是类似的,我们只需要对左右两部分中的某一部分进行递归即可。如果左边的部分元素个数大于等于k,则在左边部分继续寻找第k小的元素;否则在右边部分寻找第 $k-m$ 小的元素,其中 $m$ 是左边部分的元素个数。这样每次递归都可以将搜索范围缩小一半,平均情况下时间复杂度为 $O(n)$。
下面是快速选择的代码实现:
```python
import random
def quickselect(a, k):
"""
从a中找出第k小的元素
"""
# 随机选择枢轴元素
pivot = random.choice(a)
# 分区
left = [x for x in a if x < pivot]
right = [x for x in a if x > pivot]
# 计算左边部分的元素个数
num_left = len(left)
# 判断k在哪一部分
if k <= num_left:
return quickselect(left, k)
elif k > num_left + 1:
return quickselect(right, k - num_left - 1)
else:
return pivot
# 测试
a = [20, 43, 32, 67, 48, 89, 36, 47, 15]
k = 3
print(quickselect(a, k)) # 输出32
```
三、堆选择
堆选择(Heapselction)是一种基于堆的算法,它可以在 $O(n\log k)$ 的时间复杂度内找出第k小的元素。
堆的定义是一棵完全二叉树,其中每个节点的值都大于等于(或小于等于)它的子节点的值。堆有两种类型:最大堆(Max Heap)和最小堆(Min Heap)。在最大堆中,根节点的值最大,在最小堆中,根节点的值最小。
堆选择的思想是先将数组的前k个元素构建成一个最大堆,然后从第k+1个元素开始遍历数组,如果当前元素小于最大堆的根节点,就用当前元素替换根节点,并将最大堆重新调整为最大堆。这样遍历完整个数组后,最大堆的根节点就是第k小的元素。
下面是堆选择的代码实现:
```python
import heapq
def heapselect(a, k):
"""
从a中找出第k小的元素
"""
# 构建最大堆
heap = [-x for x in a[:k]]
heapq.heapify(heap)
# 遍历数组
for x in a[k:]:
if -x > heap[0]:
heapq.heapreplace(heap, -x)
# 返回第k小的元素
return -heap[0]
# 测试
a = [20, 43, 32, 67, 48, 89, 36, 47, 15]
k = 3
print(heapselect(a, k)) # 输出32
```
四、总结
在实际应用中,如果需要多次查询第k小的元素,可以考虑先对数组进行排序或者使用堆选择算法,因为它们的预处理时间复杂度较低($O(n\log n)$ 或 $O(k\log k)$),而查询时间复杂度较低。如果只需要查询一次第k小的元素,则快速选择算法更加适合,因为它的预处理时间复杂度为 $O(n)$,而查询时间复杂度也为 $O(n)$。