图的概念、存储方式,深度优先遍历与广度优先遍历

图的基本术语:

在这里插入图片描述
图结构中顶点具有多对多的关系,有有向图和无向图的区分,有带权图和无权图的区分。
QQ的好友双方中,一方删除好友,另一方的好友也会被删除,可以认为QQ的好友关系是一种无向图
微信的好友双方中,一方删除好友,另一方好友并不会被删除,可以认为微信的好友关系是一种有向图


图的存储

邻接矩阵

存储结构:
  图的邻接矩阵存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息(有权图的二维数组存储权重,0表示两顶点无关系;无权图的二维数组存储0,1表示两顶点无 / 有关系)。
  无向图的二维数组是一个对称矩阵,因为在无向图中,V0和V1有关联,那么V1和V0也必定有关联,因此Arr[0][1]和Arr[1][0]的值一定相等;有向图的二维数组则不满足这个规律。

邻接矩阵的缺点:
边信息的存储占用了太多的空间。试想,如果一个图有1000个顶点,其中只有10个顶点之间有关联(这种情况叫做稀疏图),却不得不建立一个1000X1000的二维数组,浪费了极大的存储空间。

邻接表

对于边数相对顶点较少的图,采用邻接表存储

存储结构:
图的所有顶点用链表或数组存储,后继节点所存储的是该顶点能够直接达到的相邻顶点

邻接表的优缺点:
  邻接表对于查找两个节点是否能够到达是非常容易的,但如果要查找与顶点A相差”一步“的顶点时,就需要遍历所有邻接表的顶点,这时候就需要使用逆邻接表

逆邻接表

存储结构:
图的所有顶点用链表或数组存储,后继节点所存储的是能够直接达到该顶点的相邻顶点(与邻接表相反)。

十字链表

存储结构:
结合了邻接链表和逆邻接链表
图结构的存储图解参考


图的遍历

遍历图中每一个顶点,且每一个顶点都只能被遍历一次

广度优先遍历(BFS,breadth first search)

  使用List中栈的特性完成遍历

 /**
     * 广度优先遍历
     */
    public static void breadthFS(Graph graph, int start, boolean[] visited, LinkedList<Integer> queue) {
        queue.offer(start);//入栈当前下标
        while (!queue.isEmpty()) {
            int front = queue.poll();//弹出栈顶下标
            if (visited[front]) {
                continue;//重新执行while循环
            }
            System.out.println(graph.vertexes[front].data);
            visited[front] = true;
            for (int index : graph.adj[front]) {
                queue.offer(index);
            }
        }
    }

深度优先遍历(DFS,depth first search)

  类似于树的前序遍历,在dfs中,不断的向下访问,然后使用递归方式回溯之前没有被遍历到的顶点
代码如下:

 /**
     * 深度优先遍历
     */
    public static void depthFS(Graph graph, int start, boolean[] visited) {
        System.out.println(graph.vertexes[start].data);
        visited[start] = true;//标记start位置元素已被访问

        for (int index : graph.adj[start]) {
            if (!visited[index]) {
                depthFS(graph, index, visited);
            }
        }
    }

邻接表的dfs / bfs遍历代码:

import java.util.LinkedList;

/**
 * 图的dfs / bfs遍历
 */
public class Graph_dfsAndBfs {
    public static void main(String[] args) {
        Graph graph = new Graph(6);
        graph.adj[0].add(1);
        graph.adj[0].add(2);
        graph.adj[0].add(3);

        graph.adj[1].add(0);
        graph.adj[1].add(3);
        graph.adj[1].add(4);

        graph.adj[2].add(0);

        graph.adj[3].add(0);
        graph.adj[3].add(1);
        graph.adj[3].add(4);
        graph.adj[3].add(5);

        graph.adj[4].add(1);
        graph.adj[4].add(3);
        graph.adj[4].add(5);

        graph.adj[5].add(3);
        graph.adj[5].add(4);
        System.out.println("图的深度优先遍历:");

        depthFS(graph, 0, new boolean[graph.size]);
        System.out.println("图的广度优先遍历:");

        breadthFS(graph, 0, new boolean[graph.size], new LinkedList<Integer>());
    }

    /**
     * 广度优先遍历
     */
    public static void breadthFS(Graph graph, int start, boolean[] visited, LinkedList<Integer> queue) {
        queue.offer(start);//入栈当前下标
        while (!queue.isEmpty()) {
            int front = queue.poll();//弹出栈顶下标
            if (visited[front]) {
                continue;//重新执行while循环
            }
            System.out.println(graph.vertexes[front].data);
            visited[front] = true;
            for (int index : graph.adj[front]) {
                queue.offer(index);
            }
        }
    }

    /**
     * 深度优先遍历
     */
    public static void depthFS(Graph graph, int start, boolean[] visited) {
        System.out.println(graph.vertexes[start].data);
        visited[start] = true;//标记start位置元素已被访问

        for (int index : graph.adj[start]) {
            if (!visited[index]) {
                depthFS(graph, index, visited);
            }
        }
    }

    /**
     * 图的顶点类
     */
    static class Vertex {
        int data;

        Vertex(int data) {
            this.data = data;
        }
    }

    /**
     * 图的存储(邻接表形式)
     */
    static class Graph {
        private int size;
        private Vertex[] vertexes;//存储每个顶点的数组
        private LinkedList<Integer> adj[];//每个顶点后的后继节点

        Graph(int size) {
            this.size = size;
            //初始化顶点和邻接矩阵
            vertexes = new Vertex[size];
            adj = new LinkedList[size];
            for (int i = 0; i < size; i++) {
                vertexes[i] = new Vertex(i);
                adj[i] = new LinkedList();
            }
        }
    }
}

图存储与遍历图文参考参考

发布了91 篇原创文章 · 获赞 54 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/BigBug_500/article/details/102879416