图BFS,DFS

1.采用邻接表的数据结构:

public class Graph {
    static ArrayList<Vertex> vertexList=new ArrayList<Vertex>();
    static int vertexNum=0;
    static int edgeNum=0;
    public Graph(){}
    //
    public static class Edge {
        int edgeName;//边的后面的节点
        Edge next;
        public Edge(){}
    }
    //
    public static class Vertex {
        String vertexName;
        Edge firstEdge=new Edge();
        public Vertex(){}
    }
    public static void main(String[] args) {
        Graph g=new Graph();
        Graph.initialGraph(g);
        Graph.outputGraph(g);
        Graph.DFS(g, 0);
        System.out.println();
        Graph.BFS(g, 0);
    }
    //根据节点名称生成节点下标,我们后续是需要用这个下标来进行遍历的
    public static int vtoe(Graph graph,String str){
        for(int i=0;i<graph.vertexNum;i++){
            if(graph.vertexList.get(i).vertexName.equals(str)){
                return i;
            }
        }
        return -1;
    }
    public static void initialGraph(Graph graph){
        Scanner scan=new Scanner(System.in);
        System.out.println("请输入顶点数和边数:");
        graph.vertexNum=scan.nextInt();
        graph.edgeNum=scan.nextInt();
        
        System.out.println("请依次输入定点名称:");
        for(int i=0;i<graph.vertexNum;i++){
            Vertex vertex=new Vertex();//构建一个个点
            String name=scan.next();
            vertex.vertexName=name;//顶点的名字
            vertex.firstEdge=null;//顶点后面的第一条边
            graph.vertexList.add(vertex);//然后把它加到点的list里面
        }
        System.out.println("请依次输入每个边:");
        for(int i=0;i<graph.edgeNum;i++){
            String preV=scan.next();//边的前一个节点
            String folV=scan.next();//边的后一个节点
            int v1=vtoe(graph,preV);//第v1个点
            int v2=vtoe(graph,folV);//第v2个点
            if(v1==-1 || v2==-1)
                System.out.println("输入顶点数据错误!");
            //下面代码是图构建的核心:链表操作
            Edge edge1=new Edge();
            edge1.edgeName=v2;
            //下面相当于链表的头插法,总是插到头结点的后面
            edge1.next=graph.vertexList.get(v1).firstEdge;
            graph.vertexList.get(v1).firstEdge=edge1;
//          下面代码加上便是构建无向图,不加便是构建有向图
//          Edge edge2=new Edge();
//          edge2.edgeName=v1;
//          edge2.next=graph.vertexList.get(v2).firstEdge;
//          graph.vertexList.get(v2).firstEdge=edge2;
        }
    }
    public static void outputGraph(Graph graph){
            Edge edge=new Edge();
            for(int i=0;i<graph.vertexNum;i++){
                System.out.print(graph.vertexList.get(i).vertexName);
                edge=graph.vertexList.get(i).firstEdge;
                while(edge!=null){
                    System.out.print("-->"+graph.vertexList.get(edge.edgeName).vertexName);
                    edge=edge.next;
                }
                System.out.println();
            }
     }
    //以邻接表为数据结构的DFS
    static int[] visited=new int[5];
    static void DFS(Graph graph,int v) {
        Edge p;
        visited[v]=1;
        System.out.print(graph.vertexList.get(v).vertexName+"-->");
        p = vertexList.get(v).firstEdge;
        while(p!=null) {
            if(visited[p.edgeName]==0)
                DFS(graph,p.edgeName);//每次要先查到最深处
            p=p.next;
        }    
    }
    static void BFS(Graph graph,int v) {
        Edge p;
        Queue<Integer> queue=new LinkedList<>();
        int[] visited=new int[vertexNum];
        System.out.print(graph.vertexList.get(v).vertexName+"-->");
        visited[v]=1;
        queue.add(v);
        while(!queue.isEmpty()) {
            int temp=queue.poll();
            p = vertexList.get(temp).firstEdge;
            while(p!=null) {
                if(visited[p.edgeName]==0) {
                    System.out.print(graph.vertexList.get(p.edgeName).vertexName+"-->");
                    visited[p.edgeName]=1;
                    queue.add(p.edgeName);
                }
                p=p.next;//首先把每个链表里面走完。(这里的链表的值是和这个节点连接的所有节点)
            }
        }
    }
    int vn,en;
    void DfsForTree(Graph graph,int v) {
        Edge p;
        visited[v]=1;
        vn++;
        p=graph.vertexList.get(v).firstEdge;
        while(p!=null) {
            en++;
            if(visited[p.edgeName]==0) {
                DfsForTree(graph, p.edgeName);
            }
            p=p.next;
        }
    }
    int GisTree(Graph g) {
        DfsForTree(g, 0);
        if(vn==g.vertexNum&&en==2*(g.edgeNum-1))
            return 1;
        else
            return 0;
    }
}

2. 对一个01矩阵用BFS求最短路径

static class point{
        int x;
        int y;
        int len;
        public point(int x, int y,int len) {
            this.x = x;
            this.y = y;
            this.len = len;
        }     
}
//01矩阵广度优先搜索 从(0,0)到(x,y)
    public static int minPathLength(int[][] grids, int x, int y) {
        int[][] dir = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};//方向
        int m = grids.length, n = grids[0].length;
        Queue<point> queue = new LinkedList<>();
        queue.add(new point(0, 0, 1));
        while (!queue.isEmpty()) {
            point cur = queue.poll();
            for (int i = 0; i < 4; i++) {
                point next = new point(cur.x + dir[i][0], cur.y + dir[i][1], cur.len+1);
                if (next.x < 0 || next.x >= m || next.y < 0 || next.y >= n) continue;
                if (grids[next.x][next.y] != 1) continue;//不能走
                grids[next.x][next.y] = 0;
                if (next.x == x && next.y == y) return next.len;
                queue.add(next);
            }
        }
        return -1;
    }

3.一个整数可以由多少个平方数组成(求最小的个数)BFS

两个数之间的差是一个平方数的话,代表两个数之间是连通的。

//求平方数集合
    private List<Integer> generateSquares(int n) {
        List<Integer> squares = new ArrayList<>();
        int square = 1;
        while (square*square <= n) {
            squares.add(square*square);
            square++;
        }
        return squares;
    }
    public int numSquares(int n) {
        List<Integer> squares = generateSquares(n);
        Queue<Integer> queue = new LinkedList<>();
        boolean[] visit = new boolean[n + 1];
        queue.add(n);
        visit[n] = true;
        int level = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            level++;
            while (size-- > 0) {
                int cur = queue.poll();
                for (int s : squares) {
                    int next = cur - s;
                    if (next < 0) {
                        break;//走不通
                    }
                    if (next == 0) {
                        return level;
                    }
                    if (visit[next]) {
                        continue;
                    }
                    visit[next] = true;
                    queue.add(cur - s);
                }
            }
        }
        return n;
    }

 4.求最大的岛屿

//01矩阵中连续1的个数(求这样的最大值)DFS深度优先搜索
    public int dfs(int [][]grid, int x, int y, int [][]visit, int count) {
        if (x < 0 || x > grid.length - 1 || y < 0 || y > grid[0].length - 1) {
            return count;
        }
        if (visit[x][y] == 1 || grid[x][y] == 0) {
            return count;
        }

        visit[x][y] = 1;
        count ++;
        count += dfs(grid, x + 1, y, visit, 0);//向右走
        count += dfs(grid, x - 1, y, visit, 0);//向左
        count += dfs(grid, x, y + 1, visit, 0);
        count += dfs(grid, x, y - 1, visit, 0);
        return count;
    }
    public int maxAreaOfIsland(int[][] grid) {
        int [][]visit = new int[grid.length][grid[0].length];
        int max = 0;
        for (int i = 0;i < grid.length;i ++) {
            for (int j = 0;j < grid[0].length;j ++) {
                if (grid[i][j] == 1) {
                    max = Math.max(max, dfs(grid, i, j, visit, 0));
                }
            }
        }
        return max;
    }

5.和上面类似,也是在01矩阵中,上面是求岛屿的最大值,这里是求一共有多少个岛屿,每个岛屿是被0包围着的

//仅仅是去遍历然后修改visit不用返回
    public void dfs(int [][]grid, int x, int y, int [][]visit) {
        if (x < 0 || x > grid.length - 1 || y < 0 || y > grid[0].length - 1) {
            return ;
        }
        if (visit[x][y] == 1 || grid[x][y] == 0) {
            return ;
        }

        visit[x][y] = 1;
        dfs(grid, x + 1, y, visit);//向右走
        dfs(grid, x - 1, y, visit);//向左
        dfs(grid, x, y + 1, visit);
        dfs(grid, x, y - 1, visit);
        return;
    }
    public int numOfIsland(int[][] grid) {
        int [][]visit = new int[grid.length][grid[0].length];
        int res = 0;
        for (int i = 0;i < grid.length;i ++) {
            for (int j = 0;j < grid[0].length;j ++) {
                if (grid[i][j] == 1&&visit[i][j]==0) {
                    //是岛屿且没有被遍历才去搜索
                    dfs(grid, i, j, visit);
                    res++;
                }
            }
        }
        return res;
    }

 6.有点像组合,但是没有解决重复的问题,从数组中取出k个数

public void dfs(List<Integer> list, int[] a, int k, int cur) {//k代表从中取的个数
        if (list.size() == k) {
            Alllist.add(new ArrayList<Integer>(list));
            return;
        }
        int n=a.length;
        for (int i = cur;i < n; i ++) {
            list.add(a[i]);
            dfs(list, a, k, i + 1);
            list.remove(list.size() - 1);           
        }
    }

 

posted @ 2019-06-28 10:58  LeeJuly  阅读(162)  评论(0)    收藏  举报