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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容

  • 聊一聊,普洱茶中的 “另类” “老茶头” 【老茶头】也叫【自然沱】,【疙瘩沱】。是...
    花瓣我心阅读 369评论 0 0
  • 我忘记了我的父亲是不是在我这个年纪依然像我一样不喜欢回家和回电话。 年少时候的父亲是邻居眼中的“髭毛猴”,野性十足...
    桑葚下了阅读 294评论 0 3
  • 信息来源:新华网 种种误读或歪读,让那些本可引领审美与思想向更高层次迈进的经典作品,无奈陷入狭隘、嘈杂的尘嚣。一部...
    青蛙和鱼摆摆阅读 370评论 0 0
  • 今天在电视剧中看到一个这样的剧情:一位刚毕业走出校门的小伙A,找到了一份房产销售工作。工作几个月后一直没有任何业务...
    那个我js阅读 90评论 0 1