图(Graph)数据结构详解:基本概念、表示方法、遍历算法及应用
创作时间:
作者:
@小白创作中心
图(Graph)数据结构详解:基本概念、表示方法、遍历算法及应用
引用
CSDN
1.
https://m.blog.csdn.net/weixin_44929475/article/details/144497450
图(Graph)是一种非常灵活且强大的数据结构,用于表示实体之间的复杂关系。在图结构中,数据由一组节点(或称为顶点)和连接这些节点的边组成。图可以用于表示社交网络、交通网络、网络路由等场景。本文将详细介绍图的基本概念、表示方法、遍历算法以及算法应用。
1. 基本概念
- 节点(Vertex):图中的一个点,代表一个对象或实体。
- 边(Edge):连接两个节点的线,代表节点之间的关系。
- 邻接(Adjacency):如果两个节点之间有边相连,则称这两个节点是邻接的。
- 路径(Path):一系列相连的边,从一个节点开始,经过若干个中间节点,到达另一个节点。
- 环(Cycle):起点和终点是同一个节点的路径。
- 连通图(Connected Graph):图中任意两个节点之间都存在路径。
- 强连通图(Strongly Connected Graph):有向图中,任意两个节点之间都存在有向路径。
- 树(Tree):一种特殊的图,没有环,且任意两个节点之间只有一条路径。
2. 表示方法
2.1 邻接矩阵(Adjacency Matrix):
- 使用一个二维数组来表示图,数组的行和列代表节点,元素值表示节点之间是否有边。
- 适用于稠密图,即边的数量接近节点数量平方的图。
2.2 邻接表(Adjacency List):
- 使用一个链表数组来表示图,每个链表包含与该节点相连的所有节点。
- 适用于稀疏图,即边的数量远小于节点数量平方的图。
3. 遍历算法
3.1 深度优先搜索(Depth-First Search, DFS):
- 类似于树的前序遍历,使用栈(递归或显式栈)来实现。
- 从任意节点开始,尽可能深地搜索图的分支。
public class GraphDFS {
private int V; // 节点数
private LinkedList<Integer> adj[]; // 邻接表
// 构造函数
@SuppressWarnings("unchecked")
public GraphDFS(int v) {
V = v;
adj = new LinkedList[v];
for (int i = 0; i < v; ++i)
adj[i] = new LinkedList();
}
// 添加边
public void addEdge(int v, int w) {
adj[v].add(w); // 添加w到v的邻接表
}
// DFS算法
public void DFS(int v) {
boolean visited[] = new boolean[V];
// 调用递归的DFS函数
DFSUtil(v, visited);
}
// 递归的DFS函数
void DFSUtil(int v, boolean visited[]) {
// 标记当前节点为已访问
visited[v] = true;
System.out.print(v + " ");
// 递归访问所有未访问的邻接节点
for (int i = 0; i < adj[v].size(); i++) {
int n = adj[v].get(i);
if (!visited[n])
DFSUtil(n, visited);
}
}
// 测试DFS算法
public static void main(String[] args) {
GraphDFS g = new GraphDFS(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);
System.out.println("DFS starting from vertex 2 : ");
g.DFS(2);
}
}
3.2 广度优先搜索(Breadth-First Search, BFS):
- 类似于树的层序遍历,使用队列来实现。
- 从任意节点开始,逐层遍历图中的节点。
import java.util.*;
public class GraphBFS {
private int V; // 节点数
private LinkedList<Integer> adj[]; // 邻接表
// 构造函数
@SuppressWarnings("unchecked")
public GraphBFS(int v) {
V = v;
adj = new LinkedList[v];
for (int i = 0; i < v; ++i)
adj[i] = new LinkedList();
}
// 添加边
public void addEdge(int v, int w) {
adj[v].add(w); // 添加w到v的邻接表
}
// BFS算法
public void BFS(int s) {
boolean visited[] = new boolean[V];
// 创建一个队列用于BFS
Queue<Integer> queue = new LinkedList<>();
// 标记起始节点为已访问并入队
visited[s] = true;
queue.add(s);
while (queue.size() != 0) {
// 出队一个节点
s = queue.poll();
System.out.print(s + " ");
// 访问其所有未访问的邻接节点
for (int i = 0; i < adj[s].size(); ++i) {
int n = adj[s].get(i);
if (!visited[n]) {
visited[n] = true;
queue.add(n);
}
}
}
}
// 测试BFS算法
public static void main(String[] args) {
GraphBFS g = new GraphBFS(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);
System.out.println("BFS starting from vertex 2 : ");
g.BFS(2);
}
}
4. 算法应用
- 最短路径问题:
- Dijkstra算法:适用于带有非负权重的图。
- Bellman-Ford算法:适用于带有负权重的图。
- Floyd-Warshall算法:计算图中所有节点对的最短路径。
- 最小生成树问题:
- Kruskal算法:贪心算法,适用于边的集合是无序的。
- Prim算法:贪心算法,适用于节点的集合是无序的。
- 网络流问题:
- Ford-Fulkerson方法:计算网络中的最大流。
- Edmonds-Karp算法:使用BFS来实现Ford-Fulkerson方法。
热门推荐
想摆脱水肿?网友热议10大利尿食物 第1名你天天在喝
口臭、牙齦流血,牙膏該怎麼選?醫師教你聰明選牙膏,維持牙齒健康
经销商综合评价第一,奔驰做了什么?
关羽在三国演义中的十大经典故事
鱼竿调性怎么选才合理?
自闭症孩子的八个特征
微波炉加热容器选择及注意事项
创业公司分红指南:机制、比例与流程全解析
倪海厦论中医:白血病(附解读)
墨子《兼爱》:兼相爱,交相利
普陀山在哪里的?位于哪个省哪个城市?普陀山的位置地图与简介
肩膀痛去医院挂什么科
异丙醇(2B类致癌物)毒性的隐匿威胁:不容忽视的潜在危险
中国农科院植保所发现提高绿僵菌杀虫活性的新病毒
2025年华侨生联考报名材料有什么?该如何准备?
锻炼的最佳时间不是“天刚亮”而是这个时间 助眠又延寿!
最佳“降压运动”是这三种,一次几分钟就管用,不是跑步、走路
如何设置合理的止损止盈策略?止损止盈对投资风险管理有何作用?
大熊猫馆2日重新开放 “萌兰”的家发生了大变化
如何检查房屋质量并进行及时的维修处理?这种房屋质量检查如何保障居住安全?
马雷斯卡:帕尔默可以出战热刺 现在恩佐总是处于正确的位置
震惊!80%的猫难逃肾衰竭,如何拯救?
流感高发期,抗流感药怎么选?玛巴洛沙韦VS奥司他韦,有何不同?
《维纳斯的诞生》中惊艳世人的女神到底是谁?
拔罐起水泡怎么恢复快
一文读懂Windows本地账户、管理员账户和标准账户
administrator账户:全面解析与管理指南
黄金与美元的关联关系及其对汇率市场的影响
假体隆鼻用哪种材料好?隆鼻术后注意事项有哪些?
念两处风情,万重烟水。