我试图弄清楚从std :: set中删除多个元素的复杂性。我使用this page作为来源。
它声称使用迭代器擦除单个项目的复杂性是分摊O(1),但使用范围形式擦除多个项目是log(c.size())+ std :: distance(first,last) (即 - 记录集合的大小+删除的元素数量。)
取面值,如果要擦除的元素数量(n)远小于集合(m)中元素的数量,这意味着循环擦除要擦除的元素并将其擦除一个时间比通过一次调用(O(log m)使用一次调用更快(O(n))更快(假设n <&lt; m)。
显然,如果真的如此,第二种形式的内部实现只会做上述循环。
这是网站上的错误吗?规格中的错误?我只是错过了一些东西吗?
谢谢, Shachar
答案 0 :(得分:2)
似乎问题隐藏在(有点狡猾)单词“摊销”背后。单项擦除具有O复杂度log(c.size()),但是O(1)的摊销复杂度。
在循环中执行多次单次擦除将因此花费日志(c.size())+擦除次数,这正是范围形式的复杂性。
Shachar
答案 1 :(得分:2)
集合的内部元素存储在平衡的二叉树中。平衡树是其中任何节点的左右子树之间的最大高度差为1的树。
维护平衡结构对于确保在最坏的情况下O(log(n))
步骤中搜索树中(集合中)的任何元素非常重要。
删除元素可能会破坏平衡。要恢复平衡,必须进行旋转。在某些情况下,一次删除会导致多次旋转,因此该操作将执行O(log(n))
个步骤,但平均而言,删除会执行O(1)
个步骤。
因此,当必须删除散布在集合上的几个元素时,一次删除的可能性很高,摊销成本将是每次删除O(1)
。
删除范围内的几个元素(first, last
,其中一个元素紧随其后)几乎可以肯定会破坏平衡,这导致复杂度的对数因子:log(n) + std::distance(first, last)