你必须会的DFS的递归实现与堆栈实现

一. 算法原理

相比于BFS利用队列实现中心扩散式搜索
DFS就是利用堆栈的思想(先进后出),利用回溯算法,或者使用dfs递归,直观上看是一条路走到黑,如果找到南墙,便回到上个路口,继续一条路走到黑…如此往复,直到到达目标,所以称之为深度优先搜索。

1.堆栈式实现方法

  • 首先将根节点压入堆栈中。
  • 从堆栈中pop一个节点,并检验它是否为目标。
    • 如果找到目标,则结束搜索并回传结果。
    • 否则将它所有尚未检验过的直接子节点加入堆栈中。
  • 若堆栈为空,表示整张图都检查过了——亦即图中没有所搜索的目标。结束搜索并回传“找不到目标”。
  • 重复步骤2。

伪代码

stack.push(root)
while(!stack.isEmpty())
	node = stack.pop()
	for each neighbor node的相邻节点
		if neighbor未被访问
			stack.push(neightbor)
			//记录路径
			stack.parent = node
			//其余操作...
			todo...

2.递归式实现方法

  • 给定根节点
  • 遍历根节点所有未被访问的相邻节点
    • 如果找到目标,则结束搜索并传回结果
    • 否则将该相邻节点设置为新的根节点,重复步骤2
    • 若没有未被访问的相邻节点,则结束本分支的搜索并返回
  • 所有分支都遍历完毕,结束搜索并回传“找不到目标”。

伪代码:

DFS()
	dfsVisit(root)

dfsVisit(node)
	for each neighbor node的相邻节点
		if neighbor没有访问过
			//记录路径
			neighbor.parent = root
			//其他操作
			todo..
			dfs(neighbor)

二.具体实现

选用常见的递归实现

package com.example.DFS;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DFS {
    // <1, [2, 3]>表示节点1的父节点是节点2,到源点距离为3
    private Map<Integer, int[]> disTo;
    /**
     * @param edges 一个节点到其他节点的距离
     *              [[0, 1, 1], [1, 2, 2]] 表示点0到点1的距离为1,点1到点2的距离为2
     * @param n   所有节点个数  1<= n <= 1000
     * @param k   源节点   1< k <n
     */
    public Map<Integer, int[]> DFS(int[][] edges, int n, int k){
        //通过edges数组生成有向图
        //<0, <{1,2}, {2,3}>>表示节点0有1,2两个相邻节点,距离分别为2, 3
        Map<Integer, List<int[]>> graph = new HashMap<>();
        for(int[] edge:edges){
            if(!graph.containsKey(edge[0]))
                graph.put(edge[0], new ArrayList<int[]>());
            graph.get(edge[0]).add(new int[]{edge[1], edge[2]});
        }
        //初始化disTo
        disTo = new HashMap<>();
        for(int i=0; i<n; i++){
            if(i==k)
                disTo.put(i, new int[]{k, 0});
            else disTo.put(i, new int[]{-1, Integer.MAX_VALUE});
        }
        dfsVisit(graph, k);
        return disTo;
    }
	
    /**
     * dfs
     * @param graph
     * @param k
     */
    private void dfsVisit(Map<Integer, List<int[]>> graph, int k){
        if(graph.containsKey(k))
            for(int[] edge:graph.get(k)){
                int[] temp = disTo.get(edge[0]);
                //保证该节点未被访问
                if(temp[0] == -1 && temp[1] == Integer.MAX_VALUE) {
                    //setParent 记录路径
                    temp[0] = k;
                    //setDisTo 记录距离
                    temp[1] = disTo.get(k)[1] + edge[1];
                    //递归实现
                    dfsVisit(graph, edge[0]);
                }
            }
    }

    /**
     * 输出结果
     * @param disTo
     * @param end
     */
    public void printPath(Map<Integer, int[]> disTo,int pathTo){
        int distance = disTo.get(pathTo)[1];
        List<Integer> path = new ArrayList<>();
        int temp = pathTo;
        path.add(temp);
        while (temp!=0 && temp!=-1){
            temp = disTo.get(temp)[0];
            path.add(temp);
        }
       System.out.print("从初始节点到节点"+end+"的距离为"+distance+"\n"
       					+"路径为:\n"+path.get(0));
        for(int i=1;i<path.size();i++){
            System.out.print("<--"+path.get(i));
        }
    }
}

1.实例

测试输入
输入:

edges:n:k:pathTo:
{{0, 1, 15},{0, 3, 5},604
{1, 5, 6}, {3, 5, 20},
{1, 2, 15}, {3, 2, 30},
{2, 4, 10}, {5, 4, 9}};

预计输出:距离:30 路径:0–>1–>5–>4

环境:windows10,java11

2.结果

试着输出到节点5的路径和距离
在这里插入图片描述

三.如何输出所有的路径?

在一个图没有环的情况下,或者先去环后,允许一个节点可以由多个不同的父节点向下遍历到,这样可以找到图中真正的所有路径


你可能还敢兴趣的图论算法(均附Java实现代码):

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hack Rabbit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值