Java实现深度优先搜索

图的遍历

图的遍历就是访问图中的每个节点并且每个节点只访问一次。但图中有那么多节点,要如何进行访问就是一个问题,所以我们需要有特定的策略来进行访问这些节点。图的访问策略一般有两种:深度优先搜索和广度优先搜索

深度优先搜索基本思想

从初始节点开始出发访问,访问该节点的第一个相邻节点,然后以该相邻节点为起点,继续访问其相邻节点,反复持续该过程直到图中所有节点已全部被访问;简单总结就是:访问完当前节点后就去访问当前节点的第一个相邻节点。这样一来,图的访问顺序就是向深处访问,而不是横向访问。

我们将要访问的节点称为头节点,相邻节点称为表节点;头节点中存储数据和第一个表节点,表节点中存储头节点的下标和头节点的下一个相邻节点;头节点使用顺序(链表)存储,表节点使用链表存储;

如下图,其深度优先搜索顺序可以v1, v2, v4, v8, v5, v3, v6, v7,注意:深度优先搜索的顺序不是唯一的,这取决于访问起点和表节点的顺序。

java 宽度优先搜索算法 java深度优先搜索_深度优先搜索

实现思路

  • 访问头节点,并将该头节点标记为以访问过
  • 访问表节点中第一个没有被访问过的头节点,这里需要循环
  • 以该头节点为起点,继续上面两步操作直到访问完所有节点,这里需要递归

代码实现

定义头节点和表节点

//头节点
public class HNode<T> {

    public T data; //数据域
    public boolean isVisit; //标识该头节点是否已经被访问过
    public TNode firstArc; //指针域,指向第一个表节点

    public HNode(T data) {
        this.data = data;
    }

    public HNode() {
    }

    @Override
    public String toString() {
        return "HNode{" +
                "data=" + data +
                ", isVisit=" + isVisit +
                ", firstArc=" + firstArc +
                '}';
    }
}

//表节点
class TNode {

    public int hNodeIndex;//存储头节点下标
    public TNode nextArc; //指针域,指向下一个相邻的表节点

    public TNode(int hNodeIndex) {
        this.hNodeIndex = hNodeIndex;
    }

}

定义一个 Graph 类,一个Graph类就表示一个图

class Graph {

    private HNode[] vertices; //存储头节点

    public Graph(HNode[] vertices) {
        this.vertices = vertices;
    }

    //构建图
    public void build(Object data) {

    }

    //图的深度优先搜索
    //index表示从顺序表中的第几个节点开始遍历
    public void dfs(int index) {
        //访问index对应的头节点
        System.out.println(vertices[index].data);
        //设置当前节点为已访问
        vertices[index].isVisit = true;
        //临时变量,用于辅助遍历表节点
        TNode temp = vertices[index].firstArc;
        //通过表节点访问未被访问过的头节点
        while (temp != null) {
            if (vertices[temp.hNodeIndex].isVisit) {
                //当前节点已经被访问过,无需再访问,继续往后寻找
                temp = temp.nextArc; //后移
            } else {
                //当前表节点对应的头节点没有被访问过,以该头节点为起点,继续执行上面代码的逻辑:访问-寻找为访问的表节点-访问-寻找完毕,退出
                dfs(temp.hNodeIndex);
            }
        }
    }

}

在main方法中测试

public class DFSDemo {

    public static void main(String[] args) {

        HNode[] nodes = new HNode[5];

        for (int i = 0; i < nodes.length; i++) {
            HNode<String> node = new HNode<>("张三-" + (i + 1));
            nodes[i] = node;
        }

        TNode node1 = new TNode(2);
        node1.nextArc = new TNode(3);
        nodes[0].firstArc = node1;
        TNode node2 = new TNode(0);
        node2.nextArc = new TNode(4);
        nodes[1].firstArc = node2;
        TNode node3 = new TNode(1);
        node3.nextArc = new TNode(3);
        nodes[2].firstArc = node3;
        TNode node4 = new TNode(0);
        node4.nextArc = new TNode(1);
        nodes[3].firstArc = node4;
        TNode node5 = new TNode(3);
        node5.nextArc = new TNode(2);
        nodes[4].firstArc = node5;

        for (HNode node : nodes) {
            System.out.println(node);
        }

        Graph graph = new Graph(nodes);

        System.out.println("--------------深度优先搜索--------------");
        graph.dfs(0);
    }
}

测试结果

java 宽度优先搜索算法 java深度优先搜索_深度优先_02