数据结构与算法:图形结构

大数据 算法
图形结构是一种比树形结构更复杂的非线性结构。在树形结构中,结点间具有分支层次关系,每一层上的结点只能和上一层中的至多一个结点相关,但可能和下一层的多个结点相关。而在图形结构中,任意两个结点之间都可能相关,即结点之间的邻接关系可以是任意的。

图形结构是一种比树形结构更复杂的非线性结构。在树形结构中,结点间具有分支层次关系,每一层上的结点只能和上一层中的至多一个结点相关,但可能和下一层的多个结点相关。而在图形结构中,任意两个结点之间都可能相关,即结点之间的邻接关系可以是任意的。

因此,图形结构被用于描述各种复杂的数据对象,在自然科学、社会科学和人文科学等许多领域有着非常广泛的应用 。图形结构在计算机科学、人工智能、电子线路分析、最短路径寻找、工程计划、化学化合物分析统计力学、遗传学、控制论语言学和社会科学等方面均有不同程度的应用可以这样说,图形结构在所有数据结构中应用最为广泛。如在地铁站中的线路图:

 

数据结构与算法:图形结构

图的定义

图是一种数据结构,其中节点可以具有零个或多个相邻元素,两个节点的连接称之为边,节点在图形结构中也被称为顶点,一个顶点到另一个顶点的经过的的线路称为路径。

  • 图形结构有3种类型:无向图、有向图、带权图
  • 无向图:顶点A与顶点B之间的边是无方向的,可以从A到B,也可以从B到A
  • 有向图:顶点A与顶点B之间的边是有方向的,可以从A到B,但不可以从B到A
  • 带权图:顶点A与顶点B之间的边是带有属性的,如A到B的 距离。

 

数据结构与算法:图形结构

图的表达方式

图的表达方式有两种:邻接矩阵(使用二维数组)和邻接表(使用数组+链表)

邻接矩阵

邻接矩阵是表示图形中各顶点之间的关系,矩阵的行和列对应各顶点,坐标位置上的值对于它们之间的关系,1为连接, 0为没有连接。在程序中用二维数组来实现。

 

数据结构与算法:图形结构

邻接表

邻接表只关系存在的边,不需要去为不存在的边分配空间,因此比邻接矩阵来说,避免了不必要的空间浪费。在程序中用数组+链表的形式实现,数组存储对应的顶点,链表存储该顶点连接的所有顶点。

 

数据结构与算法:图形结构

图的搜索算法

图形结构基础属性和方法

以下的代码演示都是以邻接矩阵表达方式来实现的

 

  1. //图形结构(邻接矩阵) 
  2. class Graph { 
  3.      //存储图中所有顶点 
  4.     private List<String> vertexes; 
  5.     //图形结构的邻接矩阵 
  6.     private int[][] matrix; 
  7.     //各顶点访问情况,true为已访问,false为未访问 
  8.     private boolean[] visited; 
  9.  
  10.     /** 
  11.      * 根据传入的顶点信息生成矩阵 
  12.      * @param s 
  13.      */ 
  14.     public Graph(String s[]) { 
  15.         vertexes = new ArrayList<>(); 
  16.         for (String vertex : s){ 
  17.             vertexes.add(vertex); 
  18.         } 
  19.         matrix = new int[s.length][s.length]; 
  20.     } 
  21.  
  22.     /** 
  23.      * 将俩个顶点连接,即生成边 
  24.      * @param index1 顶点在集合中的索引 
  25.      * @param index2 
  26.      */ 
  27.     public void connect(int index1, int index2){ 
  28.         if (index1 < 0 || index1 > matrix.length || index2 < 0 || index2 > matrix.length){ 
  29.             throw new RuntimeException("该顶点未存在"); 
  30.         } 
  31.         //将新的邻接添加的邻接矩阵中 
  32.         matrix[index1][index2] = 1; 
  33.         matrix[index2][index1] = 1; 
  34.     } 
  35.  
  36.     /** 
  37.      * 展示邻接矩阵 
  38.      */ 
  39.     public void showGraphMatrix(){ 
  40.         for (int arr[] : matrix){ 
  41.             System.out.println(Arrays.toString(arr)); 
  42.         } 
  43.     } 
  44.      
  45.     /** 
  46.      * 获取顶点在邻接矩阵对应行row中的第一个邻接顶点下标 
  47.      * @param row 
  48.      * @return 当有邻接顶点时返回邻接顶点下标,没有则返回-1 
  49.      */ 
  50.     public int getFirstNeighbor(int row){ 
  51.         for(int i =0; i<matrix.length; i++){ 
  52.             if (matrix[row][i] != 0){ 
  53.                 return i; 
  54.             } 
  55.         } 
  56.         return -1; 
  57.     } 
  58.  
  59.     /** 
  60.      * 获取顶点在邻接矩阵对于行row中col列的下一个邻接顶点 
  61.      * @param row 
  62.      * @param col 
  63.      * @return 当有邻接顶点时返回邻接顶点下标,没有则返回-1 
  64.      */ 
  65.     public int getNeighbor(int row, int col){ 
  66.         for (int i=col+1; i<matrix.length; i++){ 
  67.             if (matrix[row][i] != 0){ 
  68.                 return i; 
  69.             } 
  70.         } 
  71.         return -1; 
  72.     } 

深度优先搜索

深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。这样的访问策略是优先往纵向进行深入挖掘,而不是对一个顶点的所有邻接顶点进行横线访问。简单来说就是一条路走到死,不行再掉头。

思路:从当前顶点选一个与之连接而未访问过的顶点,将当前节点往该邻接顶点移动,如果邻接顶点没有未访问的,则回溯到上一个顶点位置,继续该步骤。直到所有顶点都访问过。

往邻接但未访问过的顶点移动

 

数据结构与算法:图形结构

邻接顶点没有未访问的,进行回溯,直到遇到未访问的邻接顶点

 

数据结构与算法:图形结构

当所有顶点都被访问过时,退出算法

 

数据结构与算法:图形结构

下面是深度优先搜索的过程动画

 

数据结构与算法:图形结构

代码演示

 

  1. public void dsf(){ 
  2.     visited = new boolean[vertexes.size()]; 
  3.     //以在集合中下标为0的顶点,进行深度搜索 
  4.     dsf(visited, 0); 
  5.  
  6. /** 
  7.  * 深度优先搜索 
  8.  * @param visited 
  9.  * @param row 
  10.  */ 
  11. public void dsf(boolean[] visited, int row){ 
  12.     //输出当前顶点 
  13.     System.out.print(vertexes.get(row) + " -> "); 
  14.     //将当前顶点设为已访问 
  15.     visited[row] = true
  16.     //获取当前顶点的邻接顶点下标 
  17.     int index = getFirstNeighbor(row); 
  18.     //如果当前顶点有邻接顶点则进行深度搜索 
  19.     while (index != -1){ 
  20.         //当邻接顶点未访问时,则递归遍历 
  21.         if (visited[index] != true){ 
  22.             dsf(visited, index); 
  23.         } 
  24.         //当邻接顶点已访问时,则寻找另一个邻接顶点 
  25.         index = getNeighbor(row, index); 
  26.     } 

宽度优先搜索

宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。

宽度优先搜索算法类似于一个分层搜索的过程,宽度优先搜索算法需要一个队列以保持访问过顶点的顺序,以便按这个顺序来访问这些顶点的邻接顶点。

思路:依次访问当前顶点的邻接顶点,并按访问顺序将这些邻接顶点存储在队列中,当当前顶点的所有邻接顶点都被访问后,从队列中弹出一个顶点,以该顶点为当前顶点继续该步骤,直到所有顶点都被访问过。

依次访问当前顶点的所有邻接顶点,并把这些邻接顶点按访问顺序存储在队列中

 

数据结构与算法:图形结构

当前顶点没有未访问的邻接顶点,从队列中弹出一个顶点,以该弹出顶点继续访问未访问的邻接顶点

 

数据结构与算法:图形结构

注意,虽然图中的顶点都已经访问过了,但还是要等队列中的所有顶点弹出访问后,算法才结束

 

数据结构与算法:图形结构

下面时宽度优先搜索的过程动画

 

数据结构与算法:图形结构

代码演示

 

  1. public void bfs(){ 
  2.     visited = new boolean[vertexes.size()]; 
  3.     ////以在集合中下标为0的顶点,进行广度优先搜索 
  4.     bfs(visited, 0); 
  5.  
  6. /** 
  7.  * 广度优先搜索 
  8.  * @param visited 
  9.  * @param row 
  10.  */ 
  11. public void bfs(boolean[] visited, int row){ 
  12.     //创建队列,存储遍历邻接顶点的顺序 
  13.     LinkedList queue = new LinkedList(); 
  14.     //输出当前顶点 
  15.     System.out.print(vertexes.get(row) + " -> "); 
  16.     //将当前顶点设为已访问 
  17.     visited[row] = true
  18.     //将当前顶点加入队列中 
  19.     queue.add(row); 
  20.     //当队列不为空时,即有未搜索的邻接顶点,进行搜索 
  21.     while (!queue.isEmpty()){ 
  22.         //按顺序从队列中弹出邻接顶点下标 
  23.         int last = (Integer)queue.removeFirst(); 
  24.         //获取该弹出顶点的邻接顶点下标 
  25.         int index = getFirstNeighbor(last); 
  26.         //当弹出顶点有邻接顶点时,进行广度搜索 
  27.         while(index != -1){ 
  28.             //当邻接顶点未访问时 
  29.             if(visited[index] != true){ 
  30.                 //输出该邻接顶点 
  31.                 System.out.print(vertexes.get(index) + " -> "); 
  32.                 //把该邻接顶点设为已访问 
  33.                 visited[index] = true
  34.                 //将该邻接顶点加入队列 
  35.                 queue.addLast(index); 
  36.             } 
  37.             //继续寻找弹出顶点的另一个邻接顶点 
  38.             index = getNeighbor(lastindex); 
  39.         } 
  40.     } 

完整演示代码

 

  1. public class GraphDemo { 
  2.     public static void main(String[] args) { 
  3.         String[] s = {"A","B","C","D","E","F","G"}; 
  4.         Graph graph = new Graph(s); 
  5.         //A-B A-C A-G A-F F-D F-E D-E E-G 
  6.         graph.connect(0, 1); 
  7.         graph.connect(0, 2); 
  8.         graph.connect(0, 6); 
  9.         graph.connect(0, 5); 
  10.         graph.connect(5, 3); 
  11.         graph.connect(5, 4); 
  12.         graph.connect(3, 4); 
  13.         graph.connect(4, 6); 
  14.         graph.showGraphMatrix(); 
  15.  
  16.         graph.dsf();//A -> B -> C -> F -> D -> E -> G ->  
  17.         System.out.println(); 
  18.         graph.bfs();//A -> B -> C -> F -> G -> D -> E ->  
  19.     } 
  20.  
  21. //图形结构 
  22. class Graph { 
  23.     //存储图中所有顶点 
  24.     private List<String> vertexes; 
  25.     //图形结构的邻接矩阵 
  26.     private int[][] matrix; 
  27.     //各顶点访问情况,true为已访问,false为未访问 
  28.     private boolean[] visited; 
  29.  
  30.     /** 
  31.      * 根据传入的顶点信息生成矩阵 
  32.      * @param s 
  33.      */ 
  34.     public Graph(String s[]) { 
  35.         vertexes = new ArrayList<>(); 
  36.         for (String vertex : s){ 
  37.             vertexes.add(vertex); 
  38.         } 
  39.         matrix = new int[s.length][s.length]; 
  40.     } 
  41.  
  42.     /** 
  43.      * 将俩个顶点连接,即生成边 
  44.      * @param index1 顶点在集合中的索引 
  45.      * @param index2 
  46.      */ 
  47.     public void connect(int index1, int index2){ 
  48.         if (index1 < 0 || index1 > matrix.length || index2 < 0 || index2 > matrix.length){ 
  49.             throw new RuntimeException("该顶点未存在"); 
  50.         } 
  51.         //将新的邻接添加的邻接矩阵中 
  52.         matrix[index1][index2] = 1; 
  53.         matrix[index2][index1] = 1; 
  54.     } 
  55.  
  56.     /** 
  57.      * 展示邻接矩阵 
  58.      */ 
  59.     public void showGraphMatrix(){ 
  60.         for (int arr[] : matrix){ 
  61.             System.out.println(Arrays.toString(arr)); 
  62.         } 
  63.     } 
  64.  
  65.     public void dsf(){ 
  66.         visited = new boolean[vertexes.size()]; 
  67.         //以在集合中下标为0的顶点,进行深度优先搜索 
  68.         dsf(visited, 0); 
  69.     } 
  70.  
  71.     /** 
  72.      * 深度优先搜索 
  73.      * @param visited 
  74.      * @param row 
  75.      */ 
  76.     public void dsf(boolean[] visited, int row){ 
  77.         //输出当前顶点 
  78.         System.out.print(vertexes.get(row) + " -> "); 
  79.         //将当前顶点设为已访问 
  80.         visited[row] = true
  81.         //获取当前顶点的邻接顶点下标 
  82.         int index = getFirstNeighbor(row); 
  83.         //如果当前顶点有邻接顶点则进行深度搜索 
  84.         while (index != -1){ 
  85.             //当邻接顶点未访问时,则递归遍历 
  86.             if (visited[index] != true){ 
  87.                 dsf(visited, index); 
  88.             } 
  89.             //当邻接顶点已访问时,则寻找另一个邻接顶点 
  90.             index = getNeighbor(row, index); 
  91.         } 
  92.     } 
  93.  
  94.     public void bfs(){ 
  95.         visited = new boolean[vertexes.size()]; 
  96.         ////以在集合中下标为0的顶点,进行广度优先搜索 
  97.         bfs(visited, 0); 
  98.     } 
  99.  
  100.     /** 
  101.      * 广度优先搜索 
  102.      * @param visited 
  103.      * @param row 
  104.      */ 
  105.     public void bfs(boolean[] visited, int row){ 
  106.         //创建队列,存储遍历邻接顶点的顺序 
  107.         Queue queue = new ArrayDeque(); 
  108.         //输出当前顶点 
  109.         System.out.print(vertexes.get(row) + " -> "); 
  110.         //将当前顶点设为已访问 
  111.         visited[row] = true
  112.         //将当前顶点加入队列中 
  113.         queue.add(row); 
  114.         //当队列不为空时,即有未搜索的邻接顶点,进行搜索 
  115.         while (!queue.isEmpty()){ 
  116.             //按顺序从队列中弹出邻接顶点下标 
  117.             int last = (Integer)queue.poll(); 
  118.             //获取该弹出顶点的邻接顶点下标 
  119.             int index = getFirstNeighbor(last); 
  120.             //当弹出顶点有邻接顶点时,进行广度搜索 
  121.             while(index != -1){ 
  122.                 //当邻接顶点未访问时 
  123.                 if(visited[index] != true){ 
  124.                     //输出该邻接顶点 
  125.                     System.out.print(vertexes.get(index) + " -> "); 
  126.                     //把该邻接顶点设为已访问 
  127.                     visited[index] = true
  128.                     //将该邻接顶点加入队列 
  129.                     queue.add(index); 
  130.                 } 
  131.                 //继续寻找弹出顶点的另一个邻接顶点 
  132.                 index = getNeighbor(lastindex); 
  133.             } 
  134.         } 
  135.     } 
  136.  
  137.     /** 
  138.      * 获取顶点在邻接矩阵对应行row中的第一个邻接顶点下标 
  139.      * @param row 
  140.      * @return 当有邻接顶点时返回邻接顶点下标,没有则返回-1 
  141.      */ 
  142.     public int getFirstNeighbor(int row){ 
  143.         for(int i =0; i<matrix.length; i++){ 
  144.             if (matrix[row][i] != 0){ 
  145.                 return i; 
  146.             } 
  147.         } 
  148.         return -1; 
  149.     } 
  150.  
  151.     /** 
  152.      * 获取顶点在邻接矩阵对于行row中col列的下一个邻接顶点 
  153.      * @param row 
  154.      * @param col 
  155.      * @return 当有邻接顶点时返回邻接顶点下标,没有则返回-1 
  156.      */ 
  157.     public int getNeighbor(int row, int col){ 
  158.         for (int i=col+1; i<matrix.length; i++){ 
  159.             if (matrix[row][i] != 0){ 
  160.                 return i; 
  161.             } 
  162.         } 
  163.         return -1; 
  164.     } 

 

责任编辑:未丽燕 来源: Gofy的博客
相关推荐

2023-03-08 08:03:09

数据结构算法归并排序

2023-10-27 07:04:20

2023-03-10 08:07:39

数据结构算法计数排序

2023-03-02 08:15:13

2023-03-07 08:02:07

数据结构算法数列

2017-08-31 09:45:43

JavaArrayList数据

2023-11-06 06:43:23

单链表查询数据结构

2023-03-13 10:08:31

数据结构算法

2023-09-15 10:33:41

算法数据结构

2023-04-27 09:13:20

排序算法数据结构

2021-05-12 09:07:09

Java数据结构算法

2023-02-08 07:52:36

跳跃表数据结构

2023-10-30 08:31:42

数据结构算法

2021-01-28 07:33:34

JavaScript链表数据

2020-12-31 05:31:01

数据结构算法

2020-10-12 11:48:31

算法与数据结构

2019-03-29 09:40:38

数据结构算法前端

2021-04-13 09:37:41

Java数据结构算法

2021-03-09 06:30:32

JAVA数据结构算法

2023-09-25 12:23:18

Python
点赞
收藏

51CTO技术栈公众号