• 图论-图的深度优先遍历-Java


    回顾力扣144/94//145/102/589/590/429,熟练掌握递归和非递归写法。

    图论不强调非递归。

    使用邻接表

    1个连通分量

    在这里插入图片描述Graph.java

    package Chapt02_DFS;
    import java.io.File;
    import java.io.IOException;
    import java.util.TreeSet;
    import java.util.Scanner;
    
    
    /// 暂时只支持无向无权图
    public class Graph {
    
        private int V;
        private int E;
        private TreeSet<Integer>[] adj;
    
        public Graph(String pathStr){
    
            File file = new File(pathStr);
    
            try(Scanner scanner = new Scanner(file)){
    
                V = scanner.nextInt();
                if(V < 0) throw new IllegalArgumentException("V must be non-negative");
                adj = new TreeSet[V];
                for(int i = 0; i < V; i ++)
                    adj[i] = new TreeSet<Integer>();
    
                E = scanner.nextInt();
                if(E < 0) throw new IllegalArgumentException("E must be non-negative");
    
                for(int i = 0; i < E; i ++){
                    int a = scanner.nextInt();
                    validateVertex(a);
                    int b = scanner.nextInt();
                    validateVertex(b);
    
                    if(a == b) throw new IllegalArgumentException("Self Loop is Detected!");
                    if(adj[a].contains(b)) throw new IllegalArgumentException("Parallel Edges are Detected!");
    
                    adj[a].add(b);
                    adj[b].add(a);
                }
            }
            catch(IOException e){
                e.printStackTrace();
            }
        }
    
        private void validateVertex(int v){
            if(v < 0 || v >= V)
                throw new IllegalArgumentException("vertex " + v + "is invalid");
        }
    
        public int V(){
            return V;
        }
    
        public int E(){
            return E;
        }
    
        public boolean hasEdge(int v, int w){
            validateVertex(v);
            validateVertex(w);
            return adj[v].contains(w);
        }
    
        public Iterable<Integer> adj(int v){
            validateVertex(v);
            return adj[v];
        }
    
        public int degree(int v){
            validateVertex(v);
            return adj[v].size();
        }
    
        @Override
        public String toString(){
            StringBuilder sb = new StringBuilder();
    
            sb.append(String.format("V = %d, E = %d\n", V, E));
            for(int v = 0; v < V; v ++){
                sb.append(String.format("%d : ", v));
                for(int w : adj[v])
                    sb.append(String.format("%d ", w));
                sb.append('\n');
            }
            return sb.toString();
        }
    
        public static void main(String[] args){
    
            Graph g = new Graph("g2.txt");
            System.out.print(g);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97

    GraphDFS.java

    package Chapt02_DFS;
    
    import java.util.ArrayList;
    
    public class GraphDFS {
    
        private Graph G;
        private boolean[] visited;
    
        //order存放遍历结果
        private ArrayList<Integer> order = new ArrayList<>();
    
        //在构造函数中对图遍历
        public GraphDFS(Graph G){
    
            this.G = G;
            /* public int V(){ return V;} 返回顶点的数量*/
            visited = new boolean[G.V()];
            dfs(0); //从第0个节点开始遍历
        }
    
        private void dfs(int v){
            visited[v] = true; //v这个顶点遍历过了
            order.add(v); //把v放到order数组中
    
            //把v的相邻顶点w进行遍历,如果相邻顶点没有被访问过则递归地对w顶点进行dfs
            for(int w: G.adj(v))
                if(!visited[w])
                    dfs(w);
        }
    
        // 返回一个可遍历的对象,具体是数组、链表、哈希表或者红黑树对用户屏蔽
        // 使用本方法访问遍历的元素
        public Iterable<Integer> order(){
            return order;
        }
    
        public static void main(String[] args){
    
            Graph g = new Graph("g2.txt");
            GraphDFS graphDFS = new GraphDFS(g);
            System.out.println(graphDFS.order());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在这里插入图片描述

    多个连通分量

    在这里插入图片描述

    只需要对GraphDFS中的构造函数进行改进
    在这里插入图片描述
    在这里插入图片描述

    GraphDFS.java

    package Chapt02_DFS;
    
    import java.util.ArrayList;
    
    public class GraphDFS {
    
        private Graph G;
        private boolean[] visited;
    
        //order存放遍历结果
        private ArrayList<Integer> order = new ArrayList<>();
    
        //在构造函数中对图遍历
        public GraphDFS(Graph G){
    
            this.G = G;
            /* public int V(){ return V;} 返回顶点的数量*/
            visited = new boolean[G.V()];
    
            for (int v = 0; v < G.V(); v++) {
                if(!visited[v]) dfs(v);
            }
     //       dfs(0); //从第0个节点开始遍历
        }
    
        private void dfs(int v){
            visited[v] = true; //v这个顶点遍历过了
            order.add(v); //把v放到order数组中
    
            //把v的相邻顶点w进行遍历,如果相邻顶点没有被访问过则递归地对w顶点进行dfs
            for(int w: G.adj(v))
                if(!visited[w])
                    dfs(w);
        }
    
        // 返回一个可遍历的对象,具体是数组、链表、哈希表或者红黑树对用户屏蔽
        // 使用本方法访问遍历的元素
        public Iterable<Integer> order(){
            return order;
        }
    
        public static void main(String[] args){
    
            Graph g = new Graph("g3.txt");
            GraphDFS graphDFS = new GraphDFS(g);
            System.out.println(graphDFS.order());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    图的先序遍历和后续遍历

    在这里插入图片描述

    package Chapt02_DFS;
    
    import java.util.ArrayList;
    
    public class GraphDFS {
    
        private Graph G;
        private boolean[] visited;
    
        //order存放遍历结果
    //    private ArrayList order = new ArrayList<>();
        private ArrayList<Integer> pre = new ArrayList<>(); // 存放先序遍历的结果
        private ArrayList<Integer> post = new ArrayList<>(); // 存放后续遍历的结果
    
    
        //在构造函数中对图遍历
        public GraphDFS(Graph G){
    
            this.G = G;
            /* public int V(){ return V;} 返回顶点的数量*/
            visited = new boolean[G.V()];
    
            for (int v = 0; v < G.V(); v++) {
                if(!visited[v]) dfs(v);
            }
     //       dfs(0); //从第0个节点开始遍历
        }
    
        private void dfs(int v){
            visited[v] = true; //v这个顶点遍历过了
    //        order.add(v); //把v放到order数组中
            pre.add(v); /*****************/
    
            //把v的相邻顶点w进行遍历,如果相邻顶点没有被访问过则递归地对w顶点进行dfs
            for(int w: G.adj(v))
                if(!visited[w])
                    dfs(w);
            post.add(v); /*****************/
        }
    
        // 返回一个可遍历的对象,具体是数组、链表、哈希表或者红黑树对用户屏蔽
        // 使用本方法访问遍历的元素
        public Iterable<Integer> pre(){
            return pre;
        }
        public Iterable<Integer> post(){
            return post;
        }
        public static void main(String[] args){
    
            Graph g = new Graph("g3.txt");
            GraphDFS graphDFS = new GraphDFS(g);
            System.out.println(graphDFS.post());
            System.out.println(graphDFS.pre());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    在这里插入图片描述

    使用邻接矩阵

    逻辑一模一样
    AdjMatrix.java

    package Chapt02_DFS;
    import java.io.*;
    import java.util.ArrayList;
    import java.util.Scanner;
    
    public class AdjMatrix {
    
        private int V;
        private int E;
        private int[][] adj;
    
        public AdjMatrix(String filename){
    
            File file = new File(filename);
    
            try(Scanner scanner = new Scanner(file)){
    
                V = scanner.nextInt();
                if(V < 0) throw new IllegalArgumentException("V must be non-negative");
                adj = new int[V][V];
    
                E = scanner.nextInt();
                if(E < 0) throw new IllegalArgumentException("E must be non-negative");
    
                for(int i = 0; i < E; i ++){
                    int a = scanner.nextInt();
                    validateVertex(a);
                    int b = scanner.nextInt();
                    validateVertex(b);
    
                    if(a == b) throw new IllegalArgumentException("Self Loop is Detected!");
                    if(adj[a][b] == 1) throw new IllegalArgumentException("Parallel Edges are Detected!");
    
                    adj[a][b] = 1;
                    adj[b][a] = 1;
                }
            }
            catch(IOException e){
                e.printStackTrace();
            }
        }
    
        private void validateVertex(int v){
            if(v < 0 || v >= V)
                throw new IllegalArgumentException("vertex " + v + "is invalid");
        }
    
        public int V(){
            return V;
        }
    
        public int E(){
            return E;
        }
    
        public boolean hasEdge(int v, int w){
            validateVertex(v);
            validateVertex(w);
            return adj[v][w] == 1;
        }
    
        public ArrayList<Integer> adj(int v){
            validateVertex(v);
            ArrayList<Integer> res = new ArrayList<>();
            for(int i = 0; i < V; i ++)
                if(adj[v][i] == 1)
                    res.add(i);
            return res;
        }
    
        public int degree(int v){
            return adj(v).size();
        }
    
        @Override
        public String toString(){
            StringBuilder sb = new StringBuilder();
    
            sb.append(String.format("V = %d, E = %d\n", V, E));
            for(int i = 0; i < V; i ++){
                for(int j = 0; j < V; j ++)
                    sb.append(String.format("%d ", adj[i][j]));
                sb.append('\n');
            }
            return sb.toString();
        }
    
        public static void main(String[] args){
    
            AdjMatrix adjMatrix = new AdjMatrix("g3.txt");
            System.out.print(adjMatrix);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94

    AdjMatrixDFS.java

    package Chapt02_DFS;
    import java.util.ArrayList;
    
    public class AdjMatrixDFS {
    
        private AdjMatrix G;
        private boolean[] visited;
    
        private ArrayList<Integer> pre = new ArrayList<>();
        private ArrayList<Integer> post = new ArrayList<>();
    
        public AdjMatrixDFS(AdjMatrix G){
    
            this.G = G;
            visited = new boolean[G.V()];
            for(int v = 0; v < G.V(); v ++)
                if(!visited[v])
                    dfs(v);
        }
    
        private void dfs(int v){
    
            visited[v] = true;
            pre.add(v);
            for(int w: G.adj(v))
                if(!visited[w])
                    dfs(w);
            post.add(v);
        }
    
        public Iterable<Integer> pre(){
            return pre;
        }
    
        public Iterable<Integer> post(){
            return post;
        }
    
        public static void main(String[] args){
    
            AdjMatrix g = new AdjMatrix("g3.txt");
            AdjMatrixDFS graphDFS = new AdjMatrixDFS(g);
            System.out.println("DFS preOrder : " + graphDFS.pre());
            System.out.println("DFS postOrder : " + graphDFS.post());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    在这里插入图片描述在这里插入图片描述

    使用接口

    Graph.java

    public interface Graph {
    
        int V();
        int E();
        boolean hasEdge(int v, int w);
        Iterable<Integer> adj(int v);
        int degree(int v);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在不同的图表中重写接口里的方法,其实是把不同图的方法都抽象了出来

    邻接表

    import java.io.File;
    import java.io.IOException;
    import java.util.LinkedList;
    import java.util.Scanner;
    
    public class AdjList implements Graph{
    
        private int V;
        private int E;
        private LinkedList<Integer>[] adj;
    
        public AdjList(String pathStr){
    
            File file = new File(pathStr);
    
            try(Scanner scanner = new Scanner(file)){
    
                V = scanner.nextInt();
                if(V < 0) throw new IllegalArgumentException("V must be non-negative");
                adj = new LinkedList[V];
                for(int i = 0; i < V; i ++)
                    adj[i] = new LinkedList<Integer>();
    
                E = scanner.nextInt();
                if(E < 0) throw new IllegalArgumentException("E must be non-negative");
    
                for(int i = 0; i < E; i ++){
                    int a = scanner.nextInt();
                    validateVertex(a);
                    int b = scanner.nextInt();
                    validateVertex(b);
    
                    if(a == b) throw new IllegalArgumentException("Self Loop is Detected!");
                    if(adj[a].contains(b)) throw new IllegalArgumentException("Parallel Edges are Detected!");
    
                    adj[a].add(b);
                    adj[b].add(a);
                }
            }
            catch(IOException e){
                e.printStackTrace();
            }
        }
    
        private void validateVertex(int v){
            if(v < 0 || v >= V)
                throw new IllegalArgumentException("vertex " + v + "is invalid");
        }
    
        public int V(){
            return V;
        }
    
        public int E(){
            return E;
        }
    
        public boolean hasEdge(int v, int w){
            validateVertex(v);
            validateVertex(w);
            return adj[v].contains(w);
        }
    
        public LinkedList<Integer> adj(int v){
            validateVertex(v);
            return adj[v];
        }
    
        public int degree(int v){
            return adj[v].size();
        }
    
        @Override
        public String toString(){
            StringBuilder sb = new StringBuilder();
    
            sb.append(String.format("V = %d, E = %d\n", V, E));
            for(int v = 0; v < V; v ++){
                sb.append(String.format("%d : ", v));
                for(int w : adj[v])
                    sb.append(String.format("%d ", w));
                sb.append('\n');
            }
            return sb.toString();
        }
    
        public static void main(String[] args){
    
            Graph adjList = new AdjList("g.txt");
            System.out.print(adjList);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    邻接矩阵

    import java.io.*;
    import java.util.ArrayList;
    import java.util.Scanner;
    
    public class AdjMatrix implements Graph {
    
        private int V;
        private int E;
        private int[][] adj;
    
        public AdjMatrix(String filename){
    
            File file = new File(filename);
    
            try(Scanner scanner = new Scanner(file)){
    
                V = scanner.nextInt();
                if(V < 0) throw new IllegalArgumentException("V must be non-negative");
                adj = new int[V][V];
    
                E = scanner.nextInt();
                if(E < 0) throw new IllegalArgumentException("E must be non-negative");
    
                for(int i = 0; i < E; i ++){
                    int a = scanner.nextInt();
                    validateVertex(a);
                    int b = scanner.nextInt();
                    validateVertex(b);
    
                    if(a == b) throw new IllegalArgumentException("Self Loop is Detected!");
                    if(adj[a][b] == 1) throw new IllegalArgumentException("Parallel Edges are Detected!");
    
                    adj[a][b] = 1;
                    adj[b][a] = 1;
                }
            }
            catch(IOException e){
                e.printStackTrace();
            }
        }
    
        private void validateVertex(int v){
            if(v < 0 || v >= V)
                throw new IllegalArgumentException("vertex " + v + "is invalid");
        }
    
        public int V(){
            return V;
        }
    
        public int E(){
            return E;
        }
    
        public boolean hasEdge(int v, int w){
            validateVertex(v);
            validateVertex(w);
            return adj[v][w] == 1;
        }
    
        public Iterable<Integer> adj(int v){
            validateVertex(v);
            ArrayList<Integer> res = new ArrayList<>();
            for(int i = 0; i < V; i ++)
                if(adj[v][i] == 1)
                    res.add(i);
            return res;
        }
    
        public int degree(int v){
            validateVertex(v);
            int res = 0;
            for(int i = 0; i < V; i ++)
                res += adj[v][i];
            return res;
        }
    
        @Override
        public String toString(){
            StringBuilder sb = new StringBuilder();
    
            sb.append(String.format("V = %d, E = %d\n", V, E));
            for(int i = 0; i < V; i ++){
                for(int j = 0; j < V; j ++)
                    sb.append(String.format("%d ", adj[i][j]));
                sb.append('\n');
            }
            return sb.toString();
        }
    
        public static void main(String[] args){
    
            Graph adjMatrix = new AdjMatrix("g.txt");
            System.out.print(adjMatrix);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97

    使用红黑树构造邻接表

    import java.io.File;
    import java.io.IOException;
    import java.util.TreeSet;
    import java.util.Scanner;
    
    public class AdjSet implements Graph{
    
        private int V;
        private int E;
        private TreeSet<Integer>[] adj;
    
        public AdjSet(String pathStr){
    
            File file = new File(pathStr);
    
            try(Scanner scanner = new Scanner(file)){
    
                V = scanner.nextInt();
                if(V < 0) throw new IllegalArgumentException("V must be non-negative");
                adj = new TreeSet[V];
                for(int i = 0; i < V; i ++)
                    adj[i] = new TreeSet<Integer>();
    
                E = scanner.nextInt();
                if(E < 0) throw new IllegalArgumentException("E must be non-negative");
    
                for(int i = 0; i < E; i ++){
                    int a = scanner.nextInt();
                    validateVertex(a);
                    int b = scanner.nextInt();
                    validateVertex(b);
    
                    if(a == b) throw new IllegalArgumentException("Self Loop is Detected!");
                    if(adj[a].contains(b)) throw new IllegalArgumentException("Parallel Edges are Detected!");
    
                    adj[a].add(b);
                    adj[b].add(a);
                }
            }
            catch(IOException e){
                e.printStackTrace();
            }
        }
    
        private void validateVertex(int v){
            if(v < 0 || v >= V)
                throw new IllegalArgumentException("vertex " + v + "is invalid");
        }
    
        public int V(){
            return V;
        }
    
        public int E(){
            return E;
        }
    
        public boolean hasEdge(int v, int w){
            validateVertex(v);
            validateVertex(w);
            return adj[v].contains(w);
        }
    
        public Iterable<Integer> adj(int v){
        // public TreeSet adj(int v){
            validateVertex(v);
            return adj[v];
        }
    
        public int degree(int v){
            validateVertex(v);
            return adj[v].size();
        }
    
        @Override
        public String toString(){
            StringBuilder sb = new StringBuilder();
    
            sb.append(String.format("V = %d, E = %d\n", V, E));
            for(int v = 0; v < V; v ++){
                sb.append(String.format("%d : ", v));
                for(int w : adj[v])
                    sb.append(String.format("%d ", w));
                sb.append('\n');
            }
            return sb.toString();
        }
    
        public static void main(String[] args){
    
            Graph adjSet = new AdjSet("g.txt");
            System.out.print(adjSet);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95

    GraphDFS.java

    package Chapt02_DFS;
    
    import java.util.ArrayList;
    
    public class GraphDFS {
    
        private Graph G;
        private boolean[] visited;
    
        private ArrayList<Integer> pre = new ArrayList<>();
        private ArrayList<Integer> post = new ArrayList<>();
    
        public GraphDFS(Graph G){
    
            this.G = G;
            visited = new boolean[G.V()];
            for(int v = 0; v < G.V(); v ++)
                if(!visited[v])
                    dfs(v);
        }
    
        private void dfs(int v){
    
            visited[v] = true;
            pre.add(v);
            for(int w: G.adj(v))
                if(!visited[w])
                    dfs(w);
            post.add(v);
        }
    
        public Iterable<Integer> pre(){
            return pre;
        }
    
        public Iterable<Integer> post(){
            return post;
        }
    
        public static void main(String[] args){
    
            Graph g1 = new AdjSet("g3.txt");
            GraphDFS graphDFS1 = new GraphDFS(g1);
            System.out.println("DFS preOrder : " + graphDFS1.pre());
            System.out.println("DFS postOrder : " + graphDFS1.post());
            System.out.println();
    
            Graph g2 = new AdjList("g3.txt");
            GraphDFS graphDFS2 = new GraphDFS(g2);
            System.out.println("DFS preOrder : " + graphDFS2.pre());
            System.out.println("DFS postOrder : " + graphDFS2.post());
            System.out.println();
    
            Graph g3 = new AdjMatrix("g3.txt");
            GraphDFS graphDFS3 = new GraphDFS(g3);
            System.out.println("DFS preOrder : " + graphDFS3.pre());
            System.out.println("DFS postOrder : " + graphDFS3.post());
            System.out.println();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    在这里插入图片描述

    使用非递归的方法遍历图——使用栈

    package Chapt02_DFS;
    
    import java.util.ArrayList;
    import java.util.Stack;
    
    public class GraphDFSnr {
    
        private Graph G;
        private boolean[] visited;
    
        private ArrayList<Integer> pre = new ArrayList<>();
    
    
        public GraphDFSnr(Graph G){
    
            this.G = G;
            visited = new boolean[G.V()];
            for(int v = 0; v < G.V(); v ++)
                if(!visited[v])
                    dfs(v);
        }
    
        private void dfs(int v){
    
            Stack<Integer> stack = new Stack<>();
            stack.push(v);
            visited[v] = true;
            while(!stack.empty()){
                int cur = stack.pop();
                pre.add(cur);
                for(int w: G.adj(v))
                    if(!visited[w]){
                        stack.push(w);
                        visited[w] = true;
                    }
            }
        }
    
    
        public Iterable<Integer> pre(){
            return pre;
        }
    
    
    
        public static void main(String[] args){
    
            Graph g1 = new AdjSet("g3.txt");
            GraphDFSnr graphDFS1 = new GraphDFSnr(g1);
            System.out.println("DFS preOrder : " + graphDFS1.pre());
    
            System.out.println();
    
            Graph g2 = new AdjList("g3.txt");
            GraphDFSnr graphDFS2 = new GraphDFSnr(g2);
            System.out.println("DFS preOrder : " + graphDFS2.pre());
    
            System.out.println();
    
            Graph g3 = new AdjMatrix("g3.txt");
            GraphDFSnr graphDFS3 = new GraphDFSnr(g3);
            System.out.println("DFS preOrder : " + graphDFS3.pre());
    
            System.out.println();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    在这里插入图片描述

    联通分量的数量

    在这里插入图片描述

    public class CC {
    
        private Graph G;
        private boolean[] visited;
        private int cccount = 0;
    
        public CC(Graph G){
    
            this.G = G;
            visited = new boolean[G.V()];
            for(int v = 0; v < G.V(); v ++)
                if(!visited[v]){
                    dfs(v);
                    cccount ++; // 在if循环内
                }
        }
    
        private void dfs(int v){
    
            visited[v] = true;
            for(int w: G.adj(v))
                if(!visited[w])
                    dfs(w);
        }
    
        public int count(){
            return cccount;
        }
    
        public static void main(String[] args){
    
            Graph g = new AdjList("g3.txt");
            CC cc = new CC(g);
            System.out.println(cc.count());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    在这里插入图片描述

    具体求解无向图的联通分量

    在这里插入图片描述
    list并不是必要的,可以通过设置visited的值来区别不同的联通分量。

    package Chapt02_DFS;
    import java.util.ArrayList;
    
    public class CC {
    
        private Graph G;
        private int[] visited; // boolean 设置为 int
        private int cccount = 0;
    
        public CC(Graph G){
    
            this.G = G;
            visited = new int[G.V()];
            for(int i = 0; i < visited.length; i ++)
                visited[i] = -1; // 把未遍历的设置为-1
    
            for(int v = 0; v < G.V(); v ++)
                if(visited[v] == -1){
                    dfs(v, cccount); //dfs(int v, int ccid),ccid初始值为ccount==0 
                    cccount ++; //遍历完一组以后,ccount的值+1
                }
        }
    
        private void dfs(int v, int ccid){
            visited[v] = ccid;
            for(int w: G.adj(v))
                if(visited[w] == -1)
                    dfs(w, ccid);
        }
    
        public int count(){
            for(int e: visited)
                System.out.print(e + " ");
            System.out.println();
            return cccount;
        }
    
        public static void main(String[] args){
    
            Graph g = new AdjList("g3.txt");
            CC cc = new CC(g);
            System.out.println(cc.count());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在这里插入图片描述

    判断两个顶点是否属于同一连通分量 / 这个图有多少联通分量,每个联通分量有多少顶点

    把验证代码调整为public
    在这里插入图片描述
    Graph.java

    import java.io.File;
    import java.io.IOException;
    import java.util.TreeSet;
    import java.util.Scanner;
    
    
    /// 暂时只支持无向无权图
    public class Graph {
    
        private int V;
        private int E;
        private TreeSet<Integer>[] adj;
    
        public Graph(String filename){
    
            File file = new File(filename);
    
            try(Scanner scanner = new Scanner(file)){
    
                V = scanner.nextInt();
                if(V < 0) throw new IllegalArgumentException("V must be non-negative");
                adj = new TreeSet[V];
                for(int i = 0; i < V; i ++)
                    adj[i] = new TreeSet<Integer>();
    
                E = scanner.nextInt();
                if(E < 0) throw new IllegalArgumentException("E must be non-negative");
    
                for(int i = 0; i < E; i ++){
                    int a = scanner.nextInt();
                    validateVertex(a);
                    int b = scanner.nextInt();
                    validateVertex(b);
    
                    if(a == b) throw new IllegalArgumentException("Self Loop is Detected!");
                    if(adj[a].contains(b)) throw new IllegalArgumentException("Parallel Edges are Detected!");
    
                    adj[a].add(b);
                    adj[b].add(a);
                }
            }
            catch(IOException e){
                e.printStackTrace();
            }
        }
    
        public void validateVertex(int v){
            if(v < 0 || v >= V)
                throw new IllegalArgumentException("vertex " + v + "is invalid");
        }
    
        public int V(){
            return V;
        }
    
        public int E(){
            return E;
        }
    
        public boolean hasEdge(int v, int w){
            validateVertex(v);
            validateVertex(w);
            return adj[v].contains(w);
        }
    
        public Iterable<Integer> adj(int v){
            validateVertex(v);
            return adj[v];
        }
    
        public int degree(int v){
            validateVertex(v);
            return adj[v].size();
        }
    
        @Override
        public String toString(){
            StringBuilder sb = new StringBuilder();
    
            sb.append(String.format("V = %d, E = %d\n", V, E));
            for(int v = 0; v < V; v ++){
                sb.append(String.format("%d : ", v));
                for(int w : adj[v])
                    sb.append(String.format("%d ", w));
                sb.append('\n');
            }
            return sb.toString();
        }
    
        public static void main(String[] args){
    
            Graph g = new Graph("g.txt");
            System.out.print(g);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    CC.java

    package Chapt02_DFS.connected;
    import Chapt02_DFS.AdjList;
    import Chapt02_DFS.Graph;
    
    import java.util.ArrayList;
    
    public class CC {
    
        private Graph_1 G;
        private int[] visited;
        private int cccount = 0;
    
        public CC(Graph_1 G){
    
            this.G = G;
            visited = new int[G.V()];
            for(int i = 0; i < visited.length; i ++)
                visited[i] = -1;
    
            for(int v = 0; v < G.V(); v ++)
                if(visited[v] == -1){
                    dfs(v, cccount);
                    cccount ++;
                }
        }
    
        private void dfs(int v, int ccid){
    
            visited[v] = ccid;
            for(int w: G.adj(v))
                if(visited[w] == -1)
                    dfs(w, ccid);
        }
    
        public int count(){
            return cccount;
        }
    
        // 判断两个顶点是否属于同一连通分量
        public boolean isConnected(int v, int w){
            G.validateVertex(v);
            G.validateVertex(w);
            return visited[v] == visited[w];
        }
    
        public ArrayList<Integer>[] components(){ // 每个联通分量设置一个ArrayList
    
            ArrayList<Integer>[] res = new ArrayList[cccount];
    
            for(int i = 0; i < cccount; i ++) // 设置联通分量的ArrayList
                res[i] = new ArrayList<Integer>();
    
            for(int v = 0; v < G.V(); v ++) // 填充每个连通分量的ArrayList
                res[visited[v]].add(v); // visited[v]是组名,表示是哪个连通分量
    
            return res;
        }
    
        public static void main(String[] args){
    
            Graph_1 g = new Graph_1("g3.txt");
            CC cc = new CC(g);
            System.out.println(cc.count());
    
            System.out.println(cc.isConnected(0, 6));
            System.out.println(cc.isConnected(5, 6));
    
            ArrayList<Integer>[] comp = cc.components(); // 把res数组给了comp数组
    
            for(int ccid = 0; ccid < comp.length; ccid ++){ // ccid = 0、1
                System.out.print(ccid + " : ");
    
                for(int w: comp[ccid]) //把res[1]/res[2]里的值取出来
                    System.out.print(w + " ");
    
                System.out.println();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    在这里插入图片描述

  • 相关阅读:
    Java代码审计安全篇-SSRF(服务端请求伪造)漏洞
    jenkins出错与恢复
    【UE5:CesiumForUnreal】——加载无高度地形数据
    大数据开发之数据仓库
    Golang基础-面向过程篇
    什么是网络安全?如何让小白简单的学习网络安全
    C规范编辑笔记(二)
    Graalvm-21 Windows初体验
    密度图计数
    欣赏绍兴的美景,感受OLED透明拼接屏带来的视觉盛宴
  • 原文地址:https://blog.csdn.net/jiangchufeng123/article/details/132657067