为什么我插入到STL列表运行缓慢
Why is my insertion into STL list running slow?
我正在尝试使用邻接表实现无向图。我使用了以下代码:
int v,e;
scanf("%d%d",&v,&e);
list<int> graph[3000];
for(int i=0;i<e;i++){
int a,b;
scanf("%d%d",&a,&b);
graph[a].push_back(b);
graph[b].push_back(a);
}
为了测试代码的运行时间,我创建了一个具有3000个顶点和所有可能边的输入文件。跑完全程用时2.2秒。我试图通过将其更改为二维数组来优化,如下所示
int graph[3000][3000];
for(int i=0;i<e;i++){
int a,b;
scanf("%d%d",&a,&b);
graph[a][p[a]]=b;
graph[b][p[b]]=a;
p[a]++;
p[b]++;
}
,其中'p'的大小为3000,大写为全0。对于相同的输入文件,此代码仅运行0.35秒。我使用的是gcc-4.3.2编译器。我知道在列表末尾插入可以在常数时间内完成,那么为什么第一个代码运行缓慢?是否有机会优化链表的实现?
Thanks in advance
避免std::list
。这是一个双重链表,它对缓存非常不友好(节点随机分布在内存中),并且涉及很大的开销(每个元素2个指针)。所以每次你添加一些东西,列表分配2*sizeof(void*)+sizeof(int)
字节和额外的operator new
内存管理开销。
在算法的后面,当你要迭代这些值时,你实际上是在整个内存中跳跃,这进一步降低了速度。
2d数组没有这个问题,但是它确实浪费了一些内存。
我通常将邻接表表示为向量的向量。
std::vector<std::vector<int> > graph;
请注意,向量也可以在O(1)
中push_back
值(以及std::deque
,它可以更快地附加,但在遍历时较慢)。如果图被期望是密集的,那么邻接矩阵可能是一个更好的选择。
插入到列表中需要分配一个新节点。所以当你做6000次回推时,你必须做6000次内存分配。在数组的情况下,你根本不需要做任何分配,所以这要快得多。这就是完全不同的地方。
要展开这里的答案,请自己实现一个链表类,您将发现为什么它很慢。
可以做一些事情,比如实现一个包含容量值、大小值和指向实际列表中第一个节点的指针的列表。该指针实际上是一个动态数组,当size==capacity时,数组的大小会被调整,容量会增加一些因子(例如10)。
缺点是它被限制为2^(容量大小* CHAR_BIT) - 1个元素,而每次只分配节点需要更长的插入时间,理论上是无限数量的节点。在更快的列表实现的容量达到最大值之前,你很可能会耗尽内存,但这并不能保证,更不用说调整列表的大小通常会涉及到它的副本,所以容量最大值的限制会突然小得多。
链表通常很慢。它们有它们的用途,但是如果你需要更快的运行时间,找到一个更好的实现,使用不同的容器,比如std::vector,或者自己创建一个解决方案,尽管老实说标准容器做得很好。
- 建议在运行时将带有类实例的列表从c++导入qml
- 运行相同函数名称C++的多个类的列表
- 为什么每当我尝试运行此链接列表删除功能时都会收到分段错误错误?
- 如何使用模板生成常规参数列表并将其传递给运行时函数?
- 如何在函数运行时逐个显示列表项
- 是否有任何 C 函数或 API 来获取当前登录用户下运行的进程列表
- std :: list(双重链接列表)未知运行时错误
- 在任务管理器的应用程序选项卡中获取运行任务的列表
- 列表迭代器不可递增?- 运行时错误
- 如何在运行时显示QT中的字符串列表
- 初始值设定项列表程序运行良好,但直接赋值时无法正常工作
- 类链接列表模板运行时错误
- C++链表/多态性未运行列表函数
- 从整数列表中交叉检查整数运行时错误
- 声明运行时已知大小的 2D 数组的列表(或向量)
- 列表迭代器不可递增 - 运行时错误
- 运行时可用信号列表
- 使用运行时定义的字符串和列表的 Sprintf
- 运行列表的实现时出错
- 为什么我插入到STL列表运行缓慢