此代码运行0.012秒:
std::list<int> list;
list.resize(100);
int size;
for(int i = 0 ; i < 10000; i++)
size = list.size();
这个为9.378秒:
std::list<int> list;
list.resize(100000);
int size;
for(int i = 0 ; i < 10000; i++)
size = list.size();
在我看来,有可能以这种方式实现std :: list,该大小将存储在私有变量中,但根据这个,每次调用size时都会再次计算。任何人都可以解释原因吗?
答案 0 :(得分:16)
常量时间size()
和常量时间list.splice
之间存在冲突。委员会选择赞成splice
。
当您在两个列表之间拼接节点时,您必须计算移动的节点以更新两个列表的大小。通过改变一些内部指针,它消除了拼接节点的许多优点。
正如评论中所指出的,C ++ 11通过放弃O(1)来改变这一点,因为splice
的一些罕见(?)用途:
void splice(const_iterator position, list& x, const_iterator first, const_iterator last);
void splice(const_iterator position, list&& x, const_iterator first, const_iterator last);
复杂性:
&x == this
时的固定时间;否则,线性时间。
答案 1 :(得分:9)
在ISO/IEC 14882:2011
,§C.2.12,第23条:“容器库”:
更改:size()成员函数的复杂性现在不变
理由:缺乏size()复杂性的规范导致实现不同,性能特征不一致。
对原始功能的影响:符合C ++ 2003的某些容器实现可能不符合本国际标准中指定的size()要求。将容器(如std :: list)调整到更严格的要求可能需要进行不兼容的更改。
评论:
在23.3.5.5 - “列表操作”中,再次在ISO/IEC 14882:2011
中:
list提供了三个拼接操作,可以破坏性地将元素从一个列表移动到另一个列表。如果get_allocator()!= x.get_allocator(),则拼接操作的行为是不确定的。
void splice(const_iterator position,list&amp; x);
void splice(const_iterator position,list&amp;&amp; x);
需要:&amp; x!=此。
效果:在位置前插入x的内容,x变为空。指针和x的移动元素的引用现在指的是那些相同的元素,但作为* this的成员。引用移动元素的迭代器将继续引用它们的元素,但它们现在表现为迭代器为* this,而不是x。 复杂性:恒定时间。void splice(const_iterator position,list&amp; x,const_iterator i);
void splice(const_iterator position,list&amp;&amp; x,const_iterator i);
效果:在列表x之前插入i指向的元素,然后从x中删除元素。如果position == i或position == ++ i,结果不会改变。指针和对* i的引用继续引用相同的元素,但作为* this的成员。 I i(包括i本身)的迭代器继续引用相同的元素,但现在表现为迭代器为* this,而不是x。 需要:我是x的有效可解引用迭代器 复杂性:恒定时间。void splice(const_iterator position,list&amp; x,const_iterator first,const_iterator last);
void splice(const_iterator position,list&amp;&amp; x,const_iterator first,const_iterator last);
效果:在位置之前插入[first,last]范围内的元素,并从x中删除元素。 需要:[first,last]是x中的有效范围。如果position是[first,last]范围内的迭代器,则结果是未定义的。指针和x的移动元素的引用现在指的是那些相同的元素,但作为* this的成员。引用移动元素的迭代器将继续引用它们的元素,但它们现在表现为迭代器为* this,而不是x。 复杂性:如果&amp; x == this,则为恒定时间;否则,线性时间。