1 引言
深度优先算法(Depth-First Search,DFS)与广度优先算法(BFS)已经有很多介绍了,深度优先算法(DFS)是一种用于遍历或搜索树或图的算法。这个算法会尽可能深地搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问过为止。
顾名思义,与广度优先算法不同,深度优先算法对树进行搜索时,不会遍历当前层级的所有节点,而是每次往下深入一层,直到搜索到当前树的最底层。
2 深度优先算法图解
如图1所示,8个节点组成了3条路径,节点0为起点,节点7为终点,现通过此图对DFS进行讲解。
第1步:将节点0加入当前搜索列表,即此时当前搜索列表为[0],已搜索列表为空[].
第2步:查找节点0的邻接节点,此处节点0有两个邻接节点(节点1和节点2),根据DFS规则,我们按先后顺序先只搜索第一个 邻接节点即节点1,将节点0加入已搜索节点,同时将节点0从搜索列表删除,将节点1加入搜索列表,即此时当前搜索列表为[1],已搜索列表为[0].
第三步,查找节点1的邻接节点,此处节点1有1个邻接节点(节点3),将节点1加入已搜索节点,同时将节点1从搜索列表删除,将节点3加入搜索列表,即此时当前搜索列表为[3],已搜索列表为[0, 1].
第4步:查找节点3的邻接节点,此处节点3有两个邻接节点(节点5和节点6),根据DFS规则,我们按先后顺序先只搜索第一个 邻接节点即节点5,将节点3加入已搜索节点,同时将节点3从搜索列表删除,将节点5加入搜索列表,即此时当前搜索列表为[5],已搜索列表为[0, 1, 3].
第5步:查找节点5的邻接节点,发现节点5无邻接节点,执行节点回溯,将节点5从搜索列表删除,将已搜索列表中的最后一个节点(节点3)加入搜索列表,同时将节点5加入已搜索列表,即此时当前搜索列表为[3],已搜索列表为[0, 1, 5].
第6步:查找节点3的邻接节点,此处节点3有两个邻接节点(节点5和节点6),节点5在已搜索列表中,我们按先后顺序搜索第二个邻接节点即节点6,将节点3加入已搜索节点,同时将节点3从搜索列表删除,将节点6加入搜索列表,即此时当前搜索列表为[6],已搜索列表为[0, 1, 5, 3].
第7步,查找节点6的邻接节点,节点6有一个邻接节点即节点7,已找到终点,搜索结束。
3 Matlab算例
以邻接矩阵为算例,进行DFS算法验证,给出一个6*6邻接矩阵:
Map = [0 1 0 0 0 0;
0 0 1 1 0 0;
0 0 0 0 0 0;
0 0 0 0 1 0;
0 0 0 0 0 1;
0 0 0 0 0 0];
完整代码如下:
clc;close all;clear
% 使用邻接矩阵表示图
Map = [0 1 0 0 0 0;
0 0 1 1 0 0;
0 0 0 0 0 0;
0 0 0 0 1 0;
0 0 0 0 0 1;
0 0 0 0 0 0];
% 队列
queue = 1;% 当前节点之前的搜寻队列(用于节点回溯)
Num = length(Map(:, 1));
visited = false(1, Num);% 已访问标志
% 从第一个节点开始深度优先搜索
node = 1;
nodepre = DFS(visited, Map, queue, node);
%% 函数定义
function nodepre = DFS(visited, Map, queue, node)
nodepre = zeros(length(Map(:, 1)), 1);
Map_Temp = Map;
% 标记已访问节点
visited(node) = true;
% 输出当前节点
disp(node);
% 遍历当前节点的每一个邻接节点
num = 1;
while 1
if num >= size(Map(1, :))
break;
end
sumnode = sum(Map(node, :)); % 判断当前节点是否有邻接节点
if sumnode > 0.5% 有邻接节点,继续查找
for i = 1:length(Map(node, :)) % 对于当前节点的每一个邻接节点
if Map(node, i) > 0.5% 判断是否与当前节点连接
if ~visited(i) % 如果邻接节点没有被访问过
num = num + 1;
queue= [queue; node];
nodepre(i) = node;% 记录前序节点
node = i;
visited(node) = true;
Map(node, i) = 0;
% 输出当前节点
disp(node);
end
end
end
else %无邻接节点,节点回溯
node = queue(end);
queue(end) = [];
% 输出当前节点
disp(node);
end
end
end
运行结果:
从结果可以看出,算法先沿1-2-3搜寻,发现节点3无邻接节点后,回溯回节点2,从节点2沿2-4-5-6搜寻直到找到终点6。
4 与BFS对比
之前我们用迷宫问题做了BFS算法算例,这里用DFS算法实现对比一下:
BFS算法搜寻过程:
DFS算法搜寻过程:
可以看出采用广度优先算法(BFS)时,搜寻范围大,需遍历图中的所有节点,但是BFS算法输出的路径是最优的;而深度优先算法(DFS)所需胡搜寻范围较小,搜寻速度快,但是得到的搜寻路径不能保证最优。