深度优先与广度优先算法
深度优先与广度优先算法应用于图的遍历,当我们需要生成一个图G的生成树T的时候,可以使用深度优先或广度优先算法。
以下是我构造的一个无向连通图,用于下面的实例说明
# 顶点与边
vertexs = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
edges = [('A', 'C'), ('A', 'B'), ('A', 'D'), ('B', 'D'), ('B', 'G'), ('C', 'E'), ('C', 'F'), ('D', 'E'), ('D', 'G'),
('E', 'F'), ('E', 'H'), ('F', 'H'), ('G', 'H')]
深度优先遍历
算法思想:尽可能先对纵深方向的顶点进行访问
伪代码
DFS(v)
(7) num(v)=i++;
(8) for 所有与v邻接的顶点u
(9) if num(u)是0
(10) 将edge(uv)连接到edges中;
(11) DFS(u);
depthFirstSearch()
(1) for 所有向量v
(2) num(v)=0;
(3) edges=null;
(4) i=1;
(5) while 有一个向量v使得num(v)是0
(6) DFS(v);
输出edges;
伪代码步骤说明:
depthFirstSearch函数,步骤(1)~(2):循环所有的顶点,将每个顶点初始标记设置为0
步骤(3):初始化edges为null
步骤(5)~(6):循环顶点的标记,只要存在一个顶点标记为0(0代表未访问,1代表已访问),则继续循环,调用DFS()函数,将顶点v传递进去
DFS函数,步骤(7):将当前的顶点的标记递增,设置为已访问
步骤(8)-(9)-(10):循环与v邻接的顶点u,如果邻接的顶点标记为0(未访问)则将uv结合的边加入到edges列表中
步骤(11):进行深度(递归)查找,将顶点u传入DFS函数
步骤说明
以上是以A为出发点的深度遍历的步骤图示,最终结果并不唯一,但是核心是在于纵深遍历
上述实例的Python代码
点击查看代码
# 顶点与边
vertexs = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
edges = [('A', 'C'), ('A', 'B'), ('A', 'D'), ('B', 'D'), ('B', 'G'), ('C', 'E'), ('C', 'F'), ('D', 'E'), ('D', 'G'),
('E', 'F'), ('E', 'H'), ('F', 'H'), ('G', 'H')]
# 顶点标记,0-代表未访问,1代表已访问
vertexs_mark = {}
# 最后产出的生成树的边
tree_edges = []
# 每个顶点的邻接顶点
adjacency_vertexs = {}
# 计算出每个顶点的邻接顶点
for edge in edges:
if edge[0] in adjacency_vertexs.keys():
adjacency_vertexs[edge[0]].append(edge[1])
else:
adjacency_vertexs[edge[0]] = [edge[1]]
if edge[1] in adjacency_vertexs.keys():
adjacency_vertexs[edge[1]].append(edge[0])
else:
adjacency_vertexs[edge[1]] = [edge[0]]
print(adjacency_vertexs)
def depth_first_search():
# 顶点标记初始化为0
for vertex in vertexs:
vertexs_mark[vertex] = 0
# 循环所有顶点
for vertex in vertexs:
if vertexs_mark[vertex] == 0:
dfs(vertex)
print(tree_edges)
def dfs(vertex):
vertexs_mark[vertex] = 1
for u in adjacency_vertexs[vertex]:
if vertexs_mark[u] == 0:
# 将此条边加入tree_edges
tree_edges.append((vertex, u))
# 递归调用,纵深查找
dfs(u)
depth_first_search()
广度优先遍历
算法思想:尽可能先对横向的顶点进行访问
伪代码
breadthFirstSearch()
for 所有顶点u # 循环所有顶点
num(u)=0; # 将所有顶点初始标记设置为0
edges=null; # 初始化edges,edges为存储的遍历结果
i=1;
while 存在一个顶点v使得num(v)==0 # 只要有一个顶点的标记为0,则循环继续
num(v)=i++; # 将顶点的标记递增
enqueue(v);//进入队列 # 将顶点放入队列
while 队列非空 # 如果队列非空
v=dequeue(); # 如果队列非空则将一个顶点出队
for 所有和v邻接的顶点u # 找到与当前顶点v邻接的所有顶点,并循环处理
if num(u)是0 # 如果邻接的顶点的标记为0
num(u)=i++; # 将顶点的标记递增
enqueue(u); # 将顶点放入循环队列
将edge(vu)连接到edges中 # 将顶点v与顶点u连接的顶点放入遍历结果edges中
输出edges;
步骤说明
以上是以A为出发点的广度遍历的步骤图示,最终结果并不唯一,核心在于先对横向的顶点进行访问
上述实例的Python代码
点击查看代码
class Queue:
""" 队列 """
def __init__(self):
self.__data = []
def enqueue(self, data):
"""往队列头中添加一个新元素"""
self.__data.insert(0, data)
def travel(self):
"""遍历所有元素"""
for i in self.__data:
print(i, end='')
print('')
def dequeue(self):
"""从队列尾删除一个元素"""
return self.__data.pop()
def is_empty(self):
"""判断队列是否为空"""
return self.__data == []
def size(self):
"""返回队列的元素个数"""
return len(self.__data)
# 顶点与边
vertexs = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
edges = [('A', 'C'), ('A', 'B'), ('A', 'D'), ('B', 'D'), ('B', 'G'), ('C', 'E'), ('C', 'F'), ('D', 'E'), ('D', 'G'),
('E', 'F'), ('E', 'H'), ('F', 'H'), ('G', 'H')]
# 顶点标记,0-代表未访问,1代表已访问
vertexs_mark = {}
# 最后产出的生成树的边
tree_edges = []
# 每个顶点的邻接顶点
adjacency_vertexs = {}
# 计算出每个顶点的邻接顶点
for edge in edges:
if edge[0] in adjacency_vertexs.keys():
adjacency_vertexs[edge[0]].append(edge[1])
else:
adjacency_vertexs[edge[0]] = [edge[1]]
if edge[1] in adjacency_vertexs.keys():
adjacency_vertexs[edge[1]].append(edge[0])
else:
adjacency_vertexs[edge[1]] = [edge[0]]
print(adjacency_vertexs)
vertex_queue = Queue()
# 广度优先搜索
def breadth_first_search():
# 顶点标记初始化
for vertex in vertexs:
vertexs_mark[vertex] = 0
# 循环所有顶点,循环所有顶点是因为图可能是非连通图
for vertex in vertexs:
if vertexs_mark[vertex] == 0:
# 进入队列
vertex_queue.enqueue(vertex)
while not vertex_queue.is_empty():
# 出队列
v = vertex_queue.dequeue()
bfs(v)
def bfs(vertex):
# 当前顶点的标记设置为1
vertexs_mark[vertex] = 1
for u in adjacency_vertexs[vertex]:
if vertexs_mark[u] == 0:
# 当前顶点的邻接顶点
vertexs_mark[u] = 1
# 顶点u进入队列
vertex_queue.enqueue(u)
# 将此条边加入tree_edges
tree_edges.append((vertex, u))
breadth_first_search()
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库