go 堆排序
阿新 • • 發佈:2022-04-21
package main import ( "fmt" ) func main() { heap := BuildHeap([]int{33, 24, 8, 3, 1001, 15, 16, 15, 30, 17, 19}) var sortedArr []int for { v,ok := heap.Pop() if !ok { break } sortedArr = append(sortedArr, v) } fmt.Println(sortedArr) } // 小頂堆(完全二叉樹,最下面一層的節點都集中在該層最左邊的連續位置上;父節點小於子節點;所以可以用陣列存放) // 儲存結構:i 為下標, 左子節點 i*2+1, 右子節點 i*2+2, 父節點 (i-1)/2 type Heap []int // 交換位置 func (h Heap) swap(i, j int) { h[j], h[i] = h[i], h[j] } // 比較節點大小 func (h Heap) less(i, j int) bool { return h[i] < h[j] } // 插入 // 首先插入最末尾節點,自下而上與父節點比較,不斷上升,一直到滿足小頂堆規則 // 兩種情況:1.一直升到堆頂;2.到某一位置時發現父節點比自己小,則停止。 func (h Heap) up(i int) { for { f := (i - 1) / 2 // 停止 if i == f || h.less(f, i) { break } // 上升 h.swap(f, i) i = f } } func (h *Heap) Push(i int) { *h = append(*h, i) h.up(len(*h) - 1) } // 刪除 // 1.將末節點和刪除節點交換,然後刪除末尾節點 // 2.原末端節點需要與新位置上的父節點做比較,如果小於要做 up(看上面的方法), // 如果大於父節點,則再和子節點做比較,即 down 操作,直到該節點下降到小於最小子節點為止。與最小的子節點交換 func (h Heap) down(i int) { for { lson := i*2 + 1 rson := i*2 + 2 if rson >= len(h) { break } if h.less(i, lson) && h.less(i, rson) { break } if h.less(lson, rson) { h.swap(i, lson) i = lson } else { h.swap(i, rson) i = rson } } } func (h *Heap) Remove(i int) (int, bool) { if i < 0 || i > len(*h)-1 { return 0, false } // 交換 tail := len(*h) - 1 h.swap(tail, i) // 刪除最後元素 x := (*h)[tail] *h = (*h)[:tail] // i節點下降或者上升 if i == 0 || (*h)[i] > (*h)[(i-1)/2] { h.down(i) } else { h.up(i) } return x, true } // 彈出頂點 func (h *Heap) Pop() (int, bool) { return h.Remove(0) } // 建堆 // 自底向上調整,不斷的將最小值向上推。倒數第二層開始,從右到左 func BuildHeap(arr []int) Heap { h := Heap(arr) last := len(arr) - 1 // 最後節點的父節點 for i := (last - 1) / 2; i >= 0; i-- { h.down(i) } return h }