[295]数据流的中位数

文章介绍了如何使用双堆(最小堆和最大堆)数据结构设计MedianFinder类,实现在数据流中动态查找和更新中位数的功能,确保精度在10-5范围内。
摘要由CSDN通过智能技术生成

中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。

例如 arr = [2,3,4] 的中位数是 3 。
例如 arr = [2,3] 的中位数是 (2 + 3) / 2 = 2.5 。
实现 MedianFinder 类:

MedianFinder() 初始化 MedianFinder 对象。

void addNum(int num) 将数据流中的整数 num 添加到数据结构中。

double findMedian() 返回到目前为止所有元素的中位数。与实际答案相差 10-5 以内的答案将被接受。

import "container/heap"

// 双堆法,大小根堆分别存储中位数的左边和右边
type MedianFinder struct {
	minHeap *MinHeap
	maxHeap *MaxHeap
}
type MinHeap []int
type MaxHeap []int

func (this MinHeap) Less(i, j int) bool {
	return this[i] < this[j]
}
func (this MinHeap) Swap(i, j int) {
	this[i], this[j] = this[j], this[i]
}
func (this MinHeap) Len() int {
	return len(this)
}
func (this *MinHeap) Push(item interface{}) {
	*this = append(*this, item.(int))
}
func (this *MinHeap) Pop() interface{} {
	if len(*this) == 0 {
		return nil
	}
	old := *this
	length := len(old)
	item := old[length-1]
	*this = old[:length-1]
	return item
}
func (this MinHeap) Peek() int {
	return this[0]
}

// 之所以取<,是因为后面存入大根堆时取了反,因此堆顶的值取反后便是该堆得最大值
func (this MaxHeap) Less(i, j int) bool {
	return this[i] < this[j]
}
func (this MaxHeap) Swap(i, j int) {
	this[i], this[j] = this[j], this[i]
}
func (this MaxHeap) Len() int {
	return len(this)
}
func (this *MaxHeap) Push(item interface{}) {
	*this = append(*this, item.(int))
}
func (this *MaxHeap) Pop() interface{} {
	if len(*this) == 0 {
		return nil
	}
	old := *this
	length := len(old)
	item := old[length-1]
	*this = old[:length-1]
	return item
}
func (this MaxHeap) Peek() int {
	return this[0]
}

func Constructor() MedianFinder {
	minHeap := &MinHeap{}
	maxHeap := &MaxHeap{}
	heap.Init(minHeap)
	heap.Init(maxHeap)
	return MedianFinder{minHeap, maxHeap}
}

func (this *MedianFinder) AddNum(num int) {
	if this.minHeap.Len() == 0 || num >= this.minHeap.Peek() {
		heap.Push(this.minHeap, num)
	} else {
		heap.Push(this.maxHeap, -num)
	}

	if this.minHeap.Len() > this.maxHeap.Len()+1 {
		heap.Push(this.maxHeap, -heap.Pop(this.minHeap).(int))
	} else if this.minHeap.Len()+1 < this.maxHeap.Len() {
		heap.Push(this.minHeap, -heap.Pop(this.maxHeap).(int))
	}

}
func (this *MedianFinder) FindMedian() float64 {
	if this.minHeap.Len() == this.maxHeap.Len() {
		return float64(this.minHeap.Peek()+(-this.maxHeap.Peek())) / 2.0
	} else if this.minHeap.Len() > this.maxHeap.Len() {
		return float64(this.minHeap.Peek())
	}
	return float64(-this.maxHeap.Peek())
}
要找出数据流中位数,可以使用两个优先队列(堆)来实现。一个小顶堆存储较大的一半数据,一个大顶堆存储较小的一半数据。 具体步骤如下: 1. 初始化两个堆,一个小顶堆 `minHeap` 和一个大顶堆 `maxHeap`。 2. 遍历数据流中的每个元素: - 如果 `minHeap` 和 `maxHeap` 的大小相等,将元素插入到 `maxHeap` 中。 - 如果 `minHeap` 的大小大于 `maxHeap`,将元素插入到 `minHeap` 中。 - 如果插入元素后,`minHeap` 的堆顶元素大于 `maxHeap` 的堆顶元素,则交换两个堆顶元素。 3. 如果两个堆的大小之和是偶数,中位数就是两个堆顶元素的平均值;如果是奇数,中位数就是 `minHeap` 的堆顶元素。 下面是使用 C++ 实现的代码示例: ```cpp #include <iostream> #include <queue> #include <vector> class MedianFinder { public: void addNum(int num) { if (minHeap.empty() || num > minHeap.top()) { minHeap.push(num); } else { maxHeap.push(num); } if (minHeap.size() > maxHeap.size() + 1) { maxHeap.push(minHeap.top()); minHeap.pop(); } else if (maxHeap.size() > minHeap.size()) { minHeap.push(maxHeap.top()); maxHeap.pop(); } } double findMedian() { if (minHeap.size() == maxHeap.size()) { return (minHeap.top() + maxHeap.top()) / 2.0; } else { return minHeap.top(); } } private: std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap; std::priority_queue<int, std::vector<int>, std::less<int>> maxHeap; }; int main() { MedianFinder finder; finder.addNum(1); finder.addNum(2); std::cout << finder.findMedian() << std::endl; // 输出 1.5 finder.addNum(3); std::cout << finder.findMedian() << std::endl; // 输出 2 return 0; } ``` 这段代码创建了一个 `MedianFinder` 类,通过 `addNum` 方法添加数据,然后通过 `findMedian` 方法获取中位数。在示例中,数据流为 1、2、3,所以中位数依次为 1.5 和 2。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值