在O中找到中位数(log n)

时间:2011-10-20 21:15:24

标签: algorithm data-structures

问题是如何在 O(log N)中找到整数值的接收流的中位数(例如12,14,252,243,15,中位数为15) N是值的数量。请注意,我们有一个整数值流,因此通过接收每个值,我们必须重新找到中位数。

示例:

  | Input | median
1 |   12  |   12
2 |   14  |   13 = (12+14)/2
3 |   252 |   14
.
.
.

P.S:使用此算法的一个示例可能是过滤图像。

3 个答案:

答案 0 :(得分:14)

好的,随着问题的更新,意图明确(不只是找到中位数,而是每次收到新号码时重新找到中位数),我认为有一种方法。

我从一堆堆开始:最大堆和最小堆。 min-heap将包含大于中位数的数字,max-heap包含小于中位数的数字。当你收到第一个号码时,那就是你的中位数。当您收到第二个时,将两个中较小的一个插入max-heap,将两个中较大的一个插入最小堆。中位数是最小堆上最小的平均值,最大堆上最大的平均值。

除了两个堆之外,您还需要存储一个整数,当您收到奇数个输入时,该整数将成为当前的中位数。您将相当简单地填充:如果您收到一个当前已满的输入,您基本上对这两个项目(新数字和旧中位数)进行排序,并将较小的项目插入堆中,并将更大的项目插入堆中对于较大的项目。您的新中位数将是这两个堆的基数的平均值(并且您将其他存储位置标记为空)。

当您收到一个空的新号码时,您会将新号码与中位数进行比较。如果它在数字之间作为堆的基础,它就是新的中位数,你已经完成了。否则,从必须保持中位数的基数中提取数字(如果新数字较大则提取较大数字,如果较小则提取较小数字)并将其放入中位数,然后将新数字插入来自的堆中。

至少如果内存服务,提取/插入堆应该是O(log N)。我相信所涉及的一切都应该是不变的复杂性。

答案 1 :(得分:4)

(我假设您正在使用一个算法,给定 n 现有数字和一个新数字,将采用对数时间来查找 n + 1的新集合的中位数数字,以便添加 n 数字的总运行时间为 O(n lg n)。)

这可能已经有了一个命名算法,但这是我的想法:维护一个红黑树,在数字到达时插入数字。在每个节点中,除了数字本身和子/父指针之外,还存储一个整数,该整数表示该节点下面存在的节点数(为方便起见,包括节点本身)。我非常确定这个信息可以在每次插入操作的对数时间内更新,即使需要树旋转也是如此。将此信息嵌入树中,如果您还跟踪树中的节点数,则可以在对数时间内查找中值。

(这可能是一个略高级别的描述;如果您需要更多详细信息,请与我们联系。)

答案 2 :(得分:2)

Hoare's selection algorithm(又名quickselect)可以在O(n)平均时间内完成此操作。

它基本上是递归地使用随机数据集对数据集进行分区,并检查相应的部分。 还有一个median of medians algorithm保证了O(n)最差的时间复杂度,但对于正常使用它通常是一种过度杀伤。