`
frank-liu
  • 浏览: 1682569 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

动态中间值的查找(dynamic median finding)

 
阅读更多

问题描述

    从一组无序的数组里求它的中间值,要求定义一个数据结构,保证用常量的时间可以找到中间值,而插入一个元素的时间复杂度为O(logn),而删除中间值元素的时间复杂度为O(logn)。这个问题要求里最严格的一点是,以上的这些特性的保持是动态的。比如说,我们要输入的元素可能有1000个,但是在我输入前面的若干个元素的时候,它们也满足以上的特性。

 

分析

    在分析这个问题之前,我们先看看中间值的定义,它无非是一组元素中间的值,使得这个值将一个数组分割成两个部分,一部分是比该元素大,另外一部分是比该元素小。但是这两个部分的元素个数相同。比如下图所示的几种情况:

 

    对于上面这种情况,正好是奇数个,我们这里取的是一种特殊情况,让这个数组里元素本身是排好序了的。所以这里取的是中间的元素3.

    而这种情况就稍微有点不一样,因为它这里元素的个数是偶数个,如果直接划分成两个部分的话,则表示左边有1, 2, 3, 而右边有4, 5, 6。那么取这个中间值,应该怎么来算呢?在左边那边串中间,最接近中间值的是3, 右边最接近的是4, 所以取的是(3 + 4) / 2。得到的值3.5就是期望的中间值。

    前面这里举出的实例更多的是一种特例,因为所有的元素都是排序了的,在大多数情况下,元素并不是排序的,很多像下图那样:

    针对这种情形,如果我们要求它的中间值,需要考虑的重点在哪里呢?既然我们要考虑的是中间值,也就是将整个数组划分成相等两个部分的那个点,可不可以用一种划分的方式来处理呢?比如说我们首先设定一个值,这个值作为临时的中间点。然后将比这个值小的放在一个集合里,然后比这个大的值放在另外一个集合里。因为前面设定的这个中间值是假设的,它可能并不准确,需要进行动态的调整。所以要达到这个条件的话,需要保证比中间值小的集合元素个数和比中间值元素大的集合个数相同。理想的情况下,它们应该是一个如下图的关系:

    所以,至少需要记录两个集合的元素个数,保证它们至少个数是很接近的,最好是相同。但是,仅仅是记录两个集合的个数就够了吗?比如说,假定左边集合已经有如下元素:{1, 5, 7}, 而右边的元素为{9, 12, 17},中间元素为8。这个时候,确实满足中间值就是8。如下图:

   

    如果下一个元素是4呢?那么左边元素集合为{1, 5, 7, 4},中间元素为8, 而右边元素不变。这个时候,实际上中间值应该就在7和8之间。这个时候对应的情况如下:

    如果不调整中间值,而如果后面再增加一个元素比如3呢?这个时候,左边的集合成了{1, 5, 7, 4, 3},中间值是8, 右边的还是没有变化。现在就有问题了。左边的集合元素比右边的集合大2, 必须要动态的去调整中间值节点。所以,必须要将8移到右边的集合里,而从左边的集合里取最大的那个来作为中间值。

    嗯,再重复一下前面的过程,当左边的集合元素个数比右边大2的时候,取左边最大的元素作为中间值。那么右边比左边大2的时候呢?取右边最小的元素作为中间值就可以了。到这一步,我们已经有一点感觉了。我们不但要记录两边集合元素的个数,还要记录左边集合的最大值和右边集合的最小值。

    保持一个集合里最大值或者最小值,可以有好几种办法来实现。一个是通过比较,保存一个比较得到的最大或者最小值,还有一种就是最大或者最小堆。现在,再结合前面问题里的一个要求,就是插入一个元素和删除一个元素的时间复杂度为O(logn)。所以,这里必然要用到最大最小堆无疑。所以,综合起来来说,前面的过程大致是这样:将一个集合开始的时候划分成两个部分。左边部分是一个最大堆,右边部分是一个最小堆。因为左边要获取最大的元素,而右边部分要获取最小的元素。当两边元素相同的时候,取的中间值就是(左边堆顶元素topleft + 右边堆顶元素topright) / 2。

    而如果不相等呢,因为前面有一个调整的手法,当两者相差达到2的时候,将元素多的堆的堆顶元素取出来加入到另外一个堆中间,这样两边的个数就相同了。所以相差为2的时候可以调整为相同。而相差为1的时候,表示某一边多一个元素,这个时候,中间值元素就正好是这个多一个的堆的堆顶元素。

    上面过程的伪码实现如下:

public double getMedian(leftset, rightSet, input) { //其中左边集合为比较小的元素集合,右边集合为大的元素集合
    while((item = input.read()) != null) // 可以读取到元素{
        if(item < leftSet.top) { // 如果小于左边集合
            leftSet.insert(item);
        } else {
            rightSet.insert(item);  //将元素加入到右边集合
        }
        // 判断两边元素个数的差异,进行调整
        if(leftSet.size() - rightSet.size() == 2) {  //如果左边元素集合比右边元素集合大2, 取顶元素加入到右边
              item = leftSet.remove();
             rightSet.insert(item);
        }
        // 同样应用于右边元素比左边元素大2的情况
        if(rightSet.size() - leftSet.size() == 2) {  //如果右边元素集合比左边元素集合大2, 取顶元素加入到左边
              item = rightSet.remove();
              leftSet.insert(item);
        }
    }
    // 在元素取完之后要判断两边集合元素的情况
    if(leftSet.size() == rightSet.size()) {
        return (leftSet.top() + rightSet.top()) / 2;
    } else if(leftSet.size() > rightSet.size()) {
        return leftSet.top();
    } else
        return rightSet.top();
}

    在这里,进一步细化到代码实现的时候,还有一个需要考虑的。就是刚开始的时候,两个集合都没有元素,该怎么来判断呢?这个时候,可以先取两个元素,比较一下两边,比较小的元素放到左边集合,大的元素放到右边集合。然后左边的实现是使用一个最大堆,而右边的实现是使用一个最小堆。按照前面伪码的提示,后面所要做的就是跟踪两边集合的个数,让它们不要超标了,并及时调整。这样整个问题就解决了。

    具体最大堆和最小堆的实现可以参照我前面关于堆方面的文章,这里因为按照提示实现具体的代码已经很容易了,就不再提供详细的实现。

 

总结

    动态的求一组数据的中位数,要点无非就是要找到最接近中间值的那个点。所以需要跟踪两边集合元素的个数和最接近中间值的那几个数。在本问题中,因为要求有其他数据操作的时间复杂度以及需要保存这些数据,所以左边采用了一个最大堆而右边采用了一个最小堆。这样左边堆顶和右边堆顶保存的永远是最接近中间值的元素。这里还有一个限制,就是对于大数据量的情况,因为要将数据保存在两个堆里,方便后面进行调整,所以这种方法就不适用了。

 

参考材料

http://stackoverflow.com/questions/10657503/find-running-median-from-a-stream-of-integers

http://shmilyaw-hotmail-com.iteye.com/blog/1775868

http://shmilyaw-hotmail-com.iteye.com/blog/1827136

  • 大小: 3.3 KB
  • 大小: 3.9 KB
  • 大小: 3.8 KB
  • 大小: 9.5 KB
  • 大小: 7.8 KB
  • 大小: 8.6 KB
  • 大小: 8.8 KB
分享到:
评论

相关推荐

    中间值的平均 - MetaTrader 5脚本.zip

    中间值(Median)是一种统计学概念,它代表数据集中间位置的数值,不受极端值的影响。在金融市场上,中间值可以用来平滑价格数据,减少噪声,从而更好地捕捉市场的核心趋势。与常见的简单移动平均线(SMA)或指数...

    Median-filtering.rar_median filter

    这种方法对于去除椒盐噪声特别有效,因为噪声点(通常是极端的高亮或暗点)在多数像素值中间显得很突兀,会被中值替换掉。同时,中值滤波在保持图像边缘细节方面优于均值滤波,因为边缘处像素值通常有较大变化,中值...

    MedianFlow.rar

    **MedianFlow追踪算法详解** MedianFlow是一种经典的运动目标追踪算法,由Matthias Kaltenbach在2009年提出。这个算法的核心是基于中值流的概念,它结合了光流法和卡尔曼滤波器的优点,适用于处理复杂的背景、光照...

    K-Median_聚类_

    K-Median是K-Means算法的一种变体,主要区别在于它使用中位数而非平均值来代表每个簇的中心,这使得它对异常值更具鲁棒性。 K-Median算法的基本步骤如下: 1. 初始化:选择K个初始聚类中心,通常随机选取数据集中...

    3x3_Median_test.zip_3X3_median vhdl_median3x3_vhdl median

    在3x3的中值滤波器中,对一个3x3的像素窗口(或数据点)进行操作,将窗口内的9个像素值按照大小排序,然后选择中间那个值作为该位置的新值,即中值。这种方法特别有效于消除椒盐噪声和其他类型的 impulse noise。 ...

    ada.rar_Adaptive median_Median Algorithm_median

    标题中的“ada.rar_Adaptive median_Median Algorithm_median”暗示了我们正在探讨一种名为“自适应中值滤波器”的算法,通常用于图像处理领域。在图像处理中,中值滤波器是一种非线性的滤波方法,它通过将图像窗口...

    (Excel)常用函数公式及操作技巧之八:大小值或中间值[借鉴].pdf

    2.3 中间值函数:=MEDIAN(A2:A14) 三、排名函数 3.1 排名函数:=RANK(B4,$B4:$Q4)+COUNTIF($B4:B4,B4) 3.2 标记出 3 个最大最小值:=RANK(B4,$B4:$Q4,2)+COUNTIF(B4:$Q4,B4) 四、TRIMMEAN 函数 4.1 TRIMMEAN ...

    Select-Median.rar_median select_medianselect_select median

    在IT领域,中位数是数据排序后位于中间位置的数值,它在统计学和算法设计中具有重要的意义。在给定的标题“Select-Median.rar_median select_medianselect_select median”和描述“存在拍好序的数组x[n]、y[n].输出...

    Median - MetaTrader 5脚本.zip

    在“Median”脚本中,ATR的值被用来设定一个通道,该通道由计算区间的极值(最高价和最低价)偏移得到。这种通道可以帮助交易者识别趋势的方向,同时提供支撑和阻力水平。通道的上边界代表潜在的阻力,下边界则代表...

    median_polish.zip_median

    总的来说,"median_polish.zip_median"提供了一种强大的工具,用于在存在异常值的情况下进行数据分析。通过Tukey的中位数平滑法,我们可以得到更为可靠的模型拟合结果,这对于理解和解释复杂数据集中的模式至关重要...

    K-Median_聚类r.rar

    与K-Means算法不同,K-Median使用中位数作为质心,而非平均值。由于中位数对异常值不敏感,因此在处理含有噪声或离群点的数据时,K-Median通常比K-Means更稳定。在MATLAB环境中,实现K-Median可以通过迭代优化过程,...

    中值滤波median_filter

    中值滤波median_filtermedian_filtermedian_filtermedian_filtermedian_filter

    Adaptive-Median-Filter-master.zip

    本项目“Adaptive-Median-Filter-master.zip”提供了一个基于Matlab的解决方案,即使用自适应中值滤波器来去除椒盐噪声。 中值滤波器是图像处理中常用的一种非线性滤波方法,它的核心思想是用输入像素周围像素的...

    The gravity p-median model

    首先,“The gravity p-median model”这篇文章提出了一个新的P-中位问题模型,即重力P-中位模型。在标准P-中位问题中,通常假定每个需求点都由最近的设施服务。但在许多实际情况中,例如当需求点是顾客社区,并且每...

    九度1004Median

    ZJU考研机试真题 九度1004Median

    题目1004:Median

    Given an increasing sequence S of N integers, the median is the number at the middle position. For example, the median of S1={11, 12, 13, 14} is 12, and the median of S2={9, 10, 15, 16, 17} is 15. The...

    017_影像平滑(medianBlur、bilateralFilter) _ 阿洲的程式教學1

    中值滤波是一种统计排序的滤波器,对于图像中的某个像素,中值滤波会将滤波范围内的所有像素排序,并用中值替换当前的像素值。在椒鹽噪音这种类型的杂讯,中值滤波能够有效地去除杂讯,且模糊的现象比平均平滑和高斯...

    分治算法思想解决median问题

    当序列长度为偶数时,中位数是中间两个数的平均值。在给定的序列中,寻找第i小数可以转化为寻找序列的中位数,因为第i小数正好位于序列排序后的特定位置。 **算法步骤** 1. **分割序列**:首先,我们需要将输入的...

Global site tag (gtag.js) - Google Analytics