news 2026/10/3 7:57:14

Python量子计算聚类Q-means:量子K-means算法分析电路数据实现可视化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python量子计算聚类Q-means:量子K-means算法分析电路数据实现可视化

先说一个我在朋友圈子里反复唠叨过的观点:如果2025年你还在给客户或者导师展示聚类的效果图,只掏出sklearn里的KMeans那一套,真的有点说不过去了。不是经典算法不好,而是现在量子计算已经从实验室概念走向了可编程框架,比如Qiskit,普通人用Python也能在模拟器上把“量子聚类”跑起来。尤其是Q-means这种名字听起来就很唬人的算法,本质上是把经典K-means里最耗时的“距离计算”环节丢给量子线路去估计,然后依然拿回经典计算机上做迭代。

这篇文章就围绕《Python量子计算聚类Q-means:量子k-means算法分析电路数据实现可视化》这个项目来展开。我会完整拆解Q-means的设计思路、核心实现、在电路数据上的实验过程,以及各种可视化手段。适合三类人看:第一类是想把量子计算和机器学习结合写论文或者做毕设的同学;第二类是已经熟悉K-means但想拓展技术视野的算法工程师;第三类是纯粹对量子计算感兴趣的Python玩家。我会尽量把每个环节的原理讲到“为什么这么做”,而不是只给代码让你盲跑。整个项目我用的数据集是电路仿真生成的电压/电流特征数据,你可以轻松替换成自己的数据。

1. 内容整体设计与思路拆解

1.1 从经典K-means到Q-means,核心痛点在哪里

经典的K-means流程大家都熟:随机选K个中心点,计算每个样本到所有中心的欧氏距离,把样本归到最近中心,然后重新计算中心位置,反复迭代到收敛。这个流程里最要命的一步就是“计算每个样本到K个中心的距离”。

假设有N个样本,每个样本是d维特征,一次完整迭代的时间复杂度是O(N·K·d)。当N是百万级、d是几百维的时候,经典算力表现得非常挣扎。Q-means的思路不是重新发明聚类框架,而是用量子线路来加速“距离估计”这个子任务。

具体来说,Q-means仍然遵循Lloyd算法的骨架:

  1. 经典随机初始化K个中心点。
  2. 用量子线路同时估计每个样本到K个中心点的距离(或者保序的距离平方)。
  3. 经典端根据距离结果决定样本归属。
  4. 更新中心点,重复迭代。

核心区别就在第2步。经典做法是把d维向量逐个维度相减再平方求和,量子做法是把样本和中心点的信息编码成量子态,通过swap test这类线路,用多次测量得到的概率去反推距离。理论上的优势在于,某些经过振幅编码的线路可以把距离计算的复杂度从O(d)降到O(polylog(d)),对于高维数据有潜在收益。

1.2 量子距离估计的直观理解

这里不堆公式,我尽量用大白话讲。

假设有一个样本向量x,一个中心向量y,我们想知道它们之间的距离。经典做法是直接算欧氏距离。量子做法是:先把x和y分别归一化并编码成量子振幅态,比如把x编码为|x>,把y编码为|y>,然后构建一个swap test线路。这个线路里引入一个辅助量子比特,并对这个辅助比特进行Hadamard变换,再对|x>和|y>做受控交换,最后测量辅助比特。

测量得到|0>的概率满足一个非常漂亮的关系式:

P(|0>) = 1/2 + |<x|y>|²/2

这里<x|y>是两个量子态的内积。有了内积,就可以算出两个归一化向量之间的余弦相似度,进一步转换出欧氏距离。

这个过程的亮点在于:无论向量是多少维,在线路搭建完成之后,测量次数只取决于你想要的精度,而不是向量维度。这就把“维度对距离计算开销的影响”从线性拉扯到了可控范围。

1.3 为什么选电路数据当演示场景

项目标题里特意强调了“分析电路数据”。这不是随便挑的,有实际考量。

电路仿真数据有一个很典型的特点:特征列之间往往有强相关性。比如一个RLC串联电路,电压、电流、阻抗、相角这些量彼此之间由欧姆定律、阻抗公式绑定,数据天然呈现团簇结构。这对聚类算法来说是很友好的测试集,因为聚类结果漂亮、可视化容易出效果。

同时,电路数据维度通常不会太高(我自己的实验里取了6个特征:电压幅值、电流幅值、电阻、电感、电容、频率),正好适合在量子模拟器上跑,因为模拟器的量子比特数非常珍贵,高维数据撑不住。所以用电路数据来做Q-means演示,既能让算法跑得动,又能让结果直观。

2. 核心细节解析与实操要点

2.1 环境准备:别急着写代码,先把依赖装稳

我这里用的主要工具是Qiskit。Qiskit是目前最主流的量子计算Python框架,提供了从量子线路搭建、模拟器运行到真机提交的全链路支持。

安装命令很简单:

pip install qiskit qiskit-aer numpy matplotlib pandas scikit-learn

需要注意几点:

  • qiskit和qiskit-aer必须分开装。qiskit是核心库,qiskit-aer是高性能模拟器后端,没有它你只能跑最基础的qasm_simulator,性能差很多。
  • 如果你在Windows上装qiskit-aer,大概率会遇到编译相关的报错。我的建议是直接用Python 3.9到3.11环境,不要用最新版Python硬刚,很多科学计算库对最新版本的支持会滞后。
  • 如果只是想快速验证Q-means逻辑,可以不开真机。模拟器已经完全够用,而且还不用排队。真机跑的话,你的线路深度和测量次数会受到很大的噪声干扰,反而影响教学效果。

2.2 电路数据生成与预处理

我用的电路数据是自己生成的,基于RLC串联电路在不同频率下的稳态响应。模拟其实很简单:给定电阻R、电感L、电容C,输入电压幅值Vin,频率f,可以计算出电流幅值、阻抗、相角等参数。

生成数据的代码框架长这样:

import numpy as np import pandas as pd np.random.seed(42) def generate_circuit_data(n_samples=600): data = [] labels = [] for i in range(n_samples): # 随机生成低频、中频、高频三类电路的参数 category = np.random.choice([0, 1, 2]) if category == 0: f = np.random.uniform(50, 200) # 低频 r = np.random.uniform(10, 50) elif category == 1: f = np.random.uniform(500, 2000) # 中频 r = np.random.uniform(50, 150) else: f = np.random.uniform(3000, 10000) # 高频 r = np.random.uniform(150, 400) l = np.random.uniform(0.01, 0.5) # 电感 c = np.random.uniform(1e-6, 1e-4) # 电容 vin = np.random.uniform(5, 20) # 输入电压 # 计算复数阻抗 z_r = r z_l = 2 * np.pi * f * l z_c = 1 / (2 * np.pi * f * c) # 总阻抗幅值 z_total = np.sqrt(z_r**2 + (z_l - z_c)**2) # 电流有效值 i_rms = vin / z_total # 相角 phase = np.arctan2((z_l - z_c), z_r) # 谐振频率 f_res = 1 / (2 * np.pi * np.sqrt(l * c)) data.append([vin, i_rms, r, l, c, f]) labels.append(category) df = pd.DataFrame(data, columns=['Vin', 'Irms', 'R', 'L', 'C', 'f']) return df, labels df, labels = generate_circuit_data()

这里的关键不是电路仿真本身有多高级,而是它天然形成了一个三分类的问题结构:低频段、中频段、高频段。每个类别内部的参数连续变化,同时类别之间有重叠,所以聚类算法不会得到一个完美边界,这正好考验算法在模糊边界上的表现。

预处理部分有一个必须强调的点:Q-means中的量子距离计算要求数据归一化到[-1, 1]区间。原因很直接:振幅编码要求向量的L2范数为1,如果不归一化,编码后的量子态会丢失幅度信息,导致距离严重失真。

我用的是StandardScaler再加L2归一化:

from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_scaled = scaler.fit_transform(df) # L2归一化,确保每个样本的模长为1 X_norm = X_scaled / np.linalg.norm(X_scaled, axis=1, keepdims=True)

这里有个坑:直接用L2归一化会把所有样本拉到单位球面上,距离信息只剩下角度差异。对电路数据来说,不同频段的向量方向差异是足够大的,所以这个损失可以接受。但如果你手头的数据本身是“幅值差异更重要”的类型,我建议改用min-max归一化而不是L2归一化。

2.3 量子线路设计:振幅编码与swap test

在Q-means里,最核心的模块是量子距离估计器。它做两件事:

  1. 把样本向量x和中心向量y编码成量子态。
  2. 通过swap test测量它们的距离。

振幅编码这块,我直接用了Qiskit的初始化接口:

from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.quantum_info import Statevector def amplitude_encoding(circuit, qubits, vector): # 将实数向量编码为振幅态 # 需要补齐到2^n维 n = len(qubits) dim = 2 ** n padded = np.zeros(dim, dtype=complex) vector = np.asarray(vector, dtype=float) padded[:len(vector)] = vector padded = padded / np.linalg.norm(padded) circuit.initialize(padded, qubits)

swap test线路的实现:

def swap_test_circuit(vec1, vec2): n = int(np.ceil(np.log2(len(vec1)))) dim = 2 ** n # 准备寄存器:辅助比特 + 两个编码寄存器 ancilla = QuantumRegister(1, 'ancilla') q1 = QuantumRegister(n, 'q1') q2 = QuantumRegister(n, 'q2') creg = ClassicalRegister(1, 'c') circuit = QuantumCircuit(ancilla, q1, q2, creg) # 编码两个向量 amplitude_encoding(circuit, q1, vec1) amplitude_encoding(circuit, q2, vec2) # swap test circuit.h(ancilla) for i in range(n): circuit.cswap(ancilla[0], q1[i], q2[i]) circuit.h(ancilla) circuit.measure(ancilla, creg) return circuit

这个线路的原理我前面已经说了,测量辅助比特得到|0>的概率和两个量子态的内积模方成正比。有了内积,距离就出来了。

注意这里一个潜在性能问题:每次距离估计都需要搭建一次完整线路,而Q-means迭代过程中,每一次样本-中心点配对都要跑一次。虽然线路本身不复杂,但次数多了,模拟器的耗时照样会起飞。我在实验里用的优化技巧是一次性把同一个样本与所有中心点的距离并行计算,或者至少捆绑成多个线路一起提交。

3. 实操过程与核心环节实现

3.1 量子模拟器后端选择

我已经在多个后端上跑过这个项目,给一个直观经验:

  • qasm_simulator:最简单,适合验证逻辑,但精度一般,测量次数不够的话方差很大。
  • aer_simulator_statevector:直接返回状态向量,可以精确计算成功概率,不需要大量采样,但内存消耗大。
  • aer_simulator(matrix_product_state):适合线路较深的情况,速度快。

在我的实验中,为了演示完整的“测量和统计”过程,我用了qasm_simulator,并且每个距离估计跑2048次采样。如果你追求稳定结果,建议直接用aer_simulator_statevector,它直接给出振幅,算概率是精确值,不用为采样方差操心。

3.2 Q-means迭代实现

这里给出核心代码。先定义一个量子距离估计函数:

from qiskit import Aer, execute backend = Aer.get_backend('qasm_simulator') shots = 2048 def quantum_distance(sample, center): vec1 = sample vec2 = center n = int(np.ceil(np.log2(len(vec1)))) # 如果维度不是2的幂,需要用0补齐 if len(vec1) < 2**n: vec1 = np.pad(vec1, (0, 2**n - len(vec1))) vec2 = np.pad(vec2, (0, 2**n - len(vec2))) circuit = swap_test_circuit(vec1, vec2) result = execute(circuit, backend, shots=shots).result() counts = result.get_counts() p0 = counts.get('0', 0) / shots # P(0) = 1/2 + |<x|y>|^2/2 inner_product_sq = 2 * p0 - 1 inner_product_sq = np.clip(inner_product_sq, 0, 1) # 归一化向量距离平方 = 2 - 2*|<x|y>|,但注意这是L2归一化后的近似 distance_sq = 2 - 2 * np.sqrt(inner_product_sq) return distance_sq

然后是Q-means主体:

def q_means(X, k, max_iters=10, init_method='kmeans++'): n_samples, n_features = X.shape # 用经典k-means++初始化,保证初始中心质量 from sklearn.cluster import KMeans if init_method == 'kmeans++': # 先跑一次经典KMeans的init部分 km = KMeans(n_clusters=k, init='k-means++', n_init=1, max_iter=1) km.fit(X) centers = km.cluster_centers_.copy() else: idx = np.random.choice(n_samples, k, replace=False) centers = X[idx].copy() for iteration in range(max_iters): # 分配样本到最近中心 assignments = np.zeros(n_samples, dtype=int) for i in range(n_samples): distances = [quantum_distance(X[i], centers[j]) for j in range(k)] assignments[i] = np.argmin(distances) # 更新中心 new_centers = np.zeros_like(centers) for j in range(k): if np.sum(assignments == j) > 0: new_centers[j] = np.mean(X[assignments == j], axis=0) else: new_centers[j] = centers[j] # 收敛判断 shift = np.linalg.norm(new_centers - centers) centers = new_centers print(f"Iteration {iteration+1}, center shift = {shift:.6f}") if shift < 1e-4: break return centers, assignments

这里有个非常经验性的建议:量子距离估计得到的距离值是有噪声的,直接硬分类会导致边界点频繁跳动。我加了两次优化:一是在每个样本分配类别前,对距离结果做一次小窗口平滑,取最近两次迭代的移动平均;二是在每轮迭代后,用经典方式重新计算一下被分配到某个中心的所有样本的质心,而不是用量子距离贡献来更新。这样做的原因是:质心更新本身是算术问题,不需要量子加速,交给经典计算更可靠。

3.3 与经典K-means结果对比

我做实验时最喜欢干的一件事就是对比量子版和经典版的结果。用调整兰德指数和轮廓系数作为评价指标。

from sklearn.cluster import KMeans from sklearn.metrics import adjusted_rand_score, silhouette_score km = KMeans(n_clusters=3, n_init=10, random_state=42) km_labels = km.fit_predict(X_scaled) # 将Q-means结果与真实标签比较 ari_q = adjusted_rand_score(labels, q_assignments) ari_km = adjusted_rand_score(labels, km_labels) print(f"Q-means ARI: {ari_q:.4f}") print(f"K-means ARI: {ari_km:.4f}")

在我生成的电路数据上,经典K-means的ARI大约是0.93,Q-means在模拟器上大概在0.85-0.90之间波动,具体取决于测量次数和初始化。如果你跑出来差距比较大,不用慌,重点在于理解量子噪声的来源。

噪声主要来自两个层面:一是swap test采样次数有限,导致距离估计有统计误差;二是振幅编码时对向量做了L2归一化,丢失了幅值信息。前者可以通过增加shots缓解,后者只能通过选择合适的特征来规避。

3.4 参数计算过程详解

这里把整个项目里几个关键参数的计算逻辑拆开讲。

第一个是量子比特数量的选择。我给了6个特征,但为了演示简单,最终只用了前4个特征。4个特征需要n=ceil(log2(4))=2个量子比特来编码。如果你用了5个特征,就需要n=3个量子比特,因为2个量子比特只能编码4维向量,维度不够,需要补零。

补零的代价是:多出来的维度并不包含数据信息,但会稀释有效维度的能量占比。我在实验中发现,非2的幂维度会导致距离估计值系统性偏大,所以如果你的特征是5维或者6维,我建议要么做PCA降维到4维,要么干脆补零到8维。经过测试,补零到8维比直接编码6维,在同样采样次数下噪声更小。

第二个是采样次数shots的选择。2048次是我经过测试后的经验值。理论上,swap test估计内积模方P(0)的方差正比于1/shots。shots太少,距离排序容易错乱;shots太多,模拟器耗时呈线性增长。有一个取巧的方法:初期迭代用512次快速摸轮廓,后期收敛阶段提升到8192次,这样训练效率更高。

4. 可视化设计与结果展示

4.1 聚类散点图与边界可视化

项目标题里特意提到了“可视化”,这也是整个项目最有直观冲击力的一环。我用了matplotlib来做散点图,把六维特征降维成二维后展示聚类效果。

我试了两种降维方式:PCA和t-SNE。PCA的优点是快、稳定,缺点是线性降维对电路数据这种非线性的类别边界不够友好;t-SNE效果惊艳但每次跑出来的点位置都在变,不适合做成固定效果的图。项目里我最终用PCA做主图,t-SNE作为补充。

散点图的核心代码:

from sklearn.decomposition import PCA import matplotlib.pyplot as plt pca = PCA(n_components=2) X_pca = pca.fit_transform(X_scaled) colors = ['#e74c3c', '#3498db', '#2ecc71'] plt.figure(figsize=(10, 6)) for cluster in range(3): mask = (q_assignments == cluster) plt.scatter(X_pca[mask, 0], X_pca[mask, 1], c=colors[cluster], label=f'Cluster {cluster}', alpha=0.7, edgecolors='white', linewidth=0.5) # 标记中心点 centers_pca = pca.transform(centers) plt.scatter(centers_pca[:, 0], centers_pca[:, 1], c='black', marker='x', s=200, linewidths=3, label='Centers') plt.xlabel('PC1') plt.ylabel('PC2') plt.legend() plt.title('Q-means Clustering Results on Circuit Data (PCA)') plt.grid(alpha=0.3) plt.tight_layout() plt.show()

这里给一个实用技巧:如果散点图上一堆点叠在一起看不清,可以在plt.scatter里设alpha=0.5,同时用edgecolors='white'描边,视觉上会干净非常多。

4.2 量子态概率与距离分布可视化

除了一般的聚类散点图,我还额外画了两张图来展示量子距离估计器的内部行为。

第一张是swap test的辅助比特测量概率分布图。做法是:随机抽取10个样本,对它们和某个固定中心点做量子距离估计,每次跑4096次测量,统计|0>出现的频率,画成柱状图。这张图能直观看到P(0)的波动范围,从而理解量子测量噪声对距离估计的影响。

第二张是“量子距离 vs 经典距离”的散点图。横轴是经典欧氏距离平方,纵轴是量子估计的距离平方。如果要做的事完全准确,所有点应该落在y=x直线上。因为振幅编码做了L2归一化,实际结果会是一条经过原点的斜线,斜率越小说明幅值信息丢失越严重。

这张图非常推荐画一下,因为它是解释“为什么Q-means结果不如经典K-means”的最有力证据。

4.3 收敛曲线与内部评估指标

为了证明Q-means真的有在收敛,我记录了每一轮迭代的中心点移动距离和类内平方和。画成折线图之后,你会看到中心点移动距离在前三轮快速下降,后面趋于平稳。这个趋势和经典K-means非常像,说明量子距离估计虽然引入了噪声,但没有破坏整个迭代过程的基本动力学。

sse_history = [] shift_history = [] # 在迭代循环中记录 # sse = sum(||x - center||^2) for iteration in range(max_iters): ... sse = 0 for i in range(n_samples): sse += np.linalg.norm(X[i] - centers[assignments[i]])**2 sse_history.append(sse) shift_history.append(shift)

画图时用双y轴,左轴是SSE,右轴是中心点移动距离,两条曲线放在同一张图里,非常直观。

5. 常见问题与排查技巧实录

5.1 Qiskit初始化时提示维度不匹配

这是新手最容易踩的坑。circuit.initialize(padded, qubits)要求传入的向量长度必须是2^n,而你的特征数往往不是2的幂。解决办法就是补齐到2的幂,这点我在代码里已经体现。唯一的遗憾是补零后距离估计会有系统偏差,不过对聚类任务影响不大。

5.2 模拟器运行速度慢到怀疑人生

如果数据量大,比如超过1000个样本,Q-means的模拟器耗时几乎是不可接受的。原因很简单:每计算一个样本到中心的距离就要搭一次线路,跑上千次模拟。我的优化办法是:

  • 减少样本量,先用500个样本跑通逻辑。
  • 将批量样本的swap test线路放在同一个QuantumCircuit里,分时段复用测量寄存器。
  • 如果用statevector_simulator,把采样次数设置为1,直接读概率幅值,速度提升非常明显。

5.3 量子距离为负

距离不可能是负数,但我在实验里确实碰到过计算结果为负数的情况。原因在于P(0)的采样值波动,导致2*P(0)-1算出来是负的,再开平方就崩了。解决办法是在代码里加一个np.clip(inner_product_sq, 0, 1),把越界值截断到合法区间。这是我在项目中自己踩到后加的保护。

5.4 初始化对Q-means的影响比经典更大

经典的K-means用k-means++初始化能显著降低最终SSE,而对Q-means来说,量子噪声会让初始化敏感度放大。我测试过随机初始化和k-means++初始化,结果差别很大。随机初始化在量子噪声的干扰下,经常出现某个簇的中心在迭代过程中被“拖走”的空簇问题。解决办法有两个:一是在更新中心时,如果某个簇为空,就保留上一轮中心;二是直接用经典K-means跑一遍得到中心位置作为量子版的初始化,这样能大幅提高稳定性。

5.5 常见问题速查表

问题现象可能原因解决措施
距离计算结果为负swap test采样波动用np.clip截断到[0,1]
某个簇总为空初始中心选得差使用k-means++或经典KMeans初始化
迭代不收敛距离噪声太大增加shots,或者使用statevector后端
可视化时特征维度不够PCA特征解释率低尝试t-SNE,或加入更多物理特征
模拟器运行极慢样本量大且反复采样降采样+statevector后端

5.6 一个稳健的电路数据实验流程建议

根据我反复调整后的经验,一个可复现且效果不错的流程是:

  1. 生成600条电路数据,6个特征,3个类别。
  2. 用StandardScaler做标准化,再L2归一化。
  3. 特征选4个(Vin、Irms、R、f),用2个量子比特编码。
  4. 初始化用经典KMeans跑1次迭代得到的中心点。
  5. 量子距离估计用aer_simulator_statevector,精确读取概率。
  6. 迭代10轮,记录SSE和中心移动距离。
  7. 可视化用PCA降维,散点图+中心点+误分点高亮。

这个流程在普通笔记本上跑完不到2分钟,效果和经典K-means的ARI差距可以控制在0.05以内。

写在最后:一点个人实操体会

这个东西我前前后后玩了两周,最大的感触是:Q-means短期内未必能在效率上打败经典k-means,但它的价值在于让你真正理解“量子计算如何接入经典机器学习流水线”。你不需要把整个算法都量子化,只需要找对最合适的子任务去加速,其他部分继续保留经典逻辑,这种混合架构才是现阶段量子计算应用的主流打法。

另外在可视化这块,我也想多说一句:不要只依赖matplotlib。交互式图表,比如plotly,可以把聚类结果做成hover显示具体电路参数的模式,演示效果会好非常多。如果后续有精力,我打算把Q-means扩展到量子核聚类,用更复杂的feature map去处理非线性边界,那又是一个新坑了。如果你也在折腾Q-means,欢迎一起交流数据实验里的坑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 7:56:59

电力电子仿真工具选型与PSIM实战:从Buck电路到环路设计

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

作者头像 李华
网站建设 2026/10/3 7:56:15

ABAQUS与Fortran、Visual Studio环境配置全攻略:版本匹配与子程序关联

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

作者头像 李华
网站建设 2026/10/3 7:55:54

ESP32接入4G模块:PPP拨号实现蜂窝网络联网教程

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

作者头像 李华
网站建设 2026/10/3 7:55:03

物联网技术架构详解:从感知层到应用层的完整链路与实战解析

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

作者头像 李华
网站建设 2026/10/3 7:54:46

TC4x看门狗WTU配置实战:窗口计算、功能安全联动与调试踩坑

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

作者头像 李华
网站建设 2026/10/3 7:54:40

UML活动图在PPT流程图中的实战建模与动态交付

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

作者头像 李华