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

题目集四到六的总结

一、前言

本阶段三次作业(第4、5、6次)围绕“数字电路模拟器”展开,是一次典型的迭代式增量开发。从最基础的与或非门,到多输入门、组合器件(译码器、选择器),再到支持子电路(模块)定义与实例化,难度呈阶梯式上升,每次作业都在前一版的基础上增加新特性,同时要求兼容旧语法。

三次作业的知识点总结如下:

作业 知识点 核心难点
第四次 5种基本门(与、或、非、异或、同或),输入信号,输出标记 正则解析连接线,迭代计算稳定
第五次 多输入门(参数化)、三态门、译码器、多路选择器、数据分配器 引脚编号管理,复杂器件逻辑
第六次 子电路定义(Cx:块)、子电路实例化、引脚方向、5种错误检测

内部与外部引脚映射,递归计算

题量:每次作业需实现约5~10种元件,并提供完整的解析、连接、计算和输出流程。第三次还增加了对子电路定义的解析,相当于开发了一个微型硬件描述语言的前端。

难度:第4次属于入门级,只需理解继承和多态;第5次开始考验对复杂器件(如译码器)的算法实现;第6次则要求系统设计能力,因为子电路内部包含元件和连接,必须处理好命名空间和信号传播。

通过这三次练习,我不仅巩固了Java面向对象编程,还接触了编译原理中的词法/语法分析思想,以及图论中的拓扑排序与迭代收敛算法。

二、设计与分析

2.1 作业四——数字电路模拟程序-1

类图设计

联想截图_20260620145910

设计思路:采用模板方法模式,ElectronicElement 定义 calculate() 抽象方法,子类实现具体逻辑。每个元件拥有 InputPin[](引脚数量可变)和 OutputPin(单输出)。引脚类封装了 getInput() 和 setInput(),并支持从源元件同步(syncFromSource)。

核心算法:主循环 while(changed) 反复调用所有元件的 calculate(),直到所有输出不再变化。这种“盲目迭代”对于无反馈组合电路是可行的,因为信号传播最多经过门级数,通常几次即可收敛。

解析策略:使用正则表达式区分三种语句:

INPUT: A-1 B-0 → 存入 inputSignals 映射。

[A1-1 A2-0] → 连接,创建元件并设置输入。

[A1 OUT] → 标记需要输出的元件名。

SourceMonitor 分析图:

联想截图_20260620152558

心得:第一次作业让我深刻体会到“面向对象”的威力——每种门只需重写 calculate,无需重复定义引脚管理。但 InputPin 和 OutputPin 作为独立类增加了对象开销,且引脚编号从0开始,而题目示例中常出现 -1 作为信号值,容易混淆。

2.2 作业五——数字电路模拟程序-2

类图设计

联想截图_20260620150509

统一引脚模型:废弃 InputPin/OutputPin 对象,改用 int[] inputs 和 int[] outputs,通过 setInput(pin, value) 直接赋值。这简化了内存管理,也方便批量重置。

复杂器件逻辑:

  译码器 (MGate):根据控制位计算地址,对应输出为0,其余为1。

  多路选择器 (ZGate):根据控制位选择一路数据输入输出。

  数据分配器 (FGate):根据控制位将数据输入送到对应输出端。

  三态门 (SGate):使能端为1时输出数据,否则输出高阻(-1)。

命名与参数解析:支持 A(3)1 表示3输入与门编号1。使用正则 ^([A-Z])\((\d+)\)(\d+)$ 提取参数。

计算引擎优化:引入 Connection 列表,传播时只更新目标引脚,但仍需全量迭代所有元件以确保组合逻辑稳定。迭代次数限制为1000。

SourceMonitor 数据:

联想截图_20260620152957

心得:数组模型让代码更紧凑,但 formatOutput 必须为每种器件重写(如三态门输出引脚编号为2,译码器输出格式为 M1:3 表示第3路为0),导致代码分散。此外,未对输入引脚进行“已驱动”检查,可能会出现未连接引脚被默认-1参与计算,造成错误结果。

2.3 作业六——数字电路模拟程序-3

类图设计

联想截图_20260620150728

子电路定义解析:遇到 C1: 开始收集直到 endc。内部包含 INPUT:、OUT: 和若干 [ ... ] 连接线。定义块不立即实例化,而是存入 subDefs 映射。

子电路实例化:当出现 C1-A 形式的引脚引用时,创建 SubCircuitInstance(若尚未创建)。该实例拥有与普通元件相同的 inputs/outputs 数组,但实际计算由内部元件完成。

内部构建:在 SubCircuitInstance 构造时,解析 def.internalLines,建立从子电路输入端口到内部元件引脚的映射(inputTargets),以及从内部元件输出到子电路输出端口的映射(outputSources)。内部连接保存在 internalConns 中。

计算流程:compute() 首先将 inputs 值通过 inputTargets 传递给内部元件,然后迭代计算内部连接(类似主循环),最后将 outputSources 中的内部输出值赋给 outputs 数组。

错误检测:

  多个输出源(include more than one input)
  没有输入信息(include none input)
  没有输出源(include none output)
  顺序错误(第一个不是输出源)
  信号冲突(同一引脚被多次驱动)
SourceMonitor 分析图:

联想截图_20260620153125

心得:子电路的引入使系统具备了层次化设计能力,但实现较为粗糙——一个子电路定义只能有一个全局实例(因为按名称唯一创建),无法参数化。此外,内部元件命名时加入了前缀(如 C1-A1)以避免冲突,但全局 allComps 中混杂了子电路内部和外部的元件,输出时需额外过滤。

三、踩坑心得

在三次作业的编码和调试过程中,我踩了不少坑,下面详述几个典型案例。

3.1 引脚编号与信号值混淆(作业4)

现象:输入 INPUT: A-1,连接 [A A1-0],预期 A1 输出1,实际输出 -1(未连接)。

原因:解析 INPUT: 时,我将信号名和值存入 inputSignals,但连接中的 [A A1-0] 中第一个 token 是信号名 A,第二个是目标引脚 A1-0。我的代码错误地将 A 当作元件名去查找,未匹配到,于是跳过了连接。

解决:修改解析逻辑,先判断 token 是否为单个大写字母且存在于 inputSignals,若是则作为信号源处理,否则视为元件。同时,信号值应在连接建立时直接设置目标引脚的输入,而非通过后续同步。

教训:数据结构与解析顺序必须严格匹配,建议先定义所有信号,再处理连接。

3.2 迭代计算陷入死循环(作业5)

现象:包含译码器 M2 和选择器 Z2 的电路,程序卡死,CPU 100%。

原因:在迭代循环中,每次 calculate() 都根据当前输入重新计算,但译码器的输出(多个引脚)是互斥的,一旦某个输出变为1,另一个变为0,导致下游元件不断变化,无法收敛(实际上是因为译码器输出所有位同时变化,但迭代顺序使得某些元件先看到旧值)。

解决:对于组合电路,理论上只需迭代到稳定,但应避免振荡。我限制了最大迭代次数(1000),并在每次迭代前将所有元件的输入重置为 -1,然后重新传播信号(确保每次迭代从干净状态开始)。同时,保证 calculate() 是纯函数(无副作用),仅依赖当前输入。

教训:组合电路不应有反馈,否则可能振荡。迭代算法必须保证单调性,或者采用拓扑排序一次计算。

3.3 子电路内部引脚无法正确映射(作业6)

现象:定义 C1: 内部有 INPUT: A B,内部连线 [A A1-0],但实例化后 A1 始终无输出。

原因:在解析内部连线时,我将 A 当作外部信号处理,而不是子电路的输入端口。因为我的 parseInternalPin 没有过滤掉输入端口名。

解决:修改 parseInternalPin,如果 token 是 def.inputs 或 def.outputs 中的名称,直接返回 null(不处理),而是在上层分别建立 inputTargets 和 outputSources 映射。对于 [A A1-0],第一个 token 是输入端口,应记录输入端口A到 A1 引脚的映射;第二个 token 是目标引脚,正常解析。

教训:子电路内部的“源”可能是外部端口,而不是具体元件,必须区分处理。

3.4 错误检测顺序不当导致误报(作业6)

现象:输入 [A1-0 A2-0] 正常,但 [A1-0 A2-0 A3-0] 报“多个输出源”。

原因:我的错误检测逻辑是“从第二个 token 开始如果发现有输出源则报错”,但 A1-0 是输出源,A2-0 和 A3-0 是输入接收端,不应该报错。实际上,多个接收端是允许的(扇出)。

解决:正确识别 token 角色:输出源必须是元件输出引脚(isOutputPin)或信号;输入接收端必须是元件输入引脚(isInputPin)。只有在接收端位置出现输出源才算“多个输出源”。我重写了角色判断,使用 Pin.isInput 标识方向。

教训:错误检测必须基于准确的语义,不能仅凭 token 位置。

3.5 输出排序错误(作业6)

现象:输出顺序为 A1, A10, A2,不符合数值升序。

原因:直接按字符串排序,10排在2前面。

解决:提取末尾数字,使用 Comparator.comparingInt(Main::extractNumber)。

教训:涉及编号时,务必考虑数值比较。

四、改进建议

基于三次作业的实践,我认为可以从以下几个方面进行改进,使代码更具可维护性和扩展性。

4.1 重构解析器,采用状态机或递归下降

当前 Main 中的解析逻辑混杂了词法分析和语法分析,且使用大量正则和 if-else,难以维护。建议将解析分为:

  Lexer:将输入行转换为 Token 流。

  Parser:根据语法规则构建 AST(抽象语法树),例如 ConnectionNode、SignalNode、SubCircuitDefNode。

  Builder:根据 AST 创建元件和连接。

这样不仅清晰,而且便于扩展新语法。

4.2 引入拓扑排序优化计算
当前迭代算法对每个元件都执行 calculate,即使其输入未变化。可改为:

建立有向图(元件为节点,连接为边)。

从输入信号开始,按拓扑序传播(使用队列)。若存在环,则报错(组合电路不应有环)。

这样一次遍历即可完成计算,时间复杂度 O(V+E)。

4.3 支持子电路多实例与参数化
当前子电路只允许一个全局实例,限制了复用。可修改为:

SubCircuitInstance 持有自己的内部元件副本(深拷贝定义中的元件原型)。

允许通过参数指定端口宽度(如 C1#(3) 表示实例化宽度为3的译码器)。

使用原型模式复制定义,避免互相干扰。

4.4 增加日志与单元测试

测试每个门电路的逻辑真值表。

测试解析器对合法/非法输入的响应。

测试错误检测的覆盖度。

日志输出可帮助调试,如设置 DEBUG 模式打印每次迭代的元件状态。

4.5 优化输出格式,统一使用格式化器

不同元件的输出格式各异(如三态门输出 -2,译码器输出 :3),可定义一个 OutputFormatter 接口,每种元件实现自己的格式化逻辑,避免在 formatOutput 中使用 instanceof。

五、总结

通过这三次作业的迭代开发,我收获了宝贵的工程经验,也对面向对象设计有了更深的理解。

纵向对比三次作业:

  第4次:让我熟悉了继承和多态,以及正则表达式的使用。但设计较为稚嫩,引脚对象过度设计。

  第5次:统一了引脚模型,新增复杂器件,锻炼了算法实现能力。但代码逐渐臃肿,解析与计算耦合严重。

  第6次:引入子电路,提升了抽象层次,同时强制进行错误处理,让我意识到健壮性的重要性。但也暴露了前期设计不足导致的重构成本。

个人成长:

  编码习惯:从“写完了事”到“先设计再编码”,开始画类图、考虑扩展点。

  调试能力:学会使用断言和日志,快速定位问题(如引脚映射错误)。

  面向对象原则:深刻体会到“开闭原则”的价值——对扩展开放,对修改关闭。例如工厂模式可使新增元件无需改动已有代码。

  全局思维:子电路实现让我意识到,系统设计时要考虑命名空间、作用域和生命周期,否则后期寸步难行。

仍需深入学习的方向:

  设计模式:工厂、访问者、观察者模式在该场景中都有用武之地。

  编译原理:如何处理嵌套子电路?如何实现作用域和符号表?

  并发编程:大规模电路如何并行模拟?

  形式化验证:如何证明电路逻辑正确性,而不是靠迭代猜测。

总之,这次作业集是一次极佳的“实战演练”,让我从零开始搭建了一个迷你EDA工具。虽然代码仍有诸多不足,但正是这些不足指引了未来改进的方向。我相信,只要持续重构和学习,我的软件设计能力定能更上一层楼。

http://www.jsqmd.com/news/1049551/

相关文章:

  • 2026 年 6 月昆明无套路包包回收清单,剔除流动私人商贩 - 讯息早知道
  • 微信小程序一键去水印,保存高清视频素材就这么简单 - 爱上科技热点
  • 手机电脑端免费去水印方法,2026年实测可用 - 爱上科技热点
  • 东莞闲置大牌包怎么变现?2026 正规靠谱回收渠道合集 - 薛定谔的梨花猫
  • 2026 年吉安市厨卫屋顶防水修缮三家横向测评:吉修匠 99.8 分稳居榜首 - 吉修匠
  • 北京品牌首饰回收渠道 2026 汇总 正规实体门店 大牌饰品全覆盖 - 薛定谔的梨花猫
  • 2026 年淄博市厨卫屋顶防水修缮三家横向测评:吉修匠 99.8 分稳居榜首 - 吉修匠
  • 2026年浙江地区GEO优化服务商实力榜单|本地企业生成式搜索优化首选指南 - 936品牌测评网
  • 合肥低分初中毕业生择校,3+2 直通公办大专,2026 完整简章,联系号码公示 - 我叫小周
  • 西安奢侈品回收 2026 添价收实体门店经营 交易可查可追溯 - 薛定谔的梨花猫
  • 嵌入式GUI内存设备:emWin旋转缩放与动画特效实战指南
  • 2026 东莞汽车音响行业登顶者:虎门杰生的全方位领先之路 - 汽车音响改装
  • 2026年6月同步更新|亨得利劳力士联保有效期官方查询,附全国正规维修网点汇总 - 亨得利官方售后
  • 应对分布式消息安全挑战:nanomsg防护策略深度解析
  • 2026最新去水印技巧,视频图片都能用 - 爱上科技热点
  • CANN/GE图引擎API:IrDefInputs方法
  • 手机去水印App实测,2026年保留原画质的技巧分享 - 工具软件使用方法推荐
  • 4层编译栈设计:构建企业级深度学习框架的架构解析
  • 微信小程序去水印合集,保存视频图片只需10秒 - 工具软件使用方法推荐
  • 嵌入式GUI开发:emWin文本显示与emWinSPY调试工具实战指南
  • 2026昆明婚纱摄影排名实测|按需求选店,原创+定制+性价比全榜单 - charlieruizvin
  • 2026合肥高新区废品回收机构性价比排行榜,这三家值得推荐 - 资讯速览
  • TSN实战:基于NXP平台的确定性网络动态配置与核心技术详解
  • 嵌入式GUI实战:emWin中LISTWHEEL与MENU控件的高级应用与优化
  • 2026外墙防水选购指南:代表性品牌深度解析,适配多场景多城市需求 - 速递信息
  • 2026南京黄金回收实力榜:经营面积超100平、配备光谱检测仪的六家机构 - 商业信息快查
  • Pearcleaner:彻底释放Mac空间的终极清理解决方案
  • MiGPT终极指南:三步将小爱音箱改造成你的专属AI管家
  • 3步掌握WAN2.2-14B-Rapid-AllInOne:开源AI视频生成实战指南
  • 专业户内隔离手车公司推荐榜:2026年行业深度评测与选购指南在电力系统运行中,户内隔离手车作为中压开关柜的核心部件,直接影响设备检修安全与供电可靠性 - 资讯速览