資料結構 堆排序 堆排序 Heap Sort

2021-07-31 15:28:39 字數 3104 閱讀 1825

堆排序是一種選擇排序,其時間複雜度為o(nlogn)。

堆的定義

n個元素的序列當且僅當滿足下列關係之一時,稱之為堆。

情形1:ki 

<= k2i 且ki 

<= k2i+1 (最小化堆小頂堆

情形2:ki >= k2i 且ki >= k2i+1 (最大化堆大頂堆

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

若將和此序列對應的一維陣列(即以一維陣列作此序列的儲存結構)看成是乙個完全二叉樹,則堆的含義表明,完全二叉樹中所有非終端結點的值均不大於(或不小於)其左、右孩子結點的值。

由此,若序列是堆,則堆頂元素(或完全二叉樹的根)必為序列中n個元素的最小值(或最大值)。

例如,下列兩個序列為堆,對應的完全二叉樹如圖:

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

堆排序(heap sort)只需要乙個記錄元素大小的輔助空間(供交換用),每個待排序的記錄僅占有乙個儲存空間。

一般用陣列來表示堆,若根結點存在序號0處, i結點的父結點下標就為(i-1)/2。i結點的左右子結點下標分別為2*i+1和2*i+2。

(注:如果根結點是從1開始,則左右孩子結點分別是2i和2i+1。)

如第0個結點左右子結點下標分別為1和2。

如最大化堆如下:

左圖為其儲存結構,右圖為其邏輯結構。

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

1.如何由乙個無序序列建成乙個堆?

2.如何在輸出堆頂元素之後,調整剩餘元素成為乙個新的堆?

先考慮第二個問題,一般在輸出堆頂元素之後,視為將這個元素排除,然後用表中最後乙個元素填補它的位置,自上向下進行調整:首先將堆頂元素和它的左右子樹的根結點進行比較,把最小的元素交換到堆頂;然後順著被破壞的路徑一路調整下去,直至葉子結點,就得到新的堆。

我們稱這個自堆頂至葉子的調整過程為「篩選」。

從無序序列建立堆的過程就是乙個反覆「篩選」的過程。

初始化堆的時候是對所有的非葉子結點進行篩選。

最後乙個非終端元素的下標是[n/2]向下取整,所以篩選只需要從第[n/2]向下取整個元素開始,從後往前進行調整。

比如,給定乙個陣列,首先根據該陣列元素構造乙個完全二叉樹。

然後從最後乙個非葉子結點開始,每次都是從父結點、左孩子、右孩子中進行比較交換,交換可能會引起孩子結點不滿足堆的性質,所以每次交換之後需要重新對被交換的孩子結點進行調整。

有了初始堆之後就可以進行排序了。

堆排序是一種選擇排序。建立的初始堆為初始的無序區。

排序開始,首先輸出堆頂元素(因為它是最值),將堆頂元素和最後乙個元素交換,這樣,第n個位置(即最後乙個位置)作為有序區,前n-1個位置仍是無序區,對無序區進行調整,得到堆之後,再交換堆頂和最後乙個元素,這樣有序區長度變為2。。。

不斷進行此操作,將剩下的元素重新調整為堆,然後輸出堆頂元素到有序區。每次交換都導致無序區-1,有序區+1。不斷重複此過程直到有序區長度增長為n-1,排序完成。

首先,建立初始的堆結構如圖:

然後,交換堆頂的元素和最後乙個元素,此時最後乙個位置作為有序區(有序區顯示為黃色),然後進行其他無序區的堆調整,重新得到大頂堆後,交換堆頂和倒數第二個元素的位置……

重複此過程:

最後,有序區擴充套件完成即排序完成:

由排序過程可見,若想得到公升序,則建立大頂堆,若想得到降序,則建立小頂堆

假設排列的元素為整型,且元素的關鍵字為其本身。

因為要進行公升序排列,所以用大頂堆。

根結點從0開始,所以i結點的左右孩子結點的下標為2i+1和2i+2。

//

堆篩選函式

//已知h[start~end]中除了start之外均滿足堆的定義

//本函式進行調整,使h[start~end]成為乙個大頂堆

typedef int

elemtype;

void heapadjust(elemtype h, int start, int

end)

if(temp > h[i])//

左右孩子中獲勝者與父親的比較

//將孩子結點上位,則以孩子結點的位置進行下一輪的篩選

h[start]=h[i];

start =i;

}h[start]= temp; //

插入最開始不和諧的元素

}void heapsort(elemtype a, int

n)

//進行排序

for(int i=n-1; i>0; --i)

}

堆排序方法對記錄數較少的檔案並不值得提倡,但對n較大的檔案還是很有效的。因為其執行時間主要耗費在建初始堆和調整建新堆時進行的反覆「篩選」上。

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

資料結構 排序(堆排序)

最小堆的特性說明 即任何一非葉節點的值不大於其左右孩子節點的值。堆排序最適合取topn的資料 include myheap.h int myswap int src,int desc 調整樹 arr 需要排序的陣列 root 根節點 size 樹的大小 int changetree int arr,...

資料結構 排序 堆排序

附加空間 乙個儲存最大記錄的空間 是否是穩定的排序方法 不穩定 include stdio.h define maxsize 10 typedef int keytype typedef struct recordtype typedef struct table void swap table t...

資料結構 排序 堆排序

堆排序是選擇排序中的一種,選擇排序的思想是在未排序的數列中選擇乙個最大或者最小的資料加入已排序序列,大根堆這個結構的根節點就是最大值,因此會大大方便選擇。在完全二叉樹中,根 左,右 手動建堆 第一步 順序建立一棵樹 第二步 檢查非葉子結點是否滿足 根 左,右,不滿足就將當前節點與最大的乙個孩子互換 ...