首页 > 技术文章 > Java数据结构与算法之DFS

njuptzheng 2020-07-17 14:54 原文

深度优先搜索算法

  1. 深度优先遍历,从初始访问结点出发,初始访问结点可能有多个邻接结点,深度优先遍历的策略就是首先访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接结点,可以这样理解:每次都在访问完当前结点后首先访问当前结点的第一个邻接结点。
  2. 我们可以看到,这样的访问策略是优先往纵向挖掘深入,而不是对一个结点的所有邻接结点进行横向访问。
  3. 显然,深度优先搜索是一个递归的过程。

算法分析:

  1. 假设起始节点为1;先搜索1节点的右侧邻接节点为2,此时将1节点置为已搜索状态;判断2节点是否为已搜索状态,若未搜索,则将2节点置为已搜索状态;每次都优先搜索判断右侧邻接节点;
  2. 如图所示,若此时已搜索至5节点,发现右侧邻接节点为2且已处于已搜索状态故递归至上一个节点8搜索左侧邻接节点处...层层递归判断至1节点(在图中没有并表明递归路径)
  3. 此时搜索判断1节点的左侧邻接节点3不为已搜索状态,故继续进行先右侧后左侧邻接节点搜索判断操作;
  4. 直至最后一个节点6搜索判断3节点为已搜索状态,故递归至最初的1节点;判断结束,搜索结束

代码实现:

// 对dfs进行一个重载,遍历我们所有的结点,并进行dfs
    public List<Integer> DFS() {
        isSreachs = new boolean[vertexList.size()];
        dfsArrays = new ArrayList<>();
        for (int i = 0; i < vertexList.size(); i++) {
            // 遍历所有的结点,进行dfs[回溯]
            if (!isSreachs[i]) {
                dfsArrays = DFS(isSreachs[i], i);
            }
        }
        return dfsArrays;
    }

    public List<Integer> DFS(boolean isSreach, int i) {
    	// 首先我们将该节点添加进数组
        dfsArrays.add(showVertexList(i));
        // 将节点设置为已经访问
        isSreachs[i] = true;
        // 查找节点i的第一个邻接节点w
        int w = getFirstNeighbor(i);
        while (w != -1) { // 说明存在w
            if (!isSreachs[w]) {
                DFS(isSreachs[w],w);
            }
            // w节点已经被访问过
            w = getNextNeightbor(i,w);
        }
        return dfsArrays;
    }

    // 得到第一个邻接结点的下标
    public int getFirstNeighbor(int index) {
        for (int j = 0; j < vertexList.size(); j++) {
            if (edges[index][j] == 1) {
                return j;
            }
        }
        return -1;
    }

    // 根据前一个邻接结点的下标来获取下一个邻接结点
    public int getNextNeightbor(int v1, int v2) {
        for (int i = v2+1; i < vertexList.size(); i++) {
            if (edges[v1][i] == 1) {
                return i;
            }
        }
        return -1;
    }

实现结果:

这里的结果与分析的结果有所出入,这是因为分析中借用了树的概念,在实现中需要左右子树递归。而这里则运用了上一节图中邻接矩阵的概念,将边用二维矩阵的形式表示出来,故搜索顺序会有些出入。
但所用的思想是一致的:一条路走到黑,再回头。

推荐阅读