堆排序
堆排序(Heapsort
)是指利用堆這種數據結構所設計的一種排序算法。堆積是一個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。堆排序可以說是一種利用堆的概念來排序的選擇排序。分爲兩種方法:
大頂堆:每個節點的值都大於或等於其子節點的值,在堆排序算法中用於升序排列;
小頂堆:每個節點的值都小於或等於其子節點的值,在堆排序算法中用於降序排列;
堆排序的平均時間複雜度爲 Ο(nlogn)
。
算法步驟
- 自底向上構建大(小)頂堆
- 把堆首(最大值)和堆尾互換
- 把堆的尺寸縮小
1
,堆化(自頂向下) - 重複步驟
2、3
,直到堆的尺寸爲1
。
- 父節點與子節點關係:
parent := (i - 1) / 2
- 左節點與父節點關係:
left := 2*i + 1
- 右節點與父節點關係:
right := 2*i + 2
動圖演示
go實現大頂堆排序
注意點
- 堆化:注意變量 左、右、最大值下標
- 建堆:利用堆化,從數組長度一半開始循環堆化
- 堆排序:首尾交換,縮減長度再堆化
//堆化,自頂向下
func heapify(arr []int, n int) {
//左右子節點
l := 2 * n + 1
r := 2 * n + 2
//最大值的下標
max := n
//與左右節點比較,max爲最大值的下標
if l < len(arr) && arr[max] < arr[l] {
max = l
}
if r < len(arr) && arr[max] < arr[r] {
max = r
}
if max != n {
//最大值放到父點上
arr[max], arr[n] = arr[n], arr[max]
//自頂向下繼續堆化
heapify(arr, max)
}
}
//構建大頂堆,自底向上
func BuildMaxHeap(arr []int) {
for i := (len(arr) - 1)/2 ; i >= 0; i-- {
heapify(arr, i)
}
}
//堆排序
func HeapSort(arr []int) {
arrLen := len(arr)
BuildMaxHeap(arr)
//首尾交換,縮減長度再堆化
for i := len(arr) - 1; i>0 ; i-- {
arr[0], arr[i] = arr[i], arr[0]
arrLen -= 1
heapify(arr[:arrLen], 0)
}
}
go實現小頂堆排序
//堆化,自頂向下
func heapify(arr []int, i int) {
arrLen := len(arr)
//左右子節點
left := 2*i + 1
right := 2*i + 2
//最小值的下標
min := i
//與左右節點比較,min爲最大值的下標
if left < arrLen && arr[left] < arr[min] {
min = left
}
if right < arrLen && arr[right] < arr[min] {
min = right
}
if min != i {
//最小值放到父點上
arr[i], arr[min] = arr[min], arr[i]
//自頂向下繼續堆化
heapify(arr, max)
}
}
//構建大頂堆,自底向上
func buildMaxHeap(arr []int) {
arrLen := len(arr)
for i := (arrLen - 1) / 2; i >= 0; i-- {
heapify(arr, i)
}
}
//堆排序
func heapSort(arr []int) {
arrLen := len(arr)
buildMaxHeap(arr)
//首尾交換
for i := arrLen - 1; i > 0; i-- {
arr[0], arr[i] = arr[i], arr[0]
arrLen -= 1
heapify(arr[:arrLen], 0)
}
}