图论中的算法

小鱼儿 2023-10-12 11:46 96阅读 0赞

图论的概念:图论是数学的一个分支,它是以图为研究对象,图论中的图是由若干个给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些实体之间的某种特定的关系,用点代表实体,用连接两点之间的线表示两个实体之间具有某种关系。

图的分类:

  • 无权无向图

5858f9f2bf584e8db18ef22dece7bae7.png

无向就是可以互相通向,没有进行方向的限制,就好比双向指向:

b46aa50657604f3bbf503abe02fbfb2e.png

  • 无权有向图

dcb5727103f8461b8036f5a17cc7ee60.png

无权就是好比每条路线占的权重一致,没有区别,故我们可以把无权图假设为每个权重都是1的有权图:

01e82284d4334cb6b2af212bf473e931.png

  • 有权无向图

ce19d33d5a5c446a88b2816cc98b0625.png

  • 有权有向图

3890cd3121b44bc2a266eb507548843b.png

BFS和DFS

我们首先来了解什么是BFS?什么又是DFS?9f90aae4a3ef47c39a94269441bb2b7c.gif

DFS俗称深度优先算法,有一种不撞南墙不回头的感觉,认准一条路,一致往下走,直到走不通位置,然后再重新返回再重复刚才的操作,直到找到目标节点为止。DFS关键点是递归以及回溯,一般用栈进行操作。在图中我们经常这样:

1eda4beca66541178d50c2675853876a.png

经典算法题之(知识补充)------ BFS和DFS的感性认识\_ProLayman的博客-CSDN博客

BFS俗称广度优先算法,相对于深度优先算法,如果把深度优先算法当成是一个莽夫的话,广度优先算法像是一个文人墨客,广度优先算法在面临一个路口时,把所有的路口记录下来,然后选择其中一个进入,然后再回退再进入另一个路口,直到找到目标节点为止。BFS关键点是状态的选取和标记,一般用队列去解决问题,在图中我们经常这样:

98039cff62114b499043b793d01125b8.png

图的存储结构

  • 邻接矩阵

概念:所谓邻接矩阵存储结构就是每个顶点用一个一维数组存储边的信息,这样所有点合起来就是用矩阵表示图中各顶点之间的邻接关系。所谓矩阵其实就是二维数组。对于有n个顶点的图 G=(V,E) 来说,我们可以用一个 n× n 的矩阵A来表示G中各顶点的相邻关系

54002ef78cd14eb99bbcac9c27b1f757.png

对应的邻接矩阵为:

4995fef987794857a0cb32713a421e05.png

与对应点直接相连为1,不直接相连为0

构建邻接矩阵:

  1. package graphtheory;
  2. import java.util.Arrays;
  3. /**
  4. * 图的表示--使用邻接矩阵
  5. */
  6. public class Graph01 {
  7. private char[] V;//顶点上的值
  8. private Vertex[] vertexs;//顶点数组
  9. private int N;
  10. //邻接矩阵
  11. private int[][] adj;
  12. //图的构造函数
  13. public Graph01(char[] arr) {//{'A','E','F','G','H','P'}
  14. //拿到数组的长度
  15. int length = arr.length;
  16. this.N = length;
  17. V = new char[length];
  18. //arr元素赋值 到V
  19. this.V = Arrays.copyOf(arr, length);
  20. //构建图中的结点
  21. vertexs = new Vertex[length];
  22. for (int i = 0; i < length; i++) {
  23. vertexs[i] = new Vertex(i,this.V[i]);//
  24. }
  25. this.adj = new int[length][length];
  26. }
  27. //打印邻接矩阵
  28. public void show() {
  29. System.out.print(" ");
  30. for (int i = 0; i < this.N; i++) {
  31. System.out.format("%4c", this.V[i]);
  32. }
  33. System.out.println();
  34. for (int i = 0; i < this.N; i++) {
  35. System.out.format("%4c",this.V[i]);
  36. for (int j = 0; j < this.N; j++) {
  37. System.out.format("%4s", this.adj[i][j] > 0?(this.adj[i][j]):"-");
  38. }
  39. System.out.println();
  40. }
  41. }
  42. /**
  43. * 创建顶点类
  44. */
  45. private class Vertex {
  46. char v;//值
  47. int index;//索引
  48. public Vertex(int index, char c) {
  49. this.index = index;
  50. this.v = v;
  51. }
  52. }
  53. public static void main(String[] args) {
  54. char arr[] = {'A', 'E', 'F', 'G', 'H', 'P'};
  55. //构建graph01
  56. Graph01 graph01 = new Graph01(arr);
  57. //进行连接
  58. int[][] adjMatrix = graph01.adj;
  59. adjMatrix[0][1]=1;
  60. adjMatrix[0][2]=1;
  61. adjMatrix[0][3]=1;
  62. adjMatrix[1][0]=1;
  63. adjMatrix[1][3]=1;
  64. adjMatrix[1][4]=1;
  65. adjMatrix[2][0]=1;
  66. adjMatrix[3][0]=1;
  67. adjMatrix[3][1]=1;
  68. adjMatrix[3][4]=1;
  69. adjMatrix[3][5]=1;
  70. adjMatrix[4][1]=1;
  71. adjMatrix[4][3]=1;
  72. adjMatrix[4][5]=1;
  73. adjMatrix[5][3]=1;
  74. adjMatrix[5][4]=1;
  75. graph01.show();
  76. }
  77. }

573219004cb046b888b45a30ae514d87.png

  • 邻接表

邻接表的概念:邻接表的思想是,对于图中的每一个顶点,用一个数组来记录这个点和哪些点相连。由于相邻的点会动态的添加,所以对于每个点,我们需要用List来记录。

54002ef78cd14eb99bbcac9c27b1f757.png

对应的邻接表为:

f663248f2c3d4b9b9950e42c38fe2a49.png

  1. package graphtheory;
  2. import java.util.ArrayList;
  3. import java.util.Arrays;
  4. import java.util.List;
  5. /**
  6. * 图的表示--使用邻接矩阵
  7. */
  8. public class Graph02 {
  9. private char[] V;//顶点上的值
  10. private Vertex[] vertexs;//顶点数组
  11. private int N;
  12. //邻接矩阵
  13. private List<Integer>[] adj;
  14. //图的构造函数
  15. public Graph02(char[] arr) {//{'A','E','F','G','H','P'}
  16. //拿到数组的长度
  17. int length = arr.length;
  18. this.N = length;
  19. V = new char[length];
  20. //arr元素赋值 到V
  21. this.V = Arrays.copyOf(arr, length);
  22. //构建图中的结点
  23. vertexs = new Vertex[length];
  24. for (int i = 0; i < length; i++) {
  25. vertexs[i] = new Vertex(i, this.V[i]);
  26. }
  27. this.adj = new List[length];
  28. for (int i = 0; i < this.N; i++) {
  29. this.adj[i]=new ArrayList<>();
  30. }
  31. }
  32. //打印邻接矩阵
  33. public void show() {
  34. System.out.println(" ");
  35. for (int i = 0; i < this.N; i++) {
  36. System.out.format("%-4c", this.V[i]);
  37. //拿到邻接表相邻结点的集合
  38. List<Integer> linkedList = this.adj[i];
  39. for (int j = 0; j < linkedList.size(); j++) {
  40. System.out.print(this.V[linkedList.get(j)] + "---->");
  41. }
  42. System.out.println();
  43. System.out.format("%-4d",vertexs[i].index);
  44. for (int j = 0; j < linkedList.size(); j++) {
  45. System.out.print(vertexs[linkedList.get(j)].index + "---->");
  46. }
  47. System.out.println();
  48. }
  49. }
  50. /**
  51. * 创建顶点类
  52. */
  53. private class Vertex {
  54. char v;//值
  55. int index;//索引
  56. int weight;//权值
  57. public Vertex(int index, char c) {
  58. this.index = index;
  59. this.v = v;
  60. this.weight = weight;
  61. }
  62. public Vertex(int index) {
  63. }
  64. }
  65. public static void main(String[] args) {
  66. char arr[] = {'A', 'E', 'F', 'G', 'H', 'P'};
  67. //构建graph01
  68. Graph02 graph02 = new Graph02(arr);
  69. //邻接表
  70. List<Integer>[] adj = graph02.adj;
  71. adj[0].add(1);
  72. adj[0].add(2);
  73. adj[0].add(3);
  74. adj[1].add(0);
  75. adj[1].add(3);
  76. adj[1].add(4);
  77. adj[2].add(0);
  78. adj[3].add(0);
  79. adj[3].add(1);
  80. adj[3].add(4);
  81. adj[3].add(5);
  82. adj[4].add(1);
  83. adj[4].add(3);
  84. adj[4].add(5);
  85. adj[5].add(3);
  86. adj[5].add(4);
  87. graph02.show();
  88. }
  89. }

a36124a7368a4aa48836bae7bb156872.png

使用邻接表求出A—P的所有路径:

  1. package graphtheory;
  2. import java.util.*;
  3. // 图的表示-- 使用邻接表
  4. public class Graph03 {
  5. private char[] V;
  6. // 顶点数组
  7. private Vertex[] vertexs;
  8. private int N;
  9. // 邻接表
  10. private List<Integer>[] adj;
  11. public Graph03(char[] arr) { // {'A','E','F','G','H','P'}
  12. int length = arr.length;
  13. this.N = length;
  14. this.V = Arrays.copyOf(arr, length);
  15. // 构建图中的结点
  16. vertexs = new Vertex[length];
  17. for (int i = 0; i < length; i++) {
  18. vertexs[i] = new Vertex(0, this.V[i]);
  19. }
  20. this.adj = new List[length];
  21. for (int i = 0; i < this.N; i++) {
  22. this.adj[i] = new ArrayList<>();
  23. }
  24. }
  25. // 打印邻接矩阵
  26. public void show() {
  27. for (int i = 0; i < this.N; i++) {
  28. System.out.format("%-4c", this.V[i]);
  29. List<Integer> linkedList = this.adj[i];
  30. for (int j = 0; j < linkedList.size(); j++) {
  31. System.out.print(this.V[linkedList.get(j)] + "---->");
  32. }
  33. System.out.println();
  34. System.out.format("%-4c", this.V[i]);
  35. for (int j = 0; j < linkedList.size(); j++) {
  36. System.out.print(linkedList.get(j) + "---->");
  37. }
  38. System.out.println();
  39. }
  40. }
  41. public void bfs(int startIndex){
  42. boolean visited[] = new boolean[this.N];
  43. List<List<Integer>> result = new ArrayList<>();
  44. // 使用队列
  45. Queue<AbstractMap.SimpleEntry<Integer,Integer>> queue = new LinkedList<>();
  46. // 将开始顶点入队
  47. queue.add(new AbstractMap.SimpleEntry<>(startIndex,0));
  48. // 设置startIndex已经被访问
  49. visited[startIndex]=true;
  50. while(!queue.isEmpty()){
  51. AbstractMap.SimpleEntry<Integer,Integer> pair = queue.poll();
  52. int key = pair.getKey(); //顶点的索引
  53. int val = pair.getValue();// 层
  54. if(result.size() == val){
  55. ArrayList list = new ArrayList();
  56. result.add(list);
  57. }
  58. List<Integer> levelList = result.get(val);
  59. levelList.add(key);
  60. // 找和key顶点直接相连的的索引
  61. List<Integer> list = this.adj[key];
  62. for(int i=0;i<list.size();i++){
  63. if(!visited[list.get(i)]){
  64. queue.add(new AbstractMap.SimpleEntry(list.get(i),val+1));
  65. visited[list.get(i)]=true;
  66. }
  67. }
  68. }
  69. for(int i=0;i<result.size();i++){
  70. System.out.println("level:"+(i+1));
  71. for(int j=0;j<result.get(i).size();j++){
  72. System.out.format("%-4d",result.get(i).get(j));
  73. }
  74. System.out.println();
  75. }
  76. }
  77. public void dfs(int startIndex,int endIndex){
  78. //创建一个数组,用来记录是否已经被访问
  79. boolean visited[] = new boolean[this.N];
  80. // 标记开始结点已经被访问过
  81. LinkedList<Character> path = new LinkedList<>();
  82. dfs(startIndex,endIndex,visited,path);
  83. }
  84. // 递归向下去找
  85. private void dfs(int startIndex,int endIndex,boolean[] visited, LinkedList<Character> path){
  86. // 递归终止的条件
  87. if(startIndex == endIndex){
  88. path.offerLast(this.V[startIndex]);
  89. System.out.println(path);
  90. // 从路径的尾部删掉最后的顶点
  91. path.pollLast();
  92. return;
  93. }
  94. // 将当前顶点加到路径中去
  95. path.offer(this.V[startIndex]);
  96. // 标识startIndex已经被访问了
  97. visited[startIndex]=true;
  98. // 递归操作
  99. // 1、先找和startIndex直接连接的顶点有哪些
  100. List<Integer> list = this.adj[startIndex];
  101. // 2、处理每一个直接连接的顶点
  102. for(int i=0;i<list.size();i++){
  103. if(!visited[list.get(i)]){
  104. dfs(list.get(i),endIndex,visited,path);
  105. }
  106. }
  107. visited[startIndex]=false; // 回溯
  108. path.pollLast();
  109. }
  110. private class Vertex {
  111. char v;
  112. int index;
  113. //权值
  114. int weight;
  115. public Vertex(int index, char v, int weight) {
  116. this.index = index;
  117. this.v = v;
  118. this.weight = weight;
  119. }
  120. public Vertex(int index, char v) {
  121. this(index, v, 1);
  122. }
  123. }
  124. public static void main(String[] args) {
  125. char arr[] = {'A', 'E', 'F', 'G', 'H', 'P' };
  126. Graph03 graph03 = new Graph03(arr);
  127. // 邻接表
  128. List<Integer>[] adj = graph03.adj;
  129. adj[0].add(1);
  130. adj[0].add(2);
  131. adj[0].add(3);
  132. adj[1].add(0);
  133. adj[1].add(3);
  134. adj[1].add(4);
  135. adj[2].add(0);
  136. adj[3].add(0);
  137. adj[3].add(1);
  138. adj[3].add(4);
  139. adj[3].add(5);
  140. adj[4].add(1);
  141. adj[4].add(3);
  142. adj[4].add(5);
  143. adj[5].add(3);
  144. adj[5].add(4);
  145. graph03.bfs(5);
  146. }
  147. }

迪杰斯特拉算法

概念:即先求出长度最短的一条最短路径,再参照它求出长度次短的一条最短路径,依次类推,直到从源点v 到其它各顶点的最短路径全部求出为止。

54002ef78cd14eb99bbcac9c27b1f757.png

假设我们求A点到各点的最短距离

fefc5a9639d04cdaa30435cd93635bd8.png 迪杰斯特拉算法过程(原理)

  1. package graphtheory;
  2. import java.util.*;
  3. // 图的单源最最短路径-迪杰斯特拉算法(从一个顶点到图中各个顶点的最短距离)
  4. public class Graph04 {
  5. private char[] V;
  6. // 顶点数组
  7. private Vertex[] vertexs;
  8. private int N;
  9. // 邻接表
  10. private List<AbstractMap.SimpleEntry<Integer, Integer>>[] adj; // key:顶点索引,val:权值
  11. public Graph04(char[] arr) { // {'A','E','F','G','H','P'}
  12. int length = arr.length;
  13. this.N = length;
  14. this.V = Arrays.copyOf(arr, length);
  15. // 构建图中的结点
  16. vertexs = new Vertex[length];
  17. for (int i = 0; i < length; i++) {
  18. vertexs[i] = new Vertex(i, this.V[i]);
  19. }
  20. this.adj = new List[length];
  21. for (int i = 0; i < this.N; i++) {
  22. this.adj[i] = new ArrayList<>();
  23. }
  24. }
  25. public int[] dijkstra(int sourceIndex) {
  26. // 1、创建距离表
  27. int[] dist = new int[this.N];
  28. Arrays.fill(dist, Integer.MAX_VALUE);
  29. // 2、创建一个标识顶点是否被访问的数组
  30. boolean[] visited = new boolean[this.N];
  31. // 3、初始化距离表
  32. // 3-1
  33. dist[sourceIndex] = 0; // 自身到自身的距离
  34. visited[sourceIndex] = true;
  35. // 3-2、找和sourceIndex直接相连的顶点
  36. List<AbstractMap.SimpleEntry<Integer, Integer>> list = this.adj[sourceIndex];
  37. for (int i = 0; i < list.size(); i++) {
  38. AbstractMap.SimpleEntry<Integer, Integer> vertex = list.get(i);
  39. int key = vertex.getKey();//顶点索引
  40. int val = vertex.getValue();//权值
  41. // 3-3 更新距离表
  42. dist[key] = val;
  43. }
  44. for (int k = 1; k < this.N; k++) {
  45. //4、在上述的最短路径dist[]中,从未被访问的顶点中选一条最短的路径长度
  46. int minDist = Integer.MAX_VALUE;
  47. int minDistIndex = -1;
  48. for (int i = 0; i < this.N; i++) {
  49. if (!visited[i] && dist[i] != Integer.MAX_VALUE && dist[i] < minDist) {
  50. minDist = dist[i];
  51. minDistIndex = i;
  52. }
  53. }
  54. // 最最短的路径长度所在的顶点与其它顶点都没有相连
  55. if (minDistIndex == -1) {
  56. break;
  57. }
  58. //5、更新距离表()
  59. // 5-1 将最最短的路径长度所在的顶点设置成已访问
  60. visited[minDistIndex] = true;
  61. // 5-2 找到和最短路径长度所在顶点直接相连的顶点
  62. List<AbstractMap.SimpleEntry<Integer, Integer>> list2 = this.adj[minDistIndex];
  63. // 5-3 minDist+权值与距离表中的数据进行比较
  64. for (int i = 0; i < list2.size(); i++) {
  65. AbstractMap.SimpleEntry<Integer, Integer> vertex = list2.get(i);
  66. int key = vertex.getKey();//顶点索引
  67. int val = vertex.getValue();//权值
  68. int newVal = minDist + val;
  69. if (!visited[key] && newVal < dist[key]) {
  70. dist[key] = newVal;
  71. }
  72. }
  73. }
  74. return dist;
  75. }
  76. private class Vertex {
  77. char v;
  78. int index;
  79. public Vertex(int index, char v) {
  80. this.index = index;
  81. this.v = v;
  82. }
  83. }
  84. public static void main(String[] args) {
  85. char arr[] = {'A', 'E', 'F', 'G', 'H', 'P'};
  86. Graph04 graph04 = new Graph04(arr);
  87. // 邻接表
  88. List<AbstractMap.SimpleEntry<Integer, Integer>>[] adj = graph04.adj;
  89. adj[0].add(new AbstractMap.SimpleEntry<>(1, 5));
  90. adj[0].add(new AbstractMap.SimpleEntry<>(2, 4));
  91. adj[0].add(new AbstractMap.SimpleEntry<>(5, 2));
  92. adj[1].add(new AbstractMap.SimpleEntry<>(0, 5));
  93. adj[1].add(new AbstractMap.SimpleEntry<>(5, 1));
  94. adj[1].add(new AbstractMap.SimpleEntry<>(4, 3));
  95. adj[2].add(new AbstractMap.SimpleEntry<>(0, 4));
  96. adj[3].add(new AbstractMap.SimpleEntry<>(4, 3));
  97. adj[3].add(new AbstractMap.SimpleEntry<>(5, 4));
  98. adj[4].add(new AbstractMap.SimpleEntry<>(1, 3));
  99. adj[4].add(new AbstractMap.SimpleEntry<>(5, 2));
  100. adj[4].add(new AbstractMap.SimpleEntry<>(3, 3));
  101. adj[5].add(new AbstractMap.SimpleEntry<>(0, 2));
  102. adj[5].add(new AbstractMap.SimpleEntry<>(1, 1));
  103. adj[5].add(new AbstractMap.SimpleEntry<>(4, 2));
  104. adj[5].add(new AbstractMap.SimpleEntry<>(3, 4));
  105. int[] dist = graph04.dijkstra(0);
  106. System.out.println(Arrays.toString(dist));
  107. }
  108. }

怎么样才能求出我们距离最短的路径呢?

我们这里需要一个前置顶点表进行记录:

7201ab7e59f54d8fbb9a9ba6f777d453.png

分图:

92069148ab954ab09c485a94374f131e.png

5de6ee6d68e746f3b1612e53dc6b3346.png

  1. package graphtheory;
  2. import java.util.*;
  3. // 图的单源最最短路径-迪杰斯特拉算法(从一个顶点到图中各个顶点的最短距离)
  4. public class Graph04 {
  5. private char[] V;
  6. // 顶点数组
  7. private Vertex[] vertexs;
  8. private int N;
  9. // 邻接表
  10. private List<AbstractMap.SimpleEntry<Integer, Integer>>[] adj; // key:顶点索引,val:权值
  11. // 1、创建距离表
  12. private int[] dist;
  13. private int[] pre;
  14. public Graph04(char[] arr) { // {'A','E','F','G','H','P'}
  15. int length = arr.length;
  16. this.N = length;
  17. this.V = Arrays.copyOf(arr, length);
  18. this.dist = new int[this.N];
  19. Arrays.fill(dist, Integer.MAX_VALUE);
  20. // 创建最短路径的前驱顶点表(为了表示最短路径)
  21. this.pre=new int[this.N];
  22. Arrays.fill(this.pre,-1);
  23. // 构建图中的结点
  24. vertexs = new Vertex[length];
  25. for (int i = 0; i < length; i++) {
  26. vertexs[i] = new Vertex(0, this.V[i]);
  27. }
  28. this.adj = new List[length];
  29. for (int i = 0; i < this.N; i++) {
  30. this.adj[i] = new ArrayList<>();
  31. }
  32. }
  33. public void dijkstra(int sourceIndex) {
  34. // 2、创建一个标识顶点是否被访问的数组
  35. boolean[] visited = new boolean[this.N];
  36. // 3、初始化距离表
  37. // 3-1
  38. dist[sourceIndex] = 0; // 自身到自身的距离
  39. visited[sourceIndex] = true;
  40. // 3-2、找和sourceIndex直接相连的顶点
  41. List<AbstractMap.SimpleEntry<Integer, Integer>> list = this.adj[sourceIndex];
  42. for (int i = 0; i < list.size(); i++) {
  43. AbstractMap.SimpleEntry<Integer, Integer> vertex = list.get(i);
  44. int key = vertex.getKey();//顶点索引
  45. int val = vertex.getValue();//权值
  46. // 3-3 更新距离表
  47. this.dist[key] = val;
  48. // 更新前驱顶点表
  49. this.pre[key]=sourceIndex;
  50. }
  51. for (int k = 1; k < this.N; k++) {
  52. //4、在上述的最短路径dist[]中,从未被访问的顶点中选一条最短的路径长度
  53. int minDist = Integer.MAX_VALUE;
  54. int minDistIndex = -1;
  55. for (int i = 0; i < this.N; i++) {
  56. if (!visited[i] && dist[i] != Integer.MAX_VALUE && dist[i] < minDist) {
  57. minDist = dist[i];
  58. minDistIndex = i;
  59. }
  60. }
  61. // 最最短的路径长度所在的顶点与其它顶点都没有相连
  62. if (minDistIndex == -1) {
  63. break;
  64. }
  65. //5、更新距离表()
  66. // 5-1 将最最短的路径长度所在的顶点设置成已访问
  67. visited[minDistIndex] = true;
  68. // 5-2 找到和最短路径长度所在顶点直接相连的顶点
  69. List<AbstractMap.SimpleEntry<Integer, Integer>> list2 = this.adj[minDistIndex];
  70. // 5-3 minDist+权值与距离表中的数据进行比较
  71. for (int i = 0; i < list2.size(); i++) {
  72. AbstractMap.SimpleEntry<Integer, Integer> vertex = list2.get(i);
  73. int key = vertex.getKey();//顶点索引
  74. int val = vertex.getValue();//权值
  75. int newVal = minDist + val;
  76. if (!visited[key] && newVal < dist[key]) {
  77. this.dist[key] = newVal;
  78. // 更新前驱顶点表
  79. this.pre[key] = minDistIndex;
  80. }
  81. }
  82. }
  83. }
  84. public void showDist(){
  85. System.out.println(Arrays.toString(this.dist));
  86. }
  87. public void getMinDist(int sourceIndex ,int targetIndex){
  88. Stack<Integer> stack = new Stack<>();
  89. stack.push(targetIndex);
  90. int preIndex = this.pre[targetIndex];
  91. while(preIndex !=-1 && preIndex!=sourceIndex){
  92. stack.push(preIndex);
  93. preIndex = this.pre[preIndex];
  94. }
  95. // 将 sourceIndex放入栈
  96. if(preIndex !=-1){
  97. stack.push(sourceIndex);
  98. }
  99. // 出栈
  100. StringBuilder res = new StringBuilder();
  101. while(!stack.isEmpty()){
  102. res.append(this.V[stack.pop()]+"-->");
  103. }
  104. System.out.println(res);
  105. }
  106. private class Vertex {
  107. char v;
  108. int index;
  109. public Vertex(int index, char v) {
  110. this.index = index;
  111. this.v = v;
  112. }
  113. }
  114. public static void main(String[] args) {
  115. char arr[] = {'A', 'E', 'F', 'G', 'H', 'P'};
  116. Graph04 graph04 = new Graph04(arr);
  117. // 邻接表
  118. List<AbstractMap.SimpleEntry<Integer, Integer>>[] adj = graph04.adj;
  119. adj[0].add(new AbstractMap.SimpleEntry<>(1, 5));
  120. adj[0].add(new AbstractMap.SimpleEntry<>(2, 4));
  121. adj[0].add(new AbstractMap.SimpleEntry<>(5, 2));
  122. adj[1].add(new AbstractMap.SimpleEntry<>(0, 5));
  123. adj[1].add(new AbstractMap.SimpleEntry<>(5, 1));
  124. adj[1].add(new AbstractMap.SimpleEntry<>(4, 3));
  125. adj[2].add(new AbstractMap.SimpleEntry<>(0, 4));
  126. adj[3].add(new AbstractMap.SimpleEntry<>(4, 3));
  127. adj[3].add(new AbstractMap.SimpleEntry<>(5, 4));
  128. adj[4].add(new AbstractMap.SimpleEntry<>(1, 3));
  129. adj[4].add(new AbstractMap.SimpleEntry<>(5, 2));
  130. adj[4].add(new AbstractMap.SimpleEntry<>(3, 3));
  131. adj[5].add(new AbstractMap.SimpleEntry<>(0, 2));
  132. adj[5].add(new AbstractMap.SimpleEntry<>(1, 1));
  133. adj[5].add(new AbstractMap.SimpleEntry<>(4, 2));
  134. adj[5].add(new AbstractMap.SimpleEntry<>(3, 4));
  135. int sourceIndex = 5;
  136. graph04.dijkstra(sourceIndex);
  137. graph04.showDist();
  138. int targetIndex = 3;
  139. // 求从源到目标顶点的最短路径
  140. graph04.getMinDist(sourceIndex,targetIndex);
  141. }
  142. }

弗洛伊德算法

具体思想:邻接矩阵dist储存路径,同时最终状态代表点点的最短路径。如果没有直接相连的两点那么默认为一个很大的值,而自身到自身的长度为0.

f89134e41bde4aadae0c6da3d948a1f2.png

A和B不认识,所以A找不到B,但是这时候A的朋友D来了,说他可以介绍B给A认识,所以A就通过D找到了B

782f6bf43dc442c0b62c1b0ba0baa6ed.png

弗洛伊德算法就是用了这样的思想

daac81fad51f4db18a7e0b066f57d92d.png30a436ca3a814e4db3bfc1f94f7d09bc.png

  • 把第1个到第n个点依次加入图中。每个点加入进行试探是否有路径长度被更改。
  • 而上述试探具体方法为遍历图中每一个点(i,j双重循环),判断每一个点对距离,是否因为加入的点而发生最小距离变化。如果发生改变,那么两点(i,j)距离就更改。
  • 转移方程::dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j])

792e1ff85d17446bab075834714ed296.png

b7716d962e6a4f56bbfadc1b1d1024b1.png

baa8aa4054a54d8d8fed38b8a8f4efb4.png

  1. package graphtheory;
  2. import java.util.*;
  3. // 图的多源最最短路径-弗洛伊德算法Floyd(从任意顶点到图中各个顶点的最短距离)
  4. public class Graph05 {
  5. private char[] V;
  6. // 顶点数组
  7. private Vertex[] vertexs;
  8. private int N;
  9. // 邻接表
  10. private List<AbstractMap.SimpleEntry<Integer, Integer>>[] adj; // key:顶点索引,val:权值
  11. private int[][] dists;
  12. public Graph05(char[] arr) { // {'A','E','F','G','H','P'}
  13. int length = arr.length;
  14. this.N = length;
  15. this.V = Arrays.copyOf(arr, length);
  16. // 构建图中的结点
  17. vertexs = new Vertex[length];
  18. for (int i = 0; i < length; i++) {
  19. vertexs[i] = new Vertex(0, this.V[i]);
  20. }
  21. this.adj = new List[length];
  22. for (int i = 0; i < this.N; i++) {
  23. this.adj[i] = new ArrayList<>();
  24. }
  25. this.dists = new int[this.N][this.N];
  26. for (int i = 0; i < this.N; i++) {
  27. for (int j = 0; j < this.N; j++) {
  28. if (i == j) {
  29. this.dists[i][j] = 0;
  30. } else {
  31. this.dists[i][j] = Integer.MAX_VALUE;
  32. }
  33. }
  34. }
  35. }
  36. private class Vertex {
  37. char v;
  38. int index;
  39. public Vertex(int index, char v) {
  40. this.index = index;
  41. this.v = v;
  42. }
  43. }
  44. public void floyd() {
  45. // 对dists进一步初始化
  46. for (int i = 0; i < this.N; i++) {
  47. List<AbstractMap.SimpleEntry<Integer, Integer>> list = this.adj[i];
  48. for (int j = 0; j < list.size(); j++) {
  49. AbstractMap.SimpleEntry<Integer, Integer> pair = list.get(j);
  50. int key = pair.getKey();
  51. int val = pair.getValue();
  52. this.dists[i][key] = val;
  53. }
  54. }
  55. // 将每个顶点加到二维数组中(是给每个二维数组中的每个元素都加) 相当于矩阵,给每个元素进行相同的操作
  56. for (int i = 0; i < this.N; i++) { // 表示的添加顶点的索引
  57. for (int m = 0; m < this.N; m++) {
  58. //同行不用进行操作
  59. if (m == i) {
  60. continue;
  61. }
  62. for (int n = 0; n < this.N; n++) {
  63. //距离无穷大也不用进行操作
  64. if (this.dists[m][i] != Integer.MAX_VALUE && this.dists[i][n] != Integer.MAX_VALUE) {
  65. this.dists[m][n] = Math.min(this.dists[m][n], this.dists[m][i] + this.dists[i][n]);
  66. }
  67. }
  68. }
  69. }
  70. show();
  71. }
  72. private void show() {
  73. System.out.format("%-4s", " ");
  74. for (int i = 0; i < this.N; i++) {
  75. System.out.format("%-4s", this.V[i]);
  76. }
  77. System.out.println();
  78. for (int i = 0; i < this.N; i++) {
  79. System.out.format("%-4s", this.V[i]);
  80. for (int j = 0; j < this.N; j++) {
  81. System.out.format("%-4s", this.dists[i][j] == Integer.MAX_VALUE ? "-" : this.dists[i][j] + "");
  82. }
  83. System.out.println();
  84. }
  85. }
  86. public static void main(String[] args) {
  87. char arr[] = {'A', 'E', 'F', 'G', 'H', 'P'};
  88. Graph05 graph05 = new Graph05(arr);
  89. // 邻接表
  90. List<AbstractMap.SimpleEntry<Integer, Integer>>[] adj = graph05.adj;
  91. adj[0].add(new AbstractMap.SimpleEntry<>(1, 5));
  92. adj[0].add(new AbstractMap.SimpleEntry<>(2, 4));
  93. adj[0].add(new AbstractMap.SimpleEntry<>(5, 2));
  94. adj[1].add(new AbstractMap.SimpleEntry<>(0, 5));
  95. adj[1].add(new AbstractMap.SimpleEntry<>(5, 1));
  96. adj[1].add(new AbstractMap.SimpleEntry<>(4, 3));
  97. adj[2].add(new AbstractMap.SimpleEntry<>(0, 4));
  98. adj[3].add(new AbstractMap.SimpleEntry<>(4, 3));
  99. adj[3].add(new AbstractMap.SimpleEntry<>(5, 4));
  100. adj[4].add(new AbstractMap.SimpleEntry<>(1, 3));
  101. adj[4].add(new AbstractMap.SimpleEntry<>(5, 2));
  102. adj[4].add(new AbstractMap.SimpleEntry<>(3, 3));
  103. adj[5].add(new AbstractMap.SimpleEntry<>(0, 2));
  104. adj[5].add(new AbstractMap.SimpleEntry<>(1, 1));
  105. adj[5].add(new AbstractMap.SimpleEntry<>(4, 2));
  106. adj[5].add(new AbstractMap.SimpleEntry<>(3, 4));
  107. graph05.floyd();
  108. int sourceIndex = 1;
  109. int targetIndex = 3;
  110. }
  111. }

发表评论

表情:
评论列表 (有 0 条评论,96人围观)

还没有评论,来说两句吧...

相关阅读

    相关 算法

    图论的概念:图论是数学的一个分支,它是以图为研究对象,图论中的图是由若干个给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些实体之间的某种特定的关系,用点代表实体,用

    相关

    一、图的常用概念   1、顶点(vertex)   2、边(edge)   3、路径   4、无向图:顶点之间的连接没有方向   ![1007094-201909

    相关

    http://[blog.csdn.net/pipisorry/article/details/52518118][blog.csdn.net_pipisorry_articl

    相关 算法

    Problem1一笔画问题 题目描述     给出一个图,求其欧拉回路(若没有回路,则求其欧拉路径),若不存在则输出‘No solution’ 输入     输入的第一

    相关 Floyd算法

    Floyd算法     时间复杂度O (n^3)   空间复杂度O (n^2) 用处   可以求任意两个点之间的最短路径长度。   得出的邻接矩阵存储 i 到 j 的