并查集:从动态连通性问题到路径压缩与按秩合并的优化实践
1. 项目概述从“找老大”到高效连通性管理如果你写过一些算法题或者处理过一些需要动态维护元素分组关系的场景大概率会听说过“并查集”这个名字。我第一次接触它是在解决一个“朋友圈”问题的时候题目大意是给定一群人和他们之间的朋友关系朋友的朋友也是朋友要求计算最终有多少个朋友圈。最直观的想法可能是深度优先搜索DFS但当我发现关系是动态添加的需要随时查询两个人在不在同一个朋友圈时DFS每次都要重新遍历效率就太低了。就在那时我遇到了并查集Union-Find它用近乎“魔法”般的常数级时间复杂度解决了这个动态连通性问题。简单来说并查集是一种树形的数据结构专门用来处理一些不相交集合的合并与查询问题。它的核心操作就两个find查和union并。find操作用于查询某个元素属于哪个集合通常用该集合的“代表元”或“根”来标识union操作用于将两个元素所在的集合合并成一个。很多资料会把它比喻成“找老大”的游戏每个集合有一个“老大”根节点find就是一路向上找到自己的老大是谁union就是把两个集合的老大变成同一个人或者让一个老大认另一个老大做老大。并查集的应用场景远不止算法竞赛。在计算机网络中它可以用来管理动态连接的主机集群在图形学中用于图像分割和像素连通区域标记在社交网络中实时计算社群关系甚至在一些编译器和数据库系统中用于管理变量的等价类。它的思想极其简洁但实现上的两个关键优化——“路径压缩”和“按秩合并”——却能让其性能产生质的飞跃达到近乎常数时间的操作效率。理解并查集不仅是掌握了一个数据结构更是学习了一种用简单组件构建高效系统的思维模式。2. 核心原理与数据结构设计拆解2.1 如何用数组表示一棵“树”并查集最精妙的地方在于它通常用一个一维数组就能表示整个森林多棵树。我们不会真的去构造一个带有指针的树节点结构体。假设我们有 n 个元素编号从 0 到 n-1。我们初始化一个长度为 n 的数组parent其中parent[i]存储的是元素 i 的“父节点”。如果parent[i] i那恭喜你找到了“根”也就是这个集合的老大。初始状态下每个元素自成一派各自为根所以parent[i] i。这个数组就是我们的全部家当。合并与查找的所有操作都围绕着更新和查询这个parent数组展开。为什么用数组数组的随机访问时间复杂度是 O(1)这对于需要频繁进行find操作的数据结构至关重要。虽然我们逻辑上在操作一棵树但物理存储是平坦的数组通过数组下标元素ID到值父节点ID的映射来体现树形的父子关系。这种设计在内存访问效率和缓存友好性上都有巨大优势。2.2 两大核心操作Find与Union的朴素实现我们先看看最直接、不加任何优化的实现理解基本逻辑。Find查找给定一个元素 x找到它所在集合的根代表元。def find_naive(x, parent): while parent[x] ! x: # 如果自己不是根 x parent[x] # 就向上找自己的父亲 return x这个过程就是沿着父指针不断向上爬直到找到那个父节点是自己的节点根节点。在初始状态下这很快但随着合并操作树可能会变得越来越高甚至退化成一条链。这时find操作的时间复杂度就会退化到 O(n)。Union合并给定两个元素 x 和 y将它们所在的集合合并。def union_naive(x, y, parent): root_x find_naive(x, parent) root_y find_naive(y, parent) if root_x ! root_y: # 如果根不同说明不在同一个集合 parent[root_x] root_y # 让其中一个根指向另一个根合并操作的核心是先找到各自的根如果根不同就让其中一个根认另一个根做父亲。这里有一个关键选择让谁认谁做父亲朴素实现随意选择比如总是让root_x认root_y做父亲。这个随意的选择正是导致树可能退化成链的元凶。想象一下如果总是将较高的树合并到较矮的树下或者反过来没有策略最终树高就无法控制。注意这里的“合并”只是改变了根节点的父指针原来集合中的所有其他元素的父指针并没有直接改变。它们仍然指向自己原来的根只不过现在它们的根有了一个新的父亲。这正是后续find操作可以进行“路径压缩”优化的基础。3. 性能飞跃的关键路径压缩与按秩合并如果只有朴素实现并查集的价值会大打折扣。正是下面这两个优化让它成为了一个高效得令人惊叹的数据结构。3.1 路径压缩让每个人都直接认识“老大”路径压缩Path Compression是在find操作中进行的优化。它的思想非常简单粗暴既然我辛辛苦苦爬到了根节点为什么不顺便把沿途所有人的“父亲”都直接改成根呢这样下次他们或他们的子孙再找根时一步就能到位。递归实现清晰直观def find_path_compression(x, parent): if parent[x] ! x: # 递归找到根并将当前节点的父节点直接设为根 parent[x] find_path_compression(parent[x], parent) return parent[x]这个递归调用会一直深入到根节点然后在回溯的过程中将路径上每个节点的parent直接指向根。例如路径 A - B - C - Root在一次find(A)之后会变成 A - Root, B - Root, C - Root。迭代实现常用避免递归栈溢出def find_path_compression_iter(x, parent): root x # 第一遍循环找到根节点 while parent[root] ! root: root parent[root] # 第二遍循环进行路径压缩 while parent[x] ! root: next_node parent[x] parent[x] root x next_node return root迭代法分两步第一步先找到根root第二步再从原节点x开始向上走把路径上所有节点的父节点都设置为root。路径压缩的效果 经过路径压缩后树的平均高度会变得非常小。理论上在经过一系列随机操作后find的摊还时间复杂度是O(α(n))其中 α(n) 是阿克曼函数的反函数这是一个增长极其缓慢的函数对于任何在宇宙可观测范围内的 nα(n) 都不会超过 5。因此我们可以认为find操作是常数时间的。3.2 按秩合并永远让“矮树”并入“高树”路径压缩主要优化了find而按秩合并Union by Rank则是在union时优化旨在避免树的不平衡增长。这里的“秩”Rank可以粗略理解为树的高度的一个上界。我们需要一个额外的数组rank初始时每个元素的秩为0或1表示只有自己。 合并时我们比较两棵树的根节点的秩如果rank[root_x] rank[root_y]就让root_y认root_x做父亲。这样合并后高树root_x的高度不变。如果rank[root_x] rank[root_y]就让root_x认root_y做父亲。如果rank[root_x] rank[root_y]则任意选择一方作为父亲并将作为父亲的根的秩加1。因为两棵高度相同的树合并新树的高度会增加1。def union_by_rank(x, y, parent, rank): root_x find(x, parent) # 这里的find是带路径压缩的 root_y find(y, parent) if root_x root_y: return # 按秩合并 if rank[root_x] rank[root_y]: parent[root_x] root_y elif rank[root_x] rank[root_y]: parent[root_y] root_x else: # 秩相等任意合并但父节点秩需加1 parent[root_y] root_x rank[root_x] 1为什么按秩合并有效它保证了树的生长是受控的。只有秩相等的两棵树合并时整体高度才会增加。这极大地延缓了树高度的增长。结合路径压缩树的高度几乎一直被压制在非常低的水平。实操心得在实际编码中特别是算法竞赛中“秩”数组有时会被简化为“大小”数组按集合元素个数合并逻辑类似都是避免随意合并导致的不平衡。但按秩合并基于高度在理论分析上更优美。如果同时使用路径压缩按秩合并中的“秩”已经不能准确代表高度而更像是一个历史高度的“估计值”或“优先级”但这并不影响算法的正确性和高效性。4. 完整实现与代码剖析将路径压缩和按秩合并结合起来我们就得到了一个工业级强度的并查集实现。下面是一个用Python编写的经典模板它包含了初始化、查找带路径压缩、合并按秩合并以及一个常用的查询连通性的方法。class UnionFind: def __init__(self, n): 初始化并查集。 :param n: 元素个数编号从 0 到 n-1 self.parent list(range(n)) # 初始时每个元素的父亲是自己 self.rank [0] * n # 初始秩为0 self.count n # 初始集合数量为n def find(self, x): 查找元素x的根同时进行路径压缩。 :param x: 元素索引 :return: 元素x所在集合的根 # 路径压缩迭代版 while self.parent[x] ! x: # 此处可进行“隔代压缩”是一种更激进的优化 # 让x直接指向其祖父节点加速收敛 self.parent[x] self.parent[self.parent[x]] x self.parent[x] return x # 递归版路径压缩代码更简洁但可能有栈溢出风险 # if self.parent[x] ! x: # self.parent[x] self.find(self.parent[x]) # return self.parent[x] def union(self, x, y): 合并元素x和y所在的集合。 :param x: 元素索引 :param y: 元素索引 :return: 如果x和y原本就在同一集合返回False否则合并并返回True root_x self.find(x) root_y self.find(y) if root_x root_y: return False # 已在同一集合无需合并 # 按秩合并 if self.rank[root_x] self.rank[root_y]: self.parent[root_x] root_y elif self.rank[root_x] self.rank[root_y]: self.parent[root_y] root_x else: # 秩相等任意合并父节点秩加1 self.parent[root_y] root_x self.rank[root_x] 1 self.count - 1 # 集合数量减少1 return True def connected(self, x, y): 判断元素x和y是否连通属于同一集合。 :param x: 元素索引 :param y: 元素索引 :return: 布尔值 return self.find(x) self.find(y) def get_count(self): 获取当前不相交集合的数量。 :return: 集合数量 return self.count代码关键点解析__init__初始化是O(n)操作。parent数组自指rank数组清零。find中的“隔代压缩”代码中self.parent[x] self.parent[self.parent[x]]这一行是迭代法路径压缩的一个小技巧。它让节点在向上查找时跳一级指向其祖父节点这比标准的迭代压缩需要两遍循环在单次操作中压缩得更快虽然可能不是一次压缩到根但在多次操作后效果同样显著。union的返回值设计为返回布尔值非常实用。在很多场景下如Kruskal算法我们只关心这次合并是否真正执行了即两个元素原本是否不在同一集合。count变量维护当前集合的数量在解决“连通分量计数”类问题时无需再次遍历O(1)时间即可获得是一个有用的优化。5. 实战应用场景与例题精讲理解了原理和实现我们来看几个典型应用感受一下并查集如何化繁为简。5.1 场景一动态连通性问题LeetCode 547. 省份数量问题描述有 n 个城市其中一些彼此相连另一些没有相连。如果城市 a 与城市 b 直接相连且城市 b 与城市 c 直接相连那么城市 a 与城市 c 间接相连。省份是一组直接或间接相连的城市。给你一个 n x n 的矩阵 isConnected其中isConnected[i][j] 1表示第 i 个城市和第 j 个城市直接相连否则为 0。返回矩阵中省份的数量。并查集解法思路初始化一个大小为 n 的并查集每个城市自成一个省份。遍历矩阵的上三角或下三角避免重复当isConnected[i][j] 1时说明城市 i 和 j 相连执行union(i, j)。遍历结束后并查集中集合的数量get_count()就是省份的数量。def findCircleNum(isConnected): n len(isConnected) uf UnionFind(n) for i in range(n): # 只需遍历 j i 的部分因为矩阵是对称的 for j in range(i 1, n): if isConnected[i][j] 1: uf.union(i, j) return uf.get_count()为什么有效并查集完美地模拟了“连通”关系的传递性。每次合并操作都将直接相连的城市归入同一集合。间接相连的城市通过传递性也会在多次合并后归于同一集合。最终一个集合就代表一个连通图省份。5.2 场景二检测图中是否有环用于图论算法问题描述给定一个无向图判断图中是否存在环。并查集解法思路初始化并查集每个顶点是一个独立集合。遍历图中的每一条边 (u, v)如果find(u) find(v)说明 u 和 v 在遍历这条边之前就已经连通了。那么加上这条边必然形成环。否则执行union(u, v)。如果遍历完所有边都没有发现上述情况则图中无环。这个方法是 Kruskal 最小生成树算法的基础。Kruskal 算法贪心地选取最短边但如果该边的两个端点已经连通属于同一集合加入它就会形成环因此必须跳过。5.3 场景三处理“等式方程”的满足性LeetCode 990. 等式方程的可满足性问题描述给定一个由字符串数组组成的方程每个方程equations[i]长度为 4形式为“ab”或“a!b”。a和b是小写字母。如果所有方程可以同时被满足返回true否则返回false。并查集解法思路 这是一个经典的并查集应用用于处理等价关系和不等关系!。由于变量是26个小写字母我们初始化一个大小为26的并查集。第一遍遍历所有等式遇到“ab”就将a和b合并到同一集合。这建立了所有变量的等价关系。第二遍遍历所有不等式遇到“a!b”就检查a和b的根。如果find(a) find(b)说明根据之前的等式推导a和b必须相等但这与当前的不等式矛盾直接返回false。如果所有不等式检查都通过则返回true。def equationsPossible(equations): uf UnionFind(26) # 对应26个字母 base ord(a) # 处理所有等式建立连通关系 for eq in equations: if eq[1] : x ord(eq[0]) - base y ord(eq[3]) - base uf.union(x, y) # 处理所有不等式检查矛盾 for eq in equations: if eq[1] !: x ord(eq[0]) - base y ord(eq[3]) - base if uf.find(x) uf.find(y): return False return True这个例子展示了并查集如何维护“等价类”并能高效地查询两个元素是否等价。6. 高级变种与常见问题排查6.1 带权并查集维护相对关系标准的并查集只能知道元素是否属于同一集合。带权并查集则在边上附加权值可以维护集合内元素之间的某种相对关系比如距离、差值等。典型问题食物链POJ 1182动物分为A、B、C三类A吃BB吃CC吃A。给出两种陈述1) X和Y是同类2) X吃Y。判断陈述的真假与之前已确定的正确陈述矛盾则为假。解法核心 我们不仅需要知道两个动物是否关联还需要知道它们之间的具体关系同类、捕食、被捕食。可以用一个额外的weight数组weight[x]表示节点 x 到其父节点parent[x]的“权值”或“关系偏移量”。在路径压缩和合并时需要同时更新这个权值。定义关系0表示同类1表示x吃父节点2表示x被父节点吃可根据循环关系模3运算。find时在递归压缩路径后需要根据原父节点与根的关系更新当前节点与根的关系。union时根据给定的x和y的关系推导出它们的根节点之间的关系并进行合并和权值计算。这比标准并查集复杂需要仔细推导关系传递的公式。它展示了并查集如何从一个简单的连通性检查工具升级为一个可以维护群内元素间复杂关系的强大数据结构。6.2 常见问题与调试技巧初始化错误最常见的错误是忘记初始化parent[i] i和rank[i] 0。这会导致find函数陷入死循环或得到错误结果。务必在构造函数中显式初始化。在union中错误使用未压缩的find在union方法内部必须使用带路径压缩的find来获取根节点。如果错误地使用了朴素查找虽然逻辑正确但会失去优化效果性能下降。确保你的union调用的是self.find(x)而不是直接访问self.parent[x]。“按秩合并”时只更新父指针忘记更新秩在两棵树秩相等的情况下合并后必须将新根的秩加1。这是控制树高的关键步骤漏掉会导致优化失效。# 正确 if rank[root_x] rank[root_y]: parent[root_y] root_x rank[root_x] 1 # 这行不能丢误用“按大小合并”与“按秩合并”两者都是优化手段通常选其一即可。如果选择“按大小合并”维护一个size数组总是让小树合并到大树在路径压缩后“大小”信息是准确的而“秩”只是高度的上界。在需要知道集合大小的场景如求最大连通分量大小“按大小合并”更方便。处理特殊索引如果元素编号不是从0开始的连续整数需要建立一个从元素到数组索引的映射通常用字典。例如处理字符串或离散的ID时。判断“合并是否有效”的逻辑在像Kruskal这样的算法中我们常需要判断一条边是否应该被加入即合并两个端点是否不会形成环。标准的写法是if uf.find(u) ! uf.find(v): # 加入这条边 uf.union(u, v) # ... 其他处理注意这里先find判断再union。union方法内部已经包含了find判断所以直接调用if uf.union(u, v):利用其返回值也是等价的且更简洁。性能测试对于超大规模数据例如元素数量超过10^5务必使用带路径压缩和按秩合并的优化版本。可以自己构造一个最坏情况的数据例如将节点逐一链接成链进行测试对比优化前后的运行时间感受性能差异。并查集是一个“思想简单细节微妙”的数据结构。第一次实现时建议严格按照模板来写并多通过具体的题目进行练习。一旦掌握你会发现它是解决一大类连通性、等价性问题的利器代码短小精悍效率却出奇地高。

相关新闻

JavaMail/Jakarta Mail企业级邮件处理实战:从协议原理到生产环境最佳实践

JavaMail/Jakarta Mail企业级邮件处理实战:从协议原理到生产环境最佳实践

1. 项目概述:为什么JavaMail依然是企业级邮件处理的基石在当今这个即时通讯满天飞的时代,电子邮件作为一项古老而稳定的协议,依然是企业内外正式沟通、系统通知、用户注册验证的绝对主力。你可能觉得发邮件很简单,不就是点个“发送…

2026/8/18 22:55:51 阅读更多 →
代码评审:从团队协作到质量保障的工程实践

代码评审:从团队协作到质量保障的工程实践

1. 从“个人英雄”到“团队工程”:为什么我们需要代码评审 在软件开发的早期,一个天才程序员单枪匹马写出改变世界的代码,是很多人的浪漫想象。但现实是,现代软件系统早已不是个人作品,而是由数十、数百甚至上千名工程…

2026/8/18 22:55:51 阅读更多 →
Axure原型设计入门:从核心认知到高效实践指南

Axure原型设计入门:从核心认知到高效实践指南

1. 从“画图工具”到“产品思维”:我理解的Axure是什么 如果你刚接触产品设计或者交互设计,大概率会听到一个名字:Axure。很多新手的第一反应是:“哦,那个画原型的工具。” 这个理解对,但也不全对。在我用了…

2026/8/18 22:54:51 阅读更多 →

最新新闻

Spring Boot集成Apache Dubbo 3.x:构建高效微服务通信与治理架构

Spring Boot集成Apache Dubbo 3.x:构建高效微服务通信与治理架构

1. 项目背景与核心价值 如果你正在构建一个微服务架构,或者想把一个单体应用拆分成多个独立部署的服务,那么服务间的通信就是你绕不开的核心问题。过去我们可能用HTTP API,简单直接,但在高并发、服务治理、链路追踪这些复杂场景下…

2026/8/18 23:23:10 阅读更多 →
基于Ollama与Milvus的Java版RAG知识库搭建指南

基于Ollama与Milvus的Java版RAG知识库搭建指南

1. 项目概述 最近在本地搭建了一个基于Ollama和Milvus的RAG知识库助手,整个过程踩了不少坑,也积累了一些经验。这个方案特别适合需要私有化部署的企业或个人开发者,既能保证数据安全,又能利用大语言模型的能力。下面我就把完整的搭…

2026/8/18 23:23:10 阅读更多 →
Blender 3MF 插件免费安装全指南:如何把模型的颜色、尺寸与打印参数完整送进切片软件

Blender 3MF 插件免费安装全指南:如何把模型的颜色、尺寸与打印参数完整送进切片软件

Blender 3MF 插件免费安装全指南:如何把模型的颜色、尺寸与打印参数完整送进切片软件 【免费下载链接】Blender3mfFormat Blender add-on to import/export 3MF files 项目地址: https://gitcode.com/gh_mirrors/bl/Blender3mfFormat 在 Blender 里花一下午调…

2026/8/18 23:23:10 阅读更多 →
Cookie全流程实战:从编码原理到安全实践,解决中文乱码与跨域传递

Cookie全流程实战:从编码原理到安全实践,解决中文乱码与跨域传递

1. 项目概述:从“Cookie中文”说起,一个被误解的实战话题 最近在和一些刚入行的朋友交流时,发现一个挺有意思的现象:很多人一看到“Cookie的发送、获取、Cookie传递中文”这个标题,第一反应是去研究Cookie里怎么存中文…

2026/8/18 23:23:10 阅读更多 →
Altium Designer快捷键全解析:从原理图到PCB的高效设计指南

Altium Designer快捷键全解析:从原理图到PCB的高效设计指南

1. 项目概述:为什么AD软件的快捷键值得你花时间掌握? 如果你是一名电子工程师,或者正在学习PCB设计,那么Altium Designer(简称AD)这款软件对你来说一定不陌生。它功能强大,但界面也相对复杂。很…

2026/8/18 23:23:10 阅读更多 →
深入解析PCI-E接口:从核心架构到实战调优的完整指南

深入解析PCI-E接口:从核心架构到实战调优的完整指南

1. 项目概述:从“插槽”到“高速公路”的认知升级 如果你拆开过近十年的台式机或者服务器,在主板上除了CPU插槽和内存条插槽,最显眼的就是那些长短不一的扩展插槽了。其中最长的、尾部带有一个卡扣的,大概率就是PCI-E插槽。很多朋…

2026/8/18 23:22:09 阅读更多 →

日新闻

告别逐帧截图:用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF

告别逐帧截图:用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF

告别逐帧截图:用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF 【免费下载链接】extract-video-ppt extract the ppt in the video 项目地址: https://gitcode.com/gh_mirrors/ex/extract-video-ppt 如果你还停留在"看网课 不停暂停 截图 …

2026/8/18 0:00:57 阅读更多 →
思源宋体TTF一站式上手:7个字重免费商用,从下载到上线的完整走查

思源宋体TTF一站式上手:7个字重免费商用,从下载到上线的完整走查

思源宋体TTF一站式上手:7个字重免费商用,从下载到上线的完整走查 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 你是不是也经历过这种时刻:设计稿里…

2026/8/18 0:00:58 阅读更多 →
华硕笔记本控制权回收指南:GHelper 如何用一个 10MB 文件替代 Armoury Crate

华硕笔记本控制权回收指南:GHelper 如何用一个 10MB 文件替代 Armoury Crate

华硕笔记本控制权回收指南:GHelper 如何用一个 10MB 文件替代 Armoury Crate 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, …

2026/8/18 0:00:59 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/18 9:15:35 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/18 9:06:28 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/18 9:04:56 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/17 18:54:37 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/17 18:55:16 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/17 18:55:55 阅读更多 →