C++ 什么';这是一个24小时逐分钟布尔记录的良好数据结构

C++ 什么';这是一个24小时逐分钟布尔记录的良好数据结构,c++,data-structures,C++,Data Structures,我的任务是创建一个数据结构,在过去24小时内每分钟保存一个布尔值。(事件X发生了吗?)我需要一直保持最后24小时。(也就是说,数据将不断添加,旧数据弹出。)数据将被持久保存到闪存驱动器。我们在一个嵌入式平台上,但内存并没有那么有限(我有128MB可用),不过碎片可能会成为一个问题。这是一个实时系统,但由于记录是每分钟一次,因此几乎没有运行时限制 界面可以是这样的: class x_record { public: // record whether or not x occurred

我的任务是创建一个数据结构,在过去24小时内每分钟保存一个布尔值。(事件X发生了吗?)我需要一直保持最后24小时。(也就是说,数据将不断添加,旧数据弹出。)数据将被持久保存到闪存驱动器。我们在一个嵌入式平台上,但内存并没有那么有限(我有128MB可用),不过碎片可能会成为一个问题。这是一个实时系统,但由于记录是每分钟一次,因此几乎没有运行时限制

界面可以是这样的:

class x_record {
  public:
    // record whether or not x occurred this minute
    void record_entry(bool x_occured);

    // how many minutes has x occured in the last 24hrs? 
    unsigned int x_occurance_minutes() const;

  private:
    // HERE BE DRAGONS 
};
存储实际数据的好数据结构是什么?我目前最喜欢的是
std::deque
和一个由24个
long
组成的数组,它们的64位中有60位用于每小时60分钟。后者是当前持久性的最爱

我想我对这两种想法的利弊都有一个很好的想法,但我希望你们中的一些人能提供更多的内幕信息,甚至更多的想法


附言:这是严格意义上的C++03+TR1+Boost 1.52,没有可用的C++11/14

我每小时都会有一个
std::vector
,而且每小时只有一个。所以你可以有一个
std::deque
。同样地,它可能是一个
std::deque
,但我看不出与向量相比有什么好处


它使事情变得高效、易于理解且不易出错。

要详细说明
向量
版本,我认为这是一个非常好的主意,因为您总是存储相同数量的数据(这至少是我所理解的):

类x_记录{
矢量数据;
无符号整数当前分钟;
公众:
x_record():数据(24*60,false),当前分钟(0){
//记录此时是否发生x
无效记录项(发生错误){
数据[currentMinute]=发生x_;
currentMinute=(currentMinute+1)%data.size();
}
};
这样,向量大小是恒定的,因此不应该分段(因为它是同时分配的)。您可以使用
currentMinute
变量跟踪当前分钟。填充所有字段时,只需使用
%(24*60)
将其设置为
0
,然后覆盖旧数据,因为您不需要它


也可以使用普通的<强>数组< /强>代替<代码>向量,但是这将需要更多的空间(因为通常C++存储<代码>布尔O/COD>值与<代码> char < />代码相同),或者是一些比特操作,在我看来,是重新发明轮子,当我们得到

向量
专门化时。

当您只关心事件在过去24小时内发生的频率,而完全忽略事件发生的时间时,您可以简单地记录事件发生的时间

考虑以下因素(未测试):

类x_记录{
公众:
//记录此时是否发生x
无效记录项(发生错误){
如果(发生x_){
m_records.insert(getTime());
}
}
//在过去24小时内x发生了多少分钟?
无符号整数x_发生时间_分钟(){
clearRecords();
返回m_记录。大小();
}
私人:
time\u t getTime()常量{
返回时间(NULL)/60;//获取分钟时间戳
}
作废clearRecords(){
//擦除过去24小时之前发生的所有记录
time\t frameStart=getTime()-60*60*24;
for(std::set::iterator it=m_recods.begin();it!=m_records.end();++it){
if(*it
如果事件很少发生,这是最合适的

它使用约束集以严格的弱顺序存储元素,因此时间戳较低的元素将首先列出。也

你应该考虑一个不同的键类型来插入到集合中,因为 TimeTyt不能保证代表秒。

< P>循环缓冲:

int countBits(std::uint32_t v) {
  // source: http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
  typedef std::uint32_t T;
  v = v - ((v >> 1) & (T)~(T)0/3);                           // temp
  v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);      // temp
  v = (v + (v >> 4)) & (T)~(T)0/255*15;                      // temp
  return (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * CHAR_BIT; // count
}

class x_record {
  public:
    x_record() { std::memset(&history, 0, sizeof(history)); }

    // record whether or not x occurred this minute
    void record_entry(bool x_occured) {
      uint64_t mask = 1 << (bit % 32);
      uint64_t set = x_occured ? mask : 0;
      history[bit / 32] = (history[bit / 32] & ~mask) | set;

      bit = (bit + 1) % (24*60);
    }

    // how many minutes has x occured in the last 24hrs? 
    int x_occurance_minutes() const {
      int count = 0;
      for (int i=0; i<45; ++i) {
        count += countBits(history[i]);
      }
      return count;
    }

  private:
    std::uint32_t history[45];
    short bit = 0;
};
int计数位(标准::uint32\u t v){
//资料来源:http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
类型定义标准::uint32_t;
v=v-((v>>1)和(T)~(T)0/3);//温度
v=(v&(T)~(T)0/15*3)+(v>>2)&(T)~(T)0/15*3);//温度
v=(v+(v>>4))&(T)~(T)0/255*15;//温度
返回(T)(v*((T)~(T)0/255))>>(sizeof(T)-1)*字符位;//计数
}
类x_记录{
公众:
x_record(){std::memset(&history,0,sizeof(history));}
//记录此时是否发生x
无效记录项(发生错误){

uint64_t mask=1我建议使用一个类,该类包含一个用于处理新值存储的计数器和一个用于通过小时/分钟访问的转换函数

动态_集处理大多数需求:

  • boost,没有C++11
  • 紧凑的
  • 处理24*60位
  • 有一个count()函数,用于对设置位进行计数
  • 返回以位形式存储的块
  • 没有std::vector的“容器”问题

正如评论中所建议的那样,
std::bitset
可能是一个不错的选择。它是一个固定大小的位序列,可以独立操作。它比
std::vector
占用的内存少(尽管你说这对你来说不是问题)。但是,如果需要使序列循环,您可能需要将其包装在另一个容器中,以便始终保持最后24*60分钟,而不是一天中的24*60分钟。

正如马吕斯·班西拉(Marius Bancila)首先建议的那样,然后(请继续投票表决该答案,他给出了解决方案的提示),
std::bitset
是理想的选择。然而,由于他的答案相当模糊,我决定发布一个更具体的描述,说明我最终使用了什么:

class x_record {
  public:
    void record_entry(bool x_occured) {
      record_ <<= 1;
      record_[0] = x_occurred;
    }

    unsigned int x_occurance_minutes() const {
      return record_.count();
    }

    void write_to(std::ostream& os) const {
      os << m_overload_minutes.to_string();
    }

    void read_from(std::istream& is) const {
      std::string bits;
      is >> std::setw(minutes_to_keep) >> bits;
      if( !is || bits.size()!=minutes_to_keep )
        throw std::runtime_error("invalid file format");

      record_ = std::bitset<60*24>(bits);
    }

  private:
    std::bitset<60*24>  record_;
};
类x_记录{
公众:
int countBits(std::uint32_t v) {
  // source: http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
  typedef std::uint32_t T;
  v = v - ((v >> 1) & (T)~(T)0/3);                           // temp
  v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);      // temp
  v = (v + (v >> 4)) & (T)~(T)0/255*15;                      // temp
  return (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * CHAR_BIT; // count
}

class x_record {
  public:
    x_record() { std::memset(&history, 0, sizeof(history)); }

    // record whether or not x occurred this minute
    void record_entry(bool x_occured) {
      uint64_t mask = 1 << (bit % 32);
      uint64_t set = x_occured ? mask : 0;
      history[bit / 32] = (history[bit / 32] & ~mask) | set;

      bit = (bit + 1) % (24*60);
    }

    // how many minutes has x occured in the last 24hrs? 
    int x_occurance_minutes() const {
      int count = 0;
      for (int i=0; i<45; ++i) {
        count += countBits(history[i]);
      }
      return count;
    }

  private:
    std::uint32_t history[45];
    short bit = 0;
};
class x_record {
  public:
    void record_entry(bool x_occured) {
      record_ <<= 1;
      record_[0] = x_occurred;
    }

    unsigned int x_occurance_minutes() const {
      return record_.count();
    }

    void write_to(std::ostream& os) const {
      os << m_overload_minutes.to_string();
    }

    void read_from(std::istream& is) const {
      std::string bits;
      is >> std::setw(minutes_to_keep) >> bits;
      if( !is || bits.size()!=minutes_to_keep )
        throw std::runtime_error("invalid file format");

      record_ = std::bitset<60*24>(bits);
    }

  private:
    std::bitset<60*24>  record_;
};