堆排序的时间复杂度为O(nlgn),由于堆是一个完全二叉树的形式,因此可以用数组来存储,通过下标的关系表示二叉树结点的父子、兄弟关系。
堆分为大顶堆以及小顶堆,以大顶堆为例。大顶堆的性质是每一个父节点的值都比孩子结点的值大,这是需要维护的最重要的性质。
在进行堆排序时,首先是将一个无序数组建成一个堆的形式,再将最后一个叶子结点和堆顶元素交换,得到最大值,然后从根结点开始向下维护堆性质,如此循环。
python实现:
1 #堆排序算法 2 def left(i) : #左孩子下标 3 return(2 * i + 1) 4 5 6 def right(i): #右孩子下标 7 return(2 * i) 8 9 10 def MAX_HEAPIFY(A, i, end): #维护堆的性质 11 l = left(i) 12 r = right(i) 13 heap_size = len(A) 14 if l < end and A[l] > A[i]: #保证当前父结点存在左孩子,找到三个结点中的最大值的下标 15 largest = l 16 else: 17 largest = i 18 if r < end and A[r] > A[largest]: 19 largest = r 20 if largest != i: #如果最大值的下标不是根节点,则交换两个值 21 A[largest], A[i] = A[i], A[largest] 22 MAX_HEAPIFY(A, largest, end) #以交换过的孩子结点的下标作为下一次的父结点,进行递归 23 24 25 def Build_max_heap(A): #将无序数组构建成为大顶堆 26 heap_size = len(A) 27 for i in range(heap_size//2, -1, -1): #从最后一个非叶子结点开始维护,逐个向上直到根节点 28 MAX_HEAPIFY(A, i, heap_size) 29 30 31 def Max_heap_sort(A): #堆排序算法 32 Build_max_heap(A) #先获得大顶堆 33 for i in range(len(A)-1, 0, -1): 34 A[i], A[0] = A[0], A[i] #将末尾结点和跟根节点交换 35 MAX_HEAPIFY(A, 0, i) #每交换一次,获得一个最大值,然后从根节点开始维护堆的性质 36 #并去掉最后一个位置元素 37 38 if __name__=='__main__': 39 list = [10, 6, 5, 8, 1, 2, 4, 9] 40 Max_heap_sort(list) 41 print(list)
结果为[1, 2, 4, 5, 6, 8, 9, 10]
这里要注意的是在MAX_HEAPIFY函数中加入结束时的下标,以此去掉数组结尾已经获得的排好序的部分。