排序算法 之 堆排序 HeapSort

介紹

堆排序在 top K 問題中使用比較頻繁。堆排序是採用二叉堆的數據結構來實現的,雖然實質上還是一維數組。二叉堆是一個近似完全二叉樹 。

二叉堆具有以下性質:
- 父節點的鍵值總是大於或等於(小於或等於)任何一個子節點的鍵值。
- 每個節點的左右子樹都是一個二叉堆(都是最大堆或最小堆)。

步驟

  • 構造最大堆(Build_Max_Heap):若數組下標範圍爲0~n,考慮到單獨一個元素是大根堆,則從下標n/2開始的元素均爲大根堆。於是只要從n/2-1開始,向前依次構造大根堆,這樣就能保證,構造到某個節點時,它的左右子樹都已經是大根堆。
  • 堆排序(HeapSort):由於堆是用數組模擬的。得到一個大根堆後,數組內部並不是有序的。因此需要將堆化數組有序化。思想是移除根節點,並做最大堆調整的遞歸運算。第一次將heap[0]與heap[n-1]交換,再對heap[0…n-2]做最大堆調整。第二次將heap[0]與heap[n-2]交換,再對heap[0…n-3]做最大堆調整。重複該操作直至heap[0]和heap[1]交換。由於每次都是將最大的數併入到後面的有序區間,故操作完後整個數組就是有序的了。
  • 最大堆調整(Max_Heapify):該方法是提供給上述兩個過程調用的。目的是將堆的末端子節點作調整,使得子節點永遠小於父節點 。

這裏寫圖片描述

這裏寫圖片描述

代碼

# -*- coding: utf-8 -*-
"""
Created on Wed Apr 27 11:53:24 2016

@author: zang
"""


from matplotlib import pyplot as plt
import random

def heapSort(ary) :
    n = len(ary)
    first = int(n/2-1)       #最後一個非葉子節點
    for start in range(first,-1,-1) :     #構造大根堆
        max_heapify(ary,start,n-1)
    for end in range(n-1,0,-1):           #堆排,將大根堆轉換成有序數組
        ary[end],ary[0] = ary[0],ary[end]
        max_heapify(ary,0,end-1)
    return ary


#最大堆調整:將堆的末端子節點作調整,使得子節點永遠小於父節點
#start爲當前需要調整最大堆的位置,end爲調整邊界
def max_heapify(ary,start,end):
    root = start
    while True :
        child = root*2 +1               #調整節點的子節點
        if child > end : break
        if child+1 <= end and ary[child] < ary[child+1] :
            child = child+1             #取較大的子節點
        if ary[root] < ary[child] :     #較大的子節點成爲父節點
            ary[root],ary[child] = ary[child],ary[root]     #交換
            root = child
        else :
            break


def plotScatter(inputList):
    plt.scatter(range(len(inputList)),inputList)
    plt.show()

if __name__ == "__main__":
    num_list = range(1000)
    unsortedList = random.sample(num_list, 30)
    print "unsortedList:"
    plotScatter(unsortedList)
    print unsortedList
    sortedList = heapSort(unsortedList)
    print "sortedList:"
    plotScatter(sortedList)
    print sortedList

測試

輸入

[796, 311, 58, 512, 470, 568, 648, 272, 132, 813, 284, 652, 887, 727, 709, 867, 206, 562, 287, 295, 805, 336, 51, 416, 799, 967, 760, 596, 161, 131]

這裏寫圖片描述

輸出

[51, 58, 131, 132, 161, 206, 272, 284, 287, 295, 311, 336, 416, 470, 512, 562, 568, 596, 648, 652, 709, 727, 760, 796, 799, 805, 813, 867, 887, 967]

這裏寫圖片描述

分析

情況 性能
Worst case performance: O(nlogn)
Best case performance: O(nlogn)
Average case performance: O(nlogn)
Worst case space complexity: O(1)

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章