1. 什么是堆排序
堆排序是一种常见的排序算法,其思想是将待排序的数组构建成一棵完全二叉树,并将其转化为一个大(小)根堆,然后进行堆顶元素和末尾元素的交换,重新调整堆的结构,重复此过程直至排序完成。
堆排序的时间复杂度为O(nlogn),空间复杂度为O(1),因此被广泛应用于海量数据的排序中。
2. Python实现堆排序
2.1 实现思路
我们可以将堆分为两类:最大堆和最小堆。
最大堆:父节点的值大于等于它的子节点的值。
最小堆:父节点的值小于等于它的子节点的值。
对于大根堆来说,堆顶元素一定是最大的值,对于小根堆来说,堆顶元素一定是最小的值。因此我们可以通过将待排序数组构建成一个大根堆,然后将堆顶元素和末尾元素进行交换,然后剔除末尾元素,重新调整堆的结构,重复此过程直至排序完成。
2.2 代码实现
def heapify(arr, n, i):
largest = i
l = 2*i + 1
r = 2*i + 2
if l < n and arr[i] < arr[l]:
largest = l
if r < n and arr[largest] < arr[r]:
largest = r
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, -1, -1):
heapify(arr, n, i)
for i in range(n-1, 0, -1):
arr[i], arr[0] = arr[0], arr[i]
heapify(arr, i, 0)
2.3 代码解析
首先我们需要定义一个堆化函数heapify(arr, n, i)
,它的作用是将以i为父节点的子树(最多包括其子孙节点)进行堆调整。在堆调整的过程中,我们需要比较当前节点和其左右子节点的大小,然后交换当前节点和子节点,持续执行这一过程直至调整完成。
在堆排序过程中,我们需要先将待排序数组构建成一个大根堆。我们可以根据二叉树的性质得知,最后一个非叶子节点的下标为(n/2)-1,因此我们可以从最后一个非叶子节点开始,对所有节点进行堆调整。实现如下:
for i in range(n, -1, -1):
heapify(arr, n, i)
堆排序过程中,我们首先需要将堆顶元素和末尾元素进行交换,然后将剩余的元素进行堆调整。对于剩余的元素,我们只需要考虑其前i个元素,因为i+1到n-1都是已经排好序的。实现如下:
for i in range(n-1, 0, -1):
arr[i], arr[0] = arr[0], arr[i]
heapify(arr, i, 0)
2.4 测试代码
arr = [12, 11, 13, 5, 6, 7]
heap_sort(arr)
print("排序后的数组为:", end=" ")
for i in range(len(arr)):
print("%d" % arr[i], end=" ")
输出结果如下:
排序后的数组为: 5 6 7 11 12 13
3. 总结
堆排序是一种高效的排序算法,其时间复杂度为O(nlogn),空间复杂度为O(1)。Python实现堆排的代码相对简单,只需要定义一个堆化函数即可。编写堆排序代码时需要注意一些细节,如何构建堆、如何进行堆调整等。因此我们需要在理解其原理的基础上,多加实践,才能达到熟练掌握的程度。