复习要点.docx
《复习要点.docx》由会员分享,可在线阅读,更多相关《复习要点.docx(15页珍藏版)》请在冰豆网上搜索。
![复习要点.docx](https://file1.bdocx.com/fileroot1/2022-11/23/4c6a7b91-9352-43cb-abb4-3e5431edb4d4/4c6a7b91-9352-43cb-abb4-3e5431edb4d41.gif)
复习要点
1.后缀表达式转换
表达式之间的转换
这里我给出一个中缀表达式:
a+b*c-(d+e)
第一步:
按照运算符的优先级对所有的运算单位加括号:
式子变成拉:
((a+(b*c))-(d+e))
第二步:
转换前缀与后缀表达式
前缀:
把运算符号移动到对应的括号前面
则变成拉:
-(+(a*(bc))+(de))
把括号去掉:
-+a*bc+de前缀式子出现
后缀:
把运算符号移动到对应的括号后面
则变成拉:
((a(bc)*)+(de)+)-
把括号去掉:
abc*+de+-后缀式子出现
发现没有,前缀式,后缀式是不需要用括号来进行优先级的确定的。
如表达式:
3+(2-5)*6/3
后缀表达式栈
3+
3+(
32+(-
325-+
325-+*
325-6+*/
325-63+*/
325-63/*+
2.时间复杂度空间复杂度计算
时间复杂度指的是算法执行时所用的时间的一个度量,空间复杂度是算法在执行时对所用存储空间的一个度量。
例如,一个有n个元素的数组,每个元素的值为n,n=1,2,...n.如果把每个元素都打印出来,从1到n的时间复杂度就是O(n),如果你是把n个元素依次进栈然后立马出栈,则所需要的空间复杂度就是O
(1)。
你可以在辅导书上看一下这方面的例题,这个知识点不是很难,认真看肯定可以明白的。
2空间复杂度
空间复杂度:
算法所需存储空间的度量,记作:
S(n)=O(f(n))
其中n为问题的规模。
一个算法所需存储空间:
算法本身的存储空间、输入数据的存储空间、算法在运行过程中临时占用的存储空间。
如果额外空间相对于输入数据量来说是个常数,则称此算法是原地工作。
3.某计算机内存按字节编址,内存地址区域从44000H到6BFFFH,共有多少K字节。
若采用16K×4bit的SRAM芯片,构成该内存区域共需多少片。
答案也有了,6BFFFH-44000H+1H=28000H=163840/1024=160K
需要20片
但是不理解为什么要“+1H”,为什么是“163840/1024”呢?
谁能解释一下答案,谢谢了!
补充:
那题中给出的16K×4bit是干吗用的啊?
别的题还有32K×8bit谢谢
4.熊猫烧香
危害程度:
该病毒感染计算机系统后,会主动搜索受感染系统中邮件地址簿列表文件,找到后按照邮件地址逐一向外发送带有该病毒附件的电子邮件,并且在该日删除系统硬盘中的可执行文件(后缀名:
.exe)和动态连接库文件(后缀名:
.dll),造成计算机系统无法正常使用。
CIH属恶性病毒,当其发作条件成熟时,其将破坏硬盘数据,同时有可能破坏BIOS程序,其发作特征
CIH病毒
是:
1、以2048个扇区为单位,从硬盘主引导区开始依次往硬盘中写入垃圾数据,直到硬盘数据被全部破坏为止。
最坏的情况下硬盘所有数据(含全部逻辑盘数据)均被破坏,如果重要信息没有备份,那就只有哭了!
2、某些主板上的FlashRom中的BIOS信息将被清除。
3、v1.4版本每月26号发作,v1.3版本每年6月26号发作,以下版本4月26号发作。
5.软件需求包括3个不同的层次――业务需求、用户需求和功能需求。
除此之外,每个系统还有各种非功能需求。
业务需求(Businessrequirement)表示组织或客户高层次的目标。
业务需求通常来自项目投资人、购买产品的客户、实际用户的管理者、市场营销部门或产品策划部门。
业务需求描述了组织为什么要开发一个系统,即组织希望达到的目标。
使用前景和范围(visionandscope)文档来记录业务需求,这份文档有时也被称作项目轮廓图或市场需求(projectcharter或marketrequirement)文档。
用户需求(userrequirement)描述的是用户的目标,或用户要求系统必须能完成的任务。
用例、场景描述和事件――响应表都是表达用户需求的有效途径。
也就是说用户需求描述了用户能使用系统来做些什么。
功能需求(functionalrequirement)规定开发人员必须在产品中实现的软件功能,用户利用这些功能来完成任务,满足业务需求。
功能需求有时也被称作行为需求(behavīoralrequirement),因为习惯上总是用“应该”对其进行描述:
“系统应该发送电子邮件来通知用户已接受其预定”。
功能需求描述是开发人员需要实现什么。
系统需求(systemrequirement)用于描述包含多个子系统的产品(即系统)的顶级需求。
系统可以只包含软件系统,也可以既包含软件又包含硬件子系统。
人也可以是系统的一部分,因此某些系统功能可能要由人来承担。
6.解释程序也称为解释器,它或者直接解释执行源程序,或者将源程序翻译成某种中间表示形式后再加以执行;
编译程序(编译器)则是将源程序翻译成目标语言程序,然后在计算机上运行目标程序。
两种语言处理程序的根本区别是:
在编译方式下,机器上运行的是与源程序等价的目标程序,源程序和编译程序都不再参与目标程序的执行过程,而在解释方式下,解释程序和源程序(或某种等价表示)要参与到程序的运行过程中,运行程序的控制权在解释程序。
解释器翻译源程序时不生成独立的目标程序,而编译器则将源程序翻译成独立的目标程序。
7.画数据流图应该注意的问题汇总
分类:
软件工程2012-04-2416:
07703人阅读评论(0)收藏举报
存储工作
画数据流图应该注意的问题
数据流图是软件设计师考试必考的题目之一,下面是画数据流图时应该注意的问题,希望对大家有所帮助。
1)适当地为数据流、加工、数据存储、外部实体命名,名字应该反应该成分的实际含义,避免空洞的名字。
2)画数据流而不画控制流
3)一个加工的输出数据流不应与输入数据流同名,即使他们的组成成分相同。
4)允许一个加工有多条数据流流向另外一个加工,也允许一个加工有两个相同的输出数据流流向另外两个不同的加工。
5)保持父图和子图平衡。
也就是说,父图中某加工的输入、输出必须与它的子图的输入、输出数据流在数量和名字上相同。
值得注意的是,如果父图的一个输入(或输出)数据流对应于子图中几个输入或输出数据流,而子图中组成这些数据流的数据项全体正好是父图中的这一个数据流,那么它们仍然算是平衡的。
6)在自顶向下的分解过程中,若一个数据存储首次出现时只与一个加工有关,那么这个数据存储应作为这个加工的内部文件而不必画出。
7)保持数据守恒。
也就是说,一个加工所有输出数据必须能从该加工的输入数据流中直接获得,或者是通过该加工能产生的数据。
8)每隔加工必须既有输入数据流也有输出数据流。
9)在整套数据流图中,每隔数据存储必须既又读的数据流,又有写的数据流。
但在某一张子图中可能只有读没有写,或者只有写没有读。
四、画分层数据流图时应注意的问题
下面从四个方面讨论画分层数据流图时应注意的问题。
1.合理编号
分层数据流图的顶层称为0层,称它是第1层的父图,而第1层既是0层图的子图,又是第2层图的父图,依此类推。
由于父图中有的加工可能就是功能单元,不能再分解,因此父图拥有的子图数少于或等于父图中的加工个数。
为了便于管理,应按下列规则为数据流图中的加工编号:
l子图中的编号为父图号和子加工的编号组成。
l子图的父图号就是父图中相应加工的编号。
为简单起见,约定第1层图的父图号为0,编号只写加工编号1、2、3...,下面各层由父图号1、1.1等加上子加工的编号1、2、3...组成。
按上述规则,图的编号即能反映出它所属的层次以及它的父图编号的信息,还能反映子加工的处理信息。
例如1表示第1层图的1号加工处理,1.1、1.2、1.3...表示父图为1号加工的子加工,1.3.1、1.3.2、1.3.3...表示父图号为1.3加工的子加工。
为了方便,对数据流图中的每个加工,可以只标出局部号,但在加工说明中,必须使用完整的编号。
例如图5-4-5可表示第1层图的1号加工的子图,编号可以简化成图中的形式。
图5-4-5简化子图编号示例
2.注意子图与父图的平衡
子图与父图的数据流必须平衡,这是分层数据流的重要性质。
这里的平衡指的是子图的输入、输出数据流必须与父图中对应加工的输入、输出数据流相同。
但下列两种情况是允许的,一是子图的输入/输出流比父图中相应加工的输入/输出流表达得更细。
例如,在图5-4-6中,若父图的“订货单”数据流是由客户、品种、帐号、数量四部分组成,则图中的子图和父图是平衡的。
在实际中,检查该类情况的平衡,需借助于数据词典进行。
二是考虑平衡时,可以忽略枝节性的数据流。
例如图5-4-6,在4号加工的子图中4.3号子加工中增加了一个输出,表示出错的数据流(由虚线所示),则子图和父图仍可看作是平衡的。
图5-4-6子图和父图的平衡图片子图和父图的平衡动画
3.局部文件
图5-4-7中的父图和子图是平衡的,但子图中的文件W并没在父图中出现。
这是由于对文件W的读、写完全局限在加工3.3之内,在父图中各个加工之间的界面上不出现,该文件是子图的局部文件或为临时文件。
图5-4-7数据流图中的局部文件
应当指出的是,如果一个临时文件在某层数据流图中的某些加工之间出现,则在该层数据流图中就必须画出这个文件。
一旦文件被单独画出,那么也需画出这个文件同其它成分之间的联系。
4.分解的程度
对于规模较大的系统的分层数据流图,如果一下子把加工直接分解成基本加工单元,一张图上画出过多的加工将使人难以理解,也增加了分解的复杂度。
然而,如果每次分解产生的子加工太少,会使分解层次过多而增加作图的工作量,阅读也不方便。
经验表明,一般说来一个加工每次分解量最多不要超过七个为宜。
同时,分解时应遵循以下原则:
l分解应自然,概念上要合理、清晰。
l上层可分解的快些(即分解成的子加工个数多些),这是因为上层是综合性描述,对可读性的影响小。
而下层应分解得慢些。
l在不影响可读性的前提下,应适当地多分解成几部分,以减少分解层数。
l一般说来,当加工可用一页纸明确地表述时,或加工只有单一输入/输出数据流时(出错处理不包括在内),就应停止对该加工的分解。
另外,对数据流图中不再作分解的加工(即功能单元),必须作出详细的加工说明,并且每个加工说明的编号必须与功能单元的编号一致。
8.软件复杂性主要表现在程序的复杂性。
程序的复杂性主要指模块内程序的复杂性。
软件复杂性的度量方法有:
1、代码行度量法:
以源代码行数作为程序复杂性的度量。
2、McCabe度量法:
一种基于程序控制流的复杂性度量方法。
9.
C++中多态性的实现方式
多态性是面向对象程序设计的一大支柱,它指的是在基类中定义的属性或服务被派生类继承之后,可以表现出不同的行为.也就是指一段程序能够处理不同类型对象的能力.在面向对象程序设计语言C++中,这种多态性的实现方式有4种,分别是强制多态、重载多态、类型参数化多态和包含多态.其中,类型参数化多态和包含多态称为一般多态性,用来系统地描述语义上相关的一组类型;强制多态和重载多态称为特殊多态性,用来描述语义上无关联的类型间的关系.
下面详细介绍这4种多态性的具体应用.
1 包含多态
在C++中公有继承关系是一种包含关系.派生类直接公有继承基类定义中的属性或服务,如果1个程序段既能处理基类的对象也能处理基类的派生类的对象,该程序段称为多态程序段.C++采用虚函数实现包含多态.一个函数一旦声明为虚函数,在编译阶段,编译器并不按照它的静态类型为它生成调用此函数的版本,而只为它生成虚函数表(表中存放与此函数同名、同参数、同返回值的虚函数的地址).在程序运行时,再根据实际对象的类型,查虚函数表,找出相应版本的函数后,才能使用它.因此,这种不是在编译阶段而是在运行阶段动态确定应使用哪一个虚函数的方式叫动态束定.
要把一个函数声明为虚函数,只要在原函数的声明之前加上virtul关键字即可.利用虚函数进行动态束定,必须用指向基类的指针或引用来访问它,这是因为C++是类型系统,在编译阶段,C++的变量名或函数名就与相应的存储单元联系起来,使用名字也就是使用对应的存储单元.这有利于检查类型系统,并可产生高效代码.但这种类型的限制缺乏灵活性,不能在运行时改变名字的含义,然而多态要求在不同的上下文中,同一名字有多种含义,C++引入虚函数的目的是告诉编译器在运行时才能确定要调用哪一个虚函数.为了把变量名与相应的存储单元分开,它用指针来调用虚函数.这样,只要改变指针所存地址的值,也就间接地改变了调用对象.例:
#include
classPoint //定义基类Point
{private:
floatx,y;
public:
Point(){};
Point(floati,floatj)
{x=i;
y=j;}
virtulfloatarea() //声明为虚函数
{return0.0;}};
constfloatPi=3.141593;
classCircle:
publicPoint //定义派生类Circle
{ private:
floatradius;
public:
Circle(floatr)
{radius=r;}
virtulfloatarea()
{returnPi3radius3radius;}};
voidmain()
{ Point3pp; //指向基类的指针pp
Circlec(5.4321);
pp=&c;
cout<area()<从上面例子可看出,利用虚函数可在基类和派生类中使用相同的函数名定义函数的不同实现,从而实现“一个接口,多种方式”.一般说来,外部函数不能声明为虚函数,成员函数(除构造函数)都可以声明为虚函数.然而,在处理虚函数时,要动态确定应该选用哪一版本函数,故它比标准函数需要更多的存储空间.因此,虚函数仅用于处理派生类中一系列同名、同参数和同返回值的函数.
2 类型参数化多态
类型参数化多态是指当1个函数(或类)对若干个类型参数操作时,这些类型具有某些公共的语义特性,可以用该函数(或类)来描述这些公共语义特性.C++中的模板是实现类型参数化多态的工具,分为类模板和函数模板.
2.1 类模板
一个类模板可以表示一组类.下面是一个通用栈类,它可以存放整数、字符或类对象.
#include
templateclassstack //stack类模板
{T3v;
T3p;
intsz;
public:
stack(ints){v=p=newT[sz=s];}
~stack(){delete[]v;}
voidpush(Ta){3p++=a;}
Tpop(){return322p;}
intsize()const{returnp2v;}}
voidmain()
{stacksch(20); //stack类模板用char实例化后创建对象
stacksi(20); //stack类模板用int实例化后创建对象
sch.push(’a’);
si.push(10);
}
其中,stack类模板中带有一个类型参数T,表示栈中存放对象的类型,它不是实际类型,因此不能用类模板直接生成实例对象.通过对类模板的实例化(即给类模板的参数指定具体类型的过程),类模板实例化后的结果是类而不是实例对象,因此可用类模板实例化后的结果类产生实例对象.在main()函数中,从stack类模板实例化了两个模板类:
stack和stack,然后又由这两个模板类分别实例化各自对象:
sch和si.
2.2 函数模板
与类模板相似,可以定义操纵一组类型的函数.下面定义了一个求两对象间的最大值的函数模板.
templateTmax(Ta,Tb){returna>b?
a:
b;}
该函数模板可以求int,char,float指针或任何重载了>运算符的类对象间的最大值.函数模板也要实例化,实例化后就生成了具体的函数代码(即特定于参数的类型),与类模板不同的是,它的实例化不需要用户显式进行,而是在函数调用时由编译器来处理.例如:
inta,b;
charc,d;
intm1=max(a,b); //调用max(inta,intb);
intm2=max(c,d); //调用max(charc,chard);
事实上,函数模板表示了一组名字相同的函数,这些函数之间以及这些函数与其它同名函数之间是重载函数的关系.在使用函数模板时,应保证函数的参数与模板函数的参数正好相配,因为编译器不会给模板函数的参数提供任何形式的转换.
总之,模板描述了一组类或一组函数,避免了为各种不同的数据类型进行重复的编码工作.
3 重载多态
重载是多态性中最简单的形式.它是指用同一名字表示不同的函数或运算符,从而使C++具有更大的灵活性和扩展性.它分为运算符重载和重载函数两种.
3.1 重载函数
重载函数是指同一作用域内名字相同、但参数不同的函数.例如:
#include
intfunc(intx,inty){returnxy:
x;}
floatfunc(floatx,floaty){returnxy:
x;}
doublefunc(doublex,doubley){returnxy:
x;}
voidmain()
{intn1=8,n2=10;
cout<<“themaxis:
”< floatm1=4.3,floatm2=2.6;
cout<<“themaxis:
”< doublef1=2.0,f2=4.9;
cout<<“themaxis:
”<运行结果为:
themaxis:
10
themaxis:
4.3
themaxis:
4.9
上述3个函数,函数名相同,函数参数不同,因为编译器是根据参数来识别重载函数,所以必须保证重载函数的参数有所不同,即两重载函数必须具有以下两种差别之一才能分辨.
(1)函数的参数个数不同;
(2)一个或多个参数的类型不同.
3.2 运算符重载
C++的基本类型(int,char,float等以及它们的派生类型)既能描述数据的存储格式,又能描述施加在数据上的操作,这种操作用运算符来指定.在基本类型中运算符都按系统预定义好的方式来工作.
为了使用户定义的类型与基本类型一样,C++也允许用户定义类型使用运算符来表示操作.实质上,运算符可以看成是一种函数,即运算符函数,只是对于基本类型,函数都是编译器给定的,不能加以改动.但对于类对象,用户却可以重新定义运算符函数,以便设置运算符在类对象中新的含义.因此,定义运算符在某类对象操作的做法即所谓的运算符重载.
运算符函数可以是类的成员函数,也可以是非成员函数,如果是非成员函数,一般将它声明为该类的友员.例:
classcomplex //复数类
{//...
public:
Complexoperator+(constComplex&com)
{Complextemp(rpart+com.rpart,ipart+com.ipart);
returntemp;}
//...};
运算符函数operator+被定义为公有的,程序中的其它函数可以调用它,在定义了该函数之后,就可以像基本类型一样对复数对象用+表达式实施运算.当程序中有语句
Complexa(10,7),b(3,5),c;
c=a+b;
时,C++编译器把表达式a+b解释为函数调用a.operator+(b),在调用时,operator+成员函数首先创建一个临时Complex类对象temp,然后把出现在加法表达式中的两个复数之和暂存其内,最后将这个临时对象返回.
4 强制多态
强制也称类型转换,是指将一种类型的值转换成另一种类型的值而进行的语义操作,从而防止类型错误.类型转换可以是隐式的,在编译阶段完成;也可以是显式的,在运行阶段完成.
4.1 基本数据类型之间的类型转换
C++定义了基本数据类型之间的转换原则,即
charshortintunsignedlongunsignedlongfloatdoublelongdouble
低高
当两个操作对象类型不一致时,在算术操作之前级别低的自动转换成级别高的类型.
上述规则不适用于赋值操作.当赋值运算符右端的类型与左端的类型不同时,右端的值要转换成左端类型,然后将转换后的值赋值给左端.
类型转换可以使用下面3种强制类型转换表达式,从而可以改变编译器所使用的规则,可以按程序员自己的意愿进行所需的类型转换.
(1)static-cast(E);
(2)T(E);
(3)(T)E;
其中,E表示一个运算表达式,T表示一个类型表达式,第三种表达式是C语言中所使用的风格,在C++中,建议不要使用,应选择使用第一种形式.例如:
设对象f的类型为double,且其值为5.26,则表达式static-cast(f)的值为5,类型为int.
4.2 用户定义类型的转换
着重介绍类类型与其它数据类型之间的转换.
(1)在C++中,把其它数据类型转换成类对象是通过转换构造函数来完成的.要求的前提是此类的转换构造函数是只带1个非缺省参数的构造函数.
(2)把类对象转换成其它数据类型是通过转换运算符函数来完成的.它是一种类似显示类型转换的机制,它的设计需要注意两点:
第一,转换运算符函数必须