在较小的窗口上,n log n
排序可能会起作用。有没有更好的算法可以做到这一点?
在较小的窗口上,n log n
排序可能会起作用。有没有更好的算法可以做到这一点?
Answers:
如果您愿意接受近似值,则可以使用其他方法。例如,一个近似值是其秩在距真实中位数一定(用户指定)距离之内的值。例如,中位数(归一化)排名为0.5,如果您指定10%的误差项,则您希望答案的排名介于0.45和0.55之间。
如果这样的答案是适当的,那么有许多解决方案可以在滑动数据窗口上工作。基本思想是维护一定大小(大约1个/误差项)的数据样本,并计算该样本的中位数。可以证明,无论输入的性质如何,所得的中位数都满足我上面提到的属性。
因此,主要问题是如何维护一定大小的数据的运行样本,对此有很多方法,包括称为储层采样的技术。例如,本文:http : //citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.24.7136
如果您将长度为k的数据窗口维护为排序的双链表,则可以通过二进制搜索(在每个新元素移入窗口时插入每个新元素)和圆形指针数组(以立即定位那些需要删除),则窗口的每次移位都需要O(log(k))努力才能插入一个元素,只有O(1)努力才能删除移出窗口的元素,并且只有O(1)努力才能找到中位数(因为每次将一个元素插入或删除到列表中,您都可以在O(1)时间中更新指向中位数的指针)。因此,用于处理长度为N的数组的总工作量为O((nk)log(k))<= O(n log(k))。这比到目前为止提出的任何其他方法都要好,这不是一个近似值,这是准确的。
正如您提到的,排序将O(n·log n)
针对一个长度的窗口n
。这样做会增加l=vectorlength
总成本O(l·n·log n)
。
最简单的方法是在从一个窗口移到下一个窗口时,在内存中保留最后n个元素的有序列表。由于将一个元素从/从有序列表中删除/插入都O(n)
将导致成本为O(l·n)
。
伪代码:
l = length(input)
aidvector = sort(input(1:n))
output(i) = aid(n/2)
for i = n+1:l
remove input(i-n) from aidvector
sort aid(n) into aidvector
output(i) = aid(n/2)
这是用于查找当前中位数的解决方案O(1),用于添加新数字的O(log n)解决方案 http://www.dsalgo.com/RunningMedian.php
我在嵌入式应用程序中使用了RunningStats C ++库。这是我发现的最简单的运行统计数据库。
从链接:
该代码是Knuth和Welford方法的扩展,用于通过一次数据计算标准偏差。它也可以通过类似的界面计算偏度和峰度。除了只需要遍历数据之外,该算法在数值上稳定且准确。