news 2026/9/2 12:02:05

鲸鱼优化算法改进实战:IWOA原理、实现与性能调优

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鲸鱼优化算法改进实战:IWOA原理、实现与性能调优

简介:本资源为一种融合双向LSTM与注意力机制的改进型鲸鱼优化算法(IWOA)实现方案,面向智能优化、时间序列预测及深度学习模型超参调优领域的研究者与工程实践者。资源包共15个文件,含2个核心Python脚本(IWOA.py、LSTM.py)、4个CSV格式实测数据集(如事.csv、社.csv等)、2个Jupyter Notebook(含WOA-BiLSTM-Attention.ipynb完整建模流程)、5个XML配置与IDE项目文件,以及.gitignore等辅助文件,整体压缩包仅299KB,轻量易部署。已有775人学习下载,适用于算法对比实验、模型结构复现及小规模时序建模任务。读者可直接运行notebook查看IWOA优化BiLSTM超参数(如hidden_nodes)的全过程,获取含注意力权重可视化、损失曲线绘制、多组数据加载逻辑在内的完整可执行代码框架,并参考XML与CSV组织方式构建自有实验数据集。

1. 项目概述:从经典WOA到IWOA的进化之路

在优化算法的世界里,鲸鱼优化算法(Whale Optimization Algorithm, WOA)一直是个挺有意思的存在。我第一次接触它,是被它那独特的灵感来源——座头鲸的“气泡网”捕食策略——给吸引住了。这个算法把鲸鱼围捕猎物的过程,抽象成了全局搜索和局部开发两个阶段,结构清晰,参数也少,在很多标准测试函数上表现不俗。但就像所有元启发式算法一样,用久了,尤其是在处理高维、多峰或者约束复杂的实际问题时,你总能感觉到经典WOA有那么点“力不从心”。比如,它容易过早收敛,陷入局部最优;在开发后期,种群多样性下降太快,导致搜索停滞。这些问题,促使我和很多同行一样,开始琢磨怎么去“改进”它,于是就有了今天要聊的“改进的鲸鱼优化算法”,我们姑且称之为IWOA。

IWOA不是一个特定的、有官方定义的算法,而是一类改进思路的统称。它的核心目标很明确:在保留WOA生物灵感与简洁框架的基础上,针对其固有缺陷进行“外科手术式”的增强,提升其收敛精度、收敛速度以及跳出局部最优的能力。简单说,就是让这群“鲸鱼”变得更聪明、更高效。无论你是刚接触优化算法的新手,想了解如何对一个经典算法进行“魔改”,还是有一定经验的研究者或工程师,正在为某个实际优化问题(比如神经网络参数调优、工程结构设计、调度排产)寻找更强大的求解器,理解IWOA的设计思路都能给你带来直接的启发。接下来,我就结合自己的一些实践和常见的改进策略,来拆解一下IWOA通常是怎么“炼”成的。

2. IWOA的核心改进思路与设计哲学

2.1 诊断经典WOA的“病灶”

要改进,先得知道毛病在哪。经典WOA的流程可以高度概括为:初始化一群鲸鱼(解)的位置,在迭代过程中,每只鲸鱼要么围绕当前最优个体进行“包围”(局部开发),要么进行随机搜索(全局探索)。选择哪种行为,由一个概率参数p和控制包围步长的系数A来决定。

它的几个主要“病灶”如下:

  1. 探索与开发的失衡与僵化:虽然算法通过pA来切换模式,但这种切换是随机的、被动的。在迭代早期,可能需要更激进的探索来广泛撒网;在后期,则需要更精细的开发来深耕区域。经典WOA的机制对此响应不够灵敏,容易导致早期开发过度(早熟)或后期探索浪费(震荡)。
  2. 种群多样性衰减过快:随着迭代进行,鲸鱼群会快速向当前最优解聚集。一旦这个最优解是个局部最优,整个种群就很容易被“困住”,因为缺乏有效的机制让部分个体“叛逆”地跳出去看看别的区域。
  3. 位置更新方式的单一性:无论是螺旋更新还是直线逼近,其更新策略相对固定。对于复杂、崎岖的适应度地形,这种单一策略可能不够高效,需要更自适应、更智能的更新规则。

注意:理解这些“病灶”是设计任何改进算法的第一步。不要一上来就堆砌复杂的数学公式,先想清楚你要解决的具体是哪个问题。

2.2 IWOA的通用改进框架

基于以上诊断,IWOA的改进通常围绕以下几个核心方向展开,我们可以将其视为一个模块化的改进框架:

  1. 参数自适应调整:让关键参数(如收敛因子a、系数AC)不再是线性或随机变化,而是根据迭代进度、种群分布情况自适应地变化。例如,让a非线性递减,前期慢降以加强探索,后期快降以加速收敛。
  2. 种群多样性维持与增强:引入外部存档、对立学习、混沌映射、或者周期性重初始化等手段,在种群趋于同质化时注入新的多样性,防止早熟收敛。
  3. 位置更新策略的融合与创新:将WOA的位置更新公式与其他优化算法的优秀策略(如差分进化DE的变异、粒子群PSO的速度更新、模拟退火的概率接收等)进行融合,形成混合算法。或者,设计多阶段、多策略的更新规则。
  4. 领导者选择机制的优化:不一定总是围绕全局最优解进行更新。可以引入多个领导者(如次优解、随机优秀解),或者以一定概率围绕历史最佳解或邻域最佳解进行更新,避免全体个体盲目跟随一个可能陷入局部最优的“领袖”。
  5. 问题特定知识的嵌入:针对特定类型的优化问题(如约束优化、多目标优化、离散优化),设计专门的编码/解码方式、约束处理机制或 Pareto 支配关系,将WOA框架与问题域知识深度结合。

3. 一种典型的IWOA实现方案详解

这里,我以融合了非线性收敛因子精英对立学习柯西变异这三种常见策略的IWOA方案为例,拆解其具体实现。这个方案在平衡探索与开发、增强跳出局部最优能力方面有较好的综合表现。

3.1 改进点一:非线性自适应收敛因子

在经典WOA中,控制搜索范围的收敛因子a通常从2线性递减到0。这很直观,但不够灵活。

改进思路:我们希望在迭代初期,a值下降慢一些,让|A|>1(探索模式)的概率维持更久,进行充分的全局探索。在迭代后期,a值加速下降,使算法快速进入开发模式,精细搜索。

实现公式: 我们可以采用指数型或余弦型的变化策略。这里给出一个常用的非线性公式:a = a_initial - (a_initial - a_final) * (t/T)^k其中,t是当前迭代数,T是总迭代数,k是一个大于1的常数(例如k=2或3)。当k>1时,(t/T)^k曲线是凸的,意味着前期变化慢,后期变化快。

实操代码片段(Python示意)

import numpy as np def nonlinear_convergence_factor(t, T, a_initial=2, a_final=0, k=3): """ 计算非线性收敛因子a t: 当前迭代次数 T: 最大迭代次数 k: 非线性指数,k>1时前期慢降,后期快降 """ return a_initial - (a_initial - a_final) * ((t / T) ** k) # 在迭代循环中 for t in range(T): a = nonlinear_convergence_factor(t, T, k=3) A = 2 * a * np.random.rand() - a # 系数A C = 2 * np.random.rand() # 系数C # ... 后续更新逻辑

为什么这样改?通过调整k值,你可以像调节“旋钮”一样控制探索与开发的节奏。对于未知的问题,可以从k=23开始尝试。实测中,这种简单的改动往往能带来收敛曲线平滑度的显著改善。

3.2 改进点二:精英对立学习增强种群初始化与迭代

对立学习(Opposition-Based Learning, OBL)是一种有效的智能计算策略,其核心思想是同时评估一个解和它的对立解,从中选取更优者。这能帮助算法更快地逼近全局最优区域。

改进思路:在算法初始化时,不仅生成随机种群,还生成其对立种群,合并后选取最优的N个个体作为初始种群。在迭代过程中,每隔一定代数(如每5代),对当前精英个体(如前20%的优秀解)执行对立学习,尝试发现更好的解。

对立解生成公式(对于定义在 [lb, ub] 上的变量)X_opposite = lb + ub - X

实操步骤

  1. 初始化阶段
    def opposition_based_initialization(pop_size, dim, lb, ub): # 生成随机种群 pop_random = np.random.rand(pop_size, dim) * (ub - lb) + lb # 生成对立种群 pop_opposite = lb + ub - pop_random # 合并种群 combined_pop = np.vstack((pop_random, pop_opposite)) # 评估合并种群的适应度 fitness = evaluate(combined_pop) # 假设的评估函数 # 选择适应度最好的 pop_size 个个体 sorted_indices = np.argsort(fitness) initial_pop = combined_pop[sorted_indices[:pop_size]] return initial_pop
  2. 迭代进化阶段
    generation_interval = 5 # 每5代进行一次精英对立学习 elite_ratio = 0.2 # 精英比例 if t % generation_interval == 0: # 1. 识别精英个体 fitness = evaluate(population) elite_size = int(pop_size * elite_ratio) elite_indices = np.argsort(fitness)[:elite_size] elites = population[elite_indices].copy() # 2. 生成精英的对立解 opposites = lb + ub - elites # 3. 评估对立解 fitness_opp = evaluate(opposites) # 4. 贪婪选择:用对立解中更好的替换原精英(如果更优) for i in range(elite_size): if fitness_opp[i] < fitness[elite_indices[i]]: # 假设最小化问题 population[elite_indices[i]] = opposites[i] fitness[elite_indices[i]] = fitness_opp[i] # 同时更新全局最优解判断 if fitness_opp[i] < best_fitness: best_fitness = fitness_opp[i] best_position = opposites[i].copy()

实操心得:对立学习的引入,相当于在算法中安装了一个“定期扫描雷达”,尤其对于对称或部分对称的搜索空间非常有效。但不宜每代都做,否则计算开销翻倍,且可能干扰算法的自然进化节奏。间隔代数generation_interval和精英比例elite_ratio是需要调优的超参数。

3.3 改进点三:柯西变异扰动帮助跳出局部最优

当算法陷入局部最优时,我们需要一个“扰动”机制来打破平衡。高斯变异是常见选择,但柯西分布因其具有更长的尾部,能产生更大范围的突变,在跳出局部最优方面时常表现更佳。

改进思路:在每次迭代更新完所有鲸鱼位置后,以一定概率对全局最优解(或所有个体)施加一个基于柯西分布的随机扰动。如果扰动产生的新解更优,则接受它。

柯西分布随机数生成:标准柯西分布的概率密度函数中心在0,两端尾巴很长。可以用np.random.standard_cauchy()生成,但要注意其值可能非常大,通常需要乘以一个缩放因子scale

实操代码片段

def cauchy_mutation(position, best_position, scale=0.1, mutation_prob=0.1): """ 对位置施加柯西变异 position: 待变异的解(可以是当前解或全局最优解) best_position: 当前全局最优解,作为变异的参考中心 scale: 变异尺度因子,控制扰动大小 mutation_prob: 变异概率 """ if np.random.rand() < mutation_prob: dim = len(position) # 生成柯西随机扰动,并与尺度因子相乘 cauchy_noise = np.random.standard_cauchy(dim) * scale # 通常围绕当前最优解进行变异 mutated_position = best_position + cauchy_noise # 确保变异后的解仍在边界内 mutated_position = np.clip(mutated_position, lb, ub) return mutated_position else: return position.copy() # 在迭代主循环中,更新种群位置后 new_best_position = cauchy_mutation(best_position, best_position, scale=0.05, mutation_prob=0.15) new_best_fitness = evaluate_single(new_best_position) # 评估变异解 if new_best_fitness < best_fitness: best_position = new_best_position best_fitness = new_best_fitness # 也可以用变异解随机替换种群中的一个较差个体

注意事项scale因子非常关键。太大可能导致搜索过于随机,破坏收敛;太小则起不到跳出局部最优的作用。一个常见的策略是让scale随着迭代次数增加而递减,例如scale = initial_scale * (1 - t/T)mutation_prob一般设置得较小(如0.05~0.2),因为变异是“偶然事件”。

4. IWOA的完整工作流程与代码整合

将以上三个改进点融入经典WOA框架,我们可以得到以下IWOA的伪代码流程。这里假设是求解最小化问题。

4.1 算法完整步骤

  1. 初始化阶段

    • 设置算法参数:种群大小N,最大迭代次数T,非线性指数k,对立学习间隔G_interval,精英比例elite_ratio,柯西变异概率p_m和尺度因子初始值scale_init
    • 使用精英对立学习初始化生成初始种群Pop
    • 评估初始种群适应度,找到全局最优解Best_X及其适应度Best_F
  2. 主迭代循环(for t = 1 to T): a.更新参数:计算当前非线性收敛因子a,进而计算AC。更新柯西变异尺度scale = scale_init * (1 - t/T)。 b.遍历种群中每个个体X_i: i. 生成随机数p(0~1),r1,r2,l(均随机)。 ii. 如果p < 0.5: * 如果|A| < 1:执行包围猎物D = |C * Best_X - X_i|X_new = Best_X - A * D。 * 如果|A| >= 1:执行随机搜索。随机选择一个个体X_randD = |C * X_rand - X_i|X_new = X_rand - A * D。 iii. 如果p >= 0.5:执行螺旋更新D = |Best_X - X_i|X_new = D * exp(b*l) * cos(2πl) + Best_X。 iv. 边界处理:确保X_new[lb, ub]范围内。 v. 评估新解X_new的适应度F_new。 vi. 贪婪选择:如果F_new < F_i,则用X_new更新X_iF_i。 c.更新全局最优:检查当前种群,更新Best_XBest_F。 d.精英对立学习(如果满足间隔条件):如果t % G_interval == 0,执行3.2节所述的精英对立学习流程,更新种群和可能的最优解。 e.柯西变异扰动:以概率p_mBest_X执行柯西变异,得到X_mutated。评估其适应度,如果更优,则接受其为新的Best_X,并可选地替换种群中的一个较差个体。

  3. 输出结果:迭代结束后,返回全局最优解Best_X及其适应度Best_F

4.2 关键参数设置经验谈

参数调优是算法应用的永恒主题。以下是一些基于经验(主要针对上述IWOA变体)的起始参考值,但强烈建议针对你的具体问题进行调整:

参数符号建议范围/值说明
种群大小N30 - 100问题维度越高,通常需要更大的种群。一般设为维度D的5-10倍。
最大迭代次数T500 - 2000取决于问题复杂度。可先设置一个较大值,观察收敛曲线平缓后即可停止。
非线性指数k2 - 4控制探索与开发节奏。k越大,前期探索越充分。
对立学习间隔G_interval5 - 20间隔太小计算开销大,太大效果减弱。通常5-10代一次。
精英比例elite_ratio0.1 - 0.3选择前10%-30%的优解进行对立学习。
柯西变异概率p_m0.05 - 0.2概率不宜过高,以免破坏收敛稳定性。
变异尺度初值scale_init0.1 * (ub - lb)与搜索空间范围相关。可设为边界跨度的0.05-0.2倍。
螺旋形状常数b1通常固定为1,定义螺旋形状。

提示:没有一套参数能通吃所有问题。最可靠的方法是设计一个参数实验(如使用部分因子实验设计),在你的特定问题实例或标准测试函数集上,观察不同参数组合对算法性能(最终解质量、收敛速度、稳定性)的影响。

5. 性能验证与对比分析实录

设计好了IWOA,我们怎么知道它真的比经典WOA强呢?不能光凭感觉,得有数据说话。这里分享我常用的验证流程和踩过的坑。

5.1 测试环境与基准函数

首先,需要一套公认的基准测试函数。常用的有CEC(Congress on Evolutionary Computation)系列、IEEE CEC标准测试函数集,或者一些经典的独立函数,如:

  • 单峰函数:Sphere, Schwefel’s Problem 1.2(检验收敛精度和速度)。
  • 多峰函数:Rastrigin, Ackley, Griewank(检验跳出局部最优的能力)。
  • 固定维度多峰函数:Shekel’s Foxholes, Kowalik(检验在复杂地形下的搜索能力)。

实操设置

  • 统一运行环境(Python版本、库版本)。
  • 对每个测试函数,分别运行经典WOA和你改进的IWOA。
  • 关键:为了公平比较,必须使用相同的随机数种子来初始化两个算法的种群。否则,一次运行结果的优劣可能只是运气。
  • 每个算法在每个函数上独立运行多次(例如30次),以消除随机性的影响。

5.2 评价指标与结果分析

运行结束后,收集以下指标进行对比:

指标计算公式/说明意义
最优值(Best)多次运行中得到的最好适应度值算法能找到的理论最优解的下限。
最差值(Worst)多次运行中得到的最差适应度值算法最差表现,反映稳定性下限。
平均值(Mean)多次运行适应度值的平均值算法平均性能的核心指标。
标准差(Std)多次运行适应度值的标准差衡量算法的鲁棒性和稳定性。标准差越小越稳定。
收敛曲线记录每次迭代的全局最优适应度,绘制平均收敛曲线直观展示算法随迭代的进化过程,比较收敛速度。

结果分析示例: 假设在30维的Rastrigin函数上运行30次。

  • 如果IWOA的Mean和Best都显著优于WOA:说明改进有效提升了寻优精度。
  • 如果IWOA的Std明显小于WOA:说明改进使算法更稳定,受初始随机性影响更小。
  • 观察收敛曲线:如果IWOA的曲线在前期下降速度与WOA相当甚至更快,并且在后期能持续下降到更低的水平,说明其在探索和开发平衡上做得更好。

一个常见的坑:只比较一次运行的结果就下结论。元启发式算法的随机性很强,必须进行多次独立重复实验,并使用统计检验(如Wilcoxon秩和检验)来判断性能差异是否具有统计显著性,而不是肉眼观察。

5.3 与其他改进版或先进算法的对比

除了和经典版比,还可以将你的IWOA与其他已知的WOA改进版本(如EWOA, WOA-S, etc.)或当前流行的先进元启发式算法(如哈里斯鹰优化HHO、麻雀搜索算法SSA、减法平均优化器AOS等)进行横向对比。这能更全面地定位你算法的性能水平。

对比维度可以增加

  • 时间复杂度:记录运行相同次数迭代所需的平均CPU时间。引入复杂改进可能会增加单次迭代耗时。
  • 成功率:在允许的误差范围内(如与理论最优值差距小于1e-5),算法找到可接受解的成功率。
  • 参数敏感性分析:测试你的IWOA对其关键超参数(如k,G_interval,p_m)变化的敏感程度。一个鲁棒的算法应对参数设置不过分敏感。

6. 实际应用场景与问题排查技巧

IWOA不是象牙塔里的玩具,最终要落到实际问题的求解上。这里列举几个典型应用场景和实践中会遇到的问题。

6.1 典型应用场景适配

  1. 神经网络超参数调优:将神经网络的超参数(学习率、层数、节点数、dropout率等)编码为鲸鱼的位置向量。适应度函数为模型在验证集上的损失或错误率。IWOA的全局搜索能力有助于在庞大的超参数空间中找到较优组合。
    • 编码注意:连续参数直接编码,离散参数(如层数)需做整数化处理(如四舍五入)。
  2. 工程优化设计:如桁架结构优化(最小化重量满足应力约束)、翼型气动外形优化等。约束处理是关键,常用罚函数法将约束问题转化为无约束问题,罚因子设置需要技巧。
  3. 生产调度与路径规划:如旅行商问题TSP、作业车间调度JSP。这是离散组合优化问题,需要设计专门的离散化WOA版本,例如基于置换的编码、基于交换或插入的位置更新操作。
  4. 特征选择:在机器学习中,将特征子集编码为0/1二进制串,1表示选中该特征。适应度是分类准确率与特征数量的加权组合(追求高准确率且特征数少)。需要二进制版本的IWOA,通常使用Sigmoid函数将连续位置映射到[0,1],再与随机数比较决定0或1。

6.2 常见问题与排查技巧速查表

在实际编码和应用IWOA时,你可能会遇到以下问题:

问题现象可能原因排查与解决思路
算法早熟,很快陷入局部最优1. 探索能力不足(A值过早变小)。
2. 种群多样性丧失过快。
3. 变异概率太低或尺度太小。
1. 检查收敛因子a的变化曲线,尝试增大非线性指数k,或使用更慢的衰减策略。
2. 增强多样性机制:提高对立学习频率、增加混沌初始化、引入小生境技术。
3. 适当提高柯西变异概率p_m或初始尺度scale_init
收敛速度慢,后期优化不明显1. 开发能力不足。
2. 围绕最优解的搜索不够精细。
3. 算法一直在进行无意义的探索。
1. 在迭代后期,确保a值能充分减小,使 `
结果不稳定,多次运行差异大1. 算法对初始种群过于敏感。
2. 随机性操作(如变异)过于剧烈。
3. 种群大小N太小。
1. 使用对立学习或混沌映射来生成质量更高的初始种群。
2. 降低变异操作的强度(减小scale)或概率(p_m)。
3. 适当增加种群大小N,用统计结果(均值±标准差)衡量性能。
处理约束优化问题效果差罚函数法中的罚因子设置不当,导致搜索偏向不可行域或忽略约束。使用自适应罚函数,让罚因子随着迭代动态调整。或者采用可行性优先的约束处理机制。
算法耗时显著增加引入了计算开销大的改进模块,如每代都对整个种群进行复杂的操作。优化代码实现(向量化操作)。审视改进模块的必要性,可能降低其执行频率(如增大对立学习间隔)。对于适应度评估本身很耗时的问题(如训练神经网络),应尽量减少评估次数。

我个人最深刻的体会是:改进算法就像给汽车调校,没有绝对的“最好”,只有针对特定路况(问题)的“更合适”。在标准测试函数上表现优异的改进策略,迁移到你的实际问题上时,可能需要重新调整参数甚至修改策略细节。永远保持实验和迭代的心态,用数据驱动决策,而不是盲目相信某篇论文的参数。最后,算法的可解释性和简洁性本身也是价值,有时一个简单精巧的改进,比堆砌复杂策略更有效、更易于维护和推广。

本文还有配套的精品资源,点击获取

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

阿里千问Agent Teams:让视频创作从手艺变成项目管理能力

阿里千问创作上线 Agent Teams 功能&#xff0c;用户提出创意&#xff0c;Agent 规划任务完成视频制作。这个方向我关注了很久&#xff0c;因为它不是简单的“输入一句话自动生成视频”&#xff0c;而是把一套完整的视频制作流程拆给了多个智能体去协作。从表面看&#xff0c;这…

作者头像 李华
网站建设 2026/9/2 12:01:27

医学病理图像识别:CNN多尺度空洞卷积与临床可解释性实战

简介&#xff1a;本资源是一套完整的医学病理图像智能识别实践项目&#xff0c;面向人工智能、医学影像分析方向的高校学生与初阶算法工程师&#xff0c;聚焦卷积神经网络在组织切片分类任务中的落地应用。压缩包共646个文件&#xff0c;包含377张高分辨率.tif病理图像、143张.…

作者头像 李华
网站建设 2026/9/2 12:01:07

用Grok和Notion整理关注列表,打造信息源数据库

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

作者头像 李华
网站建设 2026/9/2 12:00:53

MediaPipe Tasks Vision 0.10.16 vision_wasm_internal.wasm 404 修复指南

MediaPipe Tasks Vision 0.10.16 vision_wasm_internal.wasm 404 修复指南 【免费下载链接】mediapipe Cross-platform, customizable ML solutions for live and streaming media. 项目地址: https://gitcode.com/GitHub_Trending/med/mediapipe npm install 刚跑完&am…

作者头像 李华
网站建设 2026/9/2 12:00:21

【从0带做】基于Springboot3+Vue3的大学生创业平台

该项目资料获取请点击上方⬆️卡片&#xff0c;然后进入【项目实战库】板块即可搜索到。 项目演示视频 https://www.bilibili.com/video/BV14oTxzREdq 项目技术栈 前后端分离 后端&#xff1a;SpringBoot3 MyBatis Hutool 前端&#xff1a;Vue3 Element-Plus Vue-Route…

作者头像 李华
网站建设 2026/9/2 12:00:13

网站后台密码猜解工具全解析:原理、实操与防守

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

作者头像 李华