• 数据结构和算法——图结构


    图是一种数据结构;

    有向图
    带权图

    邻接矩阵

    邻接表相较于邻接矩阵,减少了存储空间;

    邻接表

    图的深度优先遍历(DFS)

    图的广度优先遍历(BFS)

    代码:

    1. import java.util.ArrayList;
    2. import java.util.Arrays;
    3. import java.util.LinkedList;
    4. public class Graph {
    5. public static void main(String[] args) {
    6. int n = 8; // 节点的个数
    7. String[] vertexs = {"1", "2", "3", "4", "5", "6", "7", "8"};
    8. Graph graph = new Graph(n);
    9. // 添加顶点
    10. for (String VertexValue : vertexs) {
    11. graph.insertVertex(VertexValue);
    12. }
    13. graph.insertEdge(0, 1, 1);
    14. graph.insertEdge(0, 2, 1);
    15. graph.insertEdge(1, 3, 1);
    16. graph.insertEdge(1, 4, 1);
    17. graph.insertEdge(2, 5, 1);
    18. graph.insertEdge(2, 6, 1);
    19. graph.insertEdge(3, 7, 1);
    20. graph.insertEdge(4, 7, 1);
    21. graph.insertEdge(5, 6, 1);
    22. // 展示邻接矩阵
    23. graph.showGraph();
    24. graph.dfs();
    25. // graph.bfs();
    26. }
    27. private ArrayList vertexList; //存储顶点的集合
    28. private int[][] edges; // 存储图的邻接矩阵
    29. private int numOfEdges; // 边的数量
    30. private boolean isVisited[]; // 是否被访问
    31. public Graph(int n) {
    32. edges = new int[n][n];
    33. vertexList = new ArrayList<>(n);
    34. numOfEdges = 0;
    35. isVisited = new boolean[n];
    36. }
    37. /**
    38. * 得到第一个邻接节点的下标
    39. *
    40. * @param index
    41. * @return
    42. */
    43. public int getFirstNeighbor(int index) {
    44. for (int j = 0; j < vertexList.size(); j++) {
    45. if (edges[index][j] > 0) {
    46. return j;
    47. }
    48. }
    49. return -1;
    50. }
    51. /**
    52. * 根据前一个邻接节点的下标来获取下一个邻接节点的下标
    53. *
    54. * @param v1
    55. * @param v2
    56. * @return
    57. */
    58. public int getNextNeighbor(int v1, int v2) {
    59. for (int j = v2 + 1; j < vertexList.size(); j++) {
    60. if (edges[v1][j] > 0) {
    61. return j;
    62. }
    63. }
    64. return -1;
    65. }
    66. /**
    67. * 深度优先遍历算法
    68. */
    69. public void dfs() {
    70. isVisited = new boolean[isVisited.length];
    71. for (int i = 0; i < getNumOfEdges(); i++) { // 节点个数5
    72. if (!isVisited[i]) {
    73. dfs(isVisited, i);
    74. }
    75. }
    76. }
    77. private void dfs(boolean[] isVisited, int i) {
    78. System.out.print(getValByIndex(i) + "->");
    79. // 将该节点设置为已访问
    80. isVisited[i] = true;
    81. // 查找节点i的第一个邻接节点
    82. int w = getFirstNeighbor(i);
    83. while (w != -1) {
    84. // 没有访问过
    85. if (!isVisited[w]) {
    86. dfs(isVisited, w);
    87. }
    88. // 邻接节点已经被访问过
    89. w = getNextNeighbor(i, w);
    90. }
    91. }
    92. /**
    93. * 遍历所有的节点,都进行广度优先搜索
    94. */
    95. public void bfs() {
    96. isVisited = new boolean[isVisited.length];
    97. for (int i = 0; i < getNumOfEdges(); i++) {
    98. if (!isVisited[i]) {
    99. bfs(isVisited, i);
    100. }
    101. }
    102. }
    103. /**
    104. * 对一个节点进行广度优先遍历的方法
    105. *
    106. * @param isVisited
    107. * @param i
    108. */
    109. private void bfs(boolean[] isVisited, int i) {
    110. int u; // 表示队列头节点对应的下标
    111. int w; // 邻接节点的下标
    112. // 队列,记录节点访问的顺序
    113. LinkedList queue = new LinkedList<>();
    114. // 访问节点
    115. System.out.print(getValByIndex(i) + "=>");
    116. // 标记为已访问
    117. isVisited[i] = true;
    118. // 将节点加入队列
    119. queue.addLast(i);
    120. while (!queue.isEmpty()) {
    121. // 取出队列的头节点下标
    122. u = (Integer) queue.removeFirst();
    123. // 得到第一个邻接点的下标
    124. w = getFirstNeighbor(u);
    125. while (w != -1) {
    126. if (!isVisited[w]) {
    127. System.out.print(getValByIndex(w) + "=>");
    128. // 标记为已访问
    129. isVisited[w] = true;
    130. // 入队
    131. queue.addLast(w);
    132. }
    133. // 以u为前驱点,找w后面的邻接点
    134. w = getNextNeighbor(u, w);
    135. }
    136. }
    137. }
    138. /**
    139. * 添加边
    140. *
    141. * @param v1 表示第一个顶点的下标
    142. * @param v2 表示第二个顶点的下标
    143. * @param weight 权值
    144. */
    145. public void insertEdge(int v1, int v2, int weight) {
    146. edges[v1][v2] = weight;
    147. edges[v2][v1] = weight; // 无向图
    148. numOfEdges++;
    149. }
    150. /**
    151. * 添加节点
    152. *
    153. * @param vertex
    154. */
    155. public void insertVertex(String vertex) {
    156. vertexList.add(vertex);
    157. }
    158. /**
    159. * 返回节点的个数
    160. *
    161. * @return
    162. */
    163. public int getNumOfEdges() {
    164. return vertexList.size();
    165. }
    166. /**
    167. * 返回节点i(下标)对应的数据
    168. *
    169. * @param i
    170. * @return
    171. */
    172. public String getValByIndex(int i) {
    173. return vertexList.get(i);
    174. }
    175. /**
    176. * 返回v1和v2的权值
    177. *
    178. * @param v1
    179. * @param v2
    180. * @return
    181. */
    182. public int getWeight(int v1, int v2) {
    183. return edges[v1][v2];
    184. }
    185. /**
    186. * 显示图对应的矩阵
    187. */
    188. public void showGraph() {
    189. for (int[] edge : edges) {
    190. System.out.println(Arrays.toString(edge));
    191. }
    192. }
    193. }

    参考视频:【尚硅谷】数据结构与算法(Java数据结构与算法)_哔哩哔哩_bilibili

  • 相关阅读:
    (项目实战)RocketMQ5.0延迟消息在聚合支付系统中的应用
    Python Day6 爬虫-lxml和多线程
    linux 进程管理相关内容
    TCP/IP 网络分层模型
    Metabase学习教程:模型-2
    PCDN技术如何适应不同用户的需求和偏好?
    RocketMQ 消费者
    mysql数据库
    leetcode_2300 咒语和药水的成功对数
    什么是 API ?
  • 原文地址:https://blog.csdn.net/m0_58961367/article/details/133985704