堆排序學習筆記及堆排序算法的python實現

堆排序(Heapsort)是指利用堆積樹(堆)這種數據結構所設計的一種排序算法,它是選擇排序的一種。能夠利用數組的特色快速定位指定索引的元素。堆分爲大根堆和小根堆,是徹底二叉樹。大根堆的要求是每一個節點的值都不大於其父節點的值,即A[PARENT[i]] >= A[i]。在數組的非降序排序中,須要使用的就是大根堆,由於根據大根堆的要求可知,最大的值必定在堆頂。html

堆排序是一種選擇排序,其時間複雜度爲O(nlogn).python


堆的定義算法

    n個元素的序列{k1,k2,…,kn}當且僅當知足下列關係之一時,稱之爲堆。數組

      情形1:k<= k2i 且k<= k2i+1 最小化堆或小頂堆數據結構

      情形2:k>= k2i 且k>= k2i+1 (化堆大頂堆ide

      其中i=1,2,…,n/2向下取整;spa

       堆能夠當作是一個徹底二叉樹。徹底二叉樹中全部非終端結點的值均不大於(或不小於)其左右孩子結點的值。堆頂元素(徹底二叉樹的根)必爲序列中的最大或最小值。設計

        若在輸出堆頂的最小值以後,使得剩餘n-1個元素的序列重又建成一個堆,則獲得n個元素的次小值。如此反覆執行,便能獲得一個有序序列,這個過程稱之爲堆排序orm

  堆排序(Heap Sort)只須要一個記錄元素大小的輔助空間(供交換用),每一個待排序的記錄僅佔有一個存儲空間。htm

堆的存儲:

    通常用數組表示堆,若根結點存在序號0處, i結點的父結點下標就爲(i-1)/2。i結點的左右子結點下標分別爲2*i+1和2*i+2。(注:若是根結點是從1開始,則左右孩子結點分別是2i和2i+1。)

wKioL1YbpqiC6pVXAAE9xN5qozU644.jpg

堆排序的實現

    實現堆排序須要解決兩個問題:

            一、如何由一個無序序列建成一個堆?

            二、如何在輸出堆頂元素以後,調整剩餘元素成爲一個新的堆。

    對於第二個問題,通常在輸出堆頂元素以後,視爲將這個元素排除,而後用表中的最後一個元素填補它的位置,自下向上調整:首先,將堆頂元素和它的左右子樹的根節點進行比較,把最小的元素交換到堆頂;而後,順着被破壞的路徑一路調整下去,直至葉子節點,就獲得新的堆。咱們稱這個自堆頂至葉子的調整過程爲「篩選」。


構造初始堆

   給定一個數組,首先,根據該數組元素構造一個徹底二叉樹;而後,從最後一個非葉子結點開始,每次都是從父結點、左孩子、右孩子中進行比較交換,交換可能會引發孩子結點不知足堆的性質,因此每次交換以後須要從新對被交換的孩子結點進行調整。

 

進行堆排序

  其基本思想爲(大頂堆):

        1)將初始待排序關鍵字序列(R1,R2....Rn)構建成大頂堆,此堆爲初始的無序區;

         2)將堆頂元素R[1]與最後一個元素R[n]交換,此時獲得新的無序區(R1,R2,......Rn-1)和新的有序區(Rn),且知足R[1,2...n-1]<=R[n]; 

         3)因爲交換後新的堆頂R[1]可能違反堆的性質,所以須要對當前無序區(R1,R2,......Rn-1)調整爲新堆,而後再次將R[1]與無序區最後一個元素交換,獲得新的無序區(R1,R2....Rn-2)和新的有序區(Rn-1,Rn)。不斷重複此過程直到有序區的元素個數爲n-1,則整個排序過程完成。

實例:

    此處是參照一篇博客總結的,大體內容都是這個博客中的(堆排序 Heap Sort

    1.初始的堆結構

             wKiom1YbrC-SO0KGAACZZCLtTfE516.jpg

    2.交換堆頂的元素和最後一個元素,此時最後一個位置做爲有序區(有序區顯示爲***),而後進行其餘無序區的堆調整,從新獲得大頂堆後,交換堆頂和倒數第二個元素的位置……

                wKioL1YbrICjV1rkAAKctRqdc7Q268.jpg

wKiom1Ybrq6jognNAAD-OD6twtc067.jpg

             想獲得升序,則創建大頂堆,若想獲得降序,則創建小頂堆

堆排序分析

  堆排序方法對記錄數較少的文件並不值得提倡,但對n較大的文件仍是頗有效的。由於其運行時間主要耗費在建初始堆和調整建新堆時進行的反覆「篩選」上。

  堆排序在最壞的狀況下,其時間複雜度也爲O(nlogn)。相對於快速排序來講,這是堆排序的最大優勢。此外,堆排序僅需一個記錄大小的供交換用的輔助存儲空間。

python代碼實現:

def fixDown(a,k,n): #自頂向下堆化,從k開始堆化
    N=n-1
    while 2*k<=N:
        j=2*k
        if j<N and a[j]<a[j+1]: #選出左右孩子節點中更大的那個
            j+=1
        if a[k]<a[j]:
            a[k],a[j]=a[j],a[k]
            k=j
        else:
            break
 
def heapSort(l):
    n=len(l)-1
    for i in range(n//2,0,-1):
        fixDown(l,i,len(l))
    while n>1:
        l[1],l[n]=l[n],l[1]
        fixDown(l,1,n)
        n-=1
    return l[1:]
 
l=[-1,26,5,77,1,61,11,59,15,48,19] #第一個元素不用,佔位
res=heapSort(l)
print(res)
相關文章
相關標籤/搜索