找到一组给定n个数的中值的方法是将它们分配到2个堆中。 1是包含较低n / 2(ceil(n / 2))数的最大堆和包含其余数的最小堆。如果以这种方式维护,则中位数是第一个堆的最大值(如果n是偶数,则与第二个堆的最小值一起)。这是我的c ++代码:
priority_queue<int, vector<int> > left;
priority_queue<int,vector<int>, greater<int> > right;
cin>>n; //n= number of items
for (int i=0;i<n;i++) {
cin>>a;
if (left.empty())
left.push(a);
else if (left.size()<=right.size()) {
if (a<=right.top())
left.push(a);
else {
left.push(right.top());
right.pop();
right.push(a);
}
}
else {
if (a>=left.top())
right.push(a);
else {
right.push(left.top());
left.pop();
left.push(a);
}
}
}
We know堆化操作有linear complexity。这是否意味着如果我们将数字逐个插入到上面代码中的两个堆中,我们会找到线性时间的中位数?
答案 0 :(得分:5)
线性时间heapify是指从未排序的数组构建堆作为批处理操作的成本,而不是通过一次插入一个值来构建堆。
考虑使用递增顺序插入值流的最小堆。堆顶部的值是最小的,因此每个值一直向下到达堆的底部。只考虑插入的值的后半部分。此时堆将具有非常接近其完整高度,即log(n),因此每个值都会向下插入log(n)个插槽,插入n / 2值的成本为O(n log(n))< / p>
如果我按照递增顺序向您的中值查找算法提供值流,则必须做的事情之一就是按递增顺序从值流构建最小堆,因此中值查找的成本为O(n的log(n))。事实上,最大堆将进行大量的删除和插入,但这只是一个常数因素,所以我认为整体复杂性仍然是O(n log(n))
答案 1 :(得分:1)
当有一个元素时,步骤的复杂性是Log 1,因为单个元素在一个堆中。
当有两个元素时,步骤的复杂性是Log 1,因为每个堆中都有一个元素。
当有四个元素时,步骤的复杂性是Log 2,因为每个堆中有两个元素。
所以,当有n个元素时,复杂性是Log n,因为每个堆中有n / 2个元素,并且
取O(Log n / 2)= O(Log n)时间。
因此,通过执行以下操作来跟踪n个元素的中位数:
2 *(Log 1 + Log 2 + Log 3 + ... + Log n / 2)步骤。
因子2来自于在2个堆中执行相同的步骤。
上述总和可以通过两种方式处理。一种方式给出了更严格的约束,但一般来说遇到的频率较低。在这里:
第二种方式是:
第二个界限更宽松,但更为人所知。
答案 2 :(得分:0)
这是一个很好的问题,特别是因为您可以使用Quickselect在 O(N)时间内找到数字列表的中位数。
但不幸的是,双优先级队列方法为您提供了 O(N log N)。
在这里重复二进制堆wiki article,heapify是一个自下而上的操作。您拥有所有数据,这使您可以狡猾并减少与 O(N)的交换/比较次数。您可以从一开始就构建最佳结构。
从顶部添加元素,一次一个,就像在这里一样,每次都需要重新组织。这很昂贵,所以整个操作最终都是 O(N log N)。