【数据结构-图】

ops/2025/3/6 3:04:05/

在这里插入图片描述
💖💝亲亲, 创作不易 看完点点专注呀♥❤💕💞

【图】

  • 目录:
      • 图的基本概念与表示方法知识点总结及示例
        • 1. 图的定义
        • 2. 无向图
        • 3. 有向图
        • 4. 图的邻接矩阵表示
        • 5. 图的邻接表表示
      • 1. 图的邻接矩阵表示
        • 有向图邻接矩阵实现
        • 无向图邻接矩阵实现
      • 2. 图的邻接表表示
        • 有向图邻接表实现
        • 无向图邻接表实现
      • 代码解释
      • 复杂度分析
      • 完全图
        • 1. 定义
        • 2. 边的数量
        • 3. 特点
      • 示例
        • 无向完全图示例
        • 有向完全图示例
      • 代码实现(Python)
      • 代码解释
      • 1. 邻接矩阵
        • 知识点总结
        • 代码示例(Python)
      • 2. 邻接表
        • 知识点总结
        • 代码示例(Python)
      • 3. 邻接多重表(主要用于无向图)
        • 知识点总结
        • 代码示例(Python)
      • 4. 十字链表(主要用于有向图)
        • 知识点总结
        • 代码示例(Python)
      • 深度优先搜索(DFS)
        • 知识点总结
        • 代码示例(Python,使用邻接表存储图)
      • 广度优先搜索(BFS)
        • 知识点总结
        • 代码示例(Python,使用邻接表存储图)
      • 总结

目录:

图的基本概念与表示方法知识点总结及示例

1. 图的定义
  • 知识点总结图(Graph)是由顶点(Vertex)的集合和边(Edge)的集合组成的一种数据结构,通常用 G = ( V , E ) G=(V, E) G=(V,E) 表示,其中 V V V 是顶点的有限非空集合, E E E 是边的集合,边表示顶点之间的关系图可以用来模拟各种现实世界中的关系,如社交网络、交通网络等。
  • 示例在一个社交网络中,每个人可以看作是图中的一个顶点,人与人之间的好友关系可以看作是图中的边。假设有三个人 A、B、C,A 和 B 是好友,B 和 C 是好友,那么这个社交网络就可以用一个包含三个顶点(A、B、C)和两条边(A - B,B - C)的图来表示。
2. 无向图
  • 知识点总结无向图中的边没有方向,即如果顶点 u u u 和顶点 v v v 之间有一条边,那么可以从 u u u v v v,也可以从 v v v u u u,边用无序对 ( u , v ) (u, v) (u,v) 表示。无向图常用于表示对称关系,如朋友关系、道路连接等
  • 示例

城市之间的道路连接可以用无向图来表示。假设有三个城市 A、B、C,城市 A 和城市 B 之间有一条双向道路,城市 B 和城市 C
之间也有一条双向道路。那么可以用一个无向图来表示这个道路网络,其中顶点 A、B、C 分别代表三个城市,边 ( A , B ) (A, B) (A,B) ( B , C ) (B, C) (B,C) 分别代表两条道路。

在这里插入图片描述

3. 有向图
  • 知识点总结有向图中的边是有方向的,每条边都有一个起始顶点和一个终止顶点,用有序对 ⟨ u , v ⟩ \langle u, v\rangle u,v 表示从顶点 u u u 到顶点 v v v 的一条有向边。有向图常用于表示非对称关系,如网页链接、任务依赖关系等
  • 示例:网页之间的链接关系可以用有向图来表示。假设有三个网页 A、B、C,网页 A 中有一个链接指向网页 B,网页 B 中有一个链接指向网页 C。那么可以用一个有向图来表示这个网页链接网络,其中顶点 A、B、C 分别代表三个网页,有向边 ⟨ A , B ⟩ \langle A, B\rangle A,B ⟨ B , C ⟩ \langle B, C\rangle B,C 分别代表两个链接。
    在这里插入图片描述
4. 图的邻接矩阵表示
  • 知识点总结:邻接矩阵是一个二维数组,对于一个有 n n n 个顶点的图,矩阵的大小为 n × n n\times n n×n。如果顶点 i i i 和顶点 j j j 之间有边相连,则矩阵中第 i i i 行第 j j j 列的元素为 1(或边的权重),否则为 0。邻接矩阵的优点是可以快速判断两个顶点之间是否有边相连,缺点是空间复杂度较高,为 O ( n 2 ) O(n^2) O(n2)
  • 示例:对于一个有 4 个顶点的无向图,其邻接矩阵如下:
列1列2列3列4列5
00110
11.01.0
21010
30010

这个邻接矩阵表示顶点 0 和顶点 1、2 之间有边相连,顶点 1 和顶点 0、2 之间有边相连,顶点 2 和顶点 0、1、3 之间有边相连,顶点 3 和顶点 2 之间有边相连。

5. 图的邻接表表示
  • 知识点总结:邻接表是一个数组,数组的每个元素是一个链表,数组的每个元素对应一个顶点,链表中存储与该顶点相邻的顶点。邻接表的优点是空间复杂度较低,为 O ( V + E ) O(V + E) O(V+E),其中 V V V 是顶点数, E E E 是边数,缺点是判断两个顶点之间是否有边相连的时间复杂度较高,为 O ( d e g r e e ( u ) ) O(degree(u)) O(degree(u)),其中 d e g r e e ( u ) degree(u) degree(u) 是顶点 u u u 的度。
  • 示例:对于上述有 4 个顶点的无向图,其邻接表表示如下:
  • 顶点 0:1 -> 2->3
  • 顶点 1:0 -> 2
  • 顶点 2:0 -> 1 -> 3
  • 顶点 3:2
    这个邻接表表示顶点 0 与顶点 1、2 相邻,顶点 1 与顶点 0、2 相邻,顶点 2 与顶点 0、1、3 相邻,顶点 3 与顶点 2 相邻。

在这里插入图片描述

1. 图的邻接矩阵表示

有向图邻接矩阵实现
#include <iostream>
#include <vector>class DirectedGraphAdjMatrix {
private:int V; // 顶点数std::vector<std::vector<int>> adjMatrix;public:DirectedGraphAdjMatrix(int vertices) : V(vertices) {adjMatrix.resize(V, std::vector<int>(V, 0));}// 添加有向边void addEdge(int u, int v) {adjMatrix[u][v] = 1;}// 打印邻接矩阵void printAdjMatrix() {for (int i = 0; i < V; ++i) {for (int j = 0; j < V; ++j) {std::cout << adjMatrix[i][j] << " ";}std::cout << std::endl;}}
};int main() {DirectedGraphAdjMatrix digraph(4);digraph.addEdge(0, 1);digraph.addEdge(0, 2);digraph.addEdge(1, 2);digraph.addEdge(2, 3);std::cout << "Directed Graph Adjacency Matrix:" << std::endl;digraph.printAdjMatrix();return 0;
}
无向图邻接矩阵实现
#include <iostream>
#include <vector>class UndirectedGraphAdjMatrix {
private:int V; // 顶点数std::vector<std::vector<int>> adjMatrix;public:UndirectedGraphAdjMatrix(int vertices) : V(vertices) {adjMatrix.resize(V, std::vector<int>(V, 0));}// 添加无向边void addEdge(int u, int v) {adjMatrix[u][v] = 1;adjMatrix[v][u] = 1;}// 打印邻接矩阵void printAdjMatrix() {for (int i = 0; i < V; ++i) {for (int j = 0; j < V; ++j) {std::cout << adjMatrix[i][j] << " ";}std::cout << std::endl;}}
};int main() {UndirectedGraphAdjMatrix undigraph(4);undigraph.addEdge(0, 1);undigraph.addEdge(0, 2);undigraph.addEdge(1, 2);undigraph.addEdge(2, 3);std::cout << "Undirected Graph Adjacency Matrix:" << std::endl;undigraph.printAdjMatrix();return 0;
}

2. 图的邻接表表示

有向图邻接表实现
#include <iostream>
#include <vector>class DirectedGraphAdjList {
private:int V; // 顶点数std::vector<std::vector<int>> adjList;public:DirectedGraphAdjList(int vertices) : V(vertices) {adjList.resize(V);}// 添加有向边void addEdge(int u, int v) {adjList[u].push_back(v);}// 打印邻接表void printAdjList() {for (int i = 0; i < V; ++i) {std::cout << "Vertex " << i << ": ";for (int v : adjList[i]) {std::cout << v << " ";}std::cout << std::endl;}}
};int main() {DirectedGraphAdjList digraph(4);digraph.addEdge(0, 1);digraph.addEdge(0, 2);digraph.addEdge(1, 2);digraph.addEdge(2, 3);std::cout << "Directed Graph Adjacency List:" << std::endl;digraph.printAdjList();return 0;
}
无向图邻接表实现
#include <iostream>
#include <vector>class UndirectedGraphAdjList {
private:int V; // 顶点数std::vector<std::vector<int>> adjList;public:UndirectedGraphAdjList(int vertices) : V(vertices) {adjList.resize(V);}// 添加无向边void addEdge(int u, int v) {adjList[u].push_back(v);adjList[v].push_back(u);}// 打印邻接表void printAdjList() {for (int i = 0; i < V; ++i) {std::cout << "Vertex " << i << ": ";for (int v : adjList[i]) {std::cout << v << " ";}std::cout << std::endl;}}
};int main() {UndirectedGraphAdjList undigraph(4);undigraph.addEdge(0, 1);undigraph.addEdge(0, 2);undigraph.addEdge(1, 2);undigraph.addEdge(2, 3);std::cout << "Undirected Graph Adjacency List:" << std::endl;undigraph.printAdjList();return 0;
}

代码解释

  • 邻接矩阵
    • 对于有向图,若顶点 u 到顶点 v 有边,则 adjMatrix[u][v] = 1
    • 对于无向图,由于边是无向的,若顶点 uv 之间有边,则 adjMatrix[u][v] = 1adjMatrix[v][u] = 1
  • 邻接表
    • 对于有向图,将目标顶点 v 加入源顶点 u 的邻接表中。
    • 对于无向图,需要同时将 v 加入 u 的邻接表和 u 加入 v 的邻接表。

复杂度分析

  • 邻接矩阵
    • 空间复杂度: O ( V 2 ) O(V^2) O(V2),其中 V V V 是顶点数。
    • 添加边的时间复杂度: O ( 1 ) O(1) O(1)
    • 查找边的时间复杂度: O ( 1 ) O(1) O(1)
  • 邻接表
    • 空间复杂度: O ( V + E ) O(V + E) O(V+E),其中 V V V 是顶点数, E E E 是边数。
    • 添加边的时间复杂度: O ( 1 ) O(1) O(1)
    • 查找边的时间复杂度:平均 O ( d e g r e e ( u ) ) O(degree(u)) O(degree(u)),其中 d e g r e e ( u ) degree(u) degree(u) 是顶点 u 的度。

完全图

1. 定义

完全图是一种特殊的图,根据边是否有方向,可分为无向完全图和有向完全图。

  • 无向完全图在一个具有 n n n 个顶点的无向图中,如果任意两个不同顶点之间都存在一条无向边,那么这个图就被称为无向完全图。也就是说,对于无向完全图中的任意两个顶点 u u u v v v u ≠ v u\neq v u=v),都有边 ( u , v ) (u, v) (u,v) 存在。
  • 有向完全图在一个具有 n n n 个顶点的有向图中,如果任意两个不同顶点之间都存在两条方向相反的有向边,即对于任意两个不同顶点 u u u v v v u ≠ v u\neq v u=v),都有有向边 ⟨ u , v ⟩ \langle u, v\rangle u,v ⟨ v , u ⟩ \langle v, u\rangle v,u 存在,那么这个图就被称为有向完全图
2. 边的数量
  • 无向完全图:对于一个具有 n n n 个顶点的无向完全图,边的数量可以通过组合数公式计算。 n n n 个顶点中任选 2 个顶点的组合数为 C n 2 = n ( n − 1 ) 2 C_{n}^2=\frac{n(n - 1)}{2} Cn2=2n(n1),所以无向完全图的边数为 n ( n − 1 ) 2 \frac{n(n - 1)}{2} 2n(n1)
  • 有向完全图:在有向完全图中,每两个不同顶点之间有两条方向相反的有向边。所以边的数量是无向完全图边数的 2 倍,即 n ( n − 1 ) n(n - 1) n(n1)
3. 特点
  • 连通性无向完全图和有向完全图都是高度连通的。在无向完全图中,任意两个顶点之间都有路径相连;在有向完全图中,从任意一个顶点出发都可以到达其他所有顶点。
  • 对称性无向完全图具有很强的对称性,每个顶点的度(与该顶点相连的边的数量)都相同,均为 n − 1 n - 1 n1;有向完全图中每个顶点的入度(指向该顶点的边的数量)和出度(从该顶点出发的边的数量)也都相同,均为 n − 1 n - 1 n1

示例

在这里插入图片描述

无向完全图示例

假设我们有一个无向完全图 G = ( V , E ) G=(V, E) G=(V,E),其中顶点集 V = { A , B , C } V = \{A, B, C\} V={A,B,C}。由于是无向完全图,任意两个不同顶点之间都有边相连,所以边集 E = { ( A , B ) , ( A , C ) , ( B , C ) } E=\{(A, B), (A, C), (B, C)\} E={(A,B),(A,C),(B,C)}。这里 n = 3 n = 3 n=3,根据边数公式 n ( n − 1 ) 2 = 3 × ( 3 − 1 ) 2 = 3 \frac{n(n - 1)}{2}=\frac{3\times(3 - 1)}{2}=3 2n(n1)=23×(31)=3,与实际边数相符。每个顶点的度都是 n − 1 = 2 n - 1 = 2 n1=2,例如顶点 A A A 与顶点 B B B C C C 相连,度为 2。

有向完全图示例

考虑一个有 3 个顶点的有向完全图,顶点集 V = { 1 , 2 , 3 } V=\{1, 2, 3\} V={1,2,3}。边集 E = { ⟨ 1 , 2 ⟩ , ⟨ 2 , 1 ⟩ , ⟨ 1 , 3 ⟩ , ⟨ 3 , 1 ⟩ , ⟨ 2 , 3 ⟩ , ⟨ 3 , 2 ⟩ } E=\{\langle 1, 2\rangle,\langle 2, 1\rangle,\langle 1, 3\rangle,\langle 3, 1\rangle,\langle 2, 3\rangle,\langle 3, 2\rangle\} E={⟨1,2,2,1,1,3,3,1,2,3,3,2⟩}。这里 n = 3 n = 3 n=3,根据边数公式 n ( n − 1 ) = 3 × ( 3 − 1 ) = 6 n(n - 1)=3\times(3 - 1)=6 n(n1)=3×(31)=6,与实际边数一致。每个顶点的入度和出度都是 n − 1 = 2 n - 1 = 2 n1=2,比如顶点 1 有两条出边 ⟨ 1 , 2 ⟩ \langle 1, 2\rangle 1,2 ⟨ 1 , 3 ⟩ \langle 1, 3\rangle 1,3,两条入边 ⟨ 2 , 1 ⟩ \langle 2, 1\rangle 2,1 ⟨ 3 , 1 ⟩ \langle 3, 1\rangle 3,1

代码实现(Python)

# 无向完全图的邻接矩阵表示
def undirected_complete_graph(n):graph = [[0] * n for _ in range(n)]for i in range(n):for j in range(i + 1, n):graph[i][j] = 1graph[j][i] = 1return graph# 有向完全图的邻接矩阵表示
def directed_complete_graph(n):graph = [[0] * n for _ in range(n)]for i in range(n):for j in range(n):if i != j:graph[i][j] = 1return graph# 示例:创建 3 个顶点的无向和有向完全图
n = 3
undirected_graph = undirected_complete_graph(n)
directed_graph = directed_complete_graph(n)print("无向完全图的邻接矩阵:")
for row in undirected_graph:print(row)print("\n有向完全图的邻接矩阵:")
for row in directed_graph:print(row)

代码解释

  • undirected_complete_graph 函数:该函数用于创建一个具有 n n n 个顶点的无向完全图的邻接矩阵。通过两层循环遍历顶点对,对于不同的顶点 i i i j j j i < j i<j i<j),将邻接矩阵中
    graph[i][j]graph[j][i] 置为 1,表示有边相连。
  • directed_complete_graph 函数:该函数用于创建一个具有 n n n 个顶点的有向完全图的邻接矩阵。通过两层循环遍历所有顶点对,当 i ≠ j i\neq j i=j 时,将邻接矩阵中 graph[i][j] 置为
    1,表示有从 i i i j j j 的有向边。
  • 主程序部分:创建了一个有 3 个顶点的无向完全图和有向完全图,并打印出它们的邻接矩阵。

在这里插入图片描述

图的常见存储方式有邻接矩阵、邻接表、邻接多重表和十字链表,下面将分别介绍这些存储方式并给出对应的代码示例。

1. 邻接矩阵

知识点总结

邻接矩阵是一个二维数组,对于一个具有 n n n 个顶点的图,其邻接矩阵是一个 n × n n\times n n×n 的矩阵。若顶点 i i i 和顶点 j j j 之间有边相连,矩阵中第 i i i 行第 j j j 列的元素值为 1(无权图)或边的权重(带权图);若无边相连,则元素值为 0(无权图)或无穷大(带权图)。

代码示例(Python)
# 无向无权图的邻接矩阵表示
class GraphAdjMatrix:def __init__(self, num_vertices):self.num_vertices = num_vertices# 初始化邻接矩阵,元素全为 0self.adj_matrix = [[0] * num_vertices for _ in range(num_vertices)]def add_edge(self, u, v):# 无向图,对称位置都置为 1self.adj_matrix[u][v] = 1self.adj_matrix[v][u] = 1def print_adj_matrix(self):for row in self.adj_matrix:print(row)# 创建一个有 4 个顶点的无向无权图
graph = GraphAdjMatrix(4)
graph.add_edge(0, 1)
graph.add_edge(0, 2)
graph.add_edge(1, 2)
graph.add_edge(2, 3)
graph.print_adj_matrix()

2. 邻接表

知识点总结

邻接表是一种数组和链表相结合的存储方式。对于每个顶点,使用一个链表来存储与该顶点相邻的所有顶点。在实际实现中,也可以用 Python 的列表或 C++ 的 std::vector 来代替链表。

代码示例(Python)
# 无向无权图的邻接表表示
class GraphAdjList:def __init__(self, num_vertices):self.num_vertices = num_vertices# 初始化邻接表,每个顶点对应一个空列表self.adj_list = [[] for _ in range(num_vertices)]def add_edge(self, u, v):# 无向图,两个顶点的邻接表都要添加对方self.adj_list[u].append(v)self.adj_list[v].append(u)def print_adj_list(self):for i in range(self.num_vertices):print(f"Vertex {i}: {self.adj_list[i]}")# 创建一个有 4 个顶点的无向无权图
graph = GraphAdjList(4)
graph.add_edge(0, 1)
graph.add_edge(0, 2)
graph.add_edge(1, 2)
graph.add_edge(2, 3)
graph.print_adj_list()

3. 邻接多重表(主要用于无向图)

在这里插入图片描述

知识点总结

邻接多重表是对邻接表的一种改进,主要用于解决无向图中边的重复存储问题。在邻接多重表中,每条边只存储一次,通过一些指针来表示边与顶点的关联关系。

代码示例(Python)
# 边节点类
class EdgeNode:def __init__(self, mark, ivex, jvex, ilink, jlink):self.mark = mark  # 标记该边是否被访问过self.ivex = ivex  # 边的一个顶点self.jvex = jvex  # 边的另一个顶点self.ilink = ilink  # 指向下一条依附于 ivex 的边self.jlink = jlink  # 指向下一条依附于 jvex 的边# 顶点节点类
class VertexNode:def __init__(self, data, firstedge):self.data = data  # 顶点的数据self.firstedge = firstedge  # 指向第一条依附于该顶点的边# 邻接多重表类
class AMLGraph:def __init__(self, num_vertices):self.num_vertices = num_verticesself.adj_multi_list = [VertexNode(i, None) for i in range(num_vertices)]def add_edge(self, u, v):new_edge = EdgeNode(0, u, v, None, None)# 处理依附于 u 的边if not self.adj_multi_list[u].firstedge:self.adj_multi_list[u].firstedge = new_edgeelse:p = self.adj_multi_list[u].firstedgewhile p.ilink and p.ivex == u:p = p.ilinkif p.ivex == u:p.ilink = new_edge# 处理依附于 v 的边if not self.adj_multi_list[v].firstedge:self.adj_multi_list[v].firstedge = new_edgeelse:p = self.adj_multi_list[v].firstedgewhile p.jlink and p.jvex == v:p = p.jlinkif p.jvex == v:p.jlink = new_edge# 创建一个有 4 个顶点的无向图
graph = AMLGraph(4)
graph.add_edge(0, 1)
graph.add_edge(0, 2)
graph.add_edge(1, 2)
graph.add_edge(2, 3)

4. 十字链表(主要用于有向图)

在这里插入图片描述

知识点总结

十字链表是有向图的一种链式存储结构,它结合了邻接表和逆邻接表的特点,能够方便地找到以某个顶点为起点的边和以某个顶点为终点的边

代码示例(Python)
# 弧节点类
class ArcNode:def __init__(self, tailvex, headvex, hlink, tlink):self.tailvex = tailvex  # 弧的起点self.headvex = headvex  # 弧的终点self.hlink = hlink  # 指向相同终点的下一条弧self.tlink = tlink  # 指向相同起点的下一条弧# 顶点节点类
class VertexNode:def __init__(self, data, firstin, firstout):self.data = data  # 顶点的数据self.firstin = firstin  # 指向第一条以该顶点为终点的弧self.firstout = firstout  # 指向第一条以该顶点为起点的弧# 十字链表类
class OLGraph:def __init__(self, num_vertices):self.num_vertices = num_verticesself.orthogonal_list = [VertexNode(i, None, None) for i in range(num_vertices)]def add_edge(self, u, v):new_arc = ArcNode(u, v, None, None)# 处理以 u 为起点的弧if not self.orthogonal_list[u].firstout:self.orthogonal_list[u].firstout = new_arcelse:p = self.orthogonal_list[u].firstoutwhile p.tlink:p = p.tlinkp.tlink = new_arc# 处理以 v 为终点的弧if not self.orthogonal_list[v].firstin:self.orthogonal_list[v].firstin = new_arcelse:p = self.orthogonal_list[v].firstinwhile p.hlink:p = p.hlinkp.hlink = new_arc# 创建一个有 4 个顶点的有向图
graph = OLGraph(4)
graph.add_edge(0, 1)
graph.add_edge(0, 2)
graph.add_edge(1, 2)
graph.add_edge(2, 3)

图的遍历是指从图中的某一顶点出发,按照某种搜索方法沿着图中的边对图中的所有顶点访问一次且仅访问一次。常见的图的遍历方法有深度优先搜索(DFS)和广度优先搜索(BFS),下面将分别介绍这两种遍历方法的知识点及代码示例。

深度优先搜索(DFS)

在这里插入图片描述

知识点总结
  • 基本思想:深度优先搜索是一种递归的搜索算法,它沿着一条路径尽可能深地访问顶点,直到无法继续,然后回溯到前一个顶点,继续探索其他路径。类似于树的先序遍历。
  • 实现步骤
    1. 选择一个起始顶点,标记该顶点为已访问。
    2. 递归地访问该顶点的所有未访问的邻接顶点。
    3. 回溯到上一个顶点,继续探索其他未访问的邻接顶点。
  • 复杂度分析
    • 时间复杂度:使用邻接矩阵存储图时,时间复杂度为 O ( V 2 ) O(V^2) O(V2),其中 V V V 是顶点数;使用邻接表存储图时,时间复杂度为 O ( V + E ) O(V + E) O(V+E),其中 E E E 是边数。
    • 空间复杂度:主要是递归栈的空间,最坏情况下为 O ( V ) O(V) O(V)
代码示例(Python,使用邻接表存储图)
# 图的邻接表表示
graph = {0: [1, 2],1: [0, 2],2: [0, 1, 3],3: [2]
}# 记录顶点是否被访问过
visited = [False] * len(graph)def dfs(v):# 标记当前顶点为已访问visited[v] = Trueprint(v, end=' ')# 递归访问所有未访问的邻接顶点for neighbor in graph[v]:if not visited[neighbor]:dfs(neighbor)# 从顶点 0 开始进行深度优先搜索
print("深度优先搜索结果:")
dfs(0)

广度优先搜索(BFS)

在这里插入图片描述

知识点总结
  • 基本思想:广度优先搜索是一种基于队列的搜索算法,它从起始顶点开始,逐层地访问顶点,先访问距离起始顶点最近的所有顶点,然后再依次访问更远的顶点。类似于树的层序遍历。
  • 实现步骤
    1. 选择一个起始顶点,标记该顶点为已访问,并将其加入队列。
    2. 当队列不为空时,取出队列的队首顶点,访问其所有未访问的邻接顶点,标记为已访问,并将它们加入队列。
    3. 重复步骤 2,直到队列为空。
  • 复杂度分析
    • 时间复杂度:使用邻接矩阵存储图时,时间复杂度为 O ( V 2 ) O(V^2) O(V2);使用邻接表存储图时,时间复杂度为 O ( V + E ) O(V + E) O(V+E)
    • 空间复杂度:主要是队列的空间,最坏情况下为 O ( V ) O(V) O(V)
代码示例(Python,使用邻接表存储图)
from collections import deque# 图的邻接表表示
graph = {0: [1, 2],1: [0, 2],2: [0, 1, 3],3: [2]
}# 记录顶点是否被访问过
visited = [False] * len(graph)def bfs(v):# 创建一个队列queue = deque()# 标记起始顶点为已访问,并加入队列visited[v] = Truequeue.append(v)while queue:# 取出队首顶点s = queue.popleft()print(s, end=' ')# 访问所有未访问的邻接顶点for neighbor in graph[s]:if not visited[neighbor]:visited[neighbor] = Truequeue.append(neighbor)# 从顶点 0 开始进行广度优先搜索
print("\n广度优先搜索结果:")
bfs(0)

总结

  • 深度优先搜索更适合探索图的深层次结构,常用于寻找连通分量、拓扑排序等问题。
  • 广度优先搜索更适合寻找最短路径等问题,因为它是逐层访问顶点的。
    在这里插入图片描述

💖💝亲亲, 创作不易 看完点点专注呀♥❤💕💞


http://www.ppmy.cn/ops/163478.html

相关文章

【蓝桥杯单片机】第十二届省赛

一、真题 二、模块构建 1.编写初始化函数(init.c) void Cls_Peripheral(void); 关闭led led对应的锁存器由Y4C控制关闭蜂鸣器和继电器 由Y5C控制 2.编写LED函数&#xff08;led.c&#xff09; void Led_Disp(unsigned char ucLed); 将ucLed取反的值赋给P0 开启锁存器…

从Java到MySQL8源码:深入解析PreparedStatement参数绑定与执行机制

引言 在数据库开发中&#xff0c;PreparedStatement&#xff08;预处理语句&#xff09;是防止SQL注入、提升性能的重要工具。它通过分离SQL结构与参数值&#xff0c;不仅增强了安全性&#xff0c;还能利用预编译优化执行效率。本文将从Java JDBC驱动和MySQL 8源码的双重视角&…

【系统架构设计师】软件架构的重要性

目录 1. 说明2. 能够满足系统的品质3. 使受益人达成一致的目标4. 能够支持计划编制过程5. 对系统开发的指导性6. 能够有效地管理复杂性7. 为复用奠定了基础8. 能够降低维护费用9. 能够支持冲突分析10.例题10.1 例题1 1. 说明 1.软件架构设计是降低成本、改进质量、按时和按需交…

蓝桥备赛(七)- 函数与递归(中)

一、函数重载 1.1 重载概念 引入&#xff1a; 比如&#xff1a;如果我们现在想要写一个函数 &#xff0c; 求两个整数的和 &#xff1a; #include <cstdio> #include <iostream> using namespace std;int IntAdd(int x, int y) {return x y; } int main() {in…

uniapp+vue3搭建项目

工具使用&#xff1a; Pinia Vue 3 官方推荐的状态管理库&#xff0c;比 Vuex 更轻量&#xff0c;支持模块化&#xff0c;结合 persistedstate 插件可以持久化存储数据。uView-plus 专为 UniApp 设计&#xff0c;支持 App、小程序、H5。UnoCSS 更轻量&#xff0c;比 TailwindCS…

计算机视觉|从0到1揭秘Diffusion:图像生成领域的新革命

一、Diffusion 的基本概念 1.1 什么是 Diffusion 模型 Diffusion 模型是一种基于扩散过程的生成模型&#xff0c;其灵感来源于非平衡热力学的理论框架。简单来说&#xff0c;它通过模拟数据的逐步退化与重建过程来生成新数据。具体而言&#xff0c;Diffusion 模型先通过正向扩…

Linux网络_应用层自定义协议与序列化_守护进程

一.协议 协议是一种 "约定". socket api 的接口, 在读写数据时, 都是按 "字符串" 的方式来发送接 收的. 如果我们要传输一些 "结构化的数据" 怎么办呢? 其实&#xff0c;协议就是双方约定好的结构化的数据 像下面&#xff0c;两端都知道数据结构…

【实战 ES】实战 Elasticsearch:快速上手与深度实践-2.2.3案例:电商订单日志每秒10万条写入优化

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 Elasticsearch批量写入性能调优实战&#xff1a;2.2.3 案例&#xff1a;电商订单日志每秒10万条写入优化1. 原始架构与瓶颈分析1.1 初始集群配置1.2 性能瓶颈定位 2. 全链路…