前情了解:
例如:
了解了完全二叉樹之後,就可以來看一下什麼是堆?
堆實際上就是乙個完全二叉樹,不同的地方在於:它是有規律的完全二叉樹,也就是說堆一定是完全二叉樹,但完全二叉樹卻不一定是堆。
對於一棵完全二叉樹來說,如果它的任意乙個父節點的值都大於或等於它的兩個子節點,這樣的堆叫做大根堆
,又稱最大堆(大頂堆);
相反如果一棵完全二叉樹,它的任意乙個父節點的值都小於或等於它的兩個子節點,這樣的堆叫做小根堆
,又稱最小堆(小頂堆)。
如下圖示:
了解完以上概念之後,就可以正式進行堆排序了,拿到一組無序的資料後,先把這組資料整理成乙個大根堆或小根堆,至於選擇哪乙個,取決於你的排序是公升序還是降序,一般來說公升序建大根堆,降序建小根堆
主題思路:
堆排序主要分為兩步,以大根堆為例進行講解:
將初始堆也就是乙個完全二叉樹構建成大根堆將堆頂資料與末節點進行交換得到最大的資料
重複上述步驟
注:在整個排序過程中,堆必須始終保證是大根堆,為森麼嘞?具體過程:只有堆始終是大根堆,才能保證每次拿到的資料是最大的,並且在調整的過程中,當前子樹中的最大資料位於根節點,便於下一次拿到最大的資料
拿到一組資料之後:
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...