【问题标题】:Fast way to implement pop_front to a std::vector将 pop_front 实现为 std::vector 的快速方法
【发布时间】:2012-03-15 18:19:36
【问题描述】:

我正在使用一些使用 std::vector 的类和实用方法。

现在我需要在其中一个类上使用每个帧的 pop_front - push_back 方法(但它们都是链接的,并且可以一起工作,所以我不能只更改一个)。

大部分操作都是遍历所有元素和 push_back 操作,所以我应该做的最好的工作是:派生这些类和实用程序的存储库,模板化所有内容,并使用双端队列或列表。

但这意味着大量的代码重写和大量的测试会让我错过最后期限。

所以我需要建议将有效的 pop_front 写入静态大小的向量(大小不会改变)。

我找到了here 一个方法:

template<typename T>
void pop_front(std::vector<T>& vec)
{
   vec.front() = vec.back();
   vec.pop_back();
   vec.front() = vec.back();  // but should this work?
}

另外一个想法应该是:

template<typename T>
void pop_front(std::vector<T>& vec, already_allocated_vector vec1)
{
   vec1.clear();
   copy(vec.begin(), vec.end()-1, vec1.begin());
   copy(vec1.begin(), vec1.end(), vec.begin());
}

这两种解决方案哪个更快?还有其他解决方案吗?

【问题讨论】:

  • “大小不会改变”是什么意思?做pop_front之后,向量会和以前一样大小吗?如果是这样,最后一个元素应该是垃圾吗?
  • 向量具有相同的大小,因为在弹出后我突然进行了推送。每一帧我都用相同的方法弹出和推送,所以在此方法之前和之后,向量的大小相同
  • 在担心速度之前,先担心正确性。如果你得到的结果完全是错误的,那么世界上所有的速度都毫无意义,而且据我所知,你的两个候选人都是错误的。第一个应命名为pop_back_and_overwrite_front_with_penultimate,第二个应命名为invoke_undefined_behavior_and_pop_back。 (写到vec1.begin() 是未定义的,因为vec1 是空的;你需要写vec1.resize(vec.size() - 1) 而不是vec1.clear()。)当我处理向量运算时,我有时会画一幅画。也许这对你也有帮助。
  • 听说过std::deque?和std::vector一样好,但可以pop_front()
  • @SebastianMach 我也在寻找同样的东西。不像std::vectorstd::deque不是连续记忆。

标签: c++ vector data-structures


【解决方案1】:

我希望:

template<typename T>
void pop_front(std::vector<T>& vec)
{
    assert(!vec.empty());
    vec.front() = std::move(vec.back());
    vec.pop_back();
}

是最有效的方法,但它不保持向量中元素的顺序。

如果需要维护vec中剩余元素的顺序,可以这样做:

template<typename T>
void pop_front(std::vector<T>& vec)
{
    assert(!vec.empty());
    vec.erase(vec.begin());
}

这将在vec 中的元素数量上具有线性时间,但这是您在不更改数据结构的情况下可以做到的最好的。

这些函数都不会将vector 保持在恒定大小,因为pop_front 操作将根据定义从容器中删除一个元素。

【讨论】:

  • 我认为假设必须保留订单,因为std::vector::pop_back保留了订单。
  • 在后面加上vec.push_back(new_value) vec.shrink_to_fit()不是更好吗?
【解决方案2】:

由于pop_front()只擦除第一个元素,所以直接实现是这样的:

template <typename V>
void pop_front(V & v)
{
    assert(!v.empty());
    v.erase(v.begin());
}

暂时不用担心速度。如果您想返回并优化代码,请要求专门的项目时间。

【讨论】:

  • 对不起,我不理解你的代码,它不应该只保留第一个元素吗?我只想擦除第一个元素,不应该是:v.erase(v.begin(), v.begin()+1); ?
  • @Mankarse:是的,天哪!谢谢!
【解决方案3】:

我也有办法……虽然不太好……

这看起来像@0xPwn 的解决方案,但他第二次没有反转向量。 这段代码你大概看懂了,我就不解释了。

#include <algorithm>
#include <vector>
template <typename T>
void pop_front(std::vector<T>& vec){
    std::reverse(vec.begin(),vec.end()); // first becomes last, reverses the vector
    vec.pop_back(); // pop last
    std::reverse(vec.begin(),vec.end()); // reverses it again, so the elements are in the same order as before

}

【讨论】:

  • 能不能再低效一点?
【解决方案4】:

如果您只是尝试擦除第一个元素,则在函数中使用:

if (my_vector.size()){ //check if there any elements in the vector array
    my_vector.erase(my_vector.begin()); //erase the firs element
}

如果你想模拟整个向量数组的弹出前端(你想从头到尾保持弹出每个元素),我建议:

reverse(my_vector.begin(),my_vector.end());  // reverse the order of the vector array
my_vector.pop_back();   // now just simple pop_back will give you the results

【讨论】:

    猜你喜欢
    • 2012-02-22
    • 1970-01-01
    • 2011-12-15
    • 2017-08-22
    • 1970-01-01
    • 2011-12-28
    • 2017-02-06
    • 1970-01-01
    • 2011-11-25
    相关资源
    最近更新 更多