我需要跟踪在最后n秒内启用标志的次数。下面是我可以提出的示例代码.StateHandler维护活动数组中标志的值,用于最后n(此处为360)秒。在我的情况下,每秒从外部调用更新函数。因此,当我需要知道自上一次360秒以来设置的次数时,我调用getEnabledInLast360Seconds。是否可以更有效地做到这一点,比如不使用布尔数的n数组大小?
#include <map>
#include <iostream>
class StateHandler
{
bool active[360];
int index;
public:
StateHandler() :
index(0),
active()
{
}
void update(bool value)
{
if (index >= 360)
{
index = 0;
}
active[index % 360] = value;
index++;
}
int getEnabledInLast360Seconds()
{
int value = 0;
for (int i = 0; i < 360; i++)
{
if (active[i])
{
value++;
}
}
return value;
}
};
int main()
{
StateHandler handler;
handler.update(true);
handler.update(true);
handler.update(true);
std::cout << handler.getEnabledInLast360Seconds();
}
答案 0 :(得分:3)
是。使用numberOfOccurrences(0,360)
和numberOfOccurrences(1,361)
有359个常用术语的事实。所以记住总和,计算常用术语,并计算新总和。
void update(bool value)
{
if (index >= 360)
{
index = 0;
}
// invariant: count reflects t-360...t-1
if (active[index]) count--;
// invariant: count reflects t-359...t-1
active[index] = value;
if (value) count++;
// invariant: count reflects t-359...t
index++;
}
(请注意,if块重置index
消除了对模运算符%
的需要,因此我将其删除了)
另一种方法是使用子集和:
subsum[0] = count(0...19)
subsum[1] = count(20...39)
subsum[17] = count(340...359)
现在你每次只需要添加18个数字,你可以每隔20秒完全替换一个子数。
答案 1 :(得分:2)
您可以简单地使用std::set<timestamp>
(或者std::queue
),而不是修复缓冲区。每次检查时,弹出超过360s的元素并计算其余元素。
如果你经常检查但经常更新,你可能想要将“弹出”添加到更新本身,以防止该组变得太大。