修剪一个连续的std容器

时间:2017-07-02 11:36:20

标签: c++ pointers containers std c++17

假设我有一个容器,如下:

std::vector<int> numbers{1,2,3,4,5,6,7,8};

“修剪”它的最有效方法是什么?如同,从中删除元素,但仅从开头或结尾。

假设我想将'数字'转换为容器{3,4,5,6,7}。我能想到的一种非常有效地去除'8'的方法是:

numbers.resize(numbers.size()-2);

这似乎保证不会重新分配和删除所有不适合新大小的尾随元素(在这种情况下只有最后一个元素,8)。

在容器的开头是否有类似的方法?并且,只要我传递给resize的参数小于或等于容器的原始大小,此操作是否保证为O(1)?

2 个答案:

答案 0 :(得分:4)

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> COUNT: <span class="Count"></span><br /> PERCENTAGE: <span class="Percent"></span>不支持有效删除前端元素,但std::vector会:http://www.boost.org/doc/libs/release/doc/html/circular_buffer.html

在某种程度上,boost::circular_buffer也支持这一点,但它有一些问题,例如常见实现一次只分配少量,这意味着它可能比{{1}分配更多次内存。 }。从std::deque删除许多元素的速度并不快,因为它必须释放许多块(而circular_buffer只增加一个整数值)。

答案 1 :(得分:2)

  

我可以想到一种方法来删除&#39; 8&#39;效率很高:

numbers.resize(numbers.size()-2);

假设这应该是-1,不,那不是你想要做的。您应该始终选择适合该作业的工具。在这种情况下,如果你想删除最后一个元素,那就是:

numbers.pop_back();

如果您想删除最后的n个元素(假设始终为n <= numbers.size()),那就是:

numbers.erase(numbers.end() - n, numbers.end());

这保证不会重新分配或额外移动 - 它只会调用适当的析构函数然后移动结束指针。如果类型是可以轻易破坏的,那么即使是第一部分也是无操作。

如果您要删除第一个 n元素,那就是对称的:

numbers.erase(numbers.begin(), numbers.begin() + n);

然而,这涉及移动所有后来的元素以填充这个洞 - 所以它是剩下多少元素的函数。 vector从后面擦除是很便宜的,但从前面擦除是很昂贵的(这本身就是拥有pop_back()但不是pop_front()的动机。因此,如果您想trim(),请先从右侧删除。

如果你从前面做了大量的擦除,你应该考虑使用一个擅长从两端修剪的容器 - 比如std::deque。好消息是 - 代码看起来都是一样的。您仍然希望使用双迭代器erase()进行修剪。

你绝对不想做的事情是(尽管它可能会有多么诱人):

numbers.assign(numbers.begin() + 2, numbers.end() - 1);

这是未定义的行为。