第13章

更新时间:2026-06-30 16:55:05  ·  所属小说:傅先生真心错付

周一下午的数据结构课,林远之布置了一道关于二叉树遍历的编程作业。题目不算难,但最后一问要求用非递归方式实现后序遍历,这部分课堂上只讲了思路,没给代码。殷洛燃在笔记本上把题目抄下来,盯着看了五分钟,脑子里有大概的方向,但落实到代码层面总觉得哪里不对。他想了想,打开手机,点开和傅承霄的聊天框。

他们没有加微信。聊天框是学校课程系统自带的私信功能,界面很简陋,白底黑字,没有表情包,没有已读回执。殷洛燃之前没用过这个功能,他花了十几秒找到发消息的入口,打了一行字,删了几个词,又加回去。

“数据结构作业最后一题,非递归后序遍历那个,能请教一下思路吗?”

发送。他把手机放在桌上,屏幕朝上,开始做其他科的作业。高等数学的定积分计算题做到第三道的时候,手机震了一下。他拿起来看,傅承霄的回复比他预想的快,也比预想的详细。

“用两个栈。第一个栈做右左的遍历,第二个栈反转顺序。或者用一个栈加一个辅助节点记录上次访问的位置。你需要代码还是思路?”

殷洛燃看着这条消息,发现傅承霄在给出方案的同时还提供了两种选择——代码还是思路。前者是给答案,后者是教方法。他在这个问题上给了对方选择权,这个细节让殷洛燃觉得有些意外。

“思路就好,代码我想自己写。”

发送。“那约个时间。今天下午四点?图书馆四楼讨论室。”

殷洛燃盯着那个标点——句号,不是问号。傅承霄没有问“行不行”,他直接给出了一个时间,默认对方会同意。这种笃定放在别人身上可能会让人觉得有些傲慢,但放在傅承霄身上,殷洛燃只觉得这件事就这么定了。

“好。哪个讨论室?”

“402。四点见。”

殷洛燃把手机翻过来扣在桌上,高等数学的积分题做到第七步,发现自己忘了在第六步代入上限。他用橡皮擦掉最后两行,重新算了一遍,这次对了。但他的注意力不在答案上,他在想傅承霄刚才发消息的节奏——每条消息之间的间隔都很规律,大概十到十五秒,不长不短,不像是刻意控制,更像是他打字的速度就是这样,快而准,不打多余的词,也不省略必要的词。

下午四点,殷洛燃准时到了图书馆四楼。

讨论室402在走廊尽头的右手边,是一间大约十平米的小房间,中间摆着一张长条桌,六把椅子围着桌子摆成半圆。靠墙有一块白板,白板笔在笔托上放了三支,黑色、蓝色、红色,墨水的痕迹都还很新,看起来刚换过不久。窗外的光经过磨砂玻璃的过滤变得柔和了许多,在桌面上铺了一层均匀的白。

傅承霄已经到了。他坐在靠白板那一侧的位置,面前摊着笔记本电脑和一本翻开的笔记本,电脑屏幕上是一个代码编辑器,背景是深色的,字体很小,殷洛燃隔着桌子看不清上面写的是什么。

“进来。”傅承霄抬头看了他一眼,下巴朝对面的椅子扬了一下。殷洛燃走过去坐下,把书包放在脚边,从里面抽出数据结构课本和笔记本。他发现傅承霄已经在白板上写了一些东西——一个二叉树的结构图,下面列出了三种遍历方式的前缀、中缀、后缀表达式。

“后序遍历的非递归实现,关键是要处理一个问题:当你从栈里弹出一个节点时,怎么知道它的右子树是否已经访问过了。”傅承霄站起来,走到白板前,拿起黑色白板笔,在那个二叉树图旁边画了一个栈的示意图。他的板书和他在课堂笔记本上的字迹一样——工整,紧凑,没有多余的花笔,信息的层级关系用缩进和符号清晰地区分开。

“第一种方法,两个栈。”傅承霄在白板上写下“方法一”三个字,“第一个栈做右左的遍历——先压节点,然后循环弹出,每次把弹出节点的左右子节点依次压入第一个栈。同时把弹出的节点压入第二个栈。最后第二个栈里存储的就是后序遍历的顺序。”

他的笔在白板上移动的节奏很快,但每个字都写得很清楚。殷洛燃在笔记本上跟着他的思路写,把他说的每一步都拆解成伪代码。写到第三步的时候他停了一下。

“这个‘右左’的遍历顺序,其实就是前序遍历的镜像?”

傅承霄偏头看了他一眼。“对。前序是左右,这个是右左。用两个栈的好处是不需要额外的状态变量来标记节点是否被访问过,缺点是多了空间开销。”

他在白板旁边写了一个简单的时间复杂度和空间复杂度的对比,然后换了一支蓝色白板笔。“第二种方法,单栈加辅助节点。”他在白板上画出第二种方法的逻辑图,用一个圆角方框代表辅助节点,箭头表示状态转移。“每次从栈里弹出节点的时候,判断它有没有右子树,或者右子树是否已经被访问过。”

殷洛燃听到这里的时候笔顿了一下。他理解了方法的整体逻辑,但有一个环节还没完全想通——当节点从栈里弹出来的时候,系统是怎么知道它的右子树已经处理完了?

“怎么判断右子树是否已经访问过?”他问。

傅承霄没有直接回答。他转过身,在白板上画了一个更具体的例子——一棵只有三个节点的二叉树,节点是A,左子节点是B,右子节点是C。他用红色白板笔在节点A旁边画了一个星号。

“用一个变量记录上一次访问的节点。每次弹出栈顶节点的时候,检查它有没有右子节点。如果没有,或者右子节点就是上一次访问的节点,那就说明它的右子树已经处理完了,可以访问当前节点。”傅承霄边说边在白板上演示状态变化,每一步都标了序号,从一到七,箭头指向清晰地标明了节点的移动路径。

殷洛燃盯着那七个序号看了一会儿,然后把笔记本翻到新的一页,自己从头到尾推演了一遍。写到第五步的时候他发现,如果用A、B、C这三个节点来模拟,傅承霄画的流程是完全正确的。他把整个流程推演完,抬起头。

“懂了。”

傅承霄看着他,目光在他的笔记本上停了一下。“你推演一遍。”

殷洛燃转过身,在白板的空余处用黑色白板笔画了一个新的二叉树——四个节点,比傅承霄的例子复杂一些。他一边画一边说,把每个节点的进出栈顺序、辅助节点的更新时机都讲了一遍。讲到最后的时候他发现自己在用傅承霄刚才的逻辑框架,但把边界条件换了一种表述方式。不是有意要改,是顺着自己的思路推到了那里。

傅承霄靠在椅背里,双手交叉放在桌面上,听他说完。沉默了两秒,然后伸手在白板上指了指殷洛燃写的某一行。“你这个地方的处理比我的版本更简洁。把右子节点是否存在的判断和是否已被访问的判断合并成一个条件,可以减少一次冗余检查。”

殷洛燃低头看了一眼自己写的条件语句——他把两个逻辑判断用了一个“或”运算符连接,确实比分开写更短。但他写的时候没有意识到这比傅承霄的版本好在哪里,他只是觉得这样写更顺。

“我只是觉得这样写更顺。”殷洛燃说。

“嗯。顺就对了。”傅承霄转回去面对自己的电脑,但没有继续打字,目光在屏幕边缘停了一下,“简洁通常是正确的标志之一。”

殷洛燃不知道他是在说这段代码还是别的什么。他没有追问。

讨论继续往下走。傅承霄在白板上又补充了几种边界情况的处理方式,殷洛燃在笔记本上跟着记录。两个人都忘了时间,窗外的光从白色变成暖黄色又变成灰蓝色,磨砂玻璃外的天色一点一点暗下去,讨论室里的光灯不知道什么时候自己亮了起来。

殷洛燃在笔记本上写满了两页,第三页写了一半的时候,他发现自己已经从“理解答案”进入了“提出问题”的阶段。他开始主动问傅承霄——如果二叉树的节点不是简单的整数类型,而是带有复杂结构的对象,存储方式需要做哪些调整?非递归实现的栈如果用系统调用自己的栈帧而不是手动维护数据结构,两者的性能差异在哪个数量级上会变得显著?

这些问题不是提前准备的,是顺着思路自然冒出来的。他自己都没想到会问这些,因为数据结构课还没讲到这么深。但当他听到傅承霄给出的答案时,他发现这些问题的答案其实就藏在傅承霄刚才讲的那些东西里,只是需要再多推一步。

傅承霄回答这些问题的时候语速比平时稍快了一些。不是急躁,是那种“有人跟上了你的节奏”之后自然的加速。他在白板上写下了更多的公式和图表,蓝色和黑色的笔迹交错在一起,像某种只有两个人能看懂的地图。

殷洛燃的手机在书包里震了好几次。他没有去看,因为每一次震动来的时候他都刚好在白板上画到某一步的关键位置,他不愿意停下来。傅承霄似乎也没有注意到手机震动的声音,或者说他注意到了但没有提,他的注意力始终在白板上的内容和他自己的思考之间来回切换。

当殷洛燃在白板上写完最后一个推导步骤、转过身面对傅承霄的时候,他看到傅承霄的嘴角有一个很轻微的上扬。

不是笑。是那种看到某个预测被验证之后的满足,转瞬即逝,像水面上的涟漪,出现的同时就在消失。但殷洛燃看到了,因为他的目光刚好在那个位置。

“你的悟性很高。”傅承霄说。

这句话的语气和他在课堂上回答问题时一样平,没有夸奖的尾音,没有上扬的语调,就是陈述一个事实。殷洛燃听到这句话的时候,手指在笔杆上轻轻搓了一下。

“你的思路很清晰。”殷洛燃说。他没有说“谢谢”,因为“谢谢”太轻了,配不上这两个小时里他感受到的东西。他说的是另一个事实——傅承霄的思路清晰到让一个几乎零基础的人能在两个小时内理解一道超纲的题目,这本身就是对他表达能力的最高证明。

傅承霄看了他一眼,没有说话。他开始收拾桌上的东西——笔记本电脑合上,笔记本合上,两支白板笔放回笔托。他的动作和来时一样安静,没有因为时间延长而产生任何多余的声响。

殷洛燃看了一眼手机。六点十分。他们从四点开始,讨论了两个小时又十分钟。他错过了室友约晚饭的消息,错过了韩膺发来的一条“最近怎么样”,还错过了课程系统推送的一份作业截止提醒。他一条都没回。

两个人一起走出讨论室。走廊里的声控灯亮起来,白光照在灰色的地面上,把两个人的影子拉得很长,交叠在一起又分开。走到图书馆门口的时候,外面的天已经彻底黑了,路灯亮着,橘黄色的光把台阶照得像铺了一层旧照片的滤镜。

“数据结构这门课你后面如果有问题,可以再来找我。”傅承霄站在图书馆门口的台阶上,双手在外套口袋里。

“好。”殷洛燃说。

傅承霄点了一下头,转身走了。他走的不是回宿舍的方向,是往校门口走。殷洛燃站在台阶上看着他的背影消失在路灯的光晕里,那个人的步伐还是那样,不快不慢,脊背挺直,像走在一条只有他自己看得见的线上。

殷洛燃低下头,翻开自己的笔记本。那两页半的笔记在白纸黑字之间穿着一些他在讨论过程中随手画的箭头和括号,有些地方的字迹因为写得快而变得潦草,但思路的脉络是清晰的——不是因为他的笔记做得好,是因为傅承霄讲得清楚。每一个概念都被拆解到最基础的单元,然后用逻辑的链条重新组装起来,像拼乐高,每一块都有它唯一该在的位置。

他忽然意识到一件事——傅承霄今天在讨论室里,没有问过他“你听懂了吗”。一次都没有。他不是通过提问来确认对方是否理解,而是通过观察。他观察殷洛燃什么时候停笔、什么时候皱眉、什么时候在白板上画图、什么时候自己提出问题。他通过这些信号来判断殷洛燃跟到了哪一步,然后自动调整接下来的讲解节奏和深度。

这种教学方式不是技巧,是一种本能。

殷洛燃把那两页半笔记从头到尾看了一遍,合上笔记本,塞进书包。他在图书馆门口的台阶上蹲下来,把鞋带重新系了一遍,系得很慢。夜风从场的方向吹过来,带着塑胶跑道的气味和远处食堂的饭菜香。他站起来,拍了拍裤子上的灰,往宿舍方向走。

走到梧桐树下的时候他停下来,掏出手机,打开和韩膺的聊天框。未读消息有三条,他一条都没点开,直接打了几个字。

“今天和他讨论数据结构。两个多小时。”

发送。他盯着屏幕看了一会儿,韩膺没有立刻回复。殷洛燃把手机塞回口袋,继续往宿舍走。梧桐树的影子在地上晃动,路灯把他的影子拉得很长很长,和树影重叠在一起,分不清哪个是哪个。他走得不快,但每一步都比前一步轻了一些,不是因为心情好,是因为身体还残留着刚才在讨论室里长时间站着画图之后的松弛感。那种松弛感让他暂时忘记了自己为什么要出现在那间讨论室里。忘记了韩膺,忘记了任务,忘记了“进度”和“汇报”这些词。他只记得傅承霄在白板上画图时袖口微微卷起露出的那一截手腕,和他说“简洁通常是正确的标志之一”时,语调里那种不带任何修饰的确定。

阅读偏好

字号
行距

阅读主题