程式猿必學之堆排序

2021-09-25 15:44:11 字數 2349 閱讀 3217

前情了解:

例如:

了解了完全二叉樹之後,就可以來看一下什麼是堆?

堆實際上就是乙個完全二叉樹,不同的地方在於:它是有規律的完全二叉樹,也就是說堆一定是完全二叉樹,但完全二叉樹卻不一定是堆。

對於一棵完全二叉樹來說,如果它的任意乙個父節點的值都大於或等於它的兩個子節點,這樣的堆叫做大根堆,又稱最大堆(大頂堆);

相反如果一棵完全二叉樹,它的任意乙個父節點的值都小於或等於它的兩個子節點,這樣的堆叫做小根堆,又稱最小堆(小頂堆)。

如下圖示:

了解完以上概念之後,就可以正式進行堆排序了,拿到一組無序的資料後,先把這組資料整理成乙個大根堆或小根堆,至於選擇哪乙個,取決於你的排序是公升序還是降序,一般來說公升序建大根堆,降序建小根堆

主題思路:

堆排序主要分為兩步,以大根堆為例進行講解:

將初始堆也就是乙個完全二叉樹構建成大根堆

將堆頂資料與末節點進行交換得到最大的資料

重複上述步驟

注:在整個排序過程中,堆必須始終保證是大根堆,為森麼嘞?

只有堆始終是大根堆,才能保證每次拿到的資料是最大的,並且在調整的過程中,當前子樹中的最大資料位於根節點,便於下一次拿到最大的資料

具體過程:

拿到一組資料之後:

step1:將初始堆構建成大根堆

a.無序序列的結構如下:

b.大根堆調整的過程如下:

我們先從最後乙個非葉子結點開始(葉結點自然不用調整,第乙個非葉子結點size/2-1=2,也就是上圖的4結點),從左至右,從下至上進行調整。

此時,整個二叉樹符合大根堆的特點,構建大根堆至此結束。

step2:將堆頂資料與末節點進行交換得到最大的資料

交換完畢後,對當前二叉樹進行調整

重複上面的過程,直至迴圈結束,就會得到一組有序的資料

穩定性、時間複雜度與空間複雜度:

空間複雜度:

因為堆排序是就地排序,空間複雜度為常數:o(1)

穩定性:不穩定

在乙個長為n 的序列,堆排序的過程是從第n / 2開始和其子節點共3個值選擇最大(大頂堆)或者最小(小頂堆),這3個元素之間的選擇當然不會破壞穩定性。但當為n / 2 - 1, n / 2 - 2, … 1這些個父節點擊擇元素時,就會破壞穩定性。有可能第n / 2個父節點交換把後面乙個元素交換過去了,而第n / 2 - 1個父節點把後面乙個相同的元素沒有交換,那麼這2個相同的元素之間的穩定性就被破壞了。所以,堆排序不是穩定的排序演算法。

**如下(含詳細注釋):

void

adjustdown

(int array,

int size,

int root)

//假設左孩子最大

int max = left;

//存在右孩子,右》左

if(right < size && array[right]

> array[left]

)//如果大於,表示符合大根堆的條件,不需要再進行調整,直接返回

if(array[root]

>= array[max]

)//將子節點中較大的那個和根節點進行交換

swap

(array + root, array + max)

;//判斷這次交換是否對其餘子樹有影響,有影響則進行調整,遞迴執行

adjustdown

(array, size, max);}

void

createheap

(int array,

int size)

}void

heapsort

(int array,

int size)

//公升序建大堆

}

必學經典演算法之 堆排序

n個元素的序列,當且僅當滿足以下關係時,稱之為堆。建堆 將n個元素建成堆。排序 輸出堆頂元素後,調整剩餘元素,使之成為大根堆 繼續輸 出堆頂,繼續調整,依此類推。一 篩選 調整堆使之成為大根堆或小根堆 輸出堆頂元素後,將堆底元素送入堆頂,由於根結點不滿足堆的性質,此時堆被破壞,而根結點的左右子樹仍然...

排序之堆排序

堆排序是一種基於比較排序的另一種排序演算法,它採用了一種近似完全二叉樹的二叉堆資料結構。演算法實現相容了插入排序的空間原址性 即只需要有限個額外的儲存空間 和歸併排序的優良時間複雜度。偽 如下 heapsort a build max heap a for i a.length downto 2 e...

排序之堆排序

這裡沒有對0號元素進行排序 堆排 public class heap public static void exec comparable array,int i,int j 下沉 private static void sink comparable array,int k,int n publi...