什么是堆排序?
在整理电脑里的大量文件时,你可能会按大小、名称或时间排序。程序处理数据也是一样,排序算法就是让杂乱的数据变得井井有条的工具。堆排序就是其中一种高效又稳定的排序方式,特别适合处理大量数据。
堆是什么?别被名字吓到
“堆”听起来像一堆垃圾,但在计算机里,它其实是一种特殊的树形结构,叫“二叉堆”。最常见的有两种:大顶堆和小顶堆。大顶堆的特点是每个父节点的值都大于等于子节点,根节点就是最大的那个。小顶堆则相反,根节点是最小的。
想象你有一堆快递盒子,大的放下面,小的放上面,最底下那个是最大的盒子——这就像是一个大顶堆的排列方式。
堆排序的基本思路
堆排序的核心分两步:建堆和排序。先把这些无序的数据调整成一个大顶堆,此时最大值就在顶部;然后把顶部元素和最后一个元素交换,相当于把最大值“扔”到最后面去。接着对剩下的数据重新调整成堆,重复这个过程,直到所有数据有序。
这就像你在整理书架,先把最厚的书找出来放到最右边,再从剩下的里面找最厚的,继续往左放,一步步就把整排书按厚度排好了。
动手实现一个简单的堆排序
下面是一个用 Python 实现堆排序的例子,逻辑清晰,适合初学者理解。
def heapify(arr, n, i):
largest = i # 假设当前节点是最大的
left = 2 * i + 1 # 左子节点
right = 2 * i + 2 # 右子节点
# 如果左子节点存在且比父节点大
if left < n and arr[left] > arr[largest]:
largest = left
# 如果右子节点存在且比当前最大还大
if right < n and arr[right] > arr[largest]:
largest = right
# 如果最大值不是父节点,就交换
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
# 继续调整受影响的子树
heapify(arr, n, largest)
def heap_sort(arr):
n = len(arr)
# 构建大顶堆,从最后一个非叶子节点开始
for i in range(n // 2 - 1, -1, -1):
heapify(arr, n, i)
# 一个个从堆顶取出元素
for i in range(n - 1, 0, -1):
arr[0], arr[i] = arr[i], arr[0] # 把堆顶(最大)移到末尾
heapify(arr, i, 0) # 重新调整堆
# 示例使用
data = [12, 11, 13, 5, 6, 7]
heap_sort(data)
print("排序后:", data)
堆排序的特点和适用场景
堆排序的时间复杂度稳定在 O(n log n),不管数据原本是乱的还是接近有序的,表现都差不多。它不需要额外的存储空间,属于原地排序,节省内存。
不过它有个缺点:不是稳定排序。也就是说,两个相等的数在排序后可能位置互换。如果你需要保持相同元素的原始顺序,就得考虑其他方法,比如归并排序。
在系统资源有限的情况下,比如老电脑跑大数据排序任务,堆排序是个不错的选择。它不像快速排序那样有最坏情况退化的问题,稳定性更好。