博客
关于我
vector构建邻接表和原始邻接表
阅读量:294 次
发布时间:2019-03-03

本文共 3467 字,大约阅读时间需要 11 分钟。

邻接表构造与遍历

在编程中,邻接表是一种常用的数据结构,用于表示图的边。它通过将每个节点的邻接信息存储在表中,使得节点的访问和遍历更加高效。以下将详细介绍如何使用邻接表构造图,并进行遍历操作。

1. 邻接表的构造

邻接表可以使用数组或向量来模拟。在本文中,我们将分别使用数组和向量两种方式来实现。

1.1 数组模拟邻接表

假设我们有 N 个节点,我们可以使用一个数组 s 来表示邻接表。每个节点 i 的邻接信息存储在 s[i] 中,具体包括以下结构:

struct st {
int to; // 结点编号
int w; // 权值
struct st *nx; // 指向下一个结点
};
ll *link; // 类型声明
s[N]; // 邻接表的表头

初始化时,我们需要为每个节点分配空间,并将其下一个结点指针初始化为 NULL

for (int i = 1; i <= n; i++) {
s[i].next = NULL;
}

然后,通过 add 函数添加边。add 函数会为指定的两个节点创建相应的邻接结点:

void add(int from, int to, int w) {
link p;
p = new ll;
p->to = to;
p->w = w;
p->nx = s[from].next;
s[from].next = p;
}

这里需要注意,由于 s 是一个数组,我们需要预先分配足够的空间来存储所有节点的邻接信息。

1.2 向量模拟邻接表

除了数组,向量在现代编程中更为常用,特别是考虑到其动态分配特性。在向量中,我们可以使用结构体 st 来存储每个邻接信息:

#include 
using namespace std;
struct st {
int to;
int w;
};
vector
s[N];

向量的初始化与数组类似,只需为每个节点清空邻接表:

for (int i = 1; i <= n; i++) {
s[i].clear();
}

添加边的逻辑与数组版本一致,只是通过向量的 push_back 方法实现:

void add(int from, int to, int w) {
st t;
t.to = to;
t.w = w;
s[from].push_back(t);
}

这种方式更加灵活,尤其是当节点数量不确定时。

2. 邻接表的遍历

邻接表的遍历可以通过深度优先搜索(DFS)或广度优先搜索(BFS)来实现。以下分别介绍这两种遍历方法。

2.1 深度优先搜索(DFS)

DFS通过递归的方式逐层访问节点,直到所有节点都被访问。实现时,可以使用递归函数,并使用一个标记数组 book 来记录已访问的节点:

void dfs(int x) {
book[x] = 1;
cout << x << " ";
link p;
p = s[x].next;
while (p) {
if (book[p->to] == 0) {
book[p->to] = 1;
dfs(p->to);
}
p = p->nx;
}
}

这种方法适用于稀疏图,递归深度较大的情况下可能会导致栈溢出。

2.2 广度优先搜索(BFS)

BFS通过队列来逐层访问节点,实现时可以使用队列数据结构。以下是 bfs 函数的实现:

void bfs(int x) {
link p;
int q[N];
int r = 0, f = 0;
book[x] = 1;
q[r++] = x;
while (r != f) {
int t = q[f++];
p = s[t].next;
while (p) {
if (book[p->to] == 0) {
book[p->to] = 1;
q[r++] = p->to;
}
p = p->nx;
}
}
}

这种方法在稠密图中表现更好,避免了递归深度的问题。

3. 示例代码

以下是完整的代码示例,展示了如何构造并遍历邻接表:

#include 
#include
using namespace std;
struct st {
int to;
int w;
};
vector
s[N];
void dfs(int x) {
book[x] = 1;
cout << x << " ";
vector
::iterator it;
it = s[x].begin();
while (it != s[x].end()) {
if (book[it->to] == 0) {
book[it->to] = 1;
dfs(it->to);
}
it++;
}
}
void bfs(int x) {
int q[n];
int r = 0, f = 0;
book[x] = 1;
q[r++] = x;
while (r != f) {
int t = q[f++];
vector
current = s[t];
for (int i = 0; i < current.size(); i++) {
if (book[current[i].to] == 0) {
book[current[i].to] = 1;
cout << current[i].to << " ";
}
q[r++] = current[i].to;
}
}
}
void add(int from, int to, int w) {
st t;
t.to = to;
t.w = w;
s[from].push_back(t);
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
s[i].clear();
}
for (int i = 1; i <= n - 1; i++) {
int x, y, w;
scanf("%d %d %d", &x, &y, &w);
add(x, y, w);
add(y, x, w);
}
cout << "邻接表" << endl;
for (int i = 1; i <= n; i++) {
cout << "[" << i << "] ";
for (auto p : s[i]) {
cout << p.to << " ";
}
cout << endl;
}
}

4. 总结

通过上述方法,我们可以轻松构造并遍历邻接表。无论是使用数组还是向量,核心逻辑保持一致,主要区别在于数据结构的选择和使用方式。理解邻接表的构造与遍历是掌握图算法的基础,后续的高级算法如最短路径、连通性检查等都会基于此进行扩展。

转载地址:http://trel.baihongyu.com/

你可能感兴趣的文章
Objective-C享元模式(Flyweight)
查看>>
Objective-C以递归的方式实现二叉搜索树算法(附完整源码)
查看>>
Objective-C内存管理教程和原理剖析(三)
查看>>
Objective-C实现 Greedy Best First Search最佳优先搜索算法(附完整源码)
查看>>
Objective-C实现 jugglerSequence杂耍者序列算法 (附完整源码)
查看>>
Objective-C实现 lattice path格子路径算法(附完整源码)
查看>>
Objective-C实现1000 位斐波那契数算法(附完整源码)
查看>>
Objective-C实现2 个数字之间的算术几何平均值算法(附完整源码)
查看>>
Objective-C实现2d 表面渲染 3d 点算法(附完整源码)
查看>>
Objective-C实现2D变换算法(附完整源码)
查看>>
Objective-C实现3n+1猜想(附完整源码)
查看>>
Objective-C实现3n+1猜想(附完整源码)
查看>>
Objective-C实现9x9乘法表算法(附完整源码)
查看>>
Objective-C实现9×9二维数组数独算法(附完整源码)
查看>>
Objective-C实现A*(A-Star)算法(附完整源码)
查看>>
Objective-C实现A-Star算法(附完整源码)
查看>>
Objective-C实现abbreviation缩写算法(附完整源码)
查看>>
Objective-C实现ABC人工蜂群算法(附完整源码)
查看>>
Objective-C实现activity selection活动选择问题算法(附完整源码)
查看>>
Objective-C实现AC算法(Aho-Corasick) 算法(附完整源码)
查看>>