如何实时计算数据流中位数

本文介绍了使用最小堆和最大堆实现的流式中位数计算器,当接收到连续输入数据时,实时更新堆结构以计算并返回当前数据流的中位数。

排序取中位数

最容易想到的思路就是直接将所有数据进行排序,然后取排序之后的中位数

不过具体的排序思路也有几种

  • 插入排序。在新的数据到达时插入有序序列
  • 平衡二叉树。插入平衡二叉树,然后取中位数

最大堆最小堆

创建一个最小堆和最大堆,其中最小堆的最小值比最大堆的最大值还大,并使最小堆最大堆数量保持均衡,那么中位数边取乎于最小最大堆堆顶

// MinHeap is a min-heap implementation.
type MinHeap []int

// Len returns the length of the heap.
func (h MinHeap) Len() int { return len(h) }

// Less compares two elements in the heap.
func (h MinHeap) Less(i, j int) bool { return h[i] < h[j] }

// Swap swaps two elements in the heap.
func (h MinHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }

// Push adds an element to the heap.
func (h *MinHeap) Push(x interface{}) {
	*h = append(*h, x.(int))
}

// Pop removes and returns the smallest element from the heap.
func (h *MinHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

// MaxHeap is a max-heap implementation.
type MaxHeap []int

// Len returns the length of the heap.
func (h MaxHeap) Len() int { return len(h) }

// Less compares two elements in the heap.
func (h MaxHeap) Less(i, j int) bool { return h[i] > h[j] }

// Swap swaps two elements in the heap.
func (h MaxHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }

// Push adds an element to the heap.
func (h *MaxHeap) Push(x interface{}) {
	*h = append(*h, x.(int))
}

// Pop removes and returns the largest element from the heap.
func (h *MaxHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

// StreamingMedianCalculator calculates the median from a continuous stream of input data.
type StreamingMedianCalculator struct {
	minHeap MinHeap
	maxHeap MaxHeap
}

// AddData adds a new data point to the calculator.
func (s *StreamingMedianCalculator) AddData(data int) {
	// 加入到对应堆,以是否大于最小堆顶值为区分
	if len(s.minHeap) == 0 || data >= s.minHeap[0] {
		heap.Push(&s.minHeap, data)
	} else {
		heap.Push(&s.maxHeap, data)
	}

	// 均衡两堆数量
	if len(s.minHeap)-len(s.maxHeap) > 1 {
		heap.Push(&s.maxHeap, heap.Pop(&s.minHeap))
	} else if len(s.maxHeap)-len(s.minHeap) > 1 {
		heap.Push(&s.minHeap, heap.Pop(&s.maxHeap))
	}
}

// GetMedian returns the current median.
func (s *StreamingMedianCalculator) GetMedian() float64 {
	if len(s.minHeap) == len(s.maxHeap) {
		return float64(s.minHeap[0]+s.maxHeap[0]) / 2
	} else if len(s.minHeap) > len(s.maxHeap) {
		return float64(s.minHeap[0])
	} else {
		return float64(s.maxHeap[0])
	}
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值