Java版jieba分词实战:Trie+DAG+HMM构建中文分词引擎
简介这是基于Python版jieba分词封装的Java实现项目面向需要在Java服务端或桌面应用中进行中文分词的开发者。项目包含完整源码、词典文件与Eclipse工程配置解压后可直接导入运行。包内共30个文件以java源码、class编译文件及txt词典为主另含xml与project配置整体4.17MB结构清晰。目前已有2210人学习使用。通过run包下test入口可快速验证分词效果支持精确模式、全模式、搜索引擎模式并能通过修改词典或扩展代码实现关键词提取、词性标注等功能适合信息检索、文本挖掘、舆情分析等场景快速集成。1. 从 Python 生态搬到 JVM这份 jieba 分词 Java 版到底能干什么只要在 Java 服务里碰过中文搜索、评论关键词提取或者客服工单分类大概率遇到过同一个尴尬Python 里一句jieba.cut就能拿到漂亮的分词结果JVM 生态却总在几个半死不活的库之间反复横跳。这份 jieba 分词 Java 版项目把 Python 版那套「词典切分 未登录词识别」的完整方案搬到了 Java 世界对外接口收敛成一个JiebaSegmenter类几行代码就能接进 Spring Boot 服务或者 ES 索引前置处理。它做得最扎实的是算法链路完整移植主词典加载成 Trie 前缀树句子用 DAG 描述所有可能的切分方式动态规划选出最大概率路径最后靠 HMM 隐马尔可夫模型兜底词典里根本没有的人名和新词。对想给系统加中文分词能力的开发者来说这份资源最大的价值不是「能分词」这个结果而是能直接打开源码看明白每一步在干什么出了问题有地方查、想改有地方下手。适合这么用业务字段的精确切分、搜索索引的前置分词、离线批量文本处理。新手照着 Demo 能跑通熟手能顺着 DAG 和 Viterbi 两条线做二次开发。下面按「架构 → 核心代码 → 运行 → 避坑 → 改造」的顺序把它拆开讲。2. 架构与模块拆解Trie 词典、DAG 切图、HMM 兜底的三层设计整份代码拆开来看其实就是一条清晰的处理流水线一个句子进来先按标点断成短句每个短句先查词典画出一张有向无环图再在这张图上用动态规划找最优切分路径上那些词典查不到、被拆成单个字的「孤儿」统一交给 HMM 猜词最后根据你选的模式决定要不要把长词再切细。三层各管一段边界非常清楚这也是它比很多「调用即黑匣子」的分词方案更适合落在自己项目里的原因。2.1 目录结构与核心类职责常见的移植版目录长这样你手上的源码如果类名稍有出入以实际为准jieba-analysis/ ├── pom.xml # Maven 工程描述坐标与编译配置 ├── src/main/java/ │ ├── JiebaSegmenter.java # 分词门面对外唯一主要入口 │ ├── WordDictionary.java # 词典单例加载 dict.txt 并维护 Trie │ ├── CharacterUtil.java # 字符类型判定中/英/数字/分隔符 │ ├── SegToken.java # 分词结果对象word startOffset endOffset │ ├── Viterbi.java # HMM 解码负责未登录词识别 │ ├── Node.java # Trie 节点children 用 HashMap 存 │ ├── Pair.java # 动态规划用的值对象 │ └── demo/ │ └── Demo.java # 可直接运行的示例入口 └── src/main/resources/ ├── dict.txt # 主词典每行「词 词频 词性」 └── prob_emit.txt # HMM 发射概率表有的版本编译进 Viterbi 类核心类的职责可以用一张表说清类名职责关键入口JiebaSegmenter分词门面切句、建 DAG、跑 DP、调 HMMprocess(paragraph, SegMode)WordDictionary词典单例加载 dict.txt维护 Trie 和词频表getInstance()、addWord()ViterbiHMM 解码输出 BMES 状态序列viterbi(sentence)CharacterUtil字符归类决定哪些片段交给谁处理identifyCharType(char)SegToken单个分词结果含原文偏移量word / startOffset / endOffsetprocess()是总控它拿到整段文本后先按中英文标点、换行把文本切成短句逐个短句调用sentenceProcess()。sentenceProcess()内部才是完整的算法链路。注意SegToken里保存的是相对整段文本的 offset不是相对短句的偏移这一点在之后对接业务字段抽取时很重要取子串直接用 token 的 offset 就能定位回原文。2.2 两种分词模式与业务场景对照Java 移植版一般保留两种SegMode对应 Python 原版的精确模式和搜索引擎模式。用「自动化研究所」这句话试一下差别INDEX 模式自动化 / 研究所 SEARCH 模式自动 / 自动化 / 研究 / 研究所INDEX 模式输出粗粒度的词典词适合业务字段抽取、标签提取这种「要准确不要冗余」的场景SEARCH 模式在粗粒度基础上把长度超过两个字的词再按词典切细同时保留原词适合搜索引擎倒排索引——召回率优先宁可多切也不漏切。两种模式的差异对照如下模式输出粒度典型用途INDEX词典词整词输出精确切分、字段提取、意图识别SEARCH整词 长词二次切分搜索索引、召回阶段的分词需要提醒的是Python 版还有一个「全模式」输出所有可能的词组合Java 移植版一般没提供这个枚举。真要全模式可以自己把 DAG 里所有边全部展开输出后面第六节会讲怎么改。2.3 技术选型为什么是 Trie DAG 动态规划 HMM四个组件缺一个都不行。Trie 前缀树解决的第一个问题是匹配效率三十万级词条如果每次切词都全量扫一遍词典性能根本扛不住。把词按字符逐层挂到树里之后一个位置能否成词只跟它后面几个字符有关查找复杂度从词典规模降到了词长级别。DAG 解决的是「一句中文有无数种切法」的问题。拿「研究生命起源」来说「研究 / 生命」和「研究生 / 命」都合法计算机需要一种结构把所有这些可能性表达出来DAG 就是干这个的每个位置 i 指向所有可能的词尾 j一条从 0 走到 n-1 的路径就是一种切分。路径太多就得靠动态规划筛选——从后往前累计对数概率保证选出来的是全局最优而不是局部最优。相比之下简单的正向最大匹配经常被「局部大词」带偏缺乏全局视角。HMM 是最后一道保险。词典再大也覆盖不了人名、地名、网络新词这部分如果硬切会被拆成单字。Viterbi 算法把连续单字串当作一个待解码序列用 B(词首)/M(词中)/E(词尾)/S(单字) 四个隐状态去猜哪些字应该并成一个词。整套设计本质上就是「确定的部分靠词典保证不确定的部分靠概率模型兜底」分离得干净二次开发时想替换哪一层都容易下手。3. 核心代码逐段解析一个句子从 getDAG 到 Viterbi 的完整旅程这一章直接进源码。代码是按常见移植版的实现逻辑整理的个别变量名、方法名和你手上的版本可能不一样但算法骨架是一致的照着看不会迷路。3.1 词典加载WordDictionary 的 Trie 构建与词频统计所有分词的基础是词典。dict.txt 每一行是「词 词频 词性」三段词性在切分时用不到所以加载时只取前两列public synchronized void loadDict() { try (BufferedReader reader new BufferedReader(new InputStreamReader( getClass().getResourceAsStream(MAIN_DICT), StandardCharsets.UTF_8))) { String line; while ((line reader.readLine()) ! null) { String[] parts line.trim().split(\\s); if (parts.length 2) continue; String word parts[0]; double freq Double.parseDouble(parts[1]); insertToTrie(word, freq); // 把词按字符逐层挂进前缀树 freqs.put(word, freq); // 词频表DP 时直接查 totalFrequency freq; // 累加总词频用于归一化 } } catch (IOException e) { throw new IllegalStateException(dict.txt 加载失败, e); } minLogProb Math.log(1.0 / totalFrequency); }这段代码干了三件事建 Trie、存词频、算总词频。insertToTrie()遍历词的每个字符在Node的childrenMap 里逐层putIfAbsent最后一个字符所在的节点标记为isWordtrue并挂上词频。totalFrequency是所有词频之和计算概率时用freq / totalFrequency得到这个词的先验概率实际计算都在对数空间进行所以minLogProb log(1/totalFrequency)是「词典外单字」的概率下限后面 HMM 和 DP 兜底都要用到它。加载是懒触发的多数版本在WordDictionary.getInstance()时一次性完成。几十万词条同时写进两个数据结构启动占用几百兆内存是常态这个特性在后面避坑章节会重点说。3.2 构建 DAGgetDAG 逐字前缀匹配词典就绪后对一个短句要做的第一件事是画出它的 DAG。核心思路从句子每个位置 i 出发在 Trie 里从根节点开始逐字往下走每走到一个isWordtrue的节点就记下这个位置 j表示「i 到 j 能组成一个词典词」private MapInteger, ListInteger getDAG(String sentence) { MapInteger, ListInteger dag new HashMap(); Node root wordDict.getTrieRoot(); int n sentence.length(); for (int i 0; i n; i) { ListInteger hits new ArrayList(); Node cur root; // 从 i 开始逐字沿着 Trie 向下匹配 for (int j i; j n; j) { cur cur.getChild(sentence.charAt(j)); if (cur null) break; // 前缀断了后面不可能再成词 if (cur.isWord()) hits.add(j); // i..j 是一个合法词典词 } if (hits.isEmpty()) hits.add(i); // 一个词都没命中退化成单字 dag.put(i, hits); } return dag; }getDAG返回的结构是MapInteger, ListIntegerkey 是起始位置value 是所有可能的结束位置。比如「研究生命起源」中位置 0研可能匹配到 1研究也可能匹配到 2研究生如果词典有这个词那dag[0]就是[1, 2]。任何一个位置即使词典全不命中也会有一条指向自己的单字边保证图一定是连通的能走到句子末尾。这一步的复杂度最坏是 O(n × 最大词长)但因为 Trie 的前缀匹配一旦断开就 break实际循环次数远小于 n²。有些版本还会限制最大匹配长度比如超过 8 个字符就不再往下走防止个别超长词典词拖慢速度。3.3 最大概率路径calc 动态规划求 route有了 DAG问题变成「从 0 出发走到 n走哪条路径概率最大」。这里用的对数概率把乘法变成加法避免概率连乘下溢成 0。动态规划从句子末尾开始往前推private MapInteger, PairInteger, Double calc(String sentence, MapInteger, ListInteger dag) { int n sentence.length(); MapInteger, PairInteger, Double route new HashMap(); route.put(n, new Pair(0, 0.0)); // 虚拟终点累计概率为 0 for (int i n - 1; i 0; i--) { double bestProb Double.NEGATIVE_INFINITY; int bestEnd i; for (int j : dag.get(i)) { String word sentence.substring(i, j 1); double prob wordDict.logFreq(word) route.get(j 1).freq; if (prob bestProb) { bestProb prob; bestEnd j; } } route.put(i, new Pair(bestEnd, bestProb)); } return route; }route.get(i)是一个Pairkey 是「位置 i 的最佳词尾」freq 是「从 i 切到句子末尾的累计最大对数概率」。核心转移方程就一行从 i 到 j 切出一个词它的概率等于这个词的对数概率logFreq(word)加上从 j1 到末尾的最佳概率route.get(j1).freq取所有候选 j 里的最大值。wordDict.logFreq(word)内部就是Math.log(freqs.get(word) / totalFrequency)。注意如果word不在词典里freqs.get会返回 null所以实现里通常有containsKey判断或者getOrDefault(word, 1.0)保证单字边也有一个基于minLogProb的保底概率。路线回溯也很简单从route.get(0).key拿到第一段的词尾再从route.get(词尾1).key拿第二段一路走到 n。3.4 未登录词识别sentenceProcess 主循环与 ViterbiDP 算完之后主循环沿最优路径把词一个个吐出来。遇到「i 的最优词尾就是它自己」这种单字节点先不急着输出攒进缓冲区攒到一批连续单字后整批交给 HMM 猜词private void sentenceProcess(String sentence, SegMode mode, ListSegToken tokens) { MapInteger, ListInteger dag getDAG(sentence); MapInteger, PairInteger, Double route calc(sentence, dag); int x 0; ListInteger singleBuf new ArrayList(); // 攒连续单字 while (x sentence.length()) { int y route.get(x).key; if (y x) { singleBuf.add(x); // 词典未命中先缓存 } else { if (!singleBuf.isEmpty()) { // 遇到词典词先处理前面的单字串 emitHmmTokens(singleBuf, sentence, tokens); singleBuf.clear(); } tokens.add(new SegToken( sentence.substring(x, y 1), x, y 1, word)); } x y 1; } if (!singleBuf.isEmpty()) { emitHmmTokens(singleBuf, sentence, tokens); // 句尾剩下的单字串别漏 } if (mode SegMode.SEARCH) { splitLongWords(tokens); // 长度2的词再按词典切细 } }emitHmmTokens从缓冲区里取出连续单字拼成一个字符串调用 Viterbi 算出每个字的状态再按状态把串切成词一个B...E连续段合并成一个词单独的S状态就是单字词。这解释了为什么「他来到了某知名高校的实验室」这类句子能把“知名”这种词典词切对——词典里没有就靠 HMM 猜。Viterbi 的实现核心是四状态 DPpublic ListCharacter viterbi(String sentence) { int n sentence.length(); double[][] dp new double[4][n]; // 0B 1M 2E 3S int[][] back new int[4][n]; // 记录前驱状态回溯用 // 首字符P(状态s) * P(该字符 | 状态s)对数空间用加法 for (int s 0; s 4; s) { dp[s][0] startProb[s] emit(s, sentence.charAt(0)); } for (int t 1; t n; t) { for (int s 0; s 4; s) { double maxVal Double.NEGATIVE_INFINITY; for (int prev 0; prev 4; prev) { double v dp[prev][t - 1] transProb[prev][s]; if (v maxVal) { maxVal v; back[s][t] prev; } } dp[s][t] maxVal emit(s, sentence.charAt(t)); } } // 合法句尾只能是 E词尾或 S单字取概率大的往回回溯 int last dp[2][n - 1] dp[3][n - 1] ? 2 : 3; ListCharacter states new ArrayList(); for (int t n - 1; t 0; t--) { states.add(STATES.charAt(last)); last back[last][t]; } Collections.reverse(states); return states; } private double emit(int state, char c) { double[] probs emitProb.get(c); return probs null ? minLogProb : probs[state]; // 生僻字给下限别抛NPE }startProb和transProb是 HMM 的初始概率和状态转移概率emitProb是发射概率prob_emit.txt加载后就是这张表。整个递推就是在算「当前字符属于状态 s 的最大对数概率 前一字符的最佳状态概率 转移概率 发射概率」。最后强制句尾落在 E 或 S保证状态序列一定合法不会出现 M 开头或者 B 结尾这种非法词形。4. 跑起来Maven 引入、Demo 运行与 SegMode 参数对照源码到手先别急着改词表按部就班把工程跑通再谈二次开发。4.1 从源码工程到本地依赖如果这份资源是完整 Maven 工程第一步打开根目录的pom.xml确认三件事groupId、artifactId、version这三个坐标值以及properties里的编译级别常见移植版一般按 JDK 8 配置。确认后在工程根目录执行mvn clean install -DskipTests这条命令把项目编译、打包并装进本地 Maven 仓库。之后在你自己的服务工程里把 pom 里的坐标原样抄进dependencies就能像用普通依赖一样引用它。如果坐标在中央仓库本来就发布过直接在依赖里写坐标拉取即可如果拉不到本地install是永远有效的后悔药。工程本身可以直接用 IDEA 打开选择根目录的 pom.xml 作为项目文件等 Maven 把依赖拉完src/main/java/demo/下的 Demo 类就能右键运行不需要额外配置。个别版本可能依赖junit之类测试库-DskipTests就是为了跳过这些不必要的环节。4.2 最小可运行 Demo写一个最简单的入口验证分词效果import com.xxx.analysis.jieba.JiebaSegmenter; import com.xxx.analysis.jieba.SegToken; public class Demo { public static void main(String[] args) { JiebaSegmenter segmenter new JiebaSegmenter(); String text 我们研究生命起源的最新进展; System.out.println( INDEX ); for (SegToken t : segmenter.process(text, JiebaSegmenter.SegMode.INDEX)) { System.out.println(t.word [ t.startOffset , t.endOffset )); } System.out.println( SEARCH ); for (SegToken t : segmenter.process(text, JiebaSegmenter.SegMode.SEARCH)) { System.out.println(t.word [ t.startOffset , t.endOffset )); } } }包名com.xxx.analysis.jieba是占位写法以你源码里package声明为准。跑起来会看到类似输出 INDEX 我们 [0, 2) 研究 [2, 4) 生命 [4, 6) 起源 [6, 8) 的 [8, 9) 最新 [9, 11) 进展 [11, 13)SegToken的三个字段很直白word是切出来的词startOffset是词在原始文本里的起始下标endOffset是结束下标左闭右开。你不需要拿着词去原文里再 indexOf 一遍直接用 offset 截取即可这就是为什么切分后做高亮、做实体对齐都方便。4.3 SegMode 参数与业务场景对照两处最容易改的参数都在process()的第二个参数上。SegMode.INDEX和SegMode.SEARCH的选择直接决定输出粒度选型参照第四节那张对照表即可。我一般按这个规则定做搜索召回就 SEARCH做数据清洗和字段抽取就 INDEX。除了模式还有一个常被忽略的预处理点英文数字混排。分词器对连续英文字母和数字的处理能力有限常见做法是在调process()之前先用CharacterUtil.identifyCharType()把文本扫一遍把连续的 LETTER 和 NUM 片段直接整体输出剩下的中文片段才交给分词器。这个预处理能省掉后面很多「产品型号被切碎」的投诉。5. 避坑与排查五个在真实业务里踩过的典型问题以下五条都是实际接项目时遇到过的坑按「现象 → 原因 → 解决」整理每条都对应源码里一个具体位置。5.1 启动慢、内存占用高现象第一次new JiebaSegmenter()卡住好几秒监控里堆内存涨了两三百兆小规格容器直接 OOM。原因WordDictionary是静态单例加载时把几十万条词频同时塞进 Trie 和 HashMap还要逐行解析、累加总词频。这些对象建完就常驻老年代不会被回收。解决给服务至少留 512MB 堆把初始化放在应用启动阶段别等第一个请求进来才触发懒加载。如果业务只用少量词不要全量加载大词典可以自己定制一个小词库文件替换MAIN_DICT路径。5.2 自定义词加了却切不出来现象调用了addWord(某项目代号, 100)结果句子还是被切成单字。原因词频给得太小log(freq / totalFrequency)是很大的负数动态规划比较时赢不过「拆成两个单字」的路径概率。另外要确认addWord的实现是否同步更新了 Trie——有的版本只写了 HashMap没写 Trie等于没加。解决给词频一个压倒性的值比如直接把词频设成词典的totalFrequency这时对数概率接近 0DP 一定会选这条路径。加完词后建议跑一遍包含该词的测试句子确认真的切出来了再继续。5.3 INDEX 和 SEARCH 输出完全一样现象同一句话用两种模式跑结果一字不差怀疑 SEARCH 没实现。原因SEARCH 模式只对长度大于 2 的词做二次切分如果测试句子全是短词、或者整句本来就没有长词典词两种模式自然没有差别。这不是 bug是测试样本选得不好。解决用「自动化研究所」这种长度超过两个字的复合词典词测试。如果对长词仍然切不出细粒度结果检查代码里splitLongWords是否真的被调到了以及它的阈值是不是写死成了别的值。5.4 英文数字混排被切得稀碎现象iPhone15 Pro 被切成 i/Phone/15/Pro索引里搜产品型号完全召回不了。原因词典里没有英文词条HMM 的发射概率表也几乎只针对汉字对字母数字序列的 BMES 状态估计基本靠猜切出来的结果自然稀碎。解决在调process()之前先用CharacterUtil.identifyCharType()识别连续 LETTER/NUM 片段直接整段输出或者把固定型号、品牌名加入自定义词典并用大词频压住让 DP 路径主动选中它。5.5 生僻字触发 NullPointerException现象文本里出现一个词典和模型都不认识的生僻字Viterbi 直接抛空指针。原因emitProb按语料里出现过的字符建索引遇到没见过的字符get(c)返回 null代码如果没做默认值处理求最大值那一步就炸了。解决把发射概率取法改成getOrDefault(c, minLogProb)或者像第 3.4 节写的那样判空后返回下限保证生僻字虽然概率极低但不会中断程序。同样检查startProb和transProb的取数逻辑统一兜底。这条改完建议顺手写进单测防止后续加词典时回归。6. 二次开发把默认分词器改造成业务自己的词表与规则6.1 注册业务词与停用词过滤接入真实业务后第一件事永远是加自定义词。常见的做法是在分词器初始化完成后批量把业务词注册进去WordDictionary dict WordDictionary.getInstance(); // 词频给到 totalFrequencyDP 一定会选中这条路径 dict.addWord(某项目代号, dict.getTotalFrequency()); dict.addWord(另一业务词, dict.getTotalFrequency()); SetString stopWords new HashSet(Arrays.asList(的, 了, 是, 在)); ListSegToken tokens segmenter.process(text, JiebaSegmenter.SegMode.INDEX); tokens.removeIf(t - stopWords.contains(t.word) || t.word.length() 1);注意过滤顺序先process再过滤停用词不要反过来。SegToken里的 offset 是相对原文的过滤后如果你还要做高亮需要保留被过滤 token 的 offset 集合否则高亮位置会错位。6.2 改 HMM 参数与验证方法如果业务领域新词密集默认 BMES 模型效果不理想可以替换prob_emit.txt为领域语料训练出的发射概率表。训练方法不复杂拿一批领域文本用当前分词器切好人工修正后统计每个汉字在 B/M/E/S 四种状态下出现的对数频率重新生成 emit 表即可。start 和 trans 不需要动除非你的语料里大量出现单字词或超长词。改完任何一行代码先用一张黄金测试集验证。我从一个翻车项目里学到的习惯是准备 20 到 50 句覆盖各类情况的样本人工标注正确切分结果存成文件每次改完代码跑一遍自动 diff而不是肉眼抽查。HMM 参数、词频、过滤规则任何一处改动都可能影响全局路径靠眼睛看十句漏三句几乎必然回归。从那以后我每次接分词需求都强制先搭黄金测试集再动手跑不通就回到上一版绝不带着怀疑上线。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Pico一体机Unity工程解析:从交互链路到APK部署的完整指南

Pico一体机Unity工程解析:从交互链路到APK部署的完整指南

简介:面向Pico一体机开发的Unity工程包,基于Unity 5.6.1f1搭建,适合VR开发者、Unity初学者及需要快速上手Pico手柄交互的团队。工程内已按项目开发场景划分好文件夹结构,并写好手柄射线检测方法,使用者只需调用Pvr_Con…

2026/10/19 5:40:26 阅读更多 →
Kiterunner与Postman联动,打造持续运转的API安全测试闭环

Kiterunner与Postman联动,打造持续运转的API安全测试闭环

UI 刚迭代完,某后台系统的接口权限验证又漏了新加的导出接口,这种场景干安全的同行应该都熟。API 安全测试最尴尬的处境不是漏洞多,而是测完一轮之后,下个版本一来,之前的结论全部作废。我自己的解法是:用 …

2026/10/19 5:40:26 阅读更多 →
CSV解析器实战:状态机与流式读取如何解决脏数据与陷阱

CSV解析器实战:状态机与流式读取如何解决脏数据与陷阱

简介:面向C#开发者的CSV解析示例程序包,聚焦CSV(逗号分隔值)文件的读取、字段分割与引号转义处理。源代码使用C#编写,配合Windows窗体演示了解析全过程,适合需要实现数据导入导出、批量处理表格数据的.NET初…

2026/10/19 5:40:26 阅读更多 →

最新新闻

C++类型转换避坑指南:隐式转换与四种强制转换详解

C++类型转换避坑指南:隐式转换与四种强制转换详解

相信每个写过一段时间C的人,都有过被类型转换“坑”到的经历。我印象最深的一次,是在维护一段遗留代码时,看到一个函数传入的是double,内部却拿它当int做数组下标。编译器一声不吭,结果在边界条件下数组越界&#xff0…

2026/10/19 6:17:45 阅读更多 →
英伟达AI开源生态观察:CUDA的技术护城河与迁移路径

英伟达AI开源生态观察:CUDA的技术护城河与迁移路径

从一次装机说起:新来的GPU服务器到手,先装驱动,再装CUDA,然后装PyTorch,跑起来一看nvidia-smi,满屏NVIDIA。再后来同事甩来一个Docker镜像,底层还是NVIDIA。这个路径几乎是今天所有AI开发者的日…

2026/10/19 6:17:45 阅读更多 →
导弹轨道建模实战:从物理分段到MATLAB-Excel-SPSS协同仿真

导弹轨道建模实战:从物理分段到MATLAB-Excel-SPSS协同仿真

简介:本资源为第八届MathorCup高校数学建模挑战赛特等奖优秀论文(编号C3289),聚焦陆基导弹打击航母这一典型军事应用场景,面向数学建模竞赛参赛者、军事运筹与应用数学方向学习者及高校指导教师。论文完整呈现了从静止…

2026/10/19 6:17:45 阅读更多 →
artcraft:数字创作中的手艺性回归与像素级控制力

artcraft:数字创作中的手艺性回归与像素级控制力

1. “Artcraft”不是新词,而是被低估的创作范式重启信号最近在几个设计类社区和开源项目讨论区里,反复看到“artcraft”这个词被零散提起——不是作为品牌名,也不是某个具体工具的代号,而是一种越来越多人在描述自己工作状态时脱口…

2026/10/19 6:17:45 阅读更多 →
Docker部署GitLab与PostgreSQL数据库分离实践:从升级困境到稳定架构

Docker部署GitLab与PostgreSQL数据库分离实践:从升级困境到稳定架构

前阵子在交流群里看到有人吐槽:公司GitLab跑了大半年,版本还停在很老的位置,每次看到新版本发布都不敢升级,因为当年图省事,一条docker run把GitLab全家桶塞进同一个容器里,数据库、代码、配置全混在一起。…

2026/10/19 6:17:45 阅读更多 →
含冰蓄冷空调的冷热电联供微网多时间尺度优化调度

含冰蓄冷空调的冷热电联供微网多时间尺度优化调度

“含冰蓄冷空调的冷热电联供型微网多时间尺度优化调度”这个标题,我第一次接手的时候心里其实挺没底的。因为这几个关键词单拆出来每一个都能单独撑起一篇论文,合在一起又是一个非常典型的“系统级优化”问题。但它真正要解决的事情,落到底层…

2026/10/19 6:16:45 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →