python實現·十大排序算法之堆排序(Heap Sort)

簡介

堆排序(Heap Sort)是利用堆這種數據結構而設計的一種排序算法,是一種選擇排序。python

堆是具備如下性質的徹底二叉樹:每一個結點的值都大於或等於其左右孩子結點的值,稱爲大頂堆;或者每一個結點的值都小於或等於其左右孩子結點的值,稱爲小頂堆。git

堆排序思路爲: 將一個無序序列調整爲一個堆,就能找出序列中的最大值(或最小值),而後將找出的這個元素與末尾元素交換,這樣有序序列元素就增長一個,無序序列元素就減小一個,對新的無序序列重複操做,從而實現排序。github

算法實現步驟

  1. 構造初始堆。將給定無序序列構形成一個大頂堆(通常升序採用大頂堆,降序採用小頂堆);算法

  2. 將堆頂元素與末尾元素進行交換,使末尾元素最大。而後繼續調整堆,再將堆頂元素與末尾元素交換,獲得第二大元素;數組

  3. 從新調整結構,使其知足堆定義,而後繼續交換堆頂元素與當前末尾元素;數據結構

  4. 如此反覆進行交換、重建、交換,直到整個序列有序。dom

Python 代碼實現

# heap_sort 代碼實現

def build(arr:List[int], root, end):
    while True:
        child = 2 * root + 1 # 左子節點的位置
        if child > end: # 若左子節點超過了最後一個節點,則終止循環
            break
        if (child + 1 <= end) and (arr[child + 1] > arr[child]): # 若右子節點在最後一個節點以前,而且右子節點比左子節點大,則咱們的孩子指針移到右子節點上
            child += 1
        if arr[child] > arr[root]: # 若最大的孩子節點大於根節點,則交換二者順序,而且將根節點指針,移到這個孩子節點上
            arr[child], arr[root] = arr[root], arr[child]
            root = child
        else:
            break

def heap_sort(arr:List[int]):
    n = len(arr)
    first_root = n // 2 - 1 # 確認最深最後的那個根節點的位置
    for root in range(first_root, -1, -1): # 由後向前遍歷全部的根節點,建堆並進行調整
        build(arr, root, n - 1)
        
    for end in range(n - 1, 0, -1): # 調整完成後,將堆頂的根節點與堆內最後一個元素調換位置,此時爲數組中最大的元素,而後從新調整堆,將最大的元素冒到堆頂。依次重複上述操做
        arr[0], arr[end] = arr[end], arr[0]
        build(arr, 0, end - 1)
複製代碼
# 測試數據
if __name__ == '__main__':
    import random
    random.seed(54)
    arr = [random.randint(0,100) for _ in range(10)]
    print("原始數據:", arr)
    heap_sort(arr)
    print("堆排序結果:", arr)
複製代碼
# 輸出結果

原始數據: [17, 56, 71, 38, 61, 62, 48, 28, 57, 42]
堆排序結果: [17, 28, 38, 42, 48, 56, 57, 61, 62, 71]
複製代碼

動畫演示

堆排序動畫演示

算法分析

  • 時間複雜度函數

    在每次重建時,隨着堆的容量的減少,層數會降低,函數時間複雜度會變化。重建堆一共須要n-1次循環,每次循環的比較次數爲\log _2i,則相加爲:測試

    T=\log _2n+\log _2(n-1)+\cdots +\log _23+\log _22=\log _2\left( n! \right)\\
\because \left( \dfrac{n}{2} \right) ^{\dfrac{n}{2}}\le n!\le n^n\\
\therefore \dfrac{n}{2}\log _2\left( \dfrac{n}{2} \right)\le \log _2\left( n! \right) \le n\log _2n

    因此堆排序時間複雜度爲O(nlog_2n)動畫

  • 空間複雜度

    空間複雜度就是在交換元素時那個臨時變量所佔的內存空間,因此堆排序空間複雜度爲O(1)

  • 穩定性

    堆排序在交換數據的時候,是比較父結點和子節點之間的數據,因此,即使是存在兩個數值相等的兄弟節點,它們的相對順序在排序也可能發生變化。所以,堆排序是不穩定的。

  • 綜合評價

    時間複雜度(平均) 時間複雜度(最好) 時間複雜度(最壞) 空間複雜度 排序方式 穩定性
    O(nlog_2n) O(nlog_2n) O(nlog_2n) O(1) in-place 不穩定

聯繫咱們

我的博客網站:www.bling2.cn/

Github地址:github.com/lb971216008…

知乎專欄:zhuanlan.zhihu.com/Use-Python-…

小專欄:xiaozhuanlan.com/Use-Python-…

博客園:www.cnblogs.com/Use-Python-…

關注
相關文章
相關標籤/搜索