当前位置: 首页 > article >正文

数据结构-图的应用,实现环形校验和拓扑排序

文章目录

  • 一、如何理解“图”?
    • 1.什么是图?
    • 2.无向图和有向图
    • 3.无权图和有权图
  • 二、JGraphT-图论数据结构和算法的 Java 库
    • 1.引入Maven依赖
    • 2.环形校验
      • 2.1 什么是循环依赖 ?
      • 2.2 单元测试代码
      • 2.3 情况1:自己依赖自己
      • 2.4 情况2:两个对象之间
      • 2.5 情况3:多个对象之间
      • 2.6 情况4:真实情况
    • 3.拓扑排序
      • 3.1 Kahn算法
      • 3.2 Lua版
      • 3.3 Java版
  • 三、参考

一、如何理解“图”?

1.什么是图?

图(Graph)是一种非线性数据结构,由顶点(Vertex)边(Edge)组成。相较于线性关系(链表)和分治关系(树),网络关系(图)的自由度更高。
在这里插入图片描述

2.无向图和有向图

根据边是否具有方向,可分为无向图(undirected graph)有向图(directed graph),如图 9-2 所示。

在无向图中,边表示两顶点之间的“双向”连接关系,例如微信或 QQ 中的“好友关系”。我们就拿微信举例子吧。我们可以把每个用户看作一个顶点。如果两个用户之间互加好友,那就在两者之间建立一条边。所以,整个微信的好友关系就可以用一张图来表示。其中,每个用户有多少个好友,对应到图中,就叫作顶点的度(Degree),就是跟顶点相连接的边的条数。

在有向图中,边具有方向性,两个方向的边是相互独立的,例如微博或抖音上的“关注”与“被关注”关系。
我们刚刚讲过,无向图中有“度”这个概念,表示一个顶点有多少条边。在有向图中,我们把度分为入度(In-degree)出度(Out-degree)
顶点的入度,表示有多少条边指向这个顶点;顶点的出度,表示有多少条边是以这个顶点为起点指向其他顶点。对应到微博的例子,入度就表示有多少粉丝,出度就表示关注了多少人。
在这里插入图片描述

3.无权图和有权图

我们还可以为边添加“权重”变量,从而得到如图 9-4 所示的有权图(weighted graph)。例如在《王者荣耀》等手游中,系统会根据共同游戏时间来计算玩家之间的“亲密度”,这种亲密度网络就可以用有权图来表示。
在这里插入图片描述

二、JGraphT-图论数据结构和算法的 Java 库

https://jgrapht.org/

1.引入Maven依赖

<dependency><groupId>org.jgrapht</groupId><artifactId>jgrapht-core</artifactId><version>${org.jgrapht.core.version}</version>
</dependency>
<dependency><groupId>org.jgrapht</groupId><artifactId>jgrapht-ext</artifactId><version>${org.jgrapht.ext.version}</version>
</dependency><properties><org.jgrapht.core.version>1.5.2</org.jgrapht.core.version><org.jgrapht.ext.version>1.5.2</org.jgrapht.ext.version>
</properties>

2.环形校验

2.1 什么是循环依赖 ?

一个或多个对象之间存在直接或间接的依赖关系,这种依赖关系构成一个环形调用,有下面 3 种方式。
在这里插入图片描述

2.2 单元测试代码

首先创建DefaultDirectedGraph有向图对象,添加顶点和边。然后创建CycleDetector环形检测对象,并将graph对象传入,调用detectCycles()方法就很容易实现环形检测。

package com.baeldung.jgrapht;import com.mxgraph.layout.mxCircleLayout;
import com.mxgraph.layout.mxIGraphLayout;
import com.mxgraph.util.mxCellRenderer;
import org.jgrapht.Graph;
import org.jgrapht.alg.cycle.CycleDetector;
import org.jgrapht.ext.JGraphXAdapter;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;
import org.junit.jupiter.api.Test;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Set;import static org.junit.jupiter.api.Assertions.*;public class DetectCyclesUnitTest {/*** 情况1:自己依赖自己*/@Testpublic void testA() {DefaultDirectedGraph<String, DefaultEdge> graph = new DefaultDirectedGraph<>(DefaultEdge.class);graph.addVertex("A");graph.addEdge("A", "A");CycleDetector<String, DefaultEdge> cycleDetector = new CycleDetector<>(graph);assertTrue(cycleDetector.detectCycles());assertTrue(cycleDetector.findCycles().contains("A"));generateImage(graph, "情况1:自己依赖自己");}/*** 情况2:两个对象之间*/@Testpublic void testB() {DefaultDirectedGraph<String, DefaultEdge> graph = new DefaultDirectedGraph<>(DefaultEdge.class);graph.addVertex("A");graph.addVertex("B");graph.addEdge("A", "B");graph.addEdge("B", "A");CycleDetector<String, DefaultEdge> cycleDetector = new CycleDetector<>(graph);assertTrue(cycleDetector.detectCycles());assertEquals(2, cycleDetector.findCycles().size());generateImage(graph, "情况2:两个对象之间");}/*** 情况3:多个对象之间*/@Testpublic void testC() {DefaultDirectedGraph<String, DefaultEdge> graph = new DefaultDirectedGraph<>(DefaultEdge.class);graph.addVertex("A");graph.addVertex("B");graph.addVertex("C");graph.addEdge("A", "B");graph.addEdge("B", "C");graph.addEdge("C", "A");CycleDetector<String, DefaultEdge> cycleDetector = new CycleDetector<>(graph);assertTrue(cycleDetector.detectCycles());assertEquals(3, cycleDetector.findCycles().size());generateImage(graph, "情况3:多个对象之间");}/*** 真实情况*/@Testvoid testX() {DefaultDirectedGraph<String, DefaultEdge> directedGraph = new DefaultDirectedGraph<>(DefaultEdge.class);directedGraph.addVertex("v1");directedGraph.addVertex("v2");directedGraph.addVertex("v3");directedGraph.addVertex("v4");directedGraph.addVertex("v5");directedGraph.addVertex("v6");directedGraph.addEdge("v2", "v1");directedGraph.addEdge("v4", "v1");directedGraph.addEdge("v5", "v1");directedGraph.addEdge("v6", "v1");directedGraph.addEdge("v3", "v2");directedGraph.addEdge("v1", "v3");CycleDetector<String, DefaultEdge> cycleDetector = new CycleDetector<>(directedGraph);assertTrue(cycleDetector.detectCycles());Set<String> cycleVertices = cycleDetector.findCycles();assertFalse(cycleVertices.isEmpty());generateImage(directedGraph, "真实情况");}/*** 生成图片** @param graph     图* @param imageName 图片名*/public static void generateImage(Graph graph, String imageName) {JGraphXAdapter<String, DefaultEdge> graphAdapter = new JGraphXAdapter<>(graph);mxIGraphLayout layout = new mxCircleLayout(graphAdapter);layout.execute(graphAdapter.getDefaultParent());File imgFile = new File("src/test/resources/" + imageName + ".png");BufferedImage image = mxCellRenderer.createBufferedImage(graphAdapter, null, 2, Color.WHITE, true, null);try {ImageIO.write(image, "PNG", imgFile);} catch (IOException e) {//ignore}}
}

2.3 情况1:自己依赖自己

A依赖于A
在这里插入图片描述

2.4 情况2:两个对象之间

A依赖于B,B依赖于A
在这里插入图片描述

2.5 情况3:多个对象之间

A依赖于C,B依赖于A,C依赖于B
在这里插入图片描述

2.6 情况4:真实情况

说是真实情况,但生产非常大的可能性会比这个复杂,我们用这个引出拓扑排序。
在这里插入图片描述

3.拓扑排序

3.1 Kahn算法

Kahn算法实际上用的是贪心算法思想,思路非常简单、好懂。

定义数据结构的时候,如果s需要先于t执行,那就添加一条s指向t的边。所以,如果某个顶点入度为0, 也就表示,没有任何顶点必须先于这个顶点执行,那么这个顶点就可以执行了。

我们先从图中,找出一个入度为0的顶点,将其输出到拓扑排序的结果序列中(对应代码中就是把它打印出来),并且把这个顶点从图中删除(也就是把这个顶点可达的顶点的入度都减1)。我们循环执行上面的过程,直到所有的顶点都被输出。最后输出的序列,就是满足局部依赖关系的拓扑排序。

我把Kahn算法用代码实现了一下,你可以结合着文字描述一块看下。不过,你应该能发现,这段代码实现更有技巧一些,并没有真正删除顶点的操作。代码中有详细的注释,你自己来看,我就不多解释了。

3.2 Lua版

拓扑排序应用非常广泛,解决的问题的模型也非常一致。凡是需要通过局部顺序来推导全局顺序的,一般都能用拓扑排序来解决。除此之外,拓扑排序还能检测图中环的存在。对于Kahn算法来说,如果最后输出出来的顶点个数,少于图中顶点个数,图中还有入度不是0顶点,那就说明,图中存在环。

local func_map = {f_A = { "f_B" },f_B = { "f_C" }
}local func_map_len = table_len(func_map)
local sorted_funcs = {}local function build_dag(func_deps)local dag = {}local in_degrees = {}for func, deps in pairs(func_deps) dodag[func] = dag[func] or {}in_degrees[func] = in_degrees[func] or 0for _, dep in pairs(deps) dodag[dep] = dag[dep] or {}in_degrees[dep] = in_degrees[dep] or 0table.insert(dag[dep], func)in_degrees[func] = in_degrees[func] + 1endendreturn dag, in_degrees
endlocal function build_sorted_funcs(dag, in_degrees)local zero_in_degree_queue = {}local sorted_funcs = {}for func, in_degree in pairs(in_degrees) doif in_degree == 0 thentable.insert(zero_in_degree_queue, func)endendwhile #zero_in_degree_queue > 0 dolocal func = table.remove(zero_in_degree_queue, 1)table.insert(sorted_funcs, func)for _, parent in pairs(dag[func]) doin_degrees[parent] = in_degrees[parent] - 1if in_degrees[parent] == 0 thentable.insert(zero_in_degree_queue, parent)endendendreturn sorted_funcs
endlocal dag, in_degrees = build_dag(func_map)
sorted_funcs = build_sorted_funcs(dag, in_degrees)function invoke(...)if #sorted_funcs == func_map_len thenfor _, func in ipairs(sorted_funcs) domud_sense[func]()endelseprint("error: graph with loop")endreturn "OK"
end

由于上面的代码是车端执行的,为了节约算力,云端在代码生成后直接给出顺序,大大减少了终端设备的计算。

local sorted_funcs = {"f_A","f_B","f_C"
}
function invoke(...)for _, func in ipairs(sorted_funcs) domud_sense[func]()endreturn "OK"
end

3.3 Java版

例子如下:
在这里插入图片描述
由于DefaultEdge中getSource()和getTarget()访问权限是protected,没有办法获取到相关的值,所有我自己继承了DefaultEdge,创建了MyEdge类。

package com.baeldung.jgrapht;import org.jgrapht.graph.DefaultEdge;public class MyEdge extends DefaultEdge {@Overridepublic String getSource() {return super.getSource().toString();}@Overridepublic String getTarget() {return super.getTarget().toString();}
}

首先初始化DefaultDirectedGraph相关顶点和边的数据。实现了两种拓扑排序:借助java API和借助jgrapht API

package com.baeldung.jgrapht;import lombok.extern.slf4j.Slf4j;
import org.jgrapht.alg.cycle.CycleDetector;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;import java.util.*;import static com.baeldung.jgrapht.DetectCyclesUnitTest.generateImage;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;/*** 拓扑排序** @author xxx* @see* @since 1.0.0*/
@Slf4j
public class TopologicalSortUnitTest {private final static DefaultDirectedGraph<String, MyEdge> graph = new DefaultDirectedGraph<>(MyEdge.class);@BeforeAllpublic static void init() {graph.addVertex("v1");graph.addVertex("v2");graph.addVertex("v3");graph.addVertex("v4");graph.addVertex("v5");graph.addVertex("v6");graph.addEdge("v2", "v1");graph.addEdge("v4", "v1");graph.addEdge("v5", "v1");graph.addEdge("v6", "v1");graph.addEdge("v3", "v2");
//        graph.addEdge("v1","v3");}/*** 拓扑排序:借助java API*/@Testvoid test1() {CycleDetector<String, MyEdge> cycleDetector = new CycleDetector<>(graph);assertFalse(cycleDetector.detectCycles());Set<String> cycleVertices = cycleDetector.findCycles();assertTrue(cycleVertices.isEmpty());generateImage(graph, "拓扑排序");//转换Map<String, Set<String>> incomingVertax = new HashMap<>();for (String func : graph.vertexSet()) {incomingVertax.putIfAbsent(func, new TreeSet<>());}Set<MyEdge> defaultEdges = graph.edgeSet();for (MyEdge myEdge : defaultEdges) {incomingVertax.putIfAbsent(myEdge.getTarget(), new TreeSet<>());incomingVertax.get(myEdge.getTarget()).add(myEdge.getSource());}Map<String, Set<String>> outgoingVertax = buildOutgoingVertax(incomingVertax);Map<String, Integer> inDegrees = buildInDegrees(incomingVertax);List<String> result = buildSortedFunctions(outgoingVertax, inDegrees);System.out.println(result);}/*** 拓扑排序:借助jgrapht API*/@Testpublic void test2() {Queue<String> zeroInDegreeQueue = new LinkedList<>();Set<String> vertexSet = graph.vertexSet();List<String> sortedFunctions = new ArrayList<>();//构建入度Map<String, Integer> indegreeMap = new HashMap<>(vertexSet.size());for (String vertex : vertexSet) {indegreeMap.put(vertex, graph.inDegreeOf(vertex));if (graph.inDegreeOf(vertex) == 0) {zeroInDegreeQueue.add(vertex);}}while (!zeroInDegreeQueue.isEmpty()) {String v = zeroInDegreeQueue.poll();sortedFunctions.add(v);Set<MyEdge> defaultEdges = graph.outgoingEdgesOf(v);for (MyEdge defaultEdge : defaultEdges) {String parent = defaultEdge.getTarget();indegreeMap.put(parent, indegreeMap.get(parent) - 1);if (indegreeMap.get(parent) == 0) {zeroInDegreeQueue.add(parent);}}}System.out.println(sortedFunctions);}/*** 构建出度顶点** @param incomingVertax 入度顶点* @return 每个顶点的出度顶点*/private static Map<String, Set<String>> buildOutgoingVertax(Map<String, Set<String>> incomingVertax) {Map<String, Set<String>> outgoingVertax = new HashMap<>();for (String func : incomingVertax.keySet()) {outgoingVertax.putIfAbsent(func, new TreeSet<>());for (String dep : incomingVertax.get(func)) {outgoingVertax.putIfAbsent(dep, new TreeSet<>());outgoingVertax.get(dep).add(func);}}return outgoingVertax;}/*** 构建入度** @param incomingVertax 入度顶点* @return 每个顶点的入度数*/private static Map<String, Integer> buildInDegrees(Map<String, Set<String>> incomingVertax) {Map<String, Integer> inDegrees = new HashMap<>();for (String func : incomingVertax.keySet()) {inDegrees.putIfAbsent(func, 0);for (String dep : incomingVertax.get(func)) {inDegrees.putIfAbsent(dep, 0);inDegrees.put(func, inDegrees.get(func) + 1);}}return inDegrees;}/*** 构建排序函数** @param outgoingVertax 出度顶点* @param inDegrees      每个顶点的入度数* @return 拓扑排序结果*/private static List<String> buildSortedFunctions(Map<String, Set<String>> outgoingVertax, Map<String, Integer> inDegrees) {Queue<String> zeroInDegreeQueue = new LinkedList<>();List<String> sortedFunctions = new ArrayList<>();for (Map.Entry<String, Integer> entry : inDegrees.entrySet()) {if (entry.getValue() == 0) {zeroInDegreeQueue.add(entry.getKey());}}while (!zeroInDegreeQueue.isEmpty()) {String func = zeroInDegreeQueue.poll();sortedFunctions.add(func);for (String parent : outgoingVertax.get(func)) {inDegrees.put(parent, inDegrees.get(parent) - 1);if (inDegrees.get(parent) == 0) {zeroInDegreeQueue.add(parent);}}}return sortedFunctions;}
}

三、参考

https://www.hello-algo.com/chapter_graph/graph/
https://www.baeldung.com/jgrapht
https://www.51cto.com/article/716548.html

相关文章:

数据结构-图的应用,实现环形校验和拓扑排序

文章目录 一、如何理解“图”&#xff1f;1.什么是图&#xff1f;2.无向图和有向图3.无权图和有权图 二、JGraphT-图论数据结构和算法的 Java 库1.引入Maven依赖2.环形校验2.1 什么是循环依赖 &#xff1f;2.2 单元测试代码2.3 情况1&#xff1a;自己依赖自己2.4 情况2&#xf…...

交换机 路由器

在计算机网络中&#xff0c;S 和 R 常常分别代表以下设备&#xff1a; S&#xff1a;Switch&#xff08;交换机&#xff09;R&#xff1a;Router&#xff08;路由器&#xff09; 简要说明&#xff1a; Switch&#xff08;交换机&#xff0c;S&#xff09; 交换机工作在数据链…...

某乎x-zse-96 破解(补环境版本)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、总体概述二、请求分析分析请求流程三、逆向分析总结一、总体概述 本文主要实现某乎x-zse-96 破解(补环境版本),相关的链接: https://www.zhihu.com/search?type=content&q=%25E7%258…...

VSCode+Cline 安装配置及使用说明

安装配置 打开VSCode&#xff0c;点击左侧Extension图标&#xff0c;在弹出页面中&#xff0c;检索Cline&#xff0c;选择Cline进行安装。 安装完毕&#xff0c;在左侧会出现一个图标&#xff0c;点击图标 选择【Use your own API key】&#xff0c;在出来的界面中选择大模型&…...

Java中Redis面试题集锦(含过期策略详解)

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Java中Redis面试题集锦&#xff08;含过期策…...

Maven 安装与配置指南(适用于 Windows、Linux 和 macOS)

Apache Maven 是一款广泛应用于 Java 项目的项目管理和构建工具。 本文提供在 Windows、Linux 和 macOS 系统上安装与配置 Maven 的详细步骤&#xff0c;旨在帮助开发者快速搭建高效的构建环境。 一、前置条件&#xff1a;安装 Java Development Kit (JDK) Maven 依赖于 Java …...

android 媒体框架之MediaCodec

一、MediaCodec 整体架构与设计思想 MediaCodec 是 Android 底层多媒体框架的核心组件&#xff0c;负责高效处理音视频编解码任务。其架构采用 生产者-消费者模型&#xff0c;通过双缓冲区队列&#xff08;输入/输出&#xff09;实现异步数据处理&#xff1a; 输入缓冲区队列…...

堆与堆排序及 Top-K 问题解析:从原理到实践

一、堆的本质与核心特性 堆是一种基于完全二叉树的数据结构&#xff0c;其核心特性为父节点与子节点的数值关系&#xff0c;分为大堆和小堆两类&#xff1a; 大堆&#xff1a;每个父节点的值均大于或等于其子节点的值&#xff0c;堆顶元素为最大值。如: 小堆&#xff1a;每个…...

Linux中检查当前用户是不是root

Linux中检查当前用户是不是root 检查当前用户是否为root用户。如果是root用户&#xff0c;输出“当前用户是root”&#xff1b;否则&#xff0c;输出“当前用户不是root”。 创建一个 aaa.sh脚本文件 写入如下内容 #!/bin/bash# 检查当前用户的UID是否为0&#xff08;root用…...

软件锁:守护隐私,安心无忧

数字化时代&#xff0c;手机已成为我们生活中不可或缺的一部分&#xff0c;它不仅存储着我们的个人信息、照片、聊天记录等重要数据&#xff0c;还承载着我们的社交、娱乐和工作等多种功能。然而&#xff0c;这也意味着手机上的隐私信息面临着诸多泄露风险。无论是家人、朋友还…...

无人机桥梁3D建模、巡检、检测的航线规划

无人机桥梁3D建模、巡检、检测的航线规划 无人机在3D建模、巡检和检测任务中的航线规划存在显著差异&#xff0c;主要体现在飞行高度、航线模式、精度要求和传感器配置等方面。以下是三者的详细对比分析&#xff1a; 1. 核心目标差异 任务类型主要目标典型应用场景3D建模 生成…...

项目:贪吃蛇实现

头文件 snake.h #include<stdio.h> #include<stdlib.h> #include<windows.h> #include<locale.h> #include<stdbool.h> #include<time.h>#define POS_X 24#define POS_Y 5 #define BODY L● #define FOOD L★ #define KEY_PRESS(VK) ((…...

【Java基础05】面向对象01

文章目录 1. 设计对象并使用1.1 类与对象1.2 封装1.2.1 private关键字1.2.2 this关键字成员变量和局部变量的区别 1.2.3 构造方法1.2.4 标准JavaBean类 1.3 对象内存图 本文部分参考这篇博客 1. 设计对象并使用 1.1 类与对象 public class 类名{1、成员变量(代表属性,一般是名…...

设计模式:观察者模式 - 实战

一、观察者模式场景 1.1 什么是观察者模式&#xff1f; 观察者模式&#xff08;Observer Pattern&#xff09;观察者模式是一种行为型设计模式&#xff0c;用于定义一种一对多的依赖关系&#xff0c;当对象的状态发生变化时&#xff0c;所有依赖于它的对象都会自动收到通知并更…...

8.8 Primary ODSA service without ODSA Portal

主要ODSA服务&#xff08;不使用ODSA门户&#xff09; 以下场景描述如下情况&#xff1a; • 主ODSA客户端应用程序被允许用于该类型的主设备&#xff0c;且对终端用户启用&#xff08;已授权&#xff09;。 • 服务提供商&#xff08;SP&#xff09;能够在不涉及ODSA门户Web服…...

YOLOv8 移动端升级:借助 GhostNetv2 主干网络,实现高效特征提取

文章目录 引言GhostNetv2概述GhostNet回顾GhostNetv2创新 YOLOv8主干网络改进原YOLOv8主干分析GhostNetv2主干替换方案整体架构设计关键模块实现 完整主干网络实现YOLOv8集成与训练模型集成训练技巧 性能对比与分析计算复杂度对比优势分析 部署优化建议结论与展望 引言 目标检…...

国产化Word处理控件Spire.Doc教程:在 C# 中打印 Word 文档终极指南

在 C# 中以编程方式打印 Word 文档可以简化业务工作流程、自动化报告和增强文档管理系统。本指南全面探讨如何使用Spire.Doc for .NET打印 Word 文档&#xff0c;涵盖从基本打印到高级自定义技术的所有内容。我们将逐步介绍每种情况下的实际代码示例&#xff0c;确保您能够在实…...

java的vscode扩展插件

在 Visual Studio Code (VSCode) 中&#xff0c;Java 开发可以通过多种方式得到支持&#xff0c;包括安装专门的扩展插件。下面是一些流行的 VSCode 扩展插件&#xff0c;可以帮助你更好地进行 Java 开发&#xff1a; Language Support for Java(TM) by Red Hat 官方支持&…...

谷歌:贝叶斯框架优化LLM推理反思

&#x1f4d6;标题&#xff1a;Beyond Markovian: Reflective Exploration via Bayes-Adaptive RL for LLM Reasoning &#x1f310;来源&#xff1a;arXiv, 2505.20561 &#x1f31f;摘要 通过强化学习 (RL) 训练的大型语言模型 (LLM) 表现出强大的推理能力和紧急反射行为&a…...

Qt SQL模块基础

Qt SQL模块基础 一、Qt SQL模块支持的数据库 官方帮助文档中的Qt支持的数据库驱动如下图&#xff1a; Qt SQL 模块中提供了一些常见的数据库驱动&#xff0c;包括网络型数据库&#xff0c;如Qracle、MS SQL Server、MySQL等&#xff0c;也包括简单的单机型数据库。 Qt SQL支…...

[9-3] 串口发送串口发送+接收 江协科技学习笔记(26个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26中断...

java 微服务中,微服务相互调用 feign 和flux 如何选择

在 Java 微服务中&#xff0c;Feign 和 Flux&#xff08;通过 WebClient 实现&#xff09;是两种不同的服务间调用方式&#xff0c;主要区别体现在编程模型、通信机制和适用场景上。 1. 编程模型 FeignFlux (WebClient)同步阻塞式&#xff1a;基于传统 Servlet 模型&#xff0…...

如何在Qt中绘制一个带有动画的弧形进度条?

如何在Qt中绘制一个弧形的进度条 在图形用户界面开发中&#xff0c;进度指示控件&#xff08;Progress Widget&#xff09;是非常常见且实用的组件。CCArcProgressWidget 是一个继承自 QWidget 的自定义控件&#xff0c;用于绘制圆弧形进度条。当然&#xff0c;笔者看了眼公开…...

参加技术会议,为程序人生的职业生涯成长添砖加瓦

参加技术会议,为程序人生的职业生涯成长添砖加瓦 关键词:技术会议、程序员职业生涯、职业成长、技术交流、人脉拓展、知识体系升级、职业竞争力 摘要:在快速迭代的IT技术领域,参加技术会议已成为程序员突破职业瓶颈、构建核心竞争力的重要途径。本文从技术会议的核心价值出…...

国产三维CAD皇冠CAD(CrownCAD)建模教程:汽车电池

在线解读『汽车电池』的三维建模流程&#xff0c;讲解3D草图、保存实体、拉伸凸台/基体、设置外观等操作技巧&#xff0c;一起和皇冠CAD&#xff08;CrownCAD&#xff09;学习制作步骤吧&#xff01; 汽车电池&#xff08;通常指铅酸蓄电池或锂离子电池&#xff09;是车辆电气系…...

记录算法笔记(2025.5.28)只出现一次的数字

给你一个 非空 整数数组 nums &#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法来解决此问题&#xff0c;且该算法只使用常量额外空间。 示例 1 &#xff1a; 输入&#xff1…...

VMware-workstation安装教程--超详细(附带安装包)附带安装CentOS系统教程

VMware-workstation安装教程--超详细&#xff08;附带安装包&#xff09;附带安装CentOS系统教程 一、下载软件VMwware二、下载需要的镜像三、在VMware上安装系统 一、下载软件VMwware 二、下载需要的镜像 三、在VMware上安装系统 VMware 被 Broadcom&#xff08;博通&#x…...

2025年- H63-Lc171--33.搜索旋转排序数组(2次二分查找,需二刷)--Java版

1.题目描述 2.思路 输入&#xff1a;旋转后的数组 nums&#xff0c;和一个整数 target 输出&#xff1a;target 在 nums 中的下标&#xff0c;如果不存在&#xff0c;返回 -1 限制&#xff1a;时间复杂度为 O(log n)&#xff0c;所以不能用遍历&#xff0c;必须使用 二分查找…...

3D-激光SLAM笔记

目录 定位方案 编译tbb ros2humble安装 命令 colcon commond not found 栅格地图生成&#xff1a; evo画轨迹曲线 安装gtsam4.0.2 安装ceres-solver1.14.0 定位方案 1 方案一&#xff1a;改动最多 fasterlio 建图&#xff0c;加闭环优化&#xff0c;参考fast-lio增加关…...

Golang 配置国内代理

使用 GOPROXY 临时设置 export GOPROXYhttps://goproxy.cn,direct永久设置 go env -w GOPROXYhttps://goproxy.cn,direct再go get下载...