在动态增长范围内找到中位数的最快方法

时间:2013-03-26 16:50:21

标签: c++ performance median

有人可以建议任何方法或链接到c ++动态范围的快速中位数发现的实现吗?例如,假设对于我的程序中的迭代,范围增大,我想在每次运行时找到中位数。

Range
4
3,4
8,3,4
2,8,3,4
7,2,8,3,4

所以上面的代码最终会为每一行产生5个中值。

3 个答案:

答案 0 :(得分:3)

在没有跟踪数组的排序副本的情况下,您可以获得的最佳效果是重新使用旧的中值并使用线性时间搜索下一个最大值来更新它。这可能听起来很简单,但是,我们必须解决一个问题。

考虑以下列表(为了便于理解而排序,但是您将它们保持在任意顺序):

    1, 2, 3, 3, 3, 4, 5
//           *

所以在这里,中位数是3(自列表排序以来的中间元素)。现在,如果你添加一个大于中位数的数字,这可能会使中位数向右移动一半指数。我看到两个问题:我们怎样才能推进一半指数? (根据定义,中位数是接下来两个值的平均值。)当我们只知道中位数为3时,我们如何知道中位数3

这可以通过不仅存储当前中位数而且还存储相同值的数字中位数的位置来解决,此处它具有“索引偏移” 1的{​​{1}},因为它是第二个3。将大于或等于3的数字添加到列表会将索引偏移更改为1.5。添加小于3的数字会将其更改为0.5

当此数字小于零时,中位数会发生变化。如果它超过相等数量的数量(减去1),它也必须改变,在这种情况下2,意味着新的中位数大于最后的相等数字。在这两种情况下,您都必须搜索下一个较小/下一个较大的数字并更新中值。要始终知道索引偏移的上限是什么(在这种情况下为2),您还必须跟踪相等数字的计数。

这应该让您大致了解如何在线性时间内实现中值更新。

答案 1 :(得分:0)

我认为您可以使用min-max-median堆。每次更新数组时,您只需要log(n)时间即可找到新的中值。对于min-max-median堆,根是中间值,左侧的树是min-max堆,而右侧是max-min堆。有关详细信息,请参阅论文“最小-最大堆和通用优先级队列”。

答案 2 :(得分:-1)

在下面填写一些代码,我已经重新设计了这个stack以提供必要的输出

    private void button1_Click(object sender, EventArgs e)
    {
        string range = "7,2,8,3,4";
        decimal median = FindMedian(range);
        MessageBox.Show(median.ToString());

    }

    public decimal FindMedian(string source)
    {
        // Create a copy of the input, and sort the copy

        int[] temp = source.Split(',').Select(m=> Convert.ToInt32(m)).ToArray();
        Array.Sort(temp);

        int count = temp.Length;
        if (count == 0) {
            throw new InvalidOperationException("Empty collection");
        }
        else if (count % 2 == 0) {
            // count is even, average two middle elements
            int a = temp[count / 2 - 1];
            int b = temp[count / 2];
            return (a + b) / 2m;
        }
        else {
            // count is odd, return the middle element
            return temp[count / 2];
        }
    }