繁体   English   中英

C ++中向量与列表的图形表示

[英]Graph representation with vectors vs lists in C++

因此,我遇到了编程竞赛的问题,涉及在不同的图形上运行许多DFS。

首先,我将图(邻接列表表示)表示为集合的向量:

vector< set<int> > graph;

还要在每次使用空集时根据给定的节点数初始化图:

set<int> tmpSet;

然后像这样初始化它:

for(int j=0;j<N;j++)//N was the number of nodes needed for the graph
   graph.push_back(tmpSet);

和我用

graph.clear();

每次清空图表。

之后要插入边缘,我使用了std :: set的插入功能。

//Insert directed edge from u to v
graph[u].insert(v);
graph[v].insert(u);

结果是程序消耗了太多内存,并且太慢而无法通过测试。 使用push_back函数的std :: list也发生了相同的事情,这是一个恒定时间的操作。 然后,当我更改为std :: vector时,内存消耗变得最小,并且我在3秒内通过了测试,而std :: set和std :: list甚至在20秒内都无法通过它们。

我的问题是,这与释放内部集合和列表的空间有关,但是向量如何表现出不同?

所以我的问题是,是否有人可以解释为什么会这样,所以我可以更好地理解stl容器在另一个容器中有一个容器的情况下的行为。

编辑:一些额外的信息:节点的数量大约为N = 3000,测试的数量超过1000。这意味着我必须创建超过1000个全部包含在变量“图”中的图。 我也知道set在O(lgn)时插入向量,而list在O(1)中插入,所以我理解为什么set 比vector花费一点时间。 但是,为什么std :: list也失败了? 还让我提到设置和列表以100Mb的内存使用量完成,而向量以3Mb的存储量完成

好的最终编辑,这是我的代码,以准确显示我如何使用图形(列表版本)。 程序中的其他任何地方都不会释放内存或更改图形数据。

vector< list<int> > graph;
list<int> tmpList;
int T; //num of test cases
int N; //num of nodes
int M; //num of edges
int main ()
{
    int u,v;
    scanf("%d",&T);//Read test cases
    for(int i=0;i<T;i++){

        scanf("%d %d",&N,&M);//Read number of nodes and number of edges
        for(int j=0;j<N;j++)
            graph.push_back(tmpList);

        for(int j=0;j<M;j++){
            scanf("%d %d",&u,&v);//Read edge from u to v
            graph[u].push_back(v);
            graph[v].push_back(u);
        }
        dfs();
        graph.clear();
    }
}

当您使用std::set来保存相邻节点号时,您会插入并以对数时间获取元素,这很慢。 但是,当您使用std::vector insert(push_back)并获取元素是在固定时间内完成的,因此时间上的差异。 因此,当您不需要在set中找到某些元素时,应使用std::vector ,否则应使用std::set

std::liststd::vector之间的差异可能是由于功能clear 对于list它是线性的,但对于vector它是雾化的常数。

订购一套。 根据您提供的函子,可以保证按特定顺序保留。 无论您添加或删除哪些元素(除非添加重复项,否则都不允许在集合中进行添加),将始终对其进行排序。

向量仅具有您明确指定的顺序。 向量中的项目是放置它们的位置。 如果您将它们乱序放置,则说明它们乱七八糟。 您现在需要对容器进行排序以将它们放回原处。

诚然,集合具有相对有限的用途。 通过适当的纪律,可以将项目插入向量并保持其有序。 但是,如果您不断地从容器中插入和移除项目,vector将会遇到很多问题。 因为它实际上只是一个数组,所以它将进行很多元素的复制/移动等等。

将项目插入向量中所花费的时间与向量中已经存在的项目数成正比。 将项目插入集合所需的时间与项目数的对数成正比。 如果项目数量很大,那就有很大的不同。 Log(100,000)为5; 这是一个重大的速度改进。 删除也一样。

但是,如果在初始化时一次完成所有插入操作,那么就没有问题。 您可以将所有内容插入向量中,对其进行排序(一次支付该价格),然后对排序后的向量使用标准算法来查找元素并遍历排序后的列表。 尽管对集合元素的迭代并非完全缓慢,但对向量进行迭代却更快。

因此,在某些情况下,排序后的向量会击败集合。 话虽如此,除非您知道这样做是必要的,否则您真的不应该为这种优化而费心。 因此,除非您对正在编写的系统类型有经验(因此知道您需要这种性能)或手头有可能告诉您需要向量而不是集合的分析数据,否则请使用集合。

通常,对性能问题的最佳答案是为您的用例描述这两种实现,并查看哪种更快。

通常,如果您在数据结构中插入了数据(而不是在末尾),那么vector可能会比较慢,否则,在大多数情况下,如果仅出于数据位置问题,vector的性能可能会优于list,这意味着如果两个元素如果在数据集中相邻,则在内存中相邻,那么下一个元素将已经在处理器的高速缓存中,而不必将内存分页到高速缓存中。

还要记住,向量的空间开销是恒定的(3个指针),而列表的空间开销是为每个元素支付的,这也减少了可以驻留在缓存中的完整元素的数量(数据加上开销)。任何一次。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM