2019-01-20
最小堆和最大堆 golang實現
二叉堆是一種特殊的堆,它滿足兩個性質:結構性和堆序性
- 結構性:二叉堆是一顆完全二叉樹,完全二叉樹可以用一個數組表示,不需要指標,所以效率更高。當用陣列表示時,陣列中任一位置i上的元素,其左兒子在位置2i上,右兒子在位置(2i+ 1)上,其父節點在位置(i/2)上。
- 堆序性質:堆的最小值或最大值在根節點上,所以可以快速找到最大值或最小值。
最大堆和最小堆是二叉堆的兩種形式。
-最大堆:根結點的鍵值是所有堆結點鍵值中最大者的堆。
-最小堆:根結點的鍵值是所有堆結點鍵值中最小者的堆。
1. 最小堆實現,不使用container/heap
type MinHeap struct { Element []int }
定義構造方法
陣列中第一個元素不使用,存放一個小於堆中任何數字的值用於結束迴圈。
// MinHeap構造方法 func NewMinHeap() *MinHeap { // 第一個元素僅用於結束insert中的 for 迴圈 h := &MinHeap{Element: []int{math.MinInt64}} return h }
插入
插入元素就直接將元素增加到堆的末尾,然後進行上浮操作,使二叉堆有序。
如果上浮一直到根,時間複雜度為O(log N),但這種上浮操作一般結束的要早。
// 插入數字,插入數字需要保證堆的性質 func (H *MinHeap) Insert(v int) { H.Element = append(H.Element, v) i := len(H.Element) - 1 // 上浮 for ; H.Element[i/2] > v; i /= 2 { H.Element[i] = H.Element[i/2] } H.Element[i] = v }
刪除最小值
刪除最大元素就直接從二叉堆頂端刪除,然後進行下沉操作。最壞時間複雜度同樣為O(log N)
// 刪除並返回最小值 func (H *MinHeap) DeleteMin() (int, error) { if len(H.Element) <= 1 { return 0, fmt.Errorf("MinHeap is empty") } minElement := H.Element[1] lastElement := H.Element[len(H.Element)-1] var i, child int for i = 1; i*2 < len(H.Element); i = child { child = i * 2 if child < len(H.Element)-1 && H.Element[child+1] < H.Element[child] { child ++ } // 下濾一層 if lastElement > H.Element[child] { H.Element[i] = H.Element[child] } else { break } } H.Element[i] = lastElement H.Element = H.Element[:len(H.Element)-1] return minElement, nil }
其他方法
// 堆的大小 func (H *MinHeap) Length() int { return len(H.Element) - 1 } // 獲取最小堆的最小值 func (H *MinHeap) Min() (int, error) { if len(H.Element) > 1 { return H.Element[1], nil } return 0, fmt.Errorf("heap is empty") } // MinHeap格式化輸出 func (H *MinHeap) String() string { return fmt.Sprintf("%v", H.Element[1:]) }
2.下面介紹container/heap包 和最大堆的實現
heap原始碼中定義了一個Interface 的介面,此介面一共包含五個方法,我們定義一個實現此介面的類就實現了一個二叉堆
container/heap/heap.go
type Interface interface { sort.Interface Push(x interface{}) // add x as element Len() Pop() interface{}// remove and return element Len() - 1. }
sort.go
type Interface interface { // Len is the number of elements in the collection. Len() int // Less reports whether the element with // index i should sort before the element with index j. Less(i, j int) bool // Swap swaps the elements with indexes i and j. Swap(i, j int) }
定義一個最大堆,並實現heap.Interface 介面
type MaxHeap []int func (h MaxHeap) Len() int { return len(h) } func (h MaxHeap) Less(i, j int) bool { // 由於是最大堆,所以使用大於號 return h[i] > h[j] } func (h *MaxHeap) Swap(i, j int) { (*h)[i], (*h)[j] = (*h)[j], (*h)[i] } func (h *MaxHeap) Push(x interface{}) { *h = append(*h, x.(int)) } // Pop 彈出最後一個元素 func (h *MaxHeap) Pop() interface{}{ res := (*h)[len(*h)-1] *h = (*h)[:len(*h)-1] return res }
測試最大堆
func main() { h := make(MaxHeap, 0) heap.Init(&h) heap.Push(&h, 8) heap.Push(&h, 1) heap.Push(&h, 4) heap.Push(&h, 5) heap.Push(&h, 2) fmt.Println(heap.Pop(&h)) fmt.Println(heap.Pop(&h)) fmt.Println(heap.Pop(&h)) fmt.Println(heap.Pop(&h)) fmt.Println(heap.Pop(&h)) } >>> 8 5 4 2 1