一、图的表示
图由点、边组成(网格可以看作特殊的图),有多种表示方式,常用的为邻接矩阵、邻接链表
1.1、邻接矩阵
邻接矩阵是用于表示图的一种常见方法
-
邻接矩阵是一个二维数组,其中行和列分别表示图中的顶点,数组中的元素表示两个顶点之间是否存在边。
-
如果顶点之间存在边,则邻接矩阵中第i行第j列的元素为1或非零值,表示连接;否则,元素为0或空,表示没有连接。
-
对于邻接矩阵 A A A, a i j a_{ij} aij表示节点 i 、 j i、j i、j是否相连,不相连则 a i j = 0 a_{ij}=0 aij=0,否则 a i j = 1 a_{ij}=1 aij=1(如果是加权图,则为权重值)
-
a i j = { 1 i , j 相邻 0 i , j 不相邻 \begin{equation} a_{ij}=\left\{ \begin{aligned} 1 & \quad i,j相邻\\ 0 & \quad i,j不相邻\\ \end{aligned} \right . \end{equation} aij={10i,j相邻i,j不相邻
邻接矩阵可以用于描述有向图和无向图
- 对于无向图,邻接矩阵是对称的,即 a i j = a j i a_{ij}=a_{ji} aij=aji;对于有向图,邻接矩阵不一定对称。
使用邻接矩阵可以方便地进行图的操作和分析,比如查找两个顶点之间是否存在边、计算顶点的度数(即与之相连的边的数量)等。
邻接矩阵在表示稀疏图(边的数量相对较少)时可能会占用较大的空间。
1.2、邻接链表
邻接链表是另一种用于表示图的常见数据结构
- 邻接链表使用链表来表示图中的边,从而更有效地表示稀疏图(边的数量相对较少)
- 在邻接链表中,每个顶点都有一个相邻顶点的链表,链表中的节点表示与该顶点相连的边。
邻接矩阵可以用于描述有向图和无向图
- 对于无向图,每条边都会在两个顶点的邻接链表中各出现一次;而对于有向图,则会分别在起点和终点的邻接链表中出现。
相比邻接矩阵,邻接链表更适合表示稀疏图,因为它只存储图中存在的边,而不用预先分配所有可能的边空间。
在进行图的遍历和搜索时,邻接链表通常也更有效率,因为只需操作与相邻顶点直接相关的边。
在python
中,没有直接内置的链表数据结构,需要自己实现***【下面的代码仅实现基本功能】***
import numpy as np
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList(object):
def __init__(self):
self.head = None
def is_empty(self):
return self.head is None
def add_node(self, data):
new_node = Node(data)
if self.head is None:
self.head = new_node
else:
current = self.head
while current.next:
current = current.next
current.next = new_node
def print_linkedlist(self):
current = self.head
print("链表各节点的值如下:")
while current:
print(current.data)
current = current.next
if __name__ == '__main__':
# 构建邻接矩阵
node_num = 6
adjacent_matrix = np.zeros((node_num, node_num))
adjacent_matrix[0, 1] = 6
adjacent_matrix[0, 5] = 4
adjacent_matrix[1, 2] = 2
adjacent_matrix[1, 4] = 3
adjacent_matrix[1, 5] = 1
adjacent_matrix[2, 3] = 7
adjacent_matrix[4, 2] = 3
adjacent_matrix[4, 3] = 2
adjacent_matrix[5, 4] = 2
print(adjacent_matrix)
# 根据邻接矩阵构建邻接链表
linkedlist_list = []
for i in range(node_num):
linkedlist = LinkedList()
linkedlist.add_node(i)
for j in range(node_num):
if adjacent_matrix[i][j] > 0:
linkedlist.add_node(j)
linkedlist_list.append(linkedlist)
# 打印链表信息
if not linkedlist.is_empty():
linkedlist.print_linkedlist()
1.3、图的展示
使用networkx
库进行图的绘制
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
def add_node_and_edge(G, adjacent_matrix):
"""
根据邻接矩阵向图中添加节点及边
:param G: 图
:param adjacent_matrix: 邻接矩阵
:return: 图
"""
for i in range(len(adjacent_matrix)):
G.add_node(i)
for i in range(len(adjacent_matrix)):
for j in range(len(adjacent_matrix)):
length = adjacent_matrix[i][j]
if length > 0:
G.add_edge(i, j, weight=length)
return G
def draw_network(G, node_feature):
"""
绘图图,边的权重越大,则连线越粗
:param G: 图
:param node_feature: 节点属性(绘图)
:return:
"""
# 获取边的权重值
weights = nx.get_edge_attributes(G, 'weight').values()
# 绘制图形
pos = nx.spring_layout(G) # 定义节点的布局
nx.draw(G, pos, with_labels=True,
node_size=node_feature['node_size'], node_color=node_feature['node_color'], font_size=node_feature['font_size'],
linewidths=node_feature['linewidths'], edge_color=node_feature['edge_color'])
# 根据权重设置边的粗细
# arrows=True能确保箭头绘制在节点之上(避免被遮盖)
# arrowstyle能设置箭头的大小
nx.draw_networkx_edges(G, pos, width=list(weights), arrows=True,
arrowstyle='fancy,head_length=1,head_width=0.8,tail_width=0.4')
# 显示图形
plt.axis("off")
plt.show()
if __name__ == '__main__':
# 创建一个有向图
G = nx.DiGraph()
# 构建邻接矩阵
node_num = 6
adjacent_matrix = np.zeros((node_num, node_num))
adjacent_matrix[0, 1] = 6
adjacent_matrix[0, 5] = 4
adjacent_matrix[1, 2] = 2
adjacent_matrix[1, 4] = 3
adjacent_matrix[1, 5] = 1
adjacent_matrix[2, 3] = 7
adjacent_matrix[4, 2] = 3
adjacent_matrix[4, 3] = 2
adjacent_matrix[5, 4] = 2
# 图中添加节点及边
G = add_node_and_edge(G, adjacent_matrix)
# 绘图
node_feature = {'node_size': 500, 'node_color': 'lightblue', 'font_size': 10, 'linewidths': 0.5, 'edge_color': 'gray'}
draw_network(G, node_feature)
二、图遍历算法
“王婆卖瓜一下”,该部分内容可以看我之前的博文***【内容非常的详细、丰富】***:
- 知乎链接:树的遍历与图的遍历 - 童年往事的文章 - 知乎 https://zhuanlan.zhihu.com/p/689713192
三、最短路算法
图的最短路算法是解决图中两个顶点之间最短路径的问题,地图导航等领域有着广泛的应用。
对于已知的静态图(点、边关系确定且保持不变),最短路算法可以分为单源最短路算法和多源最短路算法两大类。
-
单源最短路径算法:是指从图中的一个顶点到所有其他顶点的最短路径问题
- 常用的单源最短路径算法包括:
Dijkstra算法
:适用于非负权重的有向图或无向图,基于贪心策略,每次选择当前最短路径的顶点进行扩展;Bellman-Ford
算法:适用于有向图或无向图,能够处理负权边,通过对图进行松弛操作来求解最短路径;A*
算法:适用于非负权重的有向图或无向图,通常用于在加权图中从一个特定起点到一个指定终点找到最短路径- 通过结合
Dijkstra
算法的精确性和启发式方法(如贪心算法)的速度优势来优化路径搜索过程。
- 通过结合
- 常用的单源最短路径算法包括:
-
多源最短路径算法:是指从图中任意一个顶点到任意一个顶点的最短路径问题。
- 常用的多源最短路径算法包括:
Floyd-Warshall
算法:适用于有向图或无向图,能够处理负权边,通过动态规划的方式计算任意两点之间的最短路径;Johnson
算法:结合了Dijkstra
算法和Bellman-Ford
算法的思想,能够处理负权边,通过重新赋权和辅助图的方式来求解多源最短路径。
- 常用的多源最短路径算法包括:
这些算法在不同的场景下有着不同的适用性和性能表现,其中Dijkstra
算法、A*
算法、Floyd
算法是其中最常用也是最基础,需要优先掌握。
1.1、Dijkstra
算法
Dijkstra
算法是求解单源最短路(一对多)的算法,即确定一个节点(起点)到其他各个节点(终点)的最短路
可观看该视频***【非常直观】***:https://www.bilibili.com/video/BV1zz4y1m7Nq/?share_source=copy_web
也可以直接看我之前的博文***【内容非常的详细、丰富】***
- 知乎链接:
Dijkstra
算法的python
实现,求解最短路径长度及路径信息 - 童年往事的文章 - 知乎 https://zhuanlan.zhihu.com/p/676896551
1.2、Floyd
算法
Floyd
算法是求解多源最短路(多对多)的算法,即确定每个节点(起点)到其他节点(终点)的最短路
算法允许边的权重为负,但是负边构成的回路(环)的权重之和不能为负(负环)
可以直接看我之前的博文***【内容非常的详细、丰富】***
- 知乎链接:Floyd算法原理及公式推导 - 童年往事的文章 - 知乎 https://zhuanlan.zhihu.com/p/666611935
1.3、A*
算法
A*
算法是一种特殊的单源最短路径算法,通常用于在加权图中确定从一个特定节点(起点
S
S
S)到一个指定节点(终点
E
E
E)的最短路。
A*
算法通过结合Dijkstra
算法的精确性和启发式方法的速度优势优化路径搜索过程;- “实际成本”
g(n)
:从 S S S到当前节点的实际路径成本; - “预估成本”
h(n)
:用于评估从当前节点到 E E E的估计成本,常见的启发式方法包括曼哈顿距离、欧几里德距离等; - “综合成本”
f(n)
:即 f ( n ) = g ( n ) + h ( n ) f(n)=g(n)+h(n) f(n)=g(n)+h(n),启发式函数估计的成本和实际成本之和,用于决定搜索顺序。
- “实际成本”
- 启发式函数
h(n)
,通常称为估计成本函数,来估算从任一顶点 n n n到目标顶点的成本,是A*
算法与其他单源最短路径算法最主要的区别; - 在实际应用中,确保启发式函数是可行的(即它不会高估到达目标的实际成本),这样才能保证算法的效率和结果的正确性。
可以直接看我之前的博文***【一篇对算法原论文的理论解析,分析了算法有效性;一篇是示例及代码】***
- 理论分析:https://blog.csdn.net/weixin_42639395/article/details/139715043;
- 示例及代码:https://blog.csdn.net/weixin_42639395/article/details/139716790
四、相关链接
- 树的遍历与图的遍历:https://zhuanlan.zhihu.com/p/689713192;
Dijkstra
算法示例(视频):https://www.bilibili.com/video/BV1zz4y1m7Nq/?share_source=copy_web;Dijkstra
算法求解最短路径长度及路径信息:https://zhuanlan.zhihu.com/p/676896551;Floyd
算法原理及公式推导:https://zhuanlan.zhihu.com/p/666611935;A*
算法理论分析:https://blog.csdn.net/weixin_42639395/article/details/139715043;A*
示例及代码:https://blog.csdn.net/weixin_42639395/article/details/139716790