图的存储方式
-
邻接表
-
邻接矩阵
正方形矩阵
A B C D
A 0 - 7 3
B - 0 2 -
C 7 2 0 5
D 3 - 5 0
表达图。。。 生成图
有向图 无向图 权值
点 + 边
点如下
public class Node { // 点集 public int value; // 编号,值 public int in; // 入度 ,有多少个进入这个点, 无向图,入度和出度一样。 public int out; // 出度 , public ArrayList<Node> nexts; // 从当前点出发,发散出去的点,直接邻居。 public ArrayList<Edge> edges; // 属于我的边 有哪些。 A→B from 是 当前node. public Node(int value) { this.value = value; in = 0; out = 0; nexts = new ArrayList<>(); edges = new ArrayList<>(); } }
边如下
public class Edge { public int weight; // 权重 public Node from; // 从哪个node 出发 public Node to; // 到哪个node public Edge(int weight, Node from, Node to) { this.weight = weight; this.from = from; this.to = to; } }
图结构如下
public class Graph { public HashMap<Integer, Node> nodes; public HashSet<Edge> edges; public Graph() { nodes = new HashMap<>(); edges = new HashSet<>(); } }
生成图, 其他结构类型的图,生成 自己的这个图
public static Graph generatorGraph(Integer[][] matrix) { // matrix 二维数组, // matrix[0][0] = from, // matrix[0][1] = to, // matrix[0][2] = weight Graph graph = new Graph(); for (int i = 0; i < matrix.length; i++) { Integer from = matrix[i][0]; Integer to = matrix[i][1]; Integer weight = matrix[i][2]; // 判断当前点是否已经加入nodes if (!graph.nodes.containsKey(from)) { graph.nodes.put(from, new Node(from)); } if (!graph.nodes.containsKey(to)) { graph.nodes.put(to, new Node(to)); } Node fromNode = graph.nodes.get(from); Node toNode = graph.nodes.get(to); Edge edge = new Edge(weight, fromNode, toNode); fromNode.out ++; toNode.in ++; fromNode.nexts.add(toNode); graph.edges.add(edge); } return graph; }
图的宽度优先遍历
1) 宽度,都是队列
2) 从源节点开始依次按照宽度 进 队列, 然后弹出
3) 每弹出一个点,把该节点所有没有进过队列的 邻接点 放入队列
4) 直到队列为空
和二叉树的区别,可能有环 。要注意,使用一个set保存已经进入过队列的 node
public static void graphBFS(Node node) { if (node == null) { return; } LinkedList<Node> queue = new LinkedList<>(); HashSet<Node> set = new HashSet<>(); // 保存已经进入过 queue的node // 节点入队 queue.add(node); set.add(node); Node cur = null; // 开始循环 出队 while (!queue.isEmpty()) { cur = queue.poll(); // 打印处理 System.out.println(cur.value); // 把当前节点 的邻接点 都入队 for (Node tmpNode : cur.nexts) { // 判断是否已经进入过队列 if (set.contains(tmpNode)) { continue; } queue.add(tmpNode); set.add(tmpNode); } } }
图的深度优先遍历
1)深度,使用栈
2)从源节点开始把节点按照深度放入栈, 然后弹出,
3)每弹出一个点,把该节点 下一个 没有进过栈的邻接点 放入栈 , 只放一个。还要把当前节点也压进去。处理next节点。
如果都已经进过栈了。开始弹上一个
栈永远保存当前深度路劲
4)直到栈为空
public static void graphDFS(Node node){ if(node == null){ return; } HashSet<Node> set = new HashSet<>(); Stack<Node> stack = new Stack<>(); stack.push(node); set.add(node); //先处理 第一个节点 System.out.println(node.value); while(!stack.isEmpty()){ // 开始出栈 Node cur = stack.pop(); // 遍历 当前节点的 nexts for (Node nextNode : cur.nexts) { if(!set.contains(nextNode)){ //如果当前下一个节点 没 入过栈 ,开始处理当前节点, // 又因为栈要一直保存当前 深度,所以要把当前节点再压进去 stack.push(cur); stack.push(nextNode); // 当前nextNode 加入到 set set.add(nextNode); //打印处理 nextNode System.out.println(nextNode); // 只走一条路,所以直接break break; } } // 如果当前节点的下一个节点都 进入过栈,就开始依次弹出上面的节点。 } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统