☰
程序框图与流程图怎么画:符号规范、判断框与代码映射
2026/10/31 9:46:20 网站建设 项目流程

画程序框图和流程图这件事,说起来简单到有点不起眼——不就是几个方框加几支箭头吗?但我经手过的项目里,返工最多、沟通成本最高的环节,往往就卡在这几张图上。前阵子某同学把课程设计的代码发过来求助,说成绩统计的结果总是差一档,我让他先把程序框图补上,画到第三个菱形的时候他自己就停住了:两个判断条件写重了,分数落在 85 到 90 之间时会走两条不同的分支。代码里翻了半天没找出来的问题,一张流程图五分钟就把它晾在了明面上。

这就是程序框图真正的价值所在——它把"想清楚"和"写出来"这两件事强行拆开了。敲代码的时候,脑子里同时要处理语法、变量名、括号匹配、边界条件,注意力被切得很碎;而画流程图的时候,你只需要关心三件事:先做什么、再做什么、什么情况下走哪条路。没有编译器在旁边报错干扰,逻辑漏洞几乎无处可藏。这篇文章我会从一个最小的真实例子出发,把"怎么画、为什么这么画、画完怎么落到代码里"这条链路完整走一遍,中间穿插我自己踩过的坑和几条能直接抄的排版规则。适合刚学编程想理清思路的同学,也适合要给同事、给评审讲清业务逻辑的开发者,哪怕你之前只用纸笔画过草图,跟着走一遍也能把图画得像样。

1. 程序框图到底在解决什么问题

1.1 先想清楚这张图是画给谁看的

很多人画流程图画得痛苦,根本原因不是不会画,而是没搞明白这张图的读者是谁。读者不同,精细度差着好几倍。

第一种读者是你自己。这时候框图的作用相当于草稿纸,作用是"防止想到一半忘了前面",画得丑一点、字潦草一点完全没关系,甚至可以用几个汉字加箭头代替标准符号。我自己在梳理复杂条件判断的时候,经常就在便签上画三四个菱形,理完就扔了。

第二种读者是别人——同组同学、同事、接手的下一个人。这时候图就必须讲规矩了,符号得标准、箭头得有方向、变量得写清楚,因为读者没有你脑子里的上下文。这时候一张图的信息密度反而要降下来,宁可多画一页,也别把三个判断塞进一个菱形。

第三种读者是评审或者答辩场合。这种情况下框图除了讲逻辑,还承担着"证明你想过"的功能,所以起止框、输入输出框、注释这些能体现完整性的元素都得齐。

我一般会先问自己一句话:这张图是给三个月后的我看的吗?如果是,就按第二种标准画;如果只是当下理思路,随便涂。搞清楚这一点,能省掉一大半"画得太随意"或者"过度设计"的纠结。

1.2 五个框走天下:标准符号速查

程序框图的符号是有约定的,虽然不同教材细节略有差别,但核心那几个全世界通用。下面这张表是我自己整理的高频速查版,按使用频率排序:

符号名称形状用来表示什么新手常见误用
起止框圆角矩形或椭圆程序的开始与结束一个图里画多个开始框,或者干脆不画结束框
处理框矩形赋值、计算、数据处理把判断条件写进矩形里
判断框菱形条件分支,必须有出口标注只画一个出口,或者出口不写"是/否"
输入输出框平行四边形读入数据、输出结果把print写进处理框
流程线带箭头的实线执行顺序箭头缺失或双向箭头
连接点小圆圈跨页或长距离跳转的接续同一页内滥用,把图切得七零八落
注释框开口矩形加虚线补充说明拿注释框代替处理框

记住一句话就够了:矩形干活,菱形问路,平行四边形进出,圆角开头结尾。其余符号都是辅助,除非你要画特别复杂的图,否则这五类完全够用。

1.3 三个最容易被扣分的符号错误

第一个错误是判断框只画一个出口。菱形天生就是"一进两出"(或者多出),你只画一条线出去,读者就不知道另一个分支去哪了。如果另一个分支什么都不做,也要老老实实画一条线连到汇合点,这叫"空分支也要显式表达"。我在给某实验室的同学看课程设计的时候,十个里面有六七个犯这个毛病,评审一眼就能看出来。

第二个错误是流程线交叉却不加连接点。线一交叉,读者就得猜你是"交汇"还是"路过"。要么用连接点打断,要么重新排布避开交叉,这两种做法都比让线拧成麻花强。

第三个错误是把"赋值"和"判断"揉在一个框里,比如写一个矩形里面是"如果 i>10 则 sum=sum+i"。这种写法在流程图上是大忌,因为矩形和菱形的语义完全不同,混着写会让后面的代码映射变得极其别扭。判断永远单独占一个菱形,动作永远单独占一个矩形,这条规矩我建议一直守到你能闭着眼画对为止。

2. 一个最小可用的完整例子:成绩判定

2.1 需求拆解:先把一句人话变成可执行规则

题目很朴素:输入一个 0 到 100 的分数,输出对应的等级。A 是 90 分及以上,B 是 80 到 89,C 是 70 到 79,D 是 60 到 69,E 是 60 以下。

这句话听上去毫无歧义,但你真要落成框图,立刻会冒出四五个必须回答的问题:

  • 90 分算 A 还是算 B?边界到底是"大于 90"还是"大于等于 90"?
  • 分数带小数怎么办?89.5 落在哪个区间?
  • 输入 -1 或者 120 这种非法值,是报错还是当作 E?
  • 输入如果是文字呢?

这四个问题在代码里可能只是几个字符的差别,但在流程图上,它们决定了你要多画几个菱形。我的习惯是:在动笔之前,把边界问题先列成一张表,写清楚"含不含等号"。这个动作花两分钟,能省掉后面半小时的调试。

分数区间是否含左端点是否含右端点等级
90 ~ 100含含A
80 ~ 90含不含B
70 ~ 80含不含C
60 ~ 70含不含D
0 ~ 60含不含E
其他——非法输入

这张表一出来,框图的分支结构基本就定死了:因为每个区间都是"左闭右开",判断顺序可以从高到低依次问,问到一个就往下走,不需要重复判断。

2.2 第一遍:只画主干,把图拉成一条线

新手最容易犯的毛病是拿起笔就想一步到位,结果画到一半发现空间不够,只能重来。我的做法是三遍法,第一遍坚决只画主干。

这一遍的图长这样:起止框"开始" → 输入框"输入分数 score" → 判断框"score >= 90" → 处理框"grade = A" → 输出框"输出 grade" → 起止框"结束"。

你会发现这一遍只考虑了"最高分"这一条路径,中间那一堆 80 分、70 分的分支全都没画。没关系,第一遍的目的不是完整,而是确认主干的走向和图的整体高度。图往哪个方向延伸,是自上而下还是自左向右,页面纵向能放几个框,这一遍就要定下来。

顺带说一句方向问题。程序框图的主流画法是自上而下,分支向右或向左展开。我不建议你为了省纸改成横向,因为横向一长,判断框的"是/否"标注就容易被压扁,读起来很累。

2.3 第二遍:补分支,让每个菱形都有两条腿

主干定好之后,回到第一个菱形,把它剩下的那条"否"分支拉出来,接到下一个菱形score >= 80上。然后继续往下:score >= 70、score >= 60,最后一个"否"分支直接落到 E 等级。

这一遍画完,图上会出现一条明显的"阶梯":判断框一路往右下走,每个判断的"是"分支都横向拐出去,接到各自的赋值框,然后再统一汇合到输出框之前。这个阶梯形状非常典型,几乎所有的多区间判定都是这个长相。

画的时候有两个细节必须处理:

一是出口标注。每个菱形伸出来的两条线,一条标"是",一条标"否",绝对不能省。我见过有人用"上出是、下出否"的约定来省标注,结果图一复杂就彻底读不懂了。字符成本极低,收益极高。

二是汇合点的处理。多个分支最终都要流到同一个输出框,这时候会有好几条线指向同一个框的顶部。规范的做法是让所有线先汇到一条垂直的公共干线上,再由这条干线进入输出框,而不是让五条线分别扎在输出框的五个位置。

2.4 第三遍:做减法,把每个框压到一眼读完

前两遍解决的是"对不对",第三遍解决的是"好不好读"。核心动作只有一个:压缩框内文字。

判断框里最忌讳写长句子,比如"如果分数大于等于九十并且小于等于一百",读的人要在脑子里解析一遍。改成score >= 90就干脆多了。处理框里也一样,"把 A 等级赋值给 grade 变量"可以直接写grade = "A"。能用符号就不用汉字,能用短变量名就不用长的。

但压缩也有底线:不能压缩到产生歧义。i++在框图上就不如i = i + 1清楚,因为前者的读者需要额外知道这是自增语法。流程图是给逻辑看的,不是给编译器看的,语法糖在这里没有价值。

3. 从框图到代码:结构是一一对应的

3.1 三种基本结构,画法和代码是一一映射的

所有程序框图,刨到最底层都只有三种结构:顺序、选择、循环。它们和代码的对应关系是严格的,没有例外。

结构框图特征对应代码关键点
顺序若干矩形竖着串起来连续的赋值、计算语句顺序不能颠倒,颠倒就是 bug
选择一个菱形两条腿,之后重新汇合if / else或if / elif / else汇合点必须存在
循环有一条返回线回到上方while或for必须有终止条件

这里有个特别有用的推论:如果一张框图你画不出汇合点,说明代码里一定缺了 else。反过来,如果你写代码的时候发现某个分支"什么都不做",那在框图上也要老老实实画一条空线绕过去,别因为觉得多余就省略。

3.2 完整实现与逐行对照

接着前面的成绩例子,落成 Python 大概是这样:

def get_grade(score): if score < 0 or score > 100: return "非法输入" if score >= 90: grade = "A" elif score >= 80: grade = "B" elif score >= 70: grade = "C" elif score >= 60: grade = "D" else: grade = "E" return grade if __name__ == "__main__": raw = input("请输入分数:") try: s = float(raw) except ValueError: print("非法输入") else: print(get_grade(s))

这段代码和框图是能一条一条对上的:最前面那个if score < 0 or score > 100对应框图里"输入之后先做一次合法性判断"的那个菱形(第一步画主干的时候我特意没提它,现在补上);后面四个elif对应四个依次下降的菱形;最后的else对应最后那个菱形的"否"出口。

注意这里的顺序不是随便排的。从高到低判断的好处是每个分支只需要判断下界,不需要同时判断上下界。如果反过来从低到高,score >= 60这一句就必须写成score >= 60 and score < 70,条件变长,出错概率翻倍。这个"从一端往另一端推"的技巧,是流程图能直接反馈给代码优化的典型例子。

3.3 用框图反查代码漏洞

我经常做的一个练习是:拿一段写好的代码,反着画一遍框图,然后把图和代码并排放着看。这个方法抓 bug 特别灵,因为它逼着你把所有隐式分支显式化。

举个例子,前面那段代码如果漏掉了score < 0 or score > 100的判断,框图上是看不出问题的——图照样能画完整。但如果你先画图再写代码,画到"输入分数"后面那一步,你就会自然地问:"如果输进来的是 -5 呢?"这个问题一旦被问出来,那个菱形就补上了。

再举一个更隐蔽的。如果代码写成:

if score >= 90: grade = "A" elif score >= 80: grade = "B" elif score >= 90: # 笔误,重复了 grade = "C"

在代码里这条elif score >= 90永远不会被执行,静态读代码时很容易一眼扫过去。但你照着代码画框图,画到第三个菱形时会发现它和第一个菱形长得一模一样,条件完全重复——这个"视觉重复"比读代码时的"逻辑重复"更容易被注意到。

4. 循环结构:最容易画错的地方

4.1 返回线画在哪,判断框放前还是放后

循环在框图上就是一个"往回指"的箭头。听起来简单,但放置位置不同,语义完全不同,这是新手翻车最集中的地方。

判断框在循环体之前,这是"先判断后执行",对应while。判断框在循环体之后,这是"先执行后判断",对应do-while。这两者最简单的区别是:如果初始条件一上来就不满足,前者一次都不执行,后者至少执行一次。

我不会在框图上用特殊的循环符号(就是那个六边形),因为一旦用了,读者就得额外记一套约定。我的做法是永远用菱形加返回线,把语义完全展开。图的线条多一点,但任何人一眼就能看懂是先判断还是后判断。规范是给人服务的,不是反过来。

还有一点:返回线的箭头必须指向循环的入口判断框,不能随便指到中间的某个框上,否则就变成了"部分重复",语义完全不同。

4.2 一个累加求和的完整拆解

拿最经典的"求 1 到 100 的和"举例,我把它拆成几个动作来描述,你能直接照着画出图来。

第一步,起止框"开始"。第二步,处理框sum = 0,这是累加器初始化,绝对不能和下面的i = 1合并成一个框,因为它们是两个独立动作,合并后读者会以为有先后依赖之外的耦合关系。第三步,处理框i = 1,这是计数器初始化。第四步,菱形判断i <= 100。判断为"是",进入循环体:处理框sum = sum + i,处理框i = i + 1,然后一条返回线回到菱形上方。判断为"否",跳出循环,进入输出框"输出 sum",最后是"结束"。

对应的代码就是:

sum_val = 0 i = 1 while i <= 100: sum_val = sum_val + i i = i + 1 print(sum_val)

这里有个必须强调的细节:循环体里那两个处理框的顺序不能颠倒。先累加再自增,和先自增再累加,结果差一个数。在框图上,这两个框是上下关系,顺序写在纸面上,一旦画反了,肉眼非常容易发现;而在代码里,两行挨着,顺序反了可能跑半天才察觉。这也是流程图对新手特别友好的地方。

4.3 嵌套循环的排版技巧

两层循环叠在一起的时候,图会迅速膨胀。我的排版原则是"外层占满整个高度,内层缩在右半边":外层的判断框和返回线走在左侧的主干道上,内层循环整体嵌在右侧的一个矩形区域里,用一条虚线框把内层的起止范围圈出来,旁边加个注释"内层循环"。

还有个好用的小技巧:如果内层循环体特别简单(比如就是一句累加),可以把它折叠成一个处理框,框内文字写成"内层循环:j 从 1 到 n 累加 a[i][j]",然后在旁边用注释框说明细节。这样做牺牲了一点严格性,换来的是整张图还能塞进一页纸。我个人的判断标准是:图超过一页半,就该考虑折叠或者拆分了,因为没人愿意在两张纸之间来回找连接点。

5. 绘图工具怎么选:手绘、画布还是写代码

5.1 三种方式的适用场景对比

方式上手成本修改成本适合场景我的评价
纸笔手绘极低极高(重画)自己理思路、临时讨论速度快,不存档
在线画布工具低低交作业、做汇报、需要导出图片日常主力
代码化绘图中极低图会随需求频繁变更、需要版本管理长期项目首选

纸笔我到现在还在用。开会时讨论一个分支逻辑,直接在白板上画,三分钟对齐认知,比打开软件快得多。缺点是拍下来的照片过两周自己都看不清。

在线画布工具适合出成品,拖拽连线、自动对齐、导出 PNG 或者矢量图都方便,画完的图直接能贴进文档。这类工具最大的价值是"改起来不心疼",挪一个框不用擦掉重画。

代码化绘图是被严重低估的一类。它的核心优势是图和逻辑一起进版本库,需求改了,改几行描述就能重新生成,不用重新拖框。代价是前期得花一两个小时熟悉语法。

5.2 用 dot 语言描述流程图的实操

以 Graphviz 的 dot 语言为例,把前面的成绩判定写成描述文件大致是这样:

digraph grade { rankdir=TB; node [shape=box, fontname="Microsoft YaHei", fontsize=11]; start [label="开始", shape=oval]; input [label="输入 score", shape=parallelogram]; check1 [label="score >= 90 ?", shape=diamond]; check2 [label="score >= 80 ?", shape=diamond]; check3 [label="score >= 70 ?", shape=diamond]; check4 [label="score >= 60 ?", shape=diamond]; a [label="grade = A"]; b [label="grade = B"]; c [label="grade = C"]; d [label="grade = D"]; e [label="grade = E"]; output [label="输出 grade", shape=parallelogram]; end [label="结束", shape=oval]; start -> input -> check1; check1 -> a [label="是"]; check1 -> check2 [label="否"]; check2 -> b [label="是"]; check2 -> check3 [label="否"]; check3 -> c [label="是"]; check3 -> check4 [label="否"]; check4 -> d [label="是"]; check4 -> e [label="否"]; a -> output; b -> output; c -> output; d -> output; e -> output; output -> end; }

几个实际用得上的参数:rankdir=TB控制自上而下,改成LR就是横向;node [shape=box]统一默认形状,然后对个别节点单独覆盖;fontname一定要指定中文字体,不然中文会渲染成方块,这个问题我第一次用的时候卡了半小时才反应过来。汇合线如果想画得整齐,可以给输出节点加group属性,让同一列的节点尽量对齐。

5.3 排版参数:间距、字号、对齐

不管是哪个工具,出图效果好不好,八成取决于这三件事。

字号统一。所有框内文字用同一个字号,最小不低于 10pt,投影演示要 14pt 以上。字号忽大忽小是流程图看起来"业余"的头号原因。

主干垂直、分支水平。所有主流程的框,中心点对齐在同一条垂直线上;分支出去的框,中心点对齐在同一条水平线上。做到这一条,图立刻从"能看"变成"好看"。

间距均匀。框与框的垂直间距保持一致,我一般用框高的 0.6 到 0.8 倍;分支的水平间距也保持一致。手工拖拽的时候,打开网格吸附能省很多事。

6. 常见问题与排查实录

6.1 排版类问题速查

现象根本原因处理办法
线交叉严重,看起来像蜘蛛网分支全往一侧展开左右交替展开,或者引入连接点
图超出一页,看不清全貌主干太长或内层没有折叠拆成子流程,用连接点接续
菱形里的条件读不懂写了长句或复合条件拆成两个菱形,逐个判断
箭头指向混乱有双向箭头或箭头缺失每条线只允许一个方向,必须有箭头
中文显示成方块字体未指定显式设置中文字体

6.2 逻辑类问题速查

现象说明排查动作
程序跑起来死循环循环里缺自增,或返回线指错位置检查返回线是否完整回到判断框入口
某些输入没有输出菱形漏了一个分支每个菱形数一数是不是两条腿
结果差一档边界等号写反把区间表重新对一遍,重点看含不含端点
两个分支结果一样条件写重复了把菱形条件横向排开对比
代码改了图没改图和代码脱节把图放进版本库,改逻辑先改图

6.3 我自己踩过的几个坑

第一个坑是图不跟着代码更新。早些年我习惯在文档里贴一张流程图,然后代码迭代了七八轮,图还是最初那版。后来接手的人照着图理解,直接被带偏。现在的做法是:只要逻辑有改动,先改图,再改代码,图不过关不许动手写。这个顺序反过来其实也成立——先写代码再补图,补的时候你会被迫重新审一遍逻辑,往往能顺手抓出两个问题。

第二个坑是过早追求美观。我见过有人为了把图排得对称,硬是把三个本可以并列的框改成了层层嵌套,逻辑反而变复杂了。排版是为了让人读懂逻辑,逻辑永远优先,图丑一点真的没关系。

第三个坑是在图上写具体语法。有人喜欢在矩形框里写print(f"{name} 的成绩是 {score}")这种带格式化的语句,图是给逻辑看的,这种细节应该留给代码。框里写"输出成绩",注释框里再补充格式要求,这样即使后面换了语言,图也不用改。

最后分享一个我自己一直在用的小习惯:画完图之后,用手指沿着箭头走一遍,从"开始"走到"结束",每走一条路径就念出来"输入分数,判断是不是大于九十,是就输出 A,结束"。念的过程中如果哪一句卡壳了,或者需要回头再看一眼,那个地方就是图没画清楚的地方。这个动作比任何检查清单都管用,一分钟能扫出大部分问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询