请考虑以下代码段:
#include <iostream>
#include <ctime>
#include <vector>
#include <list>
using namespace std;
#define NUM_ITER 100000
int main() {
clock_t t = clock();
std::list< int > my_list;
std::vector< std::list< int >::iterator > list_ptr;
list_ptr.reserve(NUM_ITER);
for(int i = 0; i < NUM_ITER; ++i) {
my_list.push_back(0);
list_ptr.push_back(--(my_list.end()));
}
while(my_list.size() > 0) {
my_list.erase(list_ptr[list_ptr.size()-1]);
list_ptr.pop_back();
}
cout << "Done in: " << 1000*(clock()-t)/CLOCKS_PER_SEC << " msec!" << endl;
}
当我使用visual studio编译并运行它时,启用了所有优化,我得到了输出:
完成:8毫秒!
当我用g ++编译并运行它时,使用标志
g ++ main.cpp -pedantic -O2
我得到了输出
完成:7349毫秒!
这是鲁莽慢1000倍。这是为什么?根据“cppreference”调用列表中的擦除应该只使用恒定时间。
代码在同一台机器上编译和执行。
答案 0 :(得分:10)
可能是GCC发布的实现并未存储大小,而MSVC发布的实现也是如此。在这种情况下,内环为O(n ^ 2),GCC,O(n)为MSVC。
无论如何,C ++ 11要求list :: size是常量时间,你可能想把它报告为bug。
答案 1 :(得分:3)
更新解决方法:
您可以避免多次致电size()
:
size_t my_list_size = my_list.size();
while(my_list_size > 0) {
accum += *list_ptr[list_ptr.size()-1];
my_list.erase(list_ptr[list_ptr.size()-1]);
--my_list_size;
list_ptr.pop_back();
}
现在报告10毫秒。
修改强> 他们的列表实现效率不高。我尝试用以下代替:
#include <iostream>
#include <ctime>
#include <boost/container/vector.hpp>
#include <boost/container/list.hpp>
using namespace std;
#define NUM_ITER 100000
int main() {
clock_t t = clock();
boost::container::list< int > my_list;
boost::container::vector< boost::container::list< int >::iterator > list_ptr;
list_ptr.reserve(NUM_ITER);
for(int i = 0; i < NUM_ITER; ++i) {
my_list.push_back(rand());
list_ptr.push_back(--(my_list.end()));
}
unsigned long long volatile accum = 0;
while(my_list.size() > 0) {
accum += *list_ptr[list_ptr.size()-1];
my_list.erase(list_ptr[list_ptr.size()-1]);
list_ptr.pop_back();
}
cout << "Done in: " << 1000*(clock()-t)/CLOCKS_PER_SEC << " msec!" << endl;
cout << "Accumulated: " << accum << "\n";
}
现在在我的机器上运行〜0ms,而在同一台机器上使用std :: list运行~7s。
sehe@desktop:/tmp$ ./test
Done in: 0 msec!
Accumulated: 107345864261546