用邻接表表示法编写有向图的邻接表和逆邻接表,并输出邻接表和逆邻接表。再用邻接表表示法编写无向图的邻接表和逆邻接表,并输出邻接表和逆邻接表。
时间: 2024-05-22 10:08:20 浏览: 21
邻接表是图的一种存储方式,它利用数组和链表相结合的方式来表示图。邻接表存储有向图和无向图的方式略有不同。
首先我们来看有向图的邻接表。假设有n个顶点和m条边,我们可以用一个数组a来存储所有的边,a[i]表示顶点i的出边集合,每个出边用一个结构体存储,包含指向的顶点和边的权值等信息。具体实现代码如下:
```
const int N = 100010;
struct Edge {
int v, w; // v表示指向的顶点编号,w表示边的权值
};
Edge a[N]; // 存储所有的边
int h[N], e[N], ne[N], idx; // h表示邻接表头,e表示边集合,ne表示指向下一条边的指针,idx表示当前边的编号
void add(int a, int b, int c) { // 添加一条从a到b权值为c的边
e[idx] = b, ne[idx] = h[a], h[a] = idx ++; // 将边插入邻接表中
}
int main() {
int n, m;
cin >> n >> m;
memset(h, -1, sizeof h); // 初始化邻接表头为-1
for (int i = 0; i < m; i ++ ) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c); // 添加一条从a到b权值为c的边
}
for (int i = 1; i <= n; i ++ ) { // 输出邻接表
printf("Vertex %d: ", i);
for (int j = h[i]; j != -1; j = ne[j]) {
printf("-> %d(w=%d) ", e[j], a[j].w);
}
puts("");
}
return 0;
}
```
接下来我们再看有向图的逆邻接表。逆邻接表存储每个顶点的入边集合。具体实现代码如下:
```
const int N = 100010;
struct Edge {
int v, w; // v表示指向的顶点编号,w表示边的权值
};
Edge a[N]; // 存储所有的边
int rh[N], re[N], rne[N], ridx; // rh表示逆邻接表头,re表示边集合,rne表示指向下一条边的指针,ridx表示当前边的编号
void add(int a, int b, int c) { // 添加一条从a到b权值为c的边
re[ridx] = b, rne[ridx] = rh[a], rh[a] = ridx ++; // 将边插入逆邻接表中
}
int main() {
int n, m;
cin >> n >> m;
memset(rh, -1, sizeof rh); // 初始化逆邻接表头为-1
for (int i = 0; i < m; i ++ ) {
int a, b, c;
cin >> a >> b >> c;
add(b, a, c); // 添加一条从a到b权值为c的边
}
for (int i = 1; i <= n; i ++ ) { // 输出逆邻接表
printf("Vertex %d: ", i);
for (int j = rh[i]; j != -1; j = rne[j]) {
printf("<- %d(w=%d) ", re[j], a[j].w);
}
puts("");
}
return 0;
}
```
接下来我们再来看无向图的邻接表。和有向图相比,无向图的邻接表要多存储一份反向边。具体实现代码如下:
```
const int N = 100010;
struct Edge {
int v, w; // v表示指向的顶点编号,w表示边的权值
};
Edge a[N]; // 存储所有的边
int h[N], e[N], ne[N], idx; // h表示邻接表头,e表示边集合,ne表示指向下一条边的指针,idx表示当前边的编号
void add(int a, int b, int c) { // 添加一条从a到b权值为c的边
e[idx] = b, ne[idx] = h[a], h[a] = idx ++; // 将正向边插入邻接表中
e[idx] = a, ne[idx] = h[b], h[b] = idx ++; // 将反向边插入邻接表中
}
int main() {
int n, m;
cin >> n >> m;
memset(h, -1, sizeof h); // 初始化邻接表头为-1
for (int i = 0; i < m; i ++ ) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c); // 添加一条从a到b权值为c的边
}
for (int i = 1; i <= n; i ++ ) { // 输出邻接表
printf("Vertex %d: ", i);
for (int j = h[i]; j != -1; j = ne[j]) {
printf("-> %d(w=%d) ", e[j], a[j].w);
}
puts("");
}
return 0;
}
```
最后我们再看无向图的逆邻接表。和有向图相比,无向图的逆邻接表也要多存储一份反向边。具体实现代码如下:
```
const int N = 100010;
struct Edge {
int v, w; // v表示指向的顶点编号,w表示边的权值
};
Edge a[N]; // 存储所有的边
int rh[N], re[N], rne[N], ridx; // rh表示逆邻接表头,re表示边集合,rne表示指向下一条边的指针,ridx表示当前边的编号
void add(int a, int b, int c) { // 添加一条从a到b权值为c的边
re[ridx] = b, rne[ridx] = rh[a], rh[a] = ridx ++; // 将正向边插入逆邻接表中
re[ridx] = a, rne[ridx] = rh[b], rh[b] = ridx ++; // 将反向边插入逆邻接表中
}
int main() {
int n, m;
cin >> n >> m;
memset(rh, -1, sizeof rh); // 初始化逆邻接表头为-1
for (int i = 0; i < m; i ++ ) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c); // 添加一条从a到b权值为c的边
}
for (int i = 1; i <= n; i ++ ) { // 输出逆邻接表
printf("Vertex %d: ", i);
for (int j = rh[i]; j != -1; j = rne[j]) {
printf("<- %d(w=%d) ", re[j], a[j].w);
}
puts("");
}
return 0;
}
```