20191209-八大排序之堆排序

1. 堆排序

算法核心思想

堆排序利用堆的特点, 最大堆要求节点的元素都要不小于其孩子,最小堆要求节点元素都不大于其左右孩子,那么处于最大堆的根节点的元素一定是这个堆中的最大值,每次把堆顶元素放置在二叉树的尾部,然后重新建堆这样循环处理,最终就能完成排序。

核心算法逻辑如下:

  1. 建堆
  2. 把堆顶的元素和最后一个元素交换,这样,最大的元素就排到了最后面
  3. 把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置
  4. 重复上面的1到3步,之后遍历完堆

在堆中,节点i的左子节点是2*i+1,右子节点是2*i+2,故最小值堆满足如下的特点:

  1. Node(i).value < Node(2*i+1).value
  2. Node(i).value < Node(2*i+2).value

代码实现

建堆,建堆的过程通过数组的给定数组的下标,建立以给定下标为根的堆,具体过程如下:

def heapify(arr,root_index,arr_length):
    """给定数组,数组的下标,当前需要建堆的数组长度"""
    left_index = 2*root_index+1
    right_index = 2*root_index+2
    max_index = root_index
    #找到以arr[root_index]为根的堆的与左右子树3个节点中最大值的索引
    if left_index<arr_length and arr[left_index]>arr[max_index]:
        max_index = left_index
    if right_index<arr_length and arr[right_index]>arr[max_index]:
        max_index = right_index
    if max_index!=root_index:
        arr[max_index],arr[root_index] = arr[root_index],arr[max_index]
        heapify(arr,max_index,arr_length)
def buildheap(arr):
    """从堆的最后一个有子节点的索引开始建堆,然后逐一给堆添加节点"""
    for i in range(len(arr)//2,-1,-1):
        heapify(arr,i,len(arr))

将堆顶的元素与最后一个元素交换,缩短数组的长度再次建堆,重复直至排序完成

def heapSort(arr):
    arr_length = len(arr)
    buildheap(arr)#先建堆
    for i in range(arr_length):
        arr[0],arr[arr_length-i-1]= arr[arr_length-i-1],arr[0]
        heapify(arr,0,arr_length-i-1)#此时堆的结构变化,调整堆结构
    return arr

执行解析

heapify(arr,root_index,arr_length)函数实现了一个建堆的过程,一定要从堆的最下层节点开始建堆,如果从堆的最上层开始建堆,则该函数无法保证堆的所有节点满足堆的结构

建立堆后每次取堆顶的元素(arr[0]的位置)放置到第arr_len-i的位置(第一次放置在倒数第一个位置,第二次放置在倒数第二个位置,第n次放置子倒数第n个位置)当最后所有元素放置完成后排序结束。

  1. 使用使用buildheap函数建立第一个最大堆
  2. 使用heapify调整堆结构保证
  3. 使用heapsort实现堆排序的交换

时间复杂度:O(N*logN)。

总结

堆排序的时间复杂度为O(n*logn),堆排序是使用完全二叉树的特点来实现的一种排序方式

相关推荐