package com.atguigu.graph;import sun.misc.Queue;import java.util.ArrayList;import java.util.Arrays;import java.util.LinkedList;/** * 图的简单实现 * * @author Dxkstart * @create 2022-04-11-16:18 */public class Graph { private ArrayList<String> varTextList; // 存储顶点 private int[][] edges; // 存储图对应的邻接矩阵 private int numOfEdges; // 表示边的个数 private boolean[] isVisited; // 记录某个节点是否被访问 public static void main(String[] args) { int n = 5;// 节点的个数 String VarTexValue[] = {"A", "B", "C", "D", "E"}; // 创建图对象 Graph graph = new Graph(n); // 添加 for (String str : VarTexValue) { graph.add(str); } // 添加边 A-B A-C B-C B-D B-E graph.addEdge(0, 1, 1); // A-B graph.addEdge(0, 2, 1); // A-C graph.addEdge(1, 2, 1); // B-C graph.addEdge(1, 3, 1); // B-D graph.addEdge(1, 4, 1); // B-E // 显示图的矩阵 graph.showGraph(); // 测试深度优先遍历// System.out.println("测试深度优先遍历");// graph.dfs(); System.out.println(); // 测试广度优先遍历 System.out.println("测试广度优先遍历"); graph.bfs(); } // 构造器 public Graph(int n) { // 初始化矩阵和varTextList edges = new int[n][n]; varTextList = new ArrayList<String>(n); numOfEdges = 0; isVisited = new boolean[n]; } // 插入节点 public void add(String varText) { varTextList.add(varText); } // 添加边 /** * @param v1 表示点的下标 * @param v2 表示第二个顶点对应的下标 * @param weight 表示边的权值 */ public void addEdge(int v1, int v2, int weight) { edges[v1][v2] = weight; edges[v2][v1] = weight; numOfEdges++; } // 返回节点的个数 public int getNumOfVarText() { return varTextList.size(); } // 返回边的数目 public int getNumOfEdges() { return numOfEdges; } // 返回节点i(下标) 对应的数据 public String getValueByIndex(int i) { return varTextList.get(i); } // 返回v1和v2的权值 public int getWeight(int v1, int v2) { return edges[v1][v2]; } // 显示图对应的矩阵 public void showGraph() { for (int[] link : edges) { System.err.println(Arrays.toString(link)); } } // 得到当前节点的第一个邻接节点的下标 /** * @param index 当前节点的下标 * @return 如果存在就返回下标,否则返回-1 */ public int getFirstNeighbor(int index) { for (int i = 0; i < varTextList.size(); i++) { if (edges[index][i] > 0) { return i; } } return -1; } // 根据当前节点的下标获取下一个节点的下标 // v1,v2是当前节点的行和列下标 // 获取当前节点的其他邻接点 public int getNextNeighbor(int v1, int v2) { for (int i = v2 + 1; i < varTextList.size(); i++) { if (edges[v1][i] > 0) { return i; } } return -1; } // 深度优先遍历算法 public void dfs(boolean[] isVisited, int i) { // 先访问当前节点 System.out.print(getValueByIndex(i) + " -> "); // 将当前节点置为已访问 isVisited[i] = true; // 查找当前节点的第一个邻接节点 int w = getFirstNeighbor(i); while (w != -1) { if (!isVisited[w]) { dfs(isVisited, w); } // 如果w节点已经被访问过了 w = getNextNeighbor(i, w);// 2 , 0 } } // 对dfs进行重载,遍历所有的节点,并进行dfs public void dfs() { // 遍历所有的节点,进行dfs【回溯】 for (int i = 0; i < getNumOfVarText(); i++) { if (!isVisited[i]) { dfs(isVisited, i); } } } // 广度优先遍历算法 public void bfs(boolean[] isVisited, int i) { int u; // 表示队列的头结点对应的下标 int w; // 邻接节点w // 队列,记录节点访问的顺序 LinkedList<Integer> queue = new LinkedList<>(); // 访问当前节点,输出信息 System.out.print(getValueByIndex(i) + " -> "); // 标记为已访问 isVisited[i] = true; // 将当前节点加入队列 queue.addLast(i); while (!queue.isEmpty()) { // 取出队列的头结点 u = queue.getFirst(); queue.removeFirst(); // 查找节点u的第一个邻接节点w w = getFirstNeighbor(u); while (w != -1) { // 如果w没有被访问过 if (!isVisited[w]) { // 访问w节点,输出信息 System.out.print(getValueByIndex(w) + " -> "); // 标记为已访问 isVisited[w] = true; // 将当前节点加入队列 queue.addLast(w); } // 如果w被访问过,再找w的兄弟节点,即u的其他邻接点 w = getNextNeighbor(u,w); // 这里体现出了广度优先遍历 } } } // 遍历所有的节点,都进行广度优先遍历 public void bfs() { for (int i = 0; i < getNumOfVarText(); i++) { if (!isVisited[i]) { bfs(isVisited,i); } } }}