伪代码(Pseudocode)是一种算法描述语言。使用伪代码的目的是为了使被描述的算法可以容易地以任何一种编程语言(Pascal,C,Java,etc)实现。因此,伪代码必须结构清晰、代码简单、可读性好,并且类似自然语言。 介于自然语言与编程语言之间。
它以编程语言的书写形式指明算法的职能。相比于程序语言(例如Java, C++,C, Dephi 等等)它更类似自然语言。它是半角式化、不标准的语言。我们可以将整个算法运行过程的结构用接近自然语言的形式(这里,你可以使用任何一种你熟悉的文字,中文,英文 等等,关键是你把你程序的意思表达出来)描述出来. 使用伪代码, 可以帮助我们更好的表述算法, 不用拘泥于具体的实现.
人们在用不同的编程语言实现同一个算法时意识到,他们的实现(注意:这里是实现,不是功能)很不同。尤其是对于那些熟练于不同编程语言的程序员要理解一个(用其他编程语言编写的程序的)功能时可能很难,因为程序语言的形式限制了程序员对程序关键部分的理解。这样伪代码就应运而生了。
当考虑算法功能(而不是其语言实现)时,伪代码常常得到应用。计算机科学在教学中通常使用虚拟码,以使得所有的程序员都能理解。
综上,简单的说,让人便于理解的代码。不依赖于语言的,用来表示程序执行过程,而不一定能编译运行的代码。在数据结构讲算法的时候用的很多。
语法规则
例如,类Pascal语言的伪代码的语法规则是: 在伪代码中,每一条指令占一行(else if,例外)。指令后不跟任何符号(Pascal和C中语句要以分号结尾)。书写上的“缩进”表示程序中的分支程序结构。这种缩进风格也适用于if-then-else语句。用缩进取代传统Pascal中的begin和end语句来表示程序的块结构可以大大提高代码的清晰性;同一模块的语句有相同的缩进量,次一级模块的语句相对与其父级模块的语句缩进。
算法的伪代码语言在某些方面可能显得不太正规,但是给我们描述算法提供了很多方便,并且可以使我们忽略算法实现中很多麻烦的细节。通常每个算法开始时都要描述它的输入和输出,而且算法中的每一行都给编上号码,在解释算法的过程中会经常使用算法步骤中的行号来指代算法的步骤。算法的伪代码描述形式上并不是非常严格,其主要特性和通常的规定如下:
1) 算法中出现的数组、变量可以是以下类型:整数、实数、字符、位串或指针。通常这些类型可以从算法的上下文来看是清楚的,并不需要额外加以说明。
2) 在算法中的某些指令或子任务可以用文字来叙述,例如,”设x是A中的最大项”,这里A是一个数组;或者”将x插入L中”,这里L是一个链表。这样做的目的是为了避免因那些与主要问题无关的细节使算法本身杂乱无章。
3) 算术表达式可以使用通常的算术运算符(+,-,*,/,以及表示幂的^)。逻辑表达式可以使用关系运算符=,≠,<,>,≤和≥,以及逻辑运算符与(and),或(or),非(not)。
4) 赋值语句是如下形式的语句:a<-b 。
这里a是变量、数组项,b是算术表达式、逻辑表达式或指针表达式。语句的含义是将b的值赋给a。
5) 若a和b都是变量、数组项,那么记号a<->b 表示a和b的内容进行交换。
6) goto语句具有形式
goto label(goto标号)
它将导致转向具有指定标号的语句。
7) 条件语句有以下两种形式:
if c then s或者
if c then s
else s′
if i=10 then xxxx else xxxx //else 和 then 要对齐 //或者 if i=10 then xxxx //if 后面必定跟上then,else后面不用跟then elseif i=9 //elseif 要连在一起写 then xxxx yyyy else xxxx //else 跟在 elseif 的 then 对齐
这里c是逻辑表达式,s和s′是单一的语句或者是被括在do和end之间的语句串。对于上述两种形式,假若c为真,则s被执行一次。假若c为假,则在第一种形式中,if语句的执行就完成了,而在第二种形式中,执行s′。在所有的情况下,控制就进行到了下一个语句,除非在s或s′中的goto语句使控制转向到其它地方。
8) 有两种循环指令:while和for。
while语句的形式是
while c do
s
end
while time<10 do xxxxx //while后面必定要紧跟缩进的do xxxxx end
这里c是逻辑表达式,而s是由一个或更多个语句组成的语句串。当c为真时,执行s。在每一次执行s之前,c都被检查一下;假若c为假,控制就进行到紧跟在while语句后面的语句。注意,当控制第一次达到while语句时,假若c为假,则s一次也不执行。
for语句的形式是
for var init to limit by incr do
s
end
for var init to limit by incr do s end
这里var是变量,init、limit和incr都是算术表达式,而s是由一个或多个语句组成的语句串。初始时,var被赋予init的值。假若incr≥0,则只要var≤limit,就执行s并且将incr加到var上。(假若incr<0,则只要var≥limit,就执行s并且将incr加到var上)。incr的符号不能由s来该改变。
9) exit语句可以在通常的结束条件满足之前,被用来结束while循环或者for循环的执行。exit导致转向到紧接在包含exit的(最内层)while或者for循环后面的一个语句。
10) return用来指出一个算法执行的终点;如果算法在最后一条指令之后结束,它通常是被省略的;它被用得最多的场合是检测到不合需要的条件时。return的后面可以紧接被括在引号的信息。
11) 算法中的注释被括在/* */之中。诸如read和output之类的各种输入或者输出也在需要时被用到。
伪代码实例
伪代码只是像流程图一样用在程序设计的初期,帮助写出程序流程。简单的程序一般都不用写流程、写思路,但是复杂的代码,最好还是把流程写下来,总体上去考虑整个功能如何实现。写完以后不仅可以用来作为以后测试,维护的基础,还可用来与他人交流。但是,如果把全部的东西写下来必定可能会让费很多时间,那么这个时候可以采用伪代码方式。比如:
IF 九点以前 THEN
do 私人事务;
ELSE 9点到18点 THEN
工作;
ELSE
下班;
END IF
这样不但可以达到文档的效果,同时可以节约时间. 更重要的是,使结构比较清晰,表达方式更加直观.
下面介绍一种类Pascal语言的伪代码的语法规则。
在伪代码中,每一条指令占一行(else if 例外,),指令后不跟任何符号(Pascal和C中语句要以分号结尾);
书写上的“缩进”表示程序中的分支程序结构。这种缩进风格也适用于if-then-else语句。用缩进取代传统Pascal中的begin和end语句来表示程序的块结构可以大大提高代码的清晰性;同一模块的语句有相同的缩进量,次一级模块的语句相对与其父级模块的语句缩进;
在伪代码中,通常用连续的数字或字母来标示同一即模块中的连续语句,有时也可省略标号。
符号△后的内容表示注释;
在伪代码中,变量名和保留字不区分大小写,这一点和Pascal相同,与C或C++不同;
在伪代码中,变量不需声明,但变量局部于特定过程,不能不加显示的说明就使用全局变量;
赋值语句用符号←表示,x←exp表示将exp的值赋给x,其中x是一个变量,exp是一个与x同类型的变量或表达式(该表达式的结果与x同类型);多重赋值i←j←e是将表达式e的值赋给变量i和j,这种表示与j←e和i←e等价。
例如:
x←y
x←20*(y+1)
x←y←30
以上语句用C分别表示为:
x = y;
x = 20*(y+1);
x = y = 30;
选择语句用if-then-else来表示,并且这种if-then-else可以嵌套,与Pascal中的if-then-else没有什么区别。
例如:
if (Condition1)
then [ Block 1 ]
else if (Condition2)
then [ Block 2 ]
else [ Block 3 ]
循环语句有三种:while循环、repeat-until循环和for循环,其语法均与Pascal类似,只是用缩进代替begin – end;
例如:
1. x ← 0
2. y ← 0
3. z ← 0
4. while x < N
1. do x ← x + 1
2. y ← x + y
3. for t ← 0 to 10
1. do z ← ( z + x * y ) / 100
2. repeat
1. y ← y + 1
2. z ← z – y
3. until z < 0
4. z ← x * y
5. y ← y / 2
上述语句用C或C++来描述是:
x = y = z = 0;
while( z < N )
{
x ++;
y += x;
for( t = 0; t < 10; t++ )
{
z = ( z + x * y ) / 100;
do {
y ++;
z -= y;
} while( z >= 0 );
}
z = x * y;
}
y /= 2;
数组元素的存取有数组名后跟“[下标]”表示。例如A[j]指示数组A的第j个元素。符号“ …”用来指示数组中值的范围。
例如:
A[1…j]表示含元素A[1], A[2], … , A[j]的子数组;
复合数据用对象(Object)来表示,对象由属性(attribute)和域(field)构成。域的存取是由域名后接由方括号括住的对象名表示。
例如:
数组可被看作是一个对象,其属性有length,表示其中元素的个数,则length[A]就表示数组A中的元素的个数。在表示数组元素和对象属性时都要用方括号,一般来说从上下文可以看出其含义。
用于表示一个数组或对象的变量被看作是指向表示数组或对象的数据的一个指针。对于某个对象x的所有域f,赋值y←x就使f[y]=f[x],更进一步,若有f[x]←3,则不仅有f[x]=3,同时有f[y]=3,换言之,在赋值y←x后,x和y指向同一个对象。
有时,一个指针不指向任何对象,这时我们赋给他nil。
函数和过程语法与Pascal类似。
函数值利用 “return (函数返回值)” 语句来返回,调用方法与Pascal类似;过程用 “call 过程名”语句来调用;
例如:
1. x ← t + 10
2. y ← sin(x)
3. call CalValue(x,y)
参数用按值传递方式传给一个过程:被调用过程接受参数的一份副本,若他对某个参数赋值,则这种变化对发出调用的过程是不可见的。当传递一个对象时,只是拷贝指向该对象的指针,而不拷贝其各个域。
——————我是分割线——————下方解释可能更容易理解伪代码————————
伪代码是很像编程语言但又不是真正的编程语言的一种文本。伪代码提供了代码实现算法过程中会用到的结构和细节,同时又不与某种特定的编程语言联系在一起。希望你能把这些伪代码翻译成真正的代码,然后在你的计算机上执行。
下面的代码片段展示了计算两个整数的最大公约数(GCD)算法的伪代码示例:
取模操作
取模操作,在伪代码中写作Mod。它意味着整除之后的余数。比如说,13 Mod 4=1。因为13被4除,商是3,余数是1。
伪代码以一个注释开头。注释以字符“//”开始然后延伸到这一行的结束。
代码实际的第一行是算法的声明。这个算法叫做Gcd(最大公约数),它返回了一个整数结果。它有两个名为a和b的整数参数。
注 执行一个任务或者有选择地返回一个结果的一块代码称为例程、子例程、方法、过程、子过程或者函数。
声明之后的代码缩进以显示它是方法的一部分。方法主体的第一行以一个While循环开始。
只要While语句的条件保持为真,While下缩进的代码就会被执行。
While循环在End While语句处结束。End While语句并不是严格需要的,因为缩进显示了循环结束的地方,但是它(End While)提醒了什么样的语句块将要结束。
这个方法在Return语句处退出。这个算法返回了一个数值,所以这个Return语句表明了该算法应该返回哪个值。如果这个算法没有返回任何数值,例如,如果其目的是排列数值或者建立一个数据结构,那么Return语句执行后就没有任何返回值。
这个例子中的伪代码非常接近于实际的编程代码。其他的例子可能包含自然语言描述的指令和数值,这种情况下,指令用尖括号(< >)括起来,以表示需要把这些自然语言形式的指令翻译成程序代码。
通常,当声明一个参数或变量时(在Gcd算法中, 这包括参数a和b以及变量remainder),会在它前面给出数据类型,数据类型后面跟着一个冒号,如Integer: reminder。对于简单的整形循环变量,数据类型可能会被省略,如For i = 1 To 10。
伪代码不同于某些编程语言的另一个特点是它的For循环可能包含一个Step语句,用以表明循环变量每个循环后改变的数值。For循环以Next i语句结尾(i是循环变量),用来提醒你哪一个循环结束了。
例如,请思考下列的伪代码:
本书中用的伪代码使用If-Then-Else语句、Case语句和其他需要的语句。从对于真正编程语言的了解来看,读者应该很熟悉这些语句。伪代码需要的别的东西都用英语阐明。
链表(List)是一个对你来说可能不熟悉的基础数据结构。链表类似于一个自我扩展的数组。它提供了一个Add方法让用户向链表的末尾添加元素。下面的伪代码建立了一个包含数字1到10的整数链表:
在链表被初始化之后,伪代码可以像普通数组一样使用它并从链表的任意位置获取元素。与数组不同的是,链表也允许你在任何位置添加或删除元素。
本书中的许多算法被写成返回一个结果的方法或函数。方法声明的开头是结果的数据类型。如果一个方法执行了一些任务而没有返回一个结果,那么它就没有数据类型。
下列的伪代码包含了两个方法:
DoubleIt方法接受一个整数作为参数然后返回了一个整数值,这段代码加倍了输入值并返回了结果。
DoSomething方法接受一个叫做value的整数数组作为参数,它执行了一个任务但是没有返回结果。例如,它可能会随机化或排列数组中的元素。(注:本书假定数组从下标0开始。例如,一个有三个元素的数组有下标0、1、2。)
伪代码应该是很直观并易于理解的,但是伪代码存在一个问题:没有任何编译器来检测错误。作为对基础算法的检测,本书同时给你一些实际的代码作为参考,C#实现的算法和许多练习可以在本书的网站上下载。