在 C++ 中将邻接列表转换为有向无环图的邻接矩阵
Converting an Adjacency List to a an Adjacency Matrix for a Directed Acyclic Graph in C++
我试图在 C++ 中使用 DFS 实现拓扑排序,但我被困在将邻接列表转换为邻接矩阵的过程中。我遇到的问题是,对于 DAG,每个节点可能没有传出边,所以我不能简单地创建一个邻接列表,它具有这样一个对无向图有效的函数:-
void addEdge(list <int> l,int u,int v)
{
l[u].push_back(v);
l[v].push_back(u);
}
因此,如果您能提供一种为 DAG 实现邻接列表的方法并建议将其转换为邻接矩阵的代码,那将是非常有帮助的。高度赞赏避免使用结构和 类 的实现。
在这种情况下,您只需要添加一条边。
void addEdge (vector <list <int>> l, int u, int v)
{
l[u].emplace_back (v); // u directs to v
}
运行这个函数对所有的边对,你的邻接表l
就完成了。
现在,创建一个邻接矩阵作为二维方形数组,将所有元素初始化为 0
。
int mat[V][V] = {}; // V is the total number of vertices in the graph
现在,只需遍历邻接表并为每条边 (u, v)
设置 mat[u][v] = 1
,表示顶点 u
指向顶点 v
.
for (int u = 0; u < V; ++u)
for (auto v: l[u])
mat[u][v] = 1;
确保 l
已预先分配至少 V
个元素的内存,以免出现分段错误:
vector <list <int>> l(V);
实际上,您可以根据邻接表实现 DFS(以及拓扑排序)。事实上,邻接表是表示 DFS 图的最有效方式(见下文)。
DFS 所需要的只是能够查看哪些顶点与当前顶点相邻:
vector<list<int>> graph;
vector<bool> visited;
void dfs(int current) {
visited[current] = true;
// iterating over adjacent vertices
for (int other : graph[current])
if (not visited[other])
dfs(other);
}
所以你的拓扑排序看起来像这样:
enum class status { unseen, entered, left };
vector<list<int>> graph;
vector<status> visited;
vector<int> topsorted;
void topsort_impl_dfs(int current) {
visited[current] = status::entered;
// iterating over adjacent vertices
for (int other : graph[current]) {
if (visited[other] == status::unseen) {
dfs(other);
} else if (visited[other] == status::entered) {
// found a loop, not a DAG
}
// ignoring vertices with status::left, because they're already processed
}
topsorted.push_back(current);
visited[current] = status::left;
}
void topsort() {
fill(visited.begin(), visited.end(), status::unseen);
topsorted.clear();
topsorted.reserve(VERTEX_COUNT);
for (int v = 0; v < VERTEX_COUNT; ++v) {
if (visited[v] == status::unseen) {
topsort_impl_dfs(v);
}
}
// vertices are added to topsorted in an inverse order
reverse(topsorted.begin(), topsorted.end());
}
如果我们将 DFS 的实现与邻接矩阵和列表进行比较,就会得到(V
是顶点数,E
是边数):
对于邻接矩阵:在每次调用dfs(v)
时(每个顶点调用一次,总共V
)我们将迭代相应的矩阵行(V
迭代)。所以我们得到 O(V*V)
复杂度。
对于邻接列表:对于每个顶点,我们只迭代相邻的顶点。从那个角度分析这个更难,因为顶点的相邻顶点数不同。但我们可以这样看:对于每个顶点,我们迭代所有出边。每条边只有一个起点,因此,我们总共进行 E
次迭代,复杂度为 O(E)。它并不比第一种方式差,因为在最坏的情况下(完整图表)我们将有 E = O(V*V)
.
因此,如果您的图表有 V=1000 E=1000
,那么第二种方式将快约 1000 倍。
我试图在 C++ 中使用 DFS 实现拓扑排序,但我被困在将邻接列表转换为邻接矩阵的过程中。我遇到的问题是,对于 DAG,每个节点可能没有传出边,所以我不能简单地创建一个邻接列表,它具有这样一个对无向图有效的函数:-
void addEdge(list <int> l,int u,int v)
{
l[u].push_back(v);
l[v].push_back(u);
}
因此,如果您能提供一种为 DAG 实现邻接列表的方法并建议将其转换为邻接矩阵的代码,那将是非常有帮助的。高度赞赏避免使用结构和 类 的实现。
在这种情况下,您只需要添加一条边。
void addEdge (vector <list <int>> l, int u, int v)
{
l[u].emplace_back (v); // u directs to v
}
运行这个函数对所有的边对,你的邻接表l
就完成了。
现在,创建一个邻接矩阵作为二维方形数组,将所有元素初始化为 0
。
int mat[V][V] = {}; // V is the total number of vertices in the graph
现在,只需遍历邻接表并为每条边 (u, v)
设置 mat[u][v] = 1
,表示顶点 u
指向顶点 v
.
for (int u = 0; u < V; ++u)
for (auto v: l[u])
mat[u][v] = 1;
确保 l
已预先分配至少 V
个元素的内存,以免出现分段错误:
vector <list <int>> l(V);
实际上,您可以根据邻接表实现 DFS(以及拓扑排序)。事实上,邻接表是表示 DFS 图的最有效方式(见下文)。
DFS 所需要的只是能够查看哪些顶点与当前顶点相邻:
vector<list<int>> graph;
vector<bool> visited;
void dfs(int current) {
visited[current] = true;
// iterating over adjacent vertices
for (int other : graph[current])
if (not visited[other])
dfs(other);
}
所以你的拓扑排序看起来像这样:
enum class status { unseen, entered, left };
vector<list<int>> graph;
vector<status> visited;
vector<int> topsorted;
void topsort_impl_dfs(int current) {
visited[current] = status::entered;
// iterating over adjacent vertices
for (int other : graph[current]) {
if (visited[other] == status::unseen) {
dfs(other);
} else if (visited[other] == status::entered) {
// found a loop, not a DAG
}
// ignoring vertices with status::left, because they're already processed
}
topsorted.push_back(current);
visited[current] = status::left;
}
void topsort() {
fill(visited.begin(), visited.end(), status::unseen);
topsorted.clear();
topsorted.reserve(VERTEX_COUNT);
for (int v = 0; v < VERTEX_COUNT; ++v) {
if (visited[v] == status::unseen) {
topsort_impl_dfs(v);
}
}
// vertices are added to topsorted in an inverse order
reverse(topsorted.begin(), topsorted.end());
}
如果我们将 DFS 的实现与邻接矩阵和列表进行比较,就会得到(V
是顶点数,E
是边数):
对于邻接矩阵:在每次调用
dfs(v)
时(每个顶点调用一次,总共V
)我们将迭代相应的矩阵行(V
迭代)。所以我们得到O(V*V)
复杂度。对于邻接列表:对于每个顶点,我们只迭代相邻的顶点。从那个角度分析这个更难,因为顶点的相邻顶点数不同。但我们可以这样看:对于每个顶点,我们迭代所有出边。每条边只有一个起点,因此,我们总共进行
E
次迭代,复杂度为 O(E)。它并不比第一种方式差,因为在最坏的情况下(完整图表)我们将有E = O(V*V)
.
因此,如果您的图表有 V=1000 E=1000
,那么第二种方式将快约 1000 倍。