2019-01-20

最小堆和最大堆 golang實現(xiàn)

二叉堆是一種特殊的堆圾浅,它滿足兩個性質:結構性和堆序性

  • 結構性:二叉堆是一顆完全二叉樹崇决,完全二叉樹可以用一個數(shù)組表示捧韵,不需要指針互亮,所以效率更高。當用數(shù)組表示時坪蚁,數(shù)組中任一位置i上的元素奔穿,其左兒子在位置2i上,右兒子在位置(2i+ 1)上敏晤,其父節(jié)點在位置(i/2)上贱田。
  • 堆序性質:堆的最小值或最大值在根節(jié)點上,所以可以快速找到最大值或最小值嘴脾。

最大堆和最小堆是二叉堆的兩種形式男摧。
-最大堆:根結點的鍵值是所有堆結點鍵值中最大者的堆。
-最小堆:根結點的鍵值是所有堆結點鍵值中最小者的堆译打。

1. 最小堆實現(xiàn)耗拓,不使用container/heap

type MinHeap struct {
    Element []int
}

定義構造方法

數(shù)組中第一個元素不使用,存放一個小于堆中任何數(shù)字的值用于結束循環(huán)奏司。

// MinHeap構造方法
func NewMinHeap() *MinHeap {
    // 第一個元素僅用于結束insert中的 for 循環(huán)
    h := &MinHeap{Element: []int{math.MinInt64}}
    return h
}

插入

插入元素就直接將元素增加到堆的末尾乔询,然后進行上浮操作,使二叉堆有序结澄。
如果上浮一直到根哥谷,時間復雜度為O(log N),但這種上浮操作一般結束的要早麻献。

// 插入數(shù)字,插入數(shù)字需要保證堆的性質
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包 和最大堆的實現(xiàn)

heap源碼中定義了一個Interface 的接口勉吻,此接口一共包含五個方法监婶,我們定義一個實現(xiàn)此接口的類就實現(xiàn)了一個二叉堆

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)
}

定義一個最大堆,并實現(xiàn)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
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末惑惶,一起剝皮案震驚了整個濱河市煮盼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌带污,老刑警劉巖僵控,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鱼冀,居然都是意外死亡报破,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門千绪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來充易,“玉大人,你說我怎么就攤上這事荸型№镅ィ” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵瑞妇,是天一觀的道長稿静。 經常有香客問我,道長辕狰,這世上最難降的妖魔是什么自赔? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮柳琢,結果婚禮上,老公的妹妹穿的比我還像新娘润脸。我一直安慰自己柬脸,他們只是感情好,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布毙驯。 她就那樣靜靜地躺著倒堕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪爆价。 梳的紋絲不亂的頭發(fā)上垦巴,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天,我揣著相機與錄音铭段,去河邊找鬼骤宣。 笑死,一個胖子當著我的面吹牛序愚,可吹牛的內容都是我干的憔披。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼芬膝!你這毒婦竟也來了望门?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤锰霜,失蹤者是張志新(化名)和其女友劉穎筹误,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體癣缅,經...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡厨剪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了所灸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丽惶。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖爬立,靈堂內的尸體忽然破棺而出钾唬,到底是詐尸還是另有隱情,我是刑警寧澤侠驯,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布抡秆,位于F島的核電站,受9級特大地震影響吟策,放射性物質發(fā)生泄漏儒士。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一檩坚、第九天 我趴在偏房一處隱蔽的房頂上張望着撩。 院中可真熱鬧,春花似錦匾委、人聲如沸拖叙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽薯鳍。三九已至,卻和暖如春挨措,著一層夾襖步出監(jiān)牢的瞬間挖滤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工浅役, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留斩松,地道東北人。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓觉既,卻偏偏與公主長得像砸民,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內容

  • 聊一聊岭参,普洱茶中的 “另類” “老茶頭” 【老茶頭】也叫【自然沱】反惕,【疙瘩沱】。是...
    花瓣我心閱讀 369評論 0 0
  • 我忘記了我的父親是不是在我這個年紀依然像我一樣不喜歡回家和回電話。 年少時候的父親是鄰居眼中的“髭毛猴”秒际,野性十足...
    桑葚下了閱讀 296評論 0 3
  • 信息來源:新華網(wǎng) 種種誤讀或歪讀娄徊,讓那些本可引領審美與思想向更高層次邁進的經典作品闽颇,無奈陷入狹隘、嘈雜的塵囂寄锐。一部...
    青蛙和魚擺擺閱讀 373評論 0 0
  • 今天在電視劇中看到一個這樣的劇情:一位剛畢業(yè)走出校門的小伙A兵多,找到了一份房產銷售工作。工作幾個月后一直沒有任何業(yè)務...
    那個我js閱讀 90評論 0 1