我需要在Java中实现 TimeWindowBuffer ,它存储用户随着时间的推移不断接收的数字。缓冲区有一个 maxBufferSize 。用户想要知道过去几秒的平均值,即用户传入的 timeWindow (因此这是一个滑动窗口)。我们可以从系统中获取当前时间(例如Java中的System.currentTimeMills()
)。 TimeWindowBuffer 类是这样的:
public class TimeWindowBuffer {
private int maxBufferSize;
private int timeWindow;
public TimwWindowBuffer(int maxBufferSize, int timeWindow) {
this.maxBufferSize = maxBufferSize;
this.timeWindow = timeWindow;
}
public void addValue(long value) {
...
}
public double getAvg() {
...
return average;
}
// other auxiliary methods
}
示例:
假设,用户每秒都会收到一个号码(用户可能无法以特定的速率收到号码),并想知道过去5秒的平均值。
的输入:
maxBufferSize = 5,timeWindow = 5(s)
数字= { - 5 4 -8 -8 -8 1 6 1 8 5}
输出(我在此列出公式以供说明,但用户只需要结果)
:
-5 / 1(t = 1)
(-5 + 4)/ 2(t = 2)
(-5 + 4-8)/ 3(t = 3)
(-5 + 4 - 8 - 8)/ 4(t = 4)
(-5 + 4 - 8 - 8 - 8)/ 5(t = 5)
(4 - 8 - 8 - 8 + 1)/ 5(t = 6)
(-8 - 8 - 8 + 1 + 6)/ 5(t = 7)
(-8 - 8 + 1 + 6 + 1)/ 5(t = 8)
(-8 + 1 + 6 + 1 + 8)/ 5(t = 9)
(1 + 6 + 1 + 8 + 5)/ 5(t = 10)
由于没有指定 TimeWindowBuffer 的数据结构,我一直在考虑保留一对值及其增加的时间。所以我的底层缓冲区声明是这样的:
private ArrayList<Pair> buffer = new ArrayList<Pair>(maxBufferSize);
其中
class Pair {
private long value;
private long time;
...
}
由于按时间顺序添加了对,我可以对列表进行二进制搜索,并计算落入 timeWindow 的数字的平均值。问题是缓冲区有一个 maxBufferSize (尽管ArrayList没有),我必须在缓冲区已满时删除最旧的值。而且这个值仍然可以满足 timeWindow ,但现在它已经记录下来,我永远不会知道它何时到期。
我被困在这里当前。
我不需要直接回答,但在这里有一些讨论或想法。如果对问题和我的描述有任何疑惑,请现在就告诉我。
答案 0 :(得分:1)
我喜欢这样的小谜题。我没有编译此代码,也没有考虑到生产使用所需的所有内容。就像我没有设计一种方法来将错过的值设置为0 - 即,如果每个滴答都没有出现值。
但这会让你想到另一种方式......
public class TickTimer
{
private int tick = 0;
private java.util.Timer timer = new java.util.Timer();
public TickTimer(double timeWindow)
{
timer.scheduleAtFixedRate(new TickerTask(),
0, // initial delay
Math.round(1000/timeWindow)); // interval
}
private class TickerTask extends TimerTask
{
public void run ()
{
tick++;
}
}
public int getTicks()
{
return tick;
}
}
public class TimeWindowBuffer
{
int buffer[];
TickTimer timer;
final Object bufferSync = new Object();
public TimeWindowBuffer(int maxBufferSize, double timeWindow)
{
buffer = new int[maxBufferSize];
timer = TickTimer(timeWindow);
}
public boolean add(int value)
{
synchronize(bufferSync)
{
buffer[timer.getTicks() % maxBufferSize] = value;
}
}
public int averageValue()
{
int average = 0;
synchronize(bufferSync)
{
for (int i: buffer)
{
average += i;
}
}
return average/maxBufferSize;
}
}
答案 1 :(得分:0)
您的问题可以概括为使用常量内存来计算流上的某些统计信息。
对我而言,这是一个堆(优先级队列),其中time
为关键,value
为值,顶部为time
。
收到新的(time,value)
后,将其添加到堆中。如果堆大小大于缓冲区大小,只需删除堆中的根节点,直到堆足够小。
同样通过使用堆,您可以在O(1)时间内在缓冲区(即堆)中获得最小time
,因此只需删除根(具有最小time
的节点)直到所有过时的对都被清除。
对于统计信息,请保留整数sum
。向堆中添加新对时,sum = sum + value of pair
。从堆中删除根时,sum = sum - value of root
。