c – 执行“最后[二分/分/小时]”数据结构

前端之家收集整理的这篇文章主要介绍了c – 执行“最后[二分/分/小时]”数据结构前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我认为这是一个相当普遍的问题,但我似乎找不到googling的答案(可能有一个更精确的名称,我不知道的问题)

您需要使用“hit()”方法实现一个结构,用于报告命中和hitsInLastSecond | Minute | Hour方法.你有一个毫秒级的定时器.你如何有效地实现?

我的想法是这样的(在psuedo-C)

  1. class HitCounter {
  2. void hit() {
  3. hits_at[now()] = ++last_count;
  4. }
  5.  
  6. int hitsInLastSecond() {
  7. auto before_count = hits_at.lower_bound(now() - 1 * second)
  8. if (before_count == hits_at.end()) { return last_count; }
  9. return last_count - before_count->second;
  10. }
  11.  
  12. // etc for Minute,Hour
  13.  
  14. map<time_point,int> hits_at;
  15. int last_count = 0;
  16. };

这是否有效?好吗?更好吗

更新:添加修剪,并切换到一个德克,因为评论

  1. class HitCounter {
  2. void hit() {
  3. hits.push_back(make_pair(now(),++last_count));
  4. }
  5.  
  6. int hitsInLastSecond() {
  7. auto before = lower_bound(hits.begin(),hits.end(),make_pair(now() - 1 * second,-1));
  8. if (before == hits.end()) { return last_count; }
  9. return last_count - before_count->second;
  10. }
  11.  
  12. // etc for Minute,Hour
  13.  
  14. void prune() {
  15. auto old = upper_bound(hits.begin(). hits.end(),make_pair(now - 1 * hour,-1));
  16. if (old != hits.end()) {
  17. hits.erase(hits.begin(),old)
  18. }
  19. }
  20.  
  21. deqeue<pair<time_point,int>> hits;
  22. int last_count = 0;
  23. };

解决方法

你所描述的是一个直方图.

使用哈希,如果你打算纳秒精度,会吃掉你的大部分cpu.你可能需要一个环形缓冲区来存储数据.

使用std :: chrono来实现你所需要的时间精度,但是平均每秒钟的命中率似乎是你需要的最高粒度,如果你正在看整体的大局,看起来似乎并不重要,精度是多少.

这是一个部分的,介绍性的例子,介绍你如何去做:

  1. #include <array>
  2. #include <algorithm>
  3.  
  4. template<size_t RingSize>
  5. class Histogram
  6. {
  7. std::array<size_t,RingSize> m_ringBuffer;
  8. size_t m_total;
  9. size_t m_position;
  10. public:
  11. Histogram() : m_total(0)
  12. {
  13. std::fill_n(m_ringBuffer.begin(),RingSize,0);
  14. }
  15.  
  16. void addHit()
  17. {
  18. ++m_ringBuffer[m_position];
  19. ++m_total;
  20. }
  21.  
  22. void incrementPosition()
  23. {
  24. if (++m_position >= RingSize)
  25. m_position = 0;
  26. m_total -= m_ringBuffer[m_position];
  27. m_ringBuffer[m_position] = 0;
  28. }
  29.  
  30. double runningAverage() const
  31. {
  32. return (double)m_total / (double)RingSize;
  33. }
  34.  
  35. size_t runningTotal() const { return m_total; }
  36. };
  37.  
  38. Histogram<60> secondsHisto;
  39. Histogram<60> minutesHisto;
  40. Histogram<24> hoursHisto;
  41. Histogram<7> weeksHisto;

这是一个天真的实现,它假设你会每秒调用它并增加位置,并将runTotal从一个直方图转换到下一个每个RingSize(所以每60秒,添加secondsHisto.runningTotal到minutesHisto).

希望这将是一个有用的介绍性的起点.

如果要跟踪每秒点击数较长的直方图,可以使用此模型,通过增加环形尺寸,添加第二个总数来跟踪最后N个环形缓冲区条目,以便m_subTotal = sum(m_ringBuffer [m_position – N .. m_position]),类似于m_total的工作方式.

  1. size_t m_10sTotal;
  2.  
  3. ...
  4.  
  5. void addHit()
  6. {
  7. ++m_ringBuffer[m_position];
  8. ++m_total;
  9. ++m_10sTotal;
  10. }
  11.  
  12. void incrementPosition()
  13. {
  14. // subtract data from >10 sample intervals ago.
  15. m_10sTotal -= m_ringBuffer[(m_position + RingBufferSize - 10) % RingBufferSize];
  16. // for the naive total,do the subtraction after we
  17. // advance position,since it will coincide with the
  18. // location of the value RingBufferSize ago.
  19. if (++m_position >= RingBufferSize)
  20. m_position = 0;
  21. m_total -= m_ringBuffer[m_position];
  22. }

你不必使这些大小克服这些大小,这只是一个天真的刮擦模型.有各种各样的选择,例如同时增加每个直方图:

  1. secondsHisto.addHit();
  2. minutesHisto.addHit();
  3. hoursHisto.addHit();
  4. weeksHisto.addHit();

每个都独立翻转,所以都有当前的值.将每个组合的大小尽可能地按照您想要的数据返回.

猜你在找的C&C++相关文章