1. package com.atguigu.graph;
    2. import sun.misc.Queue;
    3. import java.util.ArrayList;
    4. import java.util.Arrays;
    5. import java.util.LinkedList;
    6. /**
    7. * 图的简单实现
    8. *
    9. * @author Dxkstart
    10. * @create 2022-04-11-16:18
    11. */
    12. public class Graph {
    13. private ArrayList<String> varTextList; // 存储顶点
    14. private int[][] edges; // 存储图对应的邻接矩阵
    15. private int numOfEdges; // 表示边的个数
    16. private boolean[] isVisited; // 记录某个节点是否被访问
    17. public static void main(String[] args) {
    18. int n = 5;// 节点的个数
    19. String VarTexValue[] = {"A", "B", "C", "D", "E"};
    20. // 创建图对象
    21. Graph graph = new Graph(n);
    22. // 添加
    23. for (String str : VarTexValue) {
    24. graph.add(str);
    25. }
    26. // 添加边 A-B A-C B-C B-D B-E
    27. graph.addEdge(0, 1, 1); // A-B
    28. graph.addEdge(0, 2, 1); // A-C
    29. graph.addEdge(1, 2, 1); // B-C
    30. graph.addEdge(1, 3, 1); // B-D
    31. graph.addEdge(1, 4, 1); // B-E
    32. // 显示图的矩阵
    33. graph.showGraph();
    34. // 测试深度优先遍历
    35. // System.out.println("测试深度优先遍历");
    36. // graph.dfs();
    37. System.out.println();
    38. // 测试广度优先遍历
    39. System.out.println("测试广度优先遍历");
    40. graph.bfs();
    41. }
    42. // 构造器
    43. public Graph(int n) {
    44. // 初始化矩阵和varTextList
    45. edges = new int[n][n];
    46. varTextList = new ArrayList<String>(n);
    47. numOfEdges = 0;
    48. isVisited = new boolean[n];
    49. }
    50. // 插入节点
    51. public void add(String varText) {
    52. varTextList.add(varText);
    53. }
    54. // 添加边
    55. /**
    56. * @param v1 表示点的下标
    57. * @param v2 表示第二个顶点对应的下标
    58. * @param weight 表示边的权值
    59. */
    60. public void addEdge(int v1, int v2, int weight) {
    61. edges[v1][v2] = weight;
    62. edges[v2][v1] = weight;
    63. numOfEdges++;
    64. }
    65. // 返回节点的个数
    66. public int getNumOfVarText() {
    67. return varTextList.size();
    68. }
    69. // 返回边的数目
    70. public int getNumOfEdges() {
    71. return numOfEdges;
    72. }
    73. // 返回节点i(下标) 对应的数据
    74. public String getValueByIndex(int i) {
    75. return varTextList.get(i);
    76. }
    77. // 返回v1和v2的权值
    78. public int getWeight(int v1, int v2) {
    79. return edges[v1][v2];
    80. }
    81. // 显示图对应的矩阵
    82. public void showGraph() {
    83. for (int[] link : edges) {
    84. System.err.println(Arrays.toString(link));
    85. }
    86. }
    87. // 得到当前节点的第一个邻接节点的下标
    88. /**
    89. * @param index 当前节点的下标
    90. * @return 如果存在就返回下标,否则返回-1
    91. */
    92. public int getFirstNeighbor(int index) {
    93. for (int i = 0; i < varTextList.size(); i++) {
    94. if (edges[index][i] > 0) {
    95. return i;
    96. }
    97. }
    98. return -1;
    99. }
    100. // 根据当前节点的下标获取下一个节点的下标
    101. // v1,v2是当前节点的行和列下标
    102. // 获取当前节点的其他邻接点
    103. public int getNextNeighbor(int v1, int v2) {
    104. for (int i = v2 + 1; i < varTextList.size(); i++) {
    105. if (edges[v1][i] > 0) {
    106. return i;
    107. }
    108. }
    109. return -1;
    110. }
    111. // 深度优先遍历算法
    112. public void dfs(boolean[] isVisited, int i) {
    113. // 先访问当前节点
    114. System.out.print(getValueByIndex(i) + " -> ");
    115. // 将当前节点置为已访问
    116. isVisited[i] = true;
    117. // 查找当前节点的第一个邻接节点
    118. int w = getFirstNeighbor(i);
    119. while (w != -1) {
    120. if (!isVisited[w]) {
    121. dfs(isVisited, w);
    122. }
    123. // 如果w节点已经被访问过了
    124. w = getNextNeighbor(i, w);// 2 , 0
    125. }
    126. }
    127. // 对dfs进行重载,遍历所有的节点,并进行dfs
    128. public void dfs() {
    129. // 遍历所有的节点,进行dfs【回溯】
    130. for (int i = 0; i < getNumOfVarText(); i++) {
    131. if (!isVisited[i]) {
    132. dfs(isVisited, i);
    133. }
    134. }
    135. }
    136. // 广度优先遍历算法
    137. public void bfs(boolean[] isVisited, int i) {
    138. int u; // 表示队列的头结点对应的下标
    139. int w; // 邻接节点w
    140. // 队列,记录节点访问的顺序
    141. LinkedList<Integer> queue = new LinkedList<>();
    142. // 访问当前节点,输出信息
    143. System.out.print(getValueByIndex(i) + " -> ");
    144. // 标记为已访问
    145. isVisited[i] = true;
    146. // 将当前节点加入队列
    147. queue.addLast(i);
    148. while (!queue.isEmpty()) {
    149. // 取出队列的头结点
    150. u = queue.getFirst();
    151. queue.removeFirst();
    152. // 查找节点u的第一个邻接节点w
    153. w = getFirstNeighbor(u);
    154. while (w != -1) {
    155. // 如果w没有被访问过
    156. if (!isVisited[w]) {
    157. // 访问w节点,输出信息
    158. System.out.print(getValueByIndex(w) + " -> ");
    159. // 标记为已访问
    160. isVisited[w] = true;
    161. // 将当前节点加入队列
    162. queue.addLast(w);
    163. }
    164. // 如果w被访问过,再找w的兄弟节点,即u的其他邻接点
    165. w = getNextNeighbor(u,w); // 这里体现出了广度优先遍历
    166. }
    167. }
    168. }
    169. // 遍历所有的节点,都进行广度优先遍历
    170. public void bfs() {
    171. for (int i = 0; i < getNumOfVarText(); i++) {
    172. if (!isVisited[i]) {
    173. bfs(isVisited,i);
    174. }
    175. }
    176. }
    177. }