structure/heap/heap.go

155 lines
2.3 KiB
Go
Raw Normal View History

2019-04-11 13:34:50 +00:00
package heap
import (
"474420502.top/eson/structure/compare"
)
type Heap struct {
size int
2019-04-15 23:09:32 +00:00
elements []interface{}
2019-04-11 13:34:50 +00:00
Compare compare.Compare
}
func New(Compare compare.Compare) *Heap {
2019-04-15 14:57:44 +00:00
h := &Heap{Compare: Compare}
2019-04-15 23:09:32 +00:00
h.elements = make([]interface{}, 16, 16)
return h
2019-04-11 13:34:50 +00:00
}
2019-04-15 14:57:44 +00:00
2019-04-15 23:09:32 +00:00
func (h *Heap) Size() int {
return h.size
}
2019-04-15 14:57:44 +00:00
func (h *Heap) Values() []interface{} {
2019-04-15 23:09:32 +00:00
return h.elements[0:h.size]
2019-04-15 14:57:44 +00:00
}
2019-04-15 23:09:32 +00:00
func (h *Heap) grow() {
ecap := len(h.elements)
if h.size >= ecap {
ecap = ecap << 1
grow := make([]interface{}, ecap, ecap)
copy(grow, h.elements)
h.elements = grow
}
}
func (h *Heap) Empty() bool {
return h.size < 1
}
func (h *Heap) Clear() {
h.size = 0
}
func (h *Heap) Reborn() {
h.size = 0
h.elements = make([]interface{}, 16, 16)
}
2019-04-15 14:57:44 +00:00
2019-04-15 23:09:32 +00:00
func (h *Heap) Top() (interface{}, bool) {
if h.size != 0 {
return h.elements[0], true
2019-04-15 14:57:44 +00:00
}
2019-04-15 23:09:32 +00:00
return nil, false
}
2019-04-15 14:57:44 +00:00
2019-04-15 23:09:32 +00:00
func (h *Heap) Push(v interface{}) {
if v == nil {
return
}
2019-04-15 14:57:44 +00:00
2019-04-15 23:09:32 +00:00
h.grow()
2019-04-15 14:57:44 +00:00
2019-04-15 23:09:32 +00:00
curidx := h.size
h.size++
2019-04-15 14:57:44 +00:00
// up
for curidx != 0 {
2019-04-15 23:09:32 +00:00
pidx := (curidx - 1) >> 1
pvalue := h.elements[pidx]
2019-04-15 14:57:44 +00:00
if h.Compare(v, pvalue) > 0 {
2019-04-15 23:09:32 +00:00
h.elements[curidx] = pvalue
2019-04-15 14:57:44 +00:00
curidx = pidx
} else {
break
}
}
2019-04-15 23:09:32 +00:00
h.elements[curidx] = v
}
func (h *Heap) slimming() {
elen := len(h.elements)
if elen >= 32 {
ecap := elen >> 1
if h.size <= ecap {
ecap = elen - (ecap >> 1)
slimming := make([]interface{}, ecap, ecap)
copy(slimming, h.elements)
h.elements = slimming
}
}
2019-04-15 14:57:44 +00:00
}
func (h *Heap) Pop() (interface{}, bool) {
if h.size == 0 {
return nil, false
}
2019-04-15 23:09:32 +00:00
curidx := 0
top := h.elements[curidx]
2019-04-15 14:57:44 +00:00
h.size--
2019-04-15 23:09:32 +00:00
h.slimming()
2019-04-15 14:57:44 +00:00
if h.size == 0 {
2019-04-15 23:09:32 +00:00
return top, true
2019-04-15 14:57:44 +00:00
}
2019-04-15 23:09:32 +00:00
downvalue := h.elements[h.size]
var cidx, c1, c2 int
var cvalue1, cvalue2, cvalue interface{}
// down
for {
cidx = curidx << 1
2019-04-15 14:57:44 +00:00
2019-04-15 23:09:32 +00:00
c2 = cidx + 2
if c2 < h.size {
cvalue2 = h.elements[c2]
2019-04-15 14:57:44 +00:00
2019-04-15 23:09:32 +00:00
c1 = cidx + 1
cvalue1 = h.elements[c1]
if h.Compare(cvalue1, cvalue2) >= 0 {
cidx = c1
cvalue = cvalue1
2019-04-15 14:57:44 +00:00
} else {
2019-04-15 23:09:32 +00:00
cidx = c2
cvalue = cvalue2
2019-04-15 14:57:44 +00:00
}
} else {
2019-04-15 23:09:32 +00:00
c1 = cidx + 1
if c1 < h.size {
cvalue1 = h.elements[c1]
cidx = c1
cvalue = cvalue1
2019-04-15 14:57:44 +00:00
} else {
break
}
2019-04-15 23:09:32 +00:00
2019-04-15 14:57:44 +00:00
}
2019-04-15 23:09:32 +00:00
if h.Compare(cvalue, downvalue) > 0 {
h.elements[curidx] = cvalue
curidx = cidx
2019-04-15 14:57:44 +00:00
} else {
break
}
}
2019-04-15 23:09:32 +00:00
h.elements[curidx] = downvalue
return top, true
2019-04-15 14:57:44 +00:00
}