【问题标题】:C++ Fixed Size Container to Store Most Recent Values用于存储最新值的 C++ 固定大小容器
【发布时间】:2015-03-17 13:13:12
【问题描述】:

我想知道C++中以下问题最适合的数据结构是什么

我想存储 100 个按新近度排序的花车。因此,当我添加(推送)一个新项目时,其他元素会向上移动一个位置。每次触发事件时,我都会收到一个值,然后将其添加到我的数据结构中。

当元素数量达到 100 时,我想删除(弹出)最后的项目(最旧的)。

我希望能够遍历所有元素并对它们执行一些数学运算。

我查看了所有标准 C++ 容器,但没有一个能满足我的所有需求。使用标准 C++ 代码实现这一目标的最简单方法是什么?

【问题讨论】:

  • 我认为 std::queue 对这个问题有好处
  • 我不能很容易地遍历整个 std::queue - 我想对所有项目进行加权平均。
  • @CalG 为什么你不能这样做?每次插入/弹出队列更新平均值时。
  • @Shan 浮点错误累积。
  • 如果你只需要平均值,为什么不使用运行总和和运行平均值呢? O(1) 空间和 O(1) 时间复杂度:-)

标签: c++ stack queue containers


【解决方案1】:

刚刚看到您需要对它们进行迭代。使用list

你的基本功能看起来像这样

void addToList(int value){
    list100.push_back(value);
    if(list100.size() > 100){
        list100.pop_front();
    }
}

对它们进行迭代也很容易:

for(int val : list100){
    sum += val;
}
// Average, or whatever you need to do

显然,如果您使用的不是int,则需要更改它。虽然这增加了比您需要的更多的功能,但它非常有效,因为它是一个双向链表。

http://www.cplusplus.com/reference/list/list/

【讨论】:

  • 是的,但是如何遍历所有值并取平均值?
  • 不。那是不正确的恕我直言。相同的元素总是被推 100 次。您的队列将在 100 个位置中只有 1 个元素。
  • 我认为循环缓冲区更合适,因为他有固定大小的要求。
  • 一个列表特别不适合这项工作。您既不需要可扩展性,也不需要 O(1) 中间插入,并且数据碎片会损害遍历。
  • 当然,在小数据集上差异不会很明显,但这并不是说我们应该过早地悲观。数组将其元素连续放置,并且是对缓存最友好的结构,因为没有任何浪费。另一方面,列表根本不需要整齐地放在缓存行上。即使你的所有节点最终都是并排的,你最多也浪费了 80% 的缓存空间用于指针,并且 CPU 需要重复地跳过它们,而不是仅仅增加一个寄存器。 std::list 是为了灵活性,而不是速度。
【解决方案2】:

您可以使用 std::array、std::dequeue、std::list 或 std::priority_queue

【讨论】:

    【解决方案3】:

    你想要一个循环缓冲区。您可以使用Boost's implementation 或通过分配一个数组来创建自己的数组,并跟踪使用范围的开始和结束。这归结为对模 100 进行索引。

    【讨论】:

    • 您能否处理重复项。我的意思是如果有一个数字说 20 被一次又一次地使用,那么整个缓冲区将有 20 个。我错过了什么吗?
    • @Abhinav 为什么,是的。 OP 没有提到对重复项的特殊处理。
    • 我实际上使用 std::deque 来解决我的问题 if (myDeque.size() > 100){ myDeque.pop_front() } 但是循环缓冲区是合适的
    • Quentin,恕我直言,如果未指定问题,我们将寻求通用解决方案。从这个意义上说,循环缓冲区是错误的答案。 @CalG,如果您的问题是特定情况(我打赌不可能),请更新您的问题,否则这是太具体的解决方案,因此在所有情况下都不正确!
    • @Abhinav 我不明白。如果你多次存储相同的值,一般的解决方案是不要聪明,只存储 20 次。如果您需要修剪重复项,那么您将需要更具体的解决方案。 OP 中没有任何地方出现重复值。
    【解决方案4】:

    无需创建自己的库或使用库,std::vector 是最有效的标准数据结构。一旦达到其最大大小,将不再有动态内存分配。与动态内存分配的成本相比,向上移动 100 个浮点数的成本微不足道。 (这就是为什么std::list 是一个缓慢的数据结构)。向量没有 push_front 函数。相反,您必须使用v.insert(v.begin(), f)

    当然,这假设您正在做的事情对性能至关重要,但实际上可能并非如此。在这种情况下,我会使用std::deque 来更方便地使用。

    【讨论】:

      【解决方案5】:

      MAP (std::map) 应该能够满足您的要求。使用 Key 作为对象,使用 value 作为当前推送数 nPsheCount,每当您将元素添加到地图时,它都会递增。 向 map 添加新元素时,如果元素少于 100 个,只需将数字添加到 MAP 作为键,nPushCount 作为值。 如果您已经有 100 个元素,请检查地图中是否已经存在该数字并执行以下操作:

      1. 如果map中已经存在该数字,则将该数字作为key,nPushCount作为value;
      2. 如果没有,删除具有最低 nPushCount 作为值的数字,然后添加所需的数字并更新 nPushCount。

      【讨论】:

      • 这对于一个相当简单的问题来说太复杂了
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-22
      • 1970-01-01
      • 2019-01-11
      • 1970-01-01
      • 1970-01-01
      • 2012-12-31
      相关资源
      最近更新 更多