【图论Graph Theory】链式前向星储存图与链式前向星的DFS,BFS

注:本文以 ( u , v ) (u, v) (u,v)表示从 u u u v v v有向边,本文所有图使用例题题意的图。

一、链式前向星:

1、什么是链式结构:

链式结构指的是在前一个元素的末位指向下一个元素的下标。一般使用结构体数组。

2、链式前向星是什么:

一般地,链式结构指向的是后面的元素,但是链式向星,指向的是前面的元素的下标。所以,链式前向星可被认为是向前的链式结构。

3、链式前向星的储存方式:

通常我们定义一个结构体 e d g e edge edge,内包括了 t t t(边的终点), w w w(可省,边的权值), n x t nxt nxt(下一个同起点边的下标)。用一个数组储存(注意:在无向图中,数组要开两倍空间)。

struct edge {
	int to, w, nxt;
} graph[size];

接着定义一个数组 h e a d [ ∣ V ∣ ] head[|V|] head[V],初始化为0(Linus系统下不初始化为乱码)
级每个点发出的最后一条边的下标,定义一个指针 h p p hpp hpp为零,每增加一条边。让hpp自增,然后更新 h e a d [ u ] head[u] head[u] u u u为新增边的起点)为 h p p hpp hpp。无向图只需增加两条权值为 w w w ( u , v ) (u, v) (u,v) ( v , u ) (v, u) (v,u)
我们给出链式前向星储存代码的样例:
例题:
第一行输入 n n n m m m,分别表示 ∣ V ∣ |V| V ∣ E ∣ |E| E
接着输入 m m m行,每行两个数 u u u v v v w w w,表示边的起点,终点和权值。

#include <iostream>
const int size = 100001;
using namespace std;
struct edge {
	int to, w, nxt;
} graph[size];
int head[size], hpp = 0;
void addEdge(int from, int to, int weight) {
	hpp++, graph[hpp].to = to, graph[hpp].w = w, graph[hpp].nxt = head[from];
	// 亦可写作graph[++hpp] = edge{w, to, head[from]};(C++11以上版本)
	head[from] = hpp;
}
int main() {
	int n, m;
	cin >> n >> m;
	fill(head, head + n + 1, 0); //初始化head数组,也可用for循环
	for (int i = 1; i <= m; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		addEdge(u, v, w);
	}
}

4、链式前向星遍历图:

原理:利用 h e a d head head数组,遍历每个点出发的边;输出结点即可
链式前向星的遍历代码直接给出:

for (int i = 1; i <= n; i++)
	for (int p = head[u]; p; p = graph[p].nxt) 
		cout << graph[p].to;

二、图的DFS:

图的DFS与路径DFS不大相同,图的DFS从结点开始(记为 r o o t root root),查找由 r o o t root root出发的路径的终点,以终点为 r o o t root root继续进行DFS。
求DFS(1)
链式前向星代码如下:

#include <iostream>
using namespace std;
const int size = 100001;
struct edge {
	int to, w, nxt;
} graph[size];
int head[size], hpp = 0;
void addEdge(int from, int to, int weight) {
	hpp++, graph[hpp].to = to, graph[hpp].w = w, graph[hpp].nxt = head[from];
	head[from] = hpp;
}
bool vis[size];
void dfs(int u) {
    if (vis[u]) return;
    vis[u] = true;
	cout << u;
    for (int p = head[u]; p; p = graph[p].nxt) 
		dfs(graph[p].to);
}
int main() {
	int n, m;
	cin >> n >> m;
	fill(head, head + n + 1, 0);
	memset(vis, 0, sizeof vis);
	for (int i = 1; i <= m; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		addEdge(u, v, w);
	}
	dfs(1);
}

邻接表代码如下:

#include <iostream>
const int size = 100001;
using namespace std;
vector <int> graph[size];
bool vis[size];
void dfs(int u) {
    if (vis[u]) return;
    vis[u] = true;
    cout << u;
    for (auto p: g[u]) dfs(p);
    //  C++11新特性,for (auto var: vectorName/setName) var为遍历所求得的值
}
int main() {
    int n, m;
    cin >> n >> m;
    while (m--) {
        int u, v;
        cin >> u >> v >> w;
        graph[u].push_back(v);
    }
    memset(vis, 0, sizeof vis);
    dfs(1);
}

三、图的BFS:

图的BFS与路径BFS基本相同,图的BFS从结点开始,将该结点压入队列中,队列可以用STL容器queue定义,先弹出队首元素(记为 r o o t root root),在查找由 r o o t root root出发的路径的终点,将终点压入队列,直到队列为空。
求BFS(1)
邻接表代码如下:

#include <iostream>
#include <queue>
const int size = 100001
using namespace std;
vector <int> graph[size];
bool vis[size]
queue <int> q;
void bfs(int u) {
    q.push(u);
    while (!q.empty()) {
        int v = q.front();
        q.pop();
        if (vis[v]) continue;
        vis[v] = true;
        cout << v;
        for (auto p: g[v]) q.push(p);
    }
}
int main() {
    int n, m;
    cin >> n >> m;
    while (m--) {
        int u, v, w;
        cin >> u >> v;;
        g[u].push_back(v);
    }
    memset(vis, 0, sizeof vis);
    bfs(1);
}

链式前向星代码:

#include <iostream>
using namespace std;
const int size = 100001;
struct edge {
	int to, w, nxt;
} graph[size];
int head[size], hpp = 0;
void addEdge(int from, int to, int weight) {
	hpp++, graph[hpp].to = to, graph[hpp].w = w, graph[hpp].nxt = head[from];
	head[from] = hpp;
}
bool vis[size];
queue <int> q;
void bfs(int u) {
    q.push(u);
    while (!q.empty()) {
        int v = q.front();
        q.pop();
        if (vis[v]) continue;
        vis[v] = true;
        cout << v;
    	for (int p = head[u]; p; p = graph[p].nxt) 
			q.push(graph[p].to);
    }
}
int main() {
	int n, m;
	cin >> n >> m;
	fill(head, head + n + 1, 0); //初始化head数组,也可用for循环
	memset(vis, 0, sizeof vis);
	for (int i = 1; i <= m; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		addEdge(u, v, w);
	}
	bfs(1);
}

OJ例题:洛谷—查找文献

题解,本题就是要求图的DFS和BFS,体重一大坑点就是要求排序,所以可以sort每一个vector。
题解:

#include <bits/stdc++.h>
using namespace std;
vector <int> graph[100001];
bool vis[100001];
void dfs(int u) {
    if (vis[u]) return;
    vis[u] = true;
    cout << u << " ";
    for (auto p: graph[u]) dfs(p);
}
queue <int> q;
void bfs(int u) {
    q.push(u);
    while (!q.empty()) {
        int v = q.front();
        q.pop();
        if (vis[v]) continue;
        vis[v] = true;
        cout << v << " ";
        for (auto p: graph[v]) q.push(p);
    }
}
int main() {
    int n, m;
    cin >> n >> m;
    while (m--) {
        int u, v;
        cin >> u >> v;
        graph[u].insert(v);
    }
    for (int i = 1; i <= n; i++) sort(graph[i].begin(), graph[i].end());
    memset(vis, 0, sizeof vis);
    dfs(1);
    cout << endl;
    memset(vis, 0, sizeof vis);
    bfs(1);
}

文字较多,如有错误,请私信作者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SZSKszmn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值