我需要计算运行中位数:
输入: ,,向量。k (x 1,x 2,… ,x n)
输出:向量,其中是的中位数。ÿ 我(X 我,X 我+ 1,... ,X 我+ ķ - 1)
(不作弊;我希望有确切的解决方案。元素是大整数。)
有一个简单的算法可以维护大小为的搜索树;总运行时间为。(这里的“搜索树”是指一些有效的数据结构,支持对数时间内的插入,删除和中位数查询。)O (n log k )
但是,这对我来说似乎有点愚蠢。我们将有效地学习所有大小为窗口内的所有订单统计信息,而不仅仅是中位数。此外,这在实践中不太吸引人,特别是如果大(大型搜索树趋于缓慢,内存消耗的开销不平凡,缓存效率通常较差等)。ķ
我们可以做得更好吗?
是否存在下界(例如,对于比较模型而言,平凡的算法是否渐近最优)?
编辑: David Eppstein为比较模型提供了一个很好的下界!我想知道是否有可能做一些比平凡算法更聪明的事情?
例如,我们可以沿着这些路线做些什么:将输入向量除以大小为部分;对每个部分进行排序(跟踪每个元素的原始位置);然后使用分段排序的向量在没有任何辅助数据结构的情况下有效地找到运行中值?当然,它仍然是,但是在实践中,对数组进行排序往往比维护搜索树要快得多。O (n log k )
编辑2: Saeed想了解为什么我认为排序比搜索树操作更快的一些原因。这是非常快速的基准,对于,:
- ≈8s:对每个包含元素的向量进行排序
- ≈10秒:对带有元素的向量进行排序
- ≈80s:大小为的哈希表中的插入和删除ķ
- ≈390s:大小为的平衡搜索树中的插入和删除ķ
哈希表仅用于比较;在此应用程序中没有直接使用。
总而言之,我们在排序和平衡搜索树操作的性能上几乎相差50倍。如果我们增加,情况会变得更糟。
(技术细节:数据= 32位随机整数。计算机=典型的现代笔记本电脑。测试代码使用C ++编写,使用标准库例程(std :: sort)和数据结构(std :: multiset,std ::我使用了两种不同的C ++编译器(GCC和Clang)以及两种不同的标准库实现(libstdc ++和libc ++)。传统上,std :: multiset被实现为高度优化的红黑树。)