[英]Time complexity of removing items in vectors and deque
我已经读过,在std::vector
末尾添加项目的时间复杂度是分摊常量,并且在std::deque
的顶部和底部插入项目是常量。因为这两个容器都有一个随机访问迭代器,因此访问元素任何指数都是不变的。 如果我有任何这些事实错误,请告诉我。我的问题是,如果访问std::vector
或std::deque
的元素是常量,那么为什么通过擦除O(n)删除元素的时间复杂度。 这里的答案之一指出通过擦除元素是O(n)。 我知道擦除会删除起始迭代器和结束迭代器之间的元素,所以答案基本上意味着它的O(n)
取决于两个迭代器之间的元素的数量,并且从任何向量/双端队列中删除单个元素指数会为零?
std::vector
和std::deque
情况有所不同,C ++ 98和C ++ 11也有所不同。
std::vector::erase()
的复杂性与std::vector::erase()
范围的长度以及范围的结尾和容器的末尾之间的元素数量是线性的(因此从末尾擦除元素需要不变时间)。
C ++ 2003 [lib.vector.modifiers]
读取:
iterator erase(iterator position);
iterator erase(iterator first, iterator last);`
...
复杂性:
T
的析构函数被称为等于被擦除元素数量的次数,但T
的赋值运算符被称为等于擦除元素之后的向量中元素数量的次数。
C ++ 14草案N4140 [vector.modifiers]
读取:
复杂性:
T
的析构函数被称为等于被擦除元素数量的次数,但T
的移动赋值运算符被称为等于擦除元素之后的向量中元素数量的次数。
因此,您可以看到C ++ 11/14实现通常更有效,因为它执行移动分配而不是复制分配,但复杂性保持不变。
std::deque::erase()
的复杂性与std::deque::erase()
范围的长度和两个数字的最小值呈线性关系:范围开始前剩余元素的数量,以及结束后剩余元素的数量范围。 因此,从开头或结束擦除元素需要恒定的时间。
C ++ 2003 [lib.deque.modifiers]
:
iterator erase(iterator position);
iterator erase(iterator first, iterator last);
复杂性:对析构函数的调用次数与擦除的元素数相同,但对赋值运算符的调用次数最多等于擦除元素之前的元素数量和元素数量的最小值擦除后的元素。
C ++ 14 draft N4140 [deque.modifiers]/5
:
复杂性:对析构函数的调用次数与擦除的元素数相同,但对赋值运算符的调用次数不超过擦除元素之前的元素数量和之后的元素数量中的较小者。擦除元素。
所以,它在C ++ 98和C ++ 11/14中是相同的,除了C ++ 11可以在移动赋值和复制赋值之间进行选择(这里我看到标准中的一些不一致,因为措辞没有提到移动像std::vector
这样的赋值 - 可能是另一个问题的原因)。
还要注意措辞中的“最多”和“不再”。 这允许实现比线性更有效,但在实践中它们是线性的( DEMO )。
删除向量中的元素是O(n),因为一旦删除元素,您仍需要移动所有连续元素以填充创建的间隙。 如果向量具有n个元素,那么在最坏的情况下,您将需要移位n-1个元素,因此复杂度为O(n)。
删除元素确实是O(n)
不是因为你需要做什么来找到要删除的元素,而是因为你必须对它之后的所有元素做什么。 需要向下滑动这些元素以填充空槽。
因此,平均而言,擦除将在向量的中间占据一个元素,因此您必须移动大约一半的元素。 因此O(n)
。 最好的情况是,你删除最后一个元素 - 不需要滑动。 最坏的情况是,你擦除第一个元素 - 然后必须移动每个其他元素。
通过使用这种方式时间复杂度=范围长度+移位长度(n - 范围结束)
vector<int> it = (vector<int>::iterator) &vec[pos];
vec.erase(it, it+length);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.