【发布时间】:2022-11-18 07:40:16
【问题描述】:
作为解决更大问题的一部分,即寻找最大流量问题的解决方案。在我实现 relabel-to-front 算法时,我遇到了一个我没有预料到的性能瓶颈。
存储图数据的一般结构如下:
struct edge{
int destination;
int capacity;
};
struct vertex{
int e_flow;
int h;
vector<edge> edges;
};
算法的细节对问题来说并不那么重要。在解决方案的主循环中,我遍历了除源和汇之外的所有顶点。如果在某个时候对顶点进行了更改,那么该顶点将放在列表的前面,并且迭代会从头开始。直到到达列表的末尾,我们终止。这部分现在看起来如下
//nodes are 0..nodeCount-1 with source=0 and sink=nodeCount-1
vector<int> toDischarge(nodeCount-2,0);
for(int i=1;i<sink;i++){
toDischarge[i-1]=i;
}//skip over source and sink
//custom pointer to the entry of toDischarge we are currently accessing
int point = 0;
while(point != nodeCount-2){
int val = toDischarge[point];
int oldHeight = graph[val].h;
discharge(val, graph, graph[val].e_flow);
if(graph[val].h != oldHeight){
rotate(toDischarge.begin(), toDischarge.begin()+point, toDischarge.begin()+point+1);
//if the value of the vertex has changed move it to the front and reset pointer
point = 0;
}
point++;
}
我尝试在矢量解决方案之前使用 std::list 数据结构,但速度甚至更慢,尽管从概念上讲这对我来说没有意义,因为(重新)移动列表中的元素应该很容易。经过一些研究,我发现由于列表的缓存问题,它的性能可能非常糟糕。
即使使用矢量解决方案,我也使用 valgrind 做了一些基本的基准测试并得到了以下结果。
如果我理解正确,那么超过 30% 的执行时间都花在了向量元素访问上。
我尝试过的另一个解决方案是将该迭代所需的顶点复制到一个变量中,因为它被多次访问,但性能更差,因为我认为它也在复制整个边缘列表。
什么数据结构可以提高这些操作的总体性能?如果有帮助的话,我也对其他用于存储图形数据的数据结构感兴趣。
【问题讨论】:
标签: c++ list vector data-structures