一、图

1、介绍

  图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。

数据结构与算法(七)——图

  无向完全图:在无向图中,任意两个顶点之间都存在边。含有 n 个顶点的无向完全图有 n*(n - 1)/2 条边。
  有向完全图:在有向图中,任意两个顶点之间都存在弧。含有 n 个顶点的有向完全图有 n*(n - 1)条边。
  通常认为边或弧数小于 n*logn (n是顶点个数)的图为稀疏图,反之为稠密图。

2、图的存储结构

  邻接矩阵:适用稠密图

  无向图

数据结构与算法(七)——图

  有向图

数据结构与算法(七)——图 

  网

数据结构与算法(七)——图

  邻接表:适用稀疏图

  无向图

数据结构与算法(七)——图

  有向图-顶点当弧尾

数据结构与算法(七)——图

  有向图-顶点当弧头

数据结构与算法(七)——图

  有向图-网

数据结构与算法(七)——图

3、图的遍历

数据结构与算法(七)——图

  深度优先遍历顺序为:1->2->4->8->5->3->6->7
  广度优先遍历顺序为:1->2->3->4->5->6->7->8
  深度优先遍历(DepthFirstSearch:DFS):类似于树的前序遍历
  思想:略。
  代码示例:见后

  广度优先遍历(BreadthFirstSearch:BFS):类似于树的层序遍历
  思想:需要一个辅助队列。

数据结构与算法(七)——图

  代码示例:深度优先、广度优先

  1 public class Graph {
  2 
  3     // 顶点集
  4     private List<String> vertex;
  5     // 邻接矩阵
  6     private int[][] matrix;
  7 
  8     public Graph(String[] vertex, int[][] matrix) {
  9         if (vertex == null || vertex.length == 0 || matrix == null) {
 10             return;
 11         }
 12 
 13         // 初始化顶点集
 14         this.vertex = new ArrayList<>(Arrays.asList(vertex));
 15 
 16         // 初始化邻接矩阵
 17         this.matrix = new int[vertex.length][vertex.length];
 18         for (int i = 0; i < vertex.length; i++) {
 19             System.arraycopy(matrix[i], 0, this.matrix[i], 0, vertex.length);
 20         }
 21     }
 22 
 23     // 深度优先遍历
 24     public void dfs() {
 25         // 记录某个结点是否被访问
 26         boolean[] visited = new boolean[vertex.size()];
 27         for (int i = 0; i < vertex.size(); i++) {
 28             if (!visited[i]) {
 29                 this.dfs(visited, i);
 30             }
 31         }
 32     }
 33 
 34     private void dfs(boolean[] visited, int i) {
 35         System.out.print(vertex.get(i) + "->");
 36         visited[i] = true;
 37 
 38         int w = this.getFirstNeighbor(i);
 39         // 找到
 40         while (w != -1) {
 41             if (!visited[w]) {
 42                 dfs(visited, w);
 43             }
 44             // w已经被访问过
 45             w = getNextNeighbor(i, w + 1);
 46         }
 47 
 48     }
 49 
 50     // 广度优先遍历
 51     public void bfs() {
 52         // 记录某个结点是否被访问
 53         boolean[] visited = new boolean[vertex.size()];
 54         for (int i = 0; i < vertex.size(); i++) {
 55             if (!visited[i]) {
 56                 this.bfs(visited, i);
 57             }
 58         }
 59     }
 60 
 61     private void bfs(boolean[] visited, int i) {
 62         System.out.print(vertex.get(i) + "->");
 63         visited[i] = true;
 64 
 65         // 队列.记录结点访问顺序
 66         Queue<Integer> queue = new LinkedList<>();
 67         queue.offer(i);
 68 
 69         while (!queue.isEmpty()) {
 70             final Integer u = queue.poll();
 71 
 72             // 得到u的第一个邻接结点的下标w
 73             int w = this.getFirstNeighbor(u);
 74             while (w != -1) {
 75                 if (!visited[w]) {
 76                     System.out.print(vertex.get(w) + "->");
 77                     visited[w] = true;
 78                     queue.offer(w);
 79                 }
 80                 // 以u为前驱,找w后的下一个邻接点
 81                 w = this.getNextNeighbor(u, w + 1);
 82             }
 83         }
 84     }
 85 
 86     private int getFirstNeighbor(int index) {
 87         return this.getNextNeighbor(index, 0);
 88     }
 89 
 90     // 根据前一个邻接结点的下标来获取下一个邻接结点
 91     private int getNextNeighbor(int index, int v2) {
 92         for (int j = v2; j < vertex.size(); j++) {
 93             if (matrix[index][j] > 0) {
 94                 return j;
 95             }
 96         }
 97 
 98         return -1;
 99     }
100 
101     // 显示图的邻接矩阵
102     public void showGraph() {
103         for (int[] link : this.matrix) {
104             System.out.println(Arrays.toString(link));
105         }
106     }
107 
108 }
深度、广度优先

相关文章: