在c++中使用STL创建邻接表的有效方法是什么?
What is an efficient way to create an adjacency list using STL in C++?
我目前使用的向量的向量如下:
typedef pair<int, int> vertex;
vector < vector<vertex> > adj_list(n); // n is number of vertices
// Input graph
for (int i = 0; i < edges; i++ )
{
cin >> source >> target >> weight;
vertex v(target, weight);
adj_list[source].push_back(v);
}
是list的向量,即
vector < list<vertex> > adj_list(n);
一个更好的选择?如果是,为什么?我主要关心的是高效地创建邻接表,并能够快速读取连接到特定顶点的所有顶点,以实现Dijkstra的算法。
我将使用std::deque<>,因为您很可能不需要从中间删除元素(这就是为什么有人想要使用std::list<>)。它应该比std::vector<>或std::list<>更有效。拥有连续的内存(vector)和可移动的元素(list)是有代价的——对vector和指针解引用进行大小调整/对list进行分散内存。
参见:http://www.gotw.ca/gotw/054.htm
请注意,如果您的目标是算法竞赛,那么您可能会惊讶于这种基于STL的数据结构可以占用多少内存。
您的需求是快速插入和快速迭代。渐近地,vector<vector<T> >
和vector<list<T> >
之间没有差异:
-
list<T>
是一个双链表,因此每次插入需要O(1)
时间,每个元素迭代需要O(1)
时间。 -
vector<T>
是一个数组,每次插入需要O(1)
(平摊)时间[1],每个元素迭代需要O(1)
时间。
操作的常量可能不同,但这是您必须通过分析找出的东西。
然而,空间效率将有利于vector<vector<T> >
,因为vector<list<T> >
中的每个元素也携带一个向前和向后指针。因此,您可能希望使用vector<vector<T> >
,但在某种程度上避免在常见情况下的重新分配(以节省时间),但不要保留太多(以节省空间)。
对于外部向量,你可以直接调用.reserve(n)
,其中n
是图中顶点的数量。
对于内部向量,这有点困难,它实际上取决于您的数据如何馈送到该过程。
[1] vector<T>
的实现应该在每次重新分配时将其容量翻倍,因此重新分配所花费的时间为O(1+2+4+...+n/4+n/2+n) = O(n(1/n+2/n+4/n+...+1/4+1/2+1)) <= O(1+1/2+1/4+...)) = O(2n)
。因此分布在n
元素上,插入需要O(1)
(平摊)时间。
为图形创建邻接表的最佳方法是使用"forward list"(考虑到你的语言是c++)。更多参考请访问https://www.geeksforgeeks.org/forward-list-c-set-1-introduction-important-functions/
请阅读下面的代码以了解"转发列表"的说明。注意:-在阅读代码之前,请正确理解STL库为"forward list"提供的实用程序函数。
/* The code has been designed to give output only if ENTER key is pressed,
before that it'll keep
recieving inputs from the user. So provide all your inputs in one line
seperated by whitespaces. */
/* This is the implementation of DFS */
#include<iostream>
#include<forward_list>
using namespace std;
class graph{
private:
int noOfVertices;
forward_list<int> *adj;
void dfsUtil(int v, bool *visited);
public:
graph(int v);
void addEdge(int s, int d);
void dfs(int startVertex);
};
graph::graph(int v){
noOfVertices = v;
adj = new forward_list<int>[noOfVertices];
}
void graph::addEdge(int s, int d){
adj[s].push_front(d);
}
void graph::dfs(int startVertex){
bool *visited = new bool[noOfVertices];
for(int i = 0 ; i < noOfVertices ; i++){
visited[i] = false;
adj[i].reverse();
}
dfsUtil(startVertex, visited);
}
void graph::dfsUtil(int v, bool *visited){
forward_list<int>::iterator i;
visited[v] = true;
cout << v << " ";
for(i = adj[v].begin() ; i != adj[v].end() ; i++){
if(!visited[*i])
dfsUtil(*i, visited);
}
}
int main(){
int v, s, d;
cin >> v;
graph g(v);
while(cin.peek() != 'n')
{
cin >> s >> d;
g.addEdge(s, d);
}
g.dfs(2);
}
- 在C++中初始化向量映射的最有效方法
- 将此布尔值传递给此函数的最有效方法是什么?
- 比较C++变量的最有效方法
- 在 c++ 中解决段树以外的范围查询的有效方法是什么?
- 存储变量的更有效方法是什么?
- 确保套装新鲜度的有效方法
- 当映射包含字符串向量作为值时,从值中获取键的有效方法
- 映射唯一值和重复值的有效方法.可以访问键或值的位置
- 在C++事务之间存储大量字符数据的有效方法
- 在unordered_multimap中精确迭代一次每个键的有效方法
- 一种将 Dart 中的字节数据转换为 C++ 中的无符号字符*的有效方法?
- 检查两个向量是否并行的最有效方法
- 从浮点数中删除小数部分但保留类型的有效方法
- 传递非泛型函数的最有效方法是什么?
- 按升序打印矢量的所有元素直到它为空而没有重复项的最有效方法是什么?
- 创建字符串数组的有效方法
- 返回一个引用C++中另一个类对象的对象的有效方法
- C++去除前x个元素的有效方法,在不改变向量大小的情况下将第x+1个元素推到第一个
- 将一种数据类型的向量复制到同一数据类型的结构向量中的有效方法是什么
- 从std::map值中获取密钥的有效方法