|
1、什么是NS图
什么是SI-NS图?要回答这个问题,得首先从什么是NS图说起。
1973年美国学者I.Nassi和B.Shneiderman提出了一种新的流程图形式。在这种流程图中,完全去掉了带箭头的流程线。算法中的顺序、选择和循环都用相应的方块图表示,它的整体结构清晰、可读性特好,并且能保证设计出来的程序是结构化的,因而受到欢迎。这种流程图最先在德国应用比较多,被称为Struktogram。后来在中国和日本,又称为NS图。
以下是用NS图表示的各种算法结构。
(1)顺序结构。顺序结构用图1表示。A和B组成一个顺序结构。
(2)选择结构。选择结构用图2表示。当条件P成立时执行左边的A操作,不成立则执行右边的B操作。
(3)循环结构。循环结构用图3和图4表示。图3表示当型循环,又称先测试循环。即每次循环前先测试一下条件P,当P成立才进入循环体,执行A操作。图4表示直到型循环,又称后测试循环。即每次循环先执行A操作,而后测试一下条件P,直到P成立,退出循环。

由清华大学谭浩强教授编写,发行量超过700万册的《C程序设计》[4]里,几乎每一道例题算法说明都采用了NS图。这里选用了起泡法对10个数排序问题,NS图表示的算法设计和最终的C语言程序如图5所示。

2、NS图的主要问题
NS图的主要问题是它带有长斜线的选择结构,它使得:
(1) 不适宜于计算机处理、显示和打印输出。
(2) 斜线间的条件项不宜过长,否则占据的空间太大,空间效率太低。
它带来的直接后果是,NS图难以包含语言程序的全部信息,难以从语言程序自动生成,存在“图与程序分离”的问题。用NS图创始人Ben Shneiderman自己的话讲, NS图只是一种算法设计形态,只能“在程序设计最初阶段有用”(I believe it is helpful at early stages of program design)。至今我们在各种计算机教材和文献里能见到的NS图应用,主要仍局限于算法设计阶段。
3、什么是SI-NS图
SI-NS图对NS图的部分结构进行了改造。改造后能直接从程序自动生成的NS图,现在称为SI-NS图。
以下图6、图7和图8分别是单重选择、双重选择和多重选择结构的NS图、改造后的SI-NS图,以及用C语言表示的程序逻辑。
4、SI-NS图相对于NS图的优越性
图9是用产品软件“思图程序开发维护工具软件V1.0”将上述气泡法排序C语言程序自动变换生成的SI-NS图。
SI-NS图解决了NS图存在的上述问题,能用工具软件从程序自动生成。它具有NS图结构清晰、可读性特好的优点,同时又保留了程序的全部信息。它不仅是一种算法设计形态,也是一种程序形态。它实际上是NS图和程序两者的统一体。它同时具有的这两个特性使软件工程师不仅对程序的整体结构层次一目了然,有利于整体结构性思维,也能从条件立即找到需要关注问题的细节。
它是程序静态测试中代码审查(Code Inspection)和代码走查(Code Walkthrough)[2],以及程序白盒子测试中基于代码测试(Code-Based Testing)[3]的理想平台,无论是程序测试用例的编写,还是对测试错误结果的分析,面对SI-NS图都变得简单明了。软件工程师甚至无需计算机就可以在SI-NS图上执行和诊断程序。
SI-NS图的应用也不再局限于算法设计阶段,它可以贯穿软件生存周期的软件实现、软件测试、软件交付、软件维护等过程。
5、SI-NS图相对于规范的程序代码优越性
创立了Java语言的美国Sun微系统公司在1997年9月发表过一篇很有影响的名为“Java程序代码规范”的文章[11]。文章一开始就为什么要规范程序代码提出了以下理由:
(1)在一个软件的生命周期里,80%的成本是花在维护中。
(2)很少有软件自始至终一直由它最初的设计者维护的。
(3)规范程序代码可以改善软件的可读性,使软件工程师能更快更好地理解别人提供的程序代码。
(4)如果将源代码视作一件要交付的产品,就应当像对待别的产品一样妥善地整理和包装。
文章观点和提出的上述理由无疑是非常正确的。但细看文章的规范内容,主要指的是文件的命名、注释、缩排以及语句长度等等,而程序形式仍然是一维的文字性程序。其可读性与二维图形化的SI-NS图相差甚远。
为了说明问题,请看一个已按Sun公司要求规范的func1的C代码程序,并注意程序中用红色标记的部分。
void valuestring(CELLPTR cellptr,
double value, char *vstring, int col,
int fvalue, int *color, int formatting)
/* Sets the string representation of a value */
{
char s[81];
char *fstring;
int width, pos;
if (value == HUGE_VAL)
{
strcpy(vstring, MSGERROR);
*color = ERRORCOLOR;
}
else
{
if (formatting)
{
sprintf(vstring, "%1.*f", fvalue & 15,
cellptr->v.value);
if (fvalue & COMMAS)
{
pos = strcspn(vstring, ".");
while (pos > 3)
{
pos
-= 3;
if
(vstring[pos - 1] != '-')
{
movmem(&vstring[pos], &vstring[pos + 1], strlen(vstring) - pos + 1);
vstring[pos] = ',';
}
}
}
if (fvalue & DOLLAR)
{
if (vstring[0] == '-')
{
fstring = " $";
width
= colwidth[col] - 2;
}
else
{
fstring = " $ ";
width
= colwidth[col] - 3;
}
}
else
{
fstring = "";
width = colwidth[col];
}
strcpy(s, vstring);
if (fvalue & RJUSTIFY)
{
if (strlen(vstring) > width)
vstring[width] = 0;
else
sprintf(vstring);
}
else
sprintf(vstring, "%-*s",
width, s);
movmem(vstring, &vstring[strlen(fstring)],
strlen(vstring) + 1);
strncpy(vstring, fstring, strlen(fstring));
}
*color = VALUECOLOR;
}
} /* valuestring */
程序1
一个func1的C代码程序
程序func1不长,不算太复杂,按Sun公司要求缩排也比较整齐。现在请您在看过该程序数秒钟后立即回答以下问题,要求回答必须百分之百正确。
(1)假若程序中红色标记的两个条件(value == HUGE_VAL)和 (formatting)皆不成立,问程序执行什么语句?
(2)指出程序底部那条红色标记的语句“*color = VALUECOLOR;”被执行应满足的条件。
(3)说明程序的整体结构和内部细节。
显然,只看数秒钟就要求立即回答上述问题,并且要求百分之百正确,任何人都难以办到。
以下图10是由上述C语言程序采用“思图程序开发维护工具软件V1.0”变换生成的SI-NS图。
图10由func1的C代码程序生成的SI-NS图
在SI-NS图上回答刚才提出的问题是轻而易举的。
第1个问题,假若条件(value == HUGE_VAL)不成立,以带有v的竖线分界,我们的视线立即落在右边的条件(formatting),如果(formatting)也不成立,则立即去执行右边的“%”,它表示空操作,什么也不干,但接着要去执行最下边一条语句“*color=VALUECOLOR;”。整个判断过程一目了然,论时间至多只需要2秒钟。这是自上而下,从条件到结果的测试。
在程序测试和维护中,还经常要求从一个错误结果找出产生的原因,即反过来自下而上,执行从结果到条件的测试。例如第2个问题,要求指出程序底部那条语句“*color = VALUECOLOR;”被执行应满足的条件。软件工程师只需沿该语句左边的分界线往上看,立即可以找到该语句的执行条件是value不等于HUGE_VAL。整个判断过程仍然不会超过2秒钟。
与文字性程序相比,SI-NS图贵在一目了然。我们能一眼看清楚程序的整体结构、嵌套关系和内部细节。不论自上而下,还是自下而上提出任何问题,都可以在2秒钟之内找到需要关注问题的细节,而且保证百分之百正确。
6、SI-NS图不存在二义性
我们熟知的计算机语言,文法定义中多存在二义性。例如C语言if语句的文法,用EBNF可以定义为:
《if语句》=“if”《条件》《语句》“else”《语句》|“if”《条件》《语句》.
现在考察如下C语句:
if(天晴) if (气温>30度) 去游泳; else 呆在家里看书;
倘若有人针对上述语句问:天下雨干什么?会有二种答案:
一是“呆在家里看书”,二是“什么也不干”。二种答案分别对应二种定义的语句结构:
“呆在家里看书”对应的是if语句前一种语句结构:
if (天晴) { if (气温>30度) 去游泳; } else { 呆在家里看书; }
“什么也不干”对应的是if语句后一种语句结构:
if (天晴) { if (气温>30度) 去游泳; else 呆在家里看书; }
同一个语句可以对应两种不同的语句结构,因此得到两种不同的解释,有两种不同的执行结果,但它们都符合语言所定义的文法,这就是文法的二义性。
二义性对语言来说是不允许的。我们很难想象在执行一条语句时既可能预期这样的结果,又可能预期那样的结果。因此C语言的编译规定了,在将if语句解释翻译为中间代码的时候,else 总是与它前面最近的if匹配。于是上面的if语句只能解释为后一种语句结构,答案也只可能是“什么也不干”,这才避免了C语言的二义性。但是我们不能因此否定C语言文法中实际存在的二义性,也不应低估在阅读程序代码时它给软件工程师带来的困惑。
SI-NS图不存在二义性问题。上述C语句经变换产生的SI-NS图为:
倘若也有人针对该SI-NS图问:天下雨干什么?我们只需从条件“(天晴)”往右下方看,答案是“%”,它表示空操作,“什么也不干”。此外没有第二个答案,绝对不会错看成“呆在家里看书”。
|