package main
import (
"math"
)
// 大根堆小根堆
// 最终取中间的两个元素作为中位数或者取中间一个
// 左边取最大的,因此使用排序后是递增序列的大根堆
// 右边取最小的,因此使用排序后是递减序列的小根堆
// 需要保证所有右侧元素都比左侧堆元素大
// 为了保证两侧元素均匀分布,我们可以设置,如果当前堆总长度为奇数时插入左侧大根堆,否则插入右侧
// 如果插入某个元素时,它原本应该分配到右边,但是它的值却没有左侧大根堆堆顶元素大怎么办?
// 先将左侧堆顶元素移除压入右侧小根堆,然后将新元素压入大根堆
// 同理,将右侧小根堆堆顶元素移除,插入到左侧,然后将新元素插入到右侧
// 首先,我们需要先实现了大根堆和小根堆(有序队列形式的(支持 Push 和 Pop 操作))
type smallHeap struct {
Size int
Array []int
}
func (sh *smallHeap) Push(x int) {
sh.Array = append(sh.Array, x)
// 插入索引
index := sh.Size
sh.Size++
// 向上调整
for index >= 0 {
root := (index-1)/2
if sh.Array[root] > sh.Array[index] {
sh.Array[root], sh.Array[index] = sh.Array[index], sh.Array[root]
index = root
} else {
break
}
}
}
func (sh *smallHeap) Pop() int {
if sh.Size == 0 {
return math.MinInt
}
// 弹出堆顶元素
x := sh.Array[0]
// 首尾交换
sh.Array[0], sh.Array[sh.Size-1] = sh.Array[sh.Size-1], sh.Array[0]
// 弹出
sh.Array = sh.Array[:sh.Size-1]
sh.Size--
// 向下调整
root := 0
for root < sh.Size {
left, right := 2*root+1, 2*root+2
if left >= sh.Size {
break
}
if right < sh.Size && sh.Array[right] < sh.Array[left] {
left = right
}
if sh.Array[left] > sh.Array[root] {
break
}
sh.Array[root], sh.Array[left] = sh.Array[left], sh.Array[root]
root = left
}
return x
}
func (sh *smallHeap) Top() int {
if sh.Size == 0 {
return math.MinInt
}
return sh.Array[0]
}
type bigHeap struct {
Size int
Array []int
}
func (bh *bigHeap) Push(x int) {
bh.Array = append(bh.Array, x)
// 插入索引
index := bh.Size
bh.Size++
// 向上调整
for index >= 0 {
root := (index-1)/2
if bh.Array[root] < bh.Array[index] {
bh.Array[root], bh.Array[index] = bh.Array[index], bh.Array[root]
index = root
} else {
break
}
}
}
func (bh *bigHeap) Pop() int {
if bh.Size == 0 {
return math.MinInt
}
// 弹出堆顶元素
x := bh.Array[0]
// 首尾交换
bh.Array[0], bh.Array[bh.Size-1] = bh.Array[bh.Size-1], bh.Array[0]
// 弹出
bh.Array = bh.Array[:bh.Size-1]
bh.Size--
// 向下调整
root := 0
for root < bh.Size {
left, right := 2*root+1, 2*root+2
if left >= bh.Size {
break
}
if right < bh.Size && bh.Array[right] > bh.Array[left] {
left = right
}
if bh.Array[left] < bh.Array[root] {
break
}
bh.Array[root], bh.Array[left] = bh.Array[left], bh.Array[root]
root = left
}
return x
}
func (bh *bigHeap) Top() int {
if bh.Size == 0 {
return math.MinInt
}
return bh.Array[0]
}
var small smallHeap
var big bigHeap
// 左大右小
func Insert(num int){
size := small.Size + big.Size
if size % 2 == 0 {
if small.Size > 0 && num > small.Top() {
big.Push(small.Pop())
small.Push(num)
} else {
big.Push(num)
}
} else {
if big.Size > 0 && num < big.Top() {
small.Push(big.Pop())
big.Push(num)
} else {
small.Push(num)
}
}
}
func GetMedian() float64{
size := small.Size + big.Size
if size % 2 == 1 {
return float64(big.Top())
} else {
return float64(small.Top()+big.Top())/2
}
}
