假设我有一个容器,如下:
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)?
答案 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);
这是未定义的行为。