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

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

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

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

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

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

图的定义

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

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

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

图的表达方式

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

邻接矩阵

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

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

邻接表

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

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

图的搜索算法

图形结构基础属性和方法

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

  1. //图形结构(邻接矩阵)
  2. classGraph{
  3. //存储图中所有顶点
  4. privateList<String>vertexes;
  5. //图形结构的邻接矩阵
  6. privateint[][]matrix;
  7. //各顶点访问情况,true为已访问,false为未访问
  8. privateboolean[]visited;
  9. /**
  10. *根据传入的顶点信息生成矩阵
  11. *@params
  12. */
  13. publicGraph(Strings[]){
  14. vertexes=newArrayList<>();
  15. for(Stringvertex:s){
  16. vertexes.add(vertex);
  17. }
  18. matrix=newint[s.length][s.length];
  19. }
  20. /**
  21. *将俩个顶点连接,即生成边
  22. *@paramindex1顶点在集合中的索引
  23. *@paramindex2
  24. */
  25. publicvoidconnect(intindex1,intindex2){
  26. if(index1<0||index1>matrix.length||index2<0||index2>matrix.length){
  27. thrownewRuntimeException("该顶点未存在");
  28. }
  29. //将新的邻接添加的邻接矩阵中
  30. matrix[index1][index2]=1;
  31. matrix[index2][index1]=1;
  32. }
  33. /**
  34. *展示邻接矩阵
  35. */
  36. publicvoidshowGraphMatrix(){
  37. for(intarr[]:matrix){
  38. System.out.println(Arrays.toString(arr));
  39. }
  40. }
  41. /**
  42. *获取顶点在邻接矩阵对应行row中的第一个邻接顶点下标
  43. *@paramrow
  44. *@return当有邻接顶点时返回邻接顶点下标,没有则返回-1
  45. */
  46. publicintgetFirstNeighbor(introw){
  47. for(inti=0;i<matrix.length;i++){
  48. if(matrix[row][i]!=0){
  49. returni;
  50. }
  51. }
  52. return-1;
  53. }
  54. /**
  55. *获取顶点在邻接矩阵对于行row中col列的下一个邻接顶点
  56. *@paramrow
  57. *@paramcol
  58. *@return当有邻接顶点时返回邻接顶点下标,没有则返回-1
  59. */
  60. publicintgetNeighbor(introw,intcol){
  61. for(inti=col+1;i<matrix.length;i++){
  62. if(matrix[row][i]!=0){
  63. returni;
  64. }
  65. }
  66. return-1;
  67. }
  68. }

深度优先搜索

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

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

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

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

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

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

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

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

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

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

代码演示

  1. publicvoiddsf(){
  2. visited=newboolean[vertexes.size()];
  3. //以在集合中下标为0的顶点,进行深度搜索
  4. dsf(visited,0);
  5. }
  6. /**
  7. *深度优先搜索
  8. *@paramvisited
  9. *@paramrow
  10. */
  11. publicvoiddsf(boolean[]visited,introw){
  12. //输出当前顶点
  13. System.out.print(vertexes.get(row)+"->");
  14. //将当前顶点设为已访问
  15. visited[row]=true;
  16. //获取当前顶点的邻接顶点下标
  17. intindex=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. }
  27. }

宽度优先搜索

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

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

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

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

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

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

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

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

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

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

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

代码演示

  1. publicvoidbfs(){
  2. visited=newboolean[vertexes.size()];
  3. ////以在集合中下标为0的顶点,进行广度优先搜索
  4. bfs(visited,0);
  5. }
  6. /**
  7. *广度优先搜索
  8. *@paramvisited
  9. *@paramrow
  10. */
  11. publicvoidbfs(boolean[]visited,introw){
  12. //创建队列,存储遍历邻接顶点的顺序
  13. LinkedListqueue=newLinkedList();
  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. intlast=(Integer)queue.removeFirst();
  24. //获取该弹出顶点的邻接顶点下标
  25. intindex=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(last,index);
  39. }
  40. }
  41. }

完整演示代码

  1. publicclassGraphDemo{
  2. publicstaticvoidmain(String[]args){
  3. String[]s={"A","B","C","D","E","F","G"};
  4. Graphgraph=newGraph(s);
  5. //A-BA-CA-GA-FF-DF-ED-EE-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. graph.dsf();//A->B->C->F->D->E->G->
  16. System.out.println();
  17. graph.bfs();//A->B->C->F->G->D->E->
  18. }
  19. }
  20. //图形结构
  21. classGraph{
  22. //存储图中所有顶点
  23. privateList<String>vertexes;
  24. //图形结构的邻接矩阵
  25. privateint[][]matrix;
  26. //各顶点访问情况,true为已访问,false为未访问
  27. privateboolean[]visited;
  28. /**
  29. *根据传入的顶点信息生成矩阵
  30. *@params
  31. */
  32. publicGraph(Strings[]){
  33. vertexes=newArrayList<>();
  34. for(Stringvertex:s){
  35. vertexes.add(vertex);
  36. }
  37. matrix=newint[s.length][s.length];
  38. }
  39. /**
  40. *将俩个顶点连接,即生成边
  41. *@paramindex1顶点在集合中的索引
  42. *@paramindex2
  43. */
  44. publicvoidconnect(intindex1,intindex2){
  45. if(index1<0||index1>matrix.length||index2<0||index2>matrix.length){
  46. thrownewRuntimeException("该顶点未存在");
  47. }
  48. //将新的邻接添加的邻接矩阵中
  49. matrix[index1][index2]=1;
  50. matrix[index2][index1]=1;
  51. }
  52. /**
  53. *展示邻接矩阵
  54. */
  55. publicvoidshowGraphMatrix(){
  56. for(intarr[]:matrix){
  57. System.out.println(Arrays.toString(arr));
  58. }
  59. }
  60. publicvoiddsf(){
  61. visited=newboolean[vertexes.size()];
  62. //以在集合中下标为0的顶点,进行深度优先搜索
  63. dsf(visited,0);
  64. }
  65. /**
  66. *深度优先搜索
  67. *@paramvisited
  68. *@paramrow
  69. */
  70. publicvoiddsf(boolean[]visited,introw){
  71. //输出当前顶点
  72. System.out.print(vertexes.get(row)+"->");
  73. //将当前顶点设为已访问
  74. visited[row]=true;
  75. //获取当前顶点的邻接顶点下标
  76. intindex=getFirstNeighbor(row);
  77. //如果当前顶点有邻接顶点则进行深度搜索
  78. while(index!=-1){
  79. //当邻接顶点未访问时,则递归遍历
  80. if(visited[index]!=true){
  81. dsf(visited,index);
  82. }
  83. //当邻接顶点已访问时,则寻找另一个邻接顶点
  84. index=getNeighbor(row,index);
  85. }
  86. }
  87. publicvoidbfs(){
  88. visited=newboolean[vertexes.size()];
  89. ////以在集合中下标为0的顶点,进行广度优先搜索
  90. bfs(visited,0);
  91. }
  92. /**
  93. *广度优先搜索
  94. *@paramvisited
  95. *@paramrow
  96. */
  97. publicvoidbfs(boolean[]visited,introw){
  98. //创建队列,存储遍历邻接顶点的顺序
  99. Queuequeue=newArrayDeque();
  100. //输出当前顶点
  101. System.out.print(vertexes.get(row)+"->");
  102. //将当前顶点设为已访问
  103. visited[row]=true;
  104. //将当前顶点加入队列中
  105. queue.add(row);
  106. //当队列不为空时,即有未搜索的邻接顶点,进行搜索
  107. while(!queue.isEmpty()){
  108. //按顺序从队列中弹出邻接顶点下标
  109. intlast=(Integer)queue.poll();
  110. //获取该弹出顶点的邻接顶点下标
  111. intindex=getFirstNeighbor(last);
  112. //当弹出顶点有邻接顶点时,进行广度搜索
  113. while(index!=-1){
  114. //当邻接顶点未访问时
  115. if(visited[index]!=true){
  116. //输出该邻接顶点
  117. System.out.print(vertexes.get(index)+"->");
  118. //把该邻接顶点设为已访问
  119. visited[index]=true;
  120. //将该邻接顶点加入队列
  121. queue.add(index);
  122. }
  123. //继续寻找弹出顶点的另一个邻接顶点
  124. index=getNeighbor(last,index);
  125. }
  126. }
  127. }
  128. /**
  129. *获取顶点在邻接矩阵对应行row中的第一个邻接顶点下标
  130. *@paramrow
  131. *@return当有邻接顶点时返回邻接顶点下标,没有则返回-1
  132. */
  133. publicintgetFirstNeighbor(introw){
  134. for(inti=0;i<matrix.length;i++){
  135. if(matrix[row][i]!=0){
  136. returni;
  137. }
  138. }
  139. return-1;
  140. }
  141. /**
  142. *获取顶点在邻接矩阵对于行row中col列的下一个邻接顶点
  143. *@paramrow
  144. *@paramcol
  145. *@return当有邻接顶点时返回邻接顶点下标,没有则返回-1
  146. */
  147. publicintgetNeighbor(introw,intcol){
  148. for(inti=col+1;i<matrix.length;i++){
  149. if(matrix[row][i]!=0){
  150. returni;
  151. }
  152. }
  153. return-1;
  154. }
  155. }

©本文为清一色官方代发,观点仅代表作者本人,与清一色无关。清一色对文中陈述、观点判断保持中立,不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。本文不作为投资理财建议,请读者仅作参考,并请自行承担全部责任。文中部分文字/图片/视频/音频等来源于网络,如侵犯到著作权人的权利,请与我们联系(微信/QQ:1074760229)。转载请注明出处:清一色财经

(0)
打赏 微信扫码打赏 微信扫码打赏 支付宝扫码打赏 支付宝扫码打赏
清一色的头像清一色管理团队
上一篇 2023年5月6日 07:28
下一篇 2023年5月6日 07:28

相关推荐

发表评论

登录后才能评论

联系我们

在线咨询:1643011589-QQbutton

手机:13798586780

QQ/微信:1074760229

QQ群:551893940

工作时间:工作日9:00-18:00,节假日休息

关注微信