【问题标题】:Efficient circular list高效循环列表
【发布时间】:2012-03-19 23:27:14
【问题描述】:

我想要一个简单而高效的循环缓冲区/队列。如果我使用std::vector,我必须这样做:

if ( v.size() >= limit ) {
    std::vector<int> it = v.begin();
    v.insert( it, data );
    v.erase( it+1 );
}

有没有更简单的解决方案?

【问题讨论】:

  • 我不明白你的问题...你想用 std:vector 实现一个循环列表吗?
  • 没有。这是我使用 std::vector 的实现。然而,这不是一个好看的主意。插入然后删除以保持大小固定...
  • 删除元素的第一件事不会使用delete,但可能会使用erase,而且我看不到如何在一个位置替换元素(这是上面解释的代码的净效果作为伪代码,即忽略插入后使用迭代器的未定义行为)将有助于我构建循环缓冲区。您可能是想从头部移除并在尾部插入?
  • 顺便说一句,你有一个错误:insert 可能会使迭代器 it 无效,因此 erase 可能会崩溃或损坏内存。

标签: c++ vector circular-buffer circular-list


【解决方案1】:

您希望保持缓冲区的大小,覆盖旧项目。随着时间的推移,只需覆盖旧的。如果要处理 nItems

std::vector<int> data(10);

for (int i = 0 ; i < 100 ; ++i)
{
    data[i%10] = i;
}

for (std::vector<int>::const_iterator it = data.begin() ; it !=data.end(); ++it)
{
     std::cout << *it << std::endl;
}

这种插​​入方法会将最后 10 个元素保留在缓冲区中。

【讨论】:

    【解决方案2】:

    std::list 可能比std::vector 更容易构建列表。还有std::queue

    你使用 vector 来实现循环 queue 也很有趣,但问一个关于如何实现循环 list 的问题.为什么不用地图?

    【讨论】:

    • std::queue::push() 也推到最后
    • 使用 std::list,我必须使用 push_frontpop_back 来调整大小。对吗?
    • 固定尺寸​​怎么样?地图怎么可能?
    • @mahmood 如果大小是固定的,那么使用动态结构有什么意义?
    【解决方案3】:

    c++11 中,对于固定大小的替代方案,您应该使用std::array

    const unsigned int BUFFER_SIZE = 10;
    std::array<int, BUFFER_SIZE> buffer; // The buffer size is fixed at compile time.
    for (i = 0; i < 100; ++i) {
        buffer[i % BUFFER_SIZE] = i;
    }
    

    【讨论】:

      【解决方案4】:

      试试 std::deque。该接口类似于使用 std::vector,但在开头和结尾插入和删除更有效。

      【讨论】:

        【解决方案5】:

        你可以像往常一样使用你的向量,然后创建一个 get_element(index) 函数来让它感觉循环。它非常快速和直接,因为它只是整数操作。

        template<typename T>
        T get_element(std::vector<T> vec, int index) {
            int vector_size = vec.size();
            int vector_max = vector_size - 1;
            int vector_min = 0;
            int index_diff = 0;
            int refined_index = 0;
        
            // index_diff is the amount of index-out-of-range. Positive means index was
            // bigger than the vector size, negative means index was smaller than 0
            if (index > vector_max) {
                index_diff = index - vector_max;
            } else if (index < vector_min) {
                index_diff = index;
            } else {
                index_diff = 0;
            }
        
            // Make the indexing feel circular
            // index mod 16 yields a number from 0 to 15
            if (index_diff > 0) {
                refined_index = index % vector_size;
            } else if (index_diff < 0) {
                int temp_index = index % vector_size;
        
                if (temp_index != 0) {
                    refined_index = vector_size - std::abs(temp_index);
                    // if the negative mod equals to 0, we can't have 16 - 0 = 16 index,
                    // so we set it to 0 manually
                } else {
                    refined_index = 0;
                }
            } else {
                refined_index = index;
            }
        
            return vec[refined_index];
        }
        

        然后像这样使用它:

        int result = get_element<int>(myvec, 256);
        

        请注意,任何小于 0 的索引都会从矢量的最后一个元素开始旋转,这当然是有意的。

        【讨论】:

          猜你喜欢
          • 2016-01-03
          • 2015-10-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-11-06
          • 2021-09-15
          • 2017-04-03
          相关资源
          最近更新 更多