堆排序的思想是调整和交换
基本思想:首先是建立大根堆,在大根堆的情况下,打乱一个元素,可以对其做调整恢复大根堆的性质。
1.建立大根堆:从底向上开始调整,符合调整的条件,从非叶子节点开始调整,因为需要交换节点与子节点,若没有子节点,则该节点不需要进行调整,若节点数目为n,则可以从(n-2)//2开始。
2.调整:调整这个函数有两个作用,第一,建立大根堆;第二,在大根堆的基础上交换堆顶和堆底元素,并对剩余元素继续做调整和交换。
空间复杂度:O(1) (没有额外辅助空间,在原地进行交换)
时间复杂度: O(nlogn) (在遍历数组的循环下,进行堆调整,调整的过程是logn,可以理解为树的深度)
#调整大根堆
def heapify(arr, n, i):
#参数为要调整的数组arr,数组中元素的个数n, 需要调整的元素i
#调整的条件是只递归调整交换过位置的节点,其他子节点保持不动,说明调整条件,要保证子树符合大根
#堆的性质
left = 2 * i + 1
right = left + 1
larger = i
if left < n and arr[left] > arr[larger]:
larger = left
if right < n and arr[right] > arr[larger]:
larger = right
if larger != i:
arr[larger], arr[i] = arr[i], arr[larger]
#递归调整调换过后位置元素的子树的大根堆调整
heapify(arr, n, larger)
#建立大根堆
def build_max_heap(arr):
#从底向上,非叶子节点开始调整,保证后续调整的条件
n = len(arr)
for i in range((n-2)//2, -1, -1):
heapify(arr, n, i)
#堆排序,每次取一个和堆顶元素交换,然后对剩余的元素继续进行堆调整直至没有剩余元素
def heap_sort(arr):
#建立大顶堆
build_max_heap(arr)
n = len(arr)
#将堆顶元素和最底部元素做交换,然后对剩余元素重复此操作
for i in range(n-1, -1, -1):
arr[i], arr[0] = arr[0], arr[i]
heapify(arr, i, 0)
arr = [21, 1, 4, 23, 8, 45, 10]
heap_sort(arr)
print(arr)