计算机研究生复试面试题目

Q:堆排序与快排的区别
A: 相同点:平均时间均为o(nlogn)。
不同点:堆排最坏情况为o(nlong),快排最坏为o(n^2)。空间堆排o(1),快排o(logn)。

Q:c语言栈溢出的一个例子/c语言没有可靠性检查(栈溢出)
A:在一个过程A中分配了一个数组,数组的数据存储在栈上,将这个数组名传入到另一个过程B中,这时数组退化为指针,并在过程B中写该指针,若超出这个指针范围,那么就会使得返回地址被覆盖。插入金丝雀值检测栈是否被修改。

Q:c语言程序优化
A:利用栈变量加快执行速度。循环展开利用流水线能力,多个累积变量,

Q:存储器山(访问步长,数据集大小)
A:

Q:const和volatile
A:const全局无法修改,被const修饰的局部变量仍然是变量,存储于栈上,并不是真正的常量,并没有存储在只读区。const只是告诉编译器这个常量后面不能跟一个=号。真正存在常量区的是char*s= “ asdasd”,所以const的值是可以被改变的,只是需要通过其他方式。

Q:一个参数既可以是const还可以是volatile吗?解释为什么
A:是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。

Q:解释volatile
A:被volatile修饰的变量,要求每次在读这个变量,需要小心地从内存中读取,而不是从寄存器去取。这使得在多线程环境下,任意一个线程修改了这个值,别的线程就能立即发现,并使用这个新值。

Q:alloc函数与malloc函数,
A:alloc在栈上分配,malloc在堆上分配。

Q:malloc(0),malloc(-1)
A:仍然都能能够返回一个可访问的指针,具体原因未知。

Q:malloc函数会内存泄露吗?
A:不会的。

Q:数组名与指针的区别
A:数组名不能够自增自减(a+1是正确的,数组名可理解为常量),指针能够自动加减并且按照其数据类型进行缩放。sizeof(数组名)返回数组空间按字节计算,对指针使用则是返回固定指针字节值。当数组名作为参数传递给函数时,退化为指针。数组只能被分配在静态区或栈上,指针可以指向任何一个地方。

Q:float类型如何与0比较是否相等
A:定义任意一个精度范围,用if(a<= && a>=)。推广对任意浮点数进行比较时应该使用abs(a-b) <= eps;这样的方法来判断。

Q:ifndfe的作用
A:避免头文件重复展开。

Q:“file.h”与的区别
A:“file.h”编译器从用户目录寻找文件,则是从标准库中寻找文件。

Q:#define与type def的区别
A:如#define DPS struct S*,DPS s1,s2;其中s2是结构,s1则是一个结构体指针。

Q:c语言结构体如何比较
A:memcmp进行内存上的比较

Q:可以用free去释放掉用new申请的内存吗?
A:这么做并不会出错,用free依然能够释放掉内存,但因为free是一个函数不是运算符,因此无法调用对象的析构函数。

Q:c语言可变参数列表
A:在函数形参表中用三个…表示可变参数。使用va_list的一组宏取出参数。

Q:#define与const的区别
A:对于define编译器只是简单的替换,而const具有数据类型,编译器可以据此对const变量进行安全检查。

Q:typecast一个整数使其成为一个地址
A:int p; p = (int)0x1008;

Q:static局部变量,全局变量,函数
A:static局部变量只被初始化一次,在随后使用该函数的过程中,总是保持上次的值,作用域被限制在这个函数体内部。static全局变量仅仅只在本文件内部有效,对其他文件不可见。全局变量与static全局变量的区别在于全局变量对所有其他文件是可见的。statci函数同理。

Q:strcp为什么要返回一个char*
A:为了方便链式计算,例如strlen(strcp)。strcp是以’\0’计算结尾。

Q:函数体返回一个用malloc生成的指针的做法正确吗?
A:这样做法是极不正确的,因为这会导致内存泄漏,因为被调用者无法保证调用者能够及时释放掉内存。

A:野指针无法通过NULL来判断,因为野指针会指向一个随机值。

A:静态区会初始化值为0,而堆栈区则不会对值进行初始化。

A:短小且经常调用的函数应该被写成宏函数,c++中则应该是inline

A:运算符优先级()>[]>*,因此 *(a ++)[5] 应该被翻译为 a[6][0];

A:二维数组传递参数的正确方式,f(int a[][5]),f(int (*a)[5]);

A:为什么不能把p直接指向二维数组,这是因为二维数组在内存中的存储实际上仍然是连续,不是以前自己动态分配那样,一个p指向两个*p,*p再指向int。

A:asser断言宏函数两种形式
assert Expression1,assert Expression1:Expression2

Q:在什么情况下快排为o(n^2)?
A:当代排关键字有序或基本有序时,快排退化为冒泡排序,为o(n^2)。假设一个有序的长度为n的关键字序列,那么每次partition的子序列,将总是划分成一个长度为1的子序列,和另一个长度为n-1的子序列。

Q:无限制的使用malloc会导致程序崩溃么
A:it depends, 如果这个程序是运行在一个拥有虚拟内存的操作系统上,内存不会消耗完,因为它会使用硬盘顶替堆。

Q:B+与B-树的区别
A:B+树所有数据都存在叶子结点上且叶子结点按顺序存储,而B-树不是这样,因此在查找时,B+树上的每一次查找都是走了一条从根到叶子结点的路径。同时也因为这样的特性,使得B+树有两种查找,一种是从根节点开始的随机查找,一种是从最小关键字开始的顺序查找。B+树比B-树更适合文件系统和数据库索引。因为B+树内部结点可以不包含其他信息,仅仅存储关键字值,存储空间比B-树消耗的少。同时在范围查询时,B+树明显优于B树,B-树需要中序遍历,而B+树则不用这样,因为它的叶节点是有序的。
B+树vsB-树,聚集索引vs非聚集索引
结论聚集索引就是B+树

Q:平衡二叉树(o(logn))与B+树。
A:操作系统中磁盘管理系统的基本单位是盘块,而文件系统的基本单位是簇(Cluster)。即使我们只需要这个簇上的一个字节的内容,也要把一整个簇上的内容读完。而B+树的每一个结点之所以会被设计为包含多个关键字,一方面是为了减少树的层数,另一方面也是为了尽可能的让一个结点充满簇,避免浪费。反观平衡二叉树,一个父结点仅连接两个左右孩子,树的深度远远大于B+树。并且在物理存储上是极不规整的。

Q:50W数据如何排序
A:外部排序需要多次I/O读写操作,I/O操作随着归并的趟数增多而增多。归并的趟数s则由m和k决定。s = logkm。单纯的增加k会增加内部归并的时间,因为在k个关键字中求最小关键字需要进行k-1次比较,为得到u个有序记录需要进行(u-1)(k-1)次比较。随着k的增大,内部归并时间也会增大,将会抵消掉由于增大k而减少外存信息读写时间所得效益。因此需要制定一个数据结构败者树减少内部排序时间,败者树中选择出一个最小关键字记录所需log2k次比较。置换选择排序优化m

Q:什么是稳定排序和不稳定排序?
A:设一个含n个记录的序列为{r1,r2,r3,…rn},其对应的关键字序列{k1,k2,k3….kn}。假设存在ki=kj,且在排序前ri领先于rj。若在排序之后,ri仍然领先于rj,则称排序方法是稳定的,否则则是不稳定的。

Q:什么是二叉查找树?
A:二叉查找树是一个递归定义的树形数据结构。1.若左子树不空,则所有左子树节点的值均小于根节点。2.右子树同理。3.左右子树均为二叉排序树。在这样的定义之上,能够制定出一个高效快速的查找关键字的算法。略

Q:什么是哈夫曼树?
A:设有n个权值{w1,w2,w3,w4…,wn},用这样的权值做节点值去构造一颗二叉树。在所有这样的树中,树的带权路径长度最小的二叉树,就是哈夫曼树。

Q:什么是带权路径长度?
A:从树中一个节点到另一个节点之间的分支构成这两个节点之间的路径,路径上的分支数目称为路径长度树的路径长度是从树根到每一个节点的路径长度之和。

Q:图的深度优先遍历
A:若用邻接矩阵存储图,深度遍历复杂度为o(n^2)。若用邻接表存储图,深度遍历负载度为o(n+e)。

Q:解释生成树
A:联通图的生成树是一个极小联通子图,它含有图中所有顶点,但只有足以构成一棵树的n-1条边。若在一颗生成树上添加一条边,必定会构成一个环。但是有n-1条边的图不一定就是生成树。现为图中的边赋予权值,设n个权值{w1,w2,w3,w4……wn}。使用这些含权值的边构造生成树,在所有生成树中,权值之和最小的生成树,就是最小生成树。

Q:解释虚拟内存
A:虚拟内存打破需要程序一次性全部装入才能运行的限制,之所以可以这么做是基于两个原理,时间局部性原理和空间局部性原理。为了实现虚拟内存,需要硬件上的支持和软件上的支持。硬件上需要缺页中断机构,地址翻译机构。软件上需要制定页面置换算法。因为虚拟内存为用户虚拟出一个用户地址空间,这简化了编译器和连接器的设计。

Q:解释分段与分页的区别
A:分页要对物理内存进行分块,每块物理内存的大小容量是固定,然后将进程的逻辑地址空间分成若干页,然后再将逻辑页映射到物理块上,正是因为这样的方法使得分页系统容易产生内部碎片。而分段系统不对物理内存进行分块,而是将进程的逻辑地址空间,按照用户需求,进行逻辑分段。然后将这些逻辑分段映射到物理内存上,这样使得分段系统容易产生外部碎片。较之于连续内存分配方案,分段与分页都采用离散分配方式,且都需要地址变换机构。其中分页以页为最小单位,页内总是连续的。分段以段为最小单位,段内总是连续的地址。分页对用户是可不见的,而分段对用户却不是透明的。分段系统较之于分页系统一个最突出的优点就是易于实现数据的共享,且对段的保护也十分简单,分段系统的诞生是为了适应软件工程的需求。

Q:连续内存分配方案与算法
A:单一连续,固定分区,动态分区(首次适应,最佳适应,最坏适应,邻近适应)

Q:简述系统调用过程
A:系统调用本质上就是一种过程调用,但它是一种特殊的过程调用。除了像普通过程调用一样,保护cpu现场,传递参数之外,系统调用还需要使用trap指令以软中断的形式进入到内核态,然后才能转入到相应的服务程序中执行。因为只有在内核态下才能够使用cpu指令集中的特权指令。最后在服务程序执行完毕返回调用处,并将状态模式设置为用户态,随后将控制返回给用户程序。

Q:中断服务程序的过程
A:当一个用户程序正在执行,被一个外部中断所打断时,cpu在正式进入去执行中断服务程序的时候,硬件要执行一些操作。这包括,关闭中断响应,保存当前用户程序的程序计数器,引出中断程序。这些操作被称为中断隐指令。随后在中断服务程序中将保存用户程序的cpu现场。

Q:为什么需要系统调用
A:在cpu指令集中有一部分指令为特权指令,这些指令只能让操作系统使用,如启动I/O设备指令,存取一些特殊寄存器等。限制用户程序无法直接使用特权指令,而是通过让用户程序使用系统调用间接使用特权指令,就能够保证用户程序不会随意破坏某些特殊寄存器的值,从而避免了系统崩溃。

Q:交换与覆盖的区别
A:覆盖是人为的将内存划分为固定区和覆盖区。覆盖区中的数据可以被替换,固定区中的则不行。程序运行时可以将必要的代码和数据存入固定区,而将那些不怎么活跃的代码段存入覆盖区。这样就使得程序不必一次性全部装入。但同时这样也增加了编写程序的难度。究竟哪一段程序是可以被覆盖的,哪一段是固定的,这都需要编程人员指出。而交换是将处于等待状态的进程换出内存,将就绪好的进程换入内存执行。目的是为了增加系统吞吐量。
目的不同:覆盖是为了解决程序必须一次型全部装入才能运行的限制。而交换是为了提高系统的吞吐量。

Q:TLB与cache与内存的区别
A:TLB与cache都是按内容访问的存储器,因为采用SRAM构成,这使得它们的访存速度大大快于使用DRAM组成的内存。但正因为采用SRAM使得它们的功耗高于内存,集成度低于内存。因此在计算机系统中,它们通常都是位于cpu内部,作为cpu与内存之间的高速缓存,用于解决高速cpu与慢速内存访问速度之间的矛盾。
不同点:按内容访问存储器(SRAM构成),按地址访问存储器(DRAM构成)。

Q:解释哈希表是什么
A:在记录的存储位置和它的关键字之间建立一个确定的对应关系f,这个f能使每一个关键字和结构中一个唯一的存储位置相对应。这样一来在查找时,只需根据这个对应关系f就能够快速找到关键字的存储位置,不需要进行比较便可直接取得所查记录。因此,称这个对应关系为哈希函数。按这个思想建立的表,称为哈希表。哈希函数:直接定址法,数字分析法,平方取中法,除留余数法。

Q:解释哈希冲突
A:哈希冲突就是指多个不同的关键字记录被哈希函数映射到同一个存储位置上,这就是哈希冲突。解决哈希冲突的方法通常有1.开放定址法2.链地址法。

Q:图的相关概念
A: 顶点:图中的数据元素,记V是顶点集合。
弧:记VR是两个顶点之间的关系集合。若有属于VR,则表示从顶点v到顶点w的一条弧。若存在属于VR,必有属于VR,则称(v,w)为顶点v和w的一条边。
图:图就是顶点集合V和关系集合VR所构成的一个有序二元组(V,VR)。
顶点数目与边数目:
1.在无向图中,若给定顶点数目n,那么边的取值范围便在[0,1/2n(n-1)]这个区间上。边数目为1/2n(n-1)的图,就叫做完全图
2.在有向图中,若给定顶点数目n,那么边的取值范围便在[0,n(n-1)]这个区间上。边数目为n(n-1)的图,就叫做有向完全图。
路径:是一个顶点序列所构成的有序序列。若在序列中,第一个顶点和最后一个顶点相同,称这个路径为环。若序列中不出现重复的路径称为简单路径。
联通图:若从顶点v1到v2存在路径,那么就说v1和v2之间是联通的。若在一个图中的任意两个顶点之间都是联通的,那么这个图就是联通图。

Q:解释硬中断与软中断区别
A:中断源是引起中断的源头,它来自cpu内部或cpu外部。通常来讲,来自cpu内部的中断称作软中断,是程序在执行过程中所发生的中断。常见的软中断有缺页异常,除0异常,内存访问越界等。而来自cpu外部的中断称作硬中断,是外部机器硬件发出信号请求cpu服务的中断。常见的硬中断有设备I/O完成,定时器时间到等。在一般情况下,软件中断是不可屏蔽的,硬件中断却被分为可屏蔽中断源和不可屏蔽中断源。在cpu内部有一个中断控制逻辑对外延伸出两个针脚,一个叫NMI,另一个叫INTR。连接到NMI的中断请求是不可屏蔽的,必须立即响应。连接到INTR的中断请求是可屏蔽的,可以由此来制定中断请求的优先级。从cpu响应中断的时间不同来讲,软件中断一般发生在一条指令执行过程中发生的,在指令执行途中便响应中断。而响应硬件中断则是在一条指令执行结束后才响应,cpu内部也有一个周期称作中断周期。

Q:说明一下操作系统中的数据结构。
A:操作系统中为了描述程序的运行情况,每一个程序都需要一个PCB来记录它的运行情况。将这些PCB组织起来就形成PCB表。PCB表的实现方式有多种,线性方式,连接方式,索引方式。在文件系统中,为了能对一个文件进行正确的按名存取,操作系统需要一个FCB来描述文件名的控制文件和文件的硬盘地址。将这些FCB组织起来,就形成了目录文件。常见的目录实现方式有单级文件目录,两级文件目录,树形目录。在管理组织磁盘时,通常有链接组织方式,连续组织方式和索引组织方式。在其中链接组织方式中,最著名的数据结构就是FAT表。追溯FAT表的思想起源,可以发现是来自数据结构中的静态链表静态链表的思想在树的双亲法表示中也有体现。在处理机调度时,常用到的数据结构是队列,常见的是多级反馈队列。

Q:解释文件控制块(FCB)
A:为了能对一个文件进行正确的按名存取,操作系统需要用文件控制块(FCB)来记载文件名,文件物理位置,文件物理结构等信息。将许多文件控制块组织起来,就形成了目录,称为目录文件。在早期使用文件名检索目录时,因单个文件控制块存储数据过大,使得不能一次性读入整个目录文件,这使得检索文件时需要多次读硬盘,这样降低了检索速度。为解决这个问题,引入索引节点。将除文件名之外的所有信息,从文件控制块中剥离,并将这些单独存储在硬盘。随后使用一个盘块编号指向这个盘块。这样大大地减少了目录文件存储内容,使得内存能够一次性读入目录文件,加快了按名存取文件的速度。

Q:解释数据库的二级映像功能
A:当模式发生改变时,可以通过修改外模式/模式的映像从而保证外模式不变。又因为应用程序是依据外模式编写的,外模式不变就能够保证程序代码不用变。保证了数据与程序的逻辑独立性,称数据的逻辑独立性。当内模式发生改变时,可以通过对模式/内模式映像作出改变来保证模式不发生变化。模式不变,这就保证了应用程序不用改变,简称数据的物理独立性。

Q:解释数据库第一范式,第二范式,第三范式
A: 第一范式要求每一个属性只有一个值,不允许一个属性有多个值
若关系属于第一范式,在这之上若关系中每一个非主关键字段都完全依赖于主关键字段,没有部分依赖于主关键字段,则称其满足第二范式。举例:(学号,课号)
若关系属于第一范式,在这之上若关系中每一个非主关键字段都只依赖于主关键字字段,没有传递依赖,则称其符合第三范式。举例:(学号)年龄->身份证号->学号,年龄->学号。

Q:不满足第二范式和第三范式所带来的问题
A:若一个关系的主码有两个属性组成(x,y),且不满足第二范式,那么一旦依赖于y的某个属性的域发生了变化,那么就需要同时修改多个元组。同时缺少属性y的元祖无法插入到数据库中。依赖于y的某个属性的域被多次重复存储。造成数据冗余。
若一个关系中存在传递依赖,画图示意。插入异常,数据冗余。

Q:数据库故障及其恢复策略
A:事务故障,介质故障(磁盘丢失),系统故障(因os,dbms故障或断电故障)。恢复策略– 定期转储整个数据库
– 建立事务日志 ,要求事务的每一个修改操作都要写入日志文件,在修改数据库时,要求先将记录写入日志磁盘文件中之后,才能正式开始。undo撤销,redo重新做。undo比redo需要更多io操作。redo延迟更新。
– 通过备份和日志进行恢复

Q:数据库的完整性约束条件
A:primary要求被修饰属性不能取空值,unique要求被修饰属性不能出现相同值,fpreign要求被修饰属性值必须来源于被参照关系的取值,chech要求被修饰属性值必须满足语义要求,default修饰属性取默认值

Q:解释GROUP BY,HAVING,JOIN ,ON关键字
A:GROUP BY是将查询结果集按一列或多列取值相等的原则进行分组。GROUP BY子句的列名必须要是FORM子句中列表的列名。在使用GROPU BY时要求FROM子句选出来的列名,要么在GROUP BY子句中,要么就在一个统计函数中,否则将是错误的。在分组之后,使用HAVING可以筛选组。where作用于表中元组,而HAVING作用于组。JOIN用于链接两张表,而ON则用于给出这两张表的链接条件。

Q:解释聚集索引和非聚集索引的区别
A:聚集索引要改变数据的物理存储位置,会按照指定的索引关键字对数据文件进行排序。非聚集索引则不会对数据文件进行排序,仅仅只是为数据文件建立索引,不改变数据文件的物理存储位置。一张表只能有一个聚集索引,在建立非聚集索引之前,应当先建立聚集索引。否则建立聚集索引将会改变数据文件物理位置,这将会使非聚集索引被重新构造一次。聚集索引和非聚集索引都是用B树来实现的,不同点在于聚集索引的叶节点是数据页,而非聚集索引的叶节点是指向数据的指针。

Q:数据库的并发访问会带来哪些数据不一致的问题?
A:事务是并发控制的基本单位,多个事务同时对数据操作会导致事务的原子特性遭到破坏。1:当两个事务同时访问一个共享数据时,并修改这个数据时,后面的那个事务将会覆盖前面事务所进行的操作,这就是丢失修改。2:当两个事务一个事务读数据,另一个事务写数据时,就会造成不可重复读现象。3:当一个事务正在对数据进行修改,而这种修改还没有提交到数据库中,这时,另外一个事务开始访问这个数据,并使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据。

Q:并发控制的技术有哪些?
A:主要依靠共享锁和排他锁来完成。一个要读取修改数据的事务,首先要获得该数据的共享锁。共享锁限制事务只能读数据,允许多个事务同时获得共享锁。一旦获得了共享锁的事务就可以读数据,当事务要写数据时需要获取数据的排他锁。排他锁限制其他一切事务对数据的读操作,不允许其他任何事务获取共享锁,仅允许拥有排他锁的事务对数据进行读写。获取了共享锁的事务要将锁转变为排他锁,就必须等到所有事务释放共享锁之后,才能转变为排他锁。这就会引发出另一个问题,若有两个事务均获有共享锁,并都要转换为排他锁,这就会发生事务相互等待对方释放共享锁。因此将发生死锁。解决死锁的方法是使用更新锁,需要修改数据的事务在开始时便申请更新锁,因为一次只有一个事务能拥有更新锁,这就解决了死锁问题。

Q:简述三级封锁协议
A: 一级封锁协议:写数据时必须要加排他锁,直到事务结束时再释放,但是读数据却不要求加锁
二级封锁协议:在一级封锁协议之上,要求读数据要加共享锁,读完就可以释放。
三级封锁协议:在一级封锁协议之上,要求读数据要加共享锁,直到事务结束才能释放。

Q:解释触发器
A:触发器一般有两种,一种是AFTER触发器,一种是INSTEAD OF触发器。after触发器是在某一类操作结束之后,触发器才会触发,而instead of触发器将替换某一类操作。触发器能够实现比check约束更复杂的约束条件,从而有力的保障了数据库的一致性和完整性。在数据库中存有inserted和deleted两张表,这两张表暂存了sql操作之后的数据内容。比如被delete操作所删除掉的数据都会存在deleted表中,在触发器代码中可以通过访问deleted表,查询出上一次delete操作所删除的数据,从而根据数据执行响应操作。
sql语句为 create trigger 触发器名 on 表名 for 操作名

Q:解释存储过程和T-sql的区别
A:存储过程比T-sql代码执行速度快,因为存储过程是预编译,在第一次运行存储过程时就会被编译,优化;在随后调用存储过程便不再进行编译优化,而是直接执行。但T-sql代码每次运行,都需要编译优化过后再执行。这样就使得存储过程的执行效率高于T-sql。当客户计算机操作访问数据库时,存储过程能够有效的减少网络流量。客户计算机只需发送调用存储过程的命令就可以了,但反观T-sql,客户计算机需要传送整段T-sql代码。同时从另一方面讲,存储过程是很好的封装,能够避免用户对数据库进行非法的访问,提高了数据安全。

Q:简述关系模型
A:给定一组域D1,D2,D3……Dn。D1,D2,…Dn的笛卡尔积称为元组。D1,D2,…Dn的笛卡尔的子集,称作在域D1,D2,D3……Dn上的关系。

Q:什么是软件生命周期?
A:一个软件从定义,开发,使用,维护,直至被弃用,要经历一个漫长的周期。通常就把这段时间称为软件生命周期。概括的说一般将生命周期分为三个阶段,软件定义,软件开发,软件运行维护。将软件生命周期中的各项开发活动的流程用一个合理的框架——开发模型来规范描述,就称是软件过程模型。它规定了各项任务完成的步骤。
软件定义:问题定义,需求分析,可行性研究
软件开发时期:概要设计,详细设计,编码和单元测试,综合测试

Q:常见过程模型及其主要特点。
A:瀑布模型:后一阶段的工作必须要等前一阶段的工作完成之后才能进行。这使得瀑布模型极其依赖前一段工作,若某一段的工作没有输出正确结果,那么后续所有工作输出的结果都将是不正确的。这样的依赖性的特征,也使得瀑布模型并不适合现代化软件开发,因为用户的需求总是在不停变化的。同时每个阶段之间都会产生大量的文档,工作量很大。
增量模型:首先实现一个核心的产品,这通常是第一个增量,这个增量能够满足用户的基本需求,但还有很多特征没有加上。然后立即将这个核心产品交与用户检验,用户对其使用评估,用户的评估结果都将指导下一个增量的开发。增量模型要求每一个增量都是可运行的产品。这样极大的增加了用户与开发人员的交流,能够很好的适应用户的需求变化。这样的特征要求软件满足开闭原则。在具体编程中可以使用设计模式中的依赖倒转原则和里氏替换原则来指导实现。
里氏替换原则:程序中能使用基类对象完成的任务,将其替换为子类对象也能够完成,且程序不会出错和异常。面向对象语言达成里氏原则的具体实现方法就是继承机制,最好的办法就是将父类申明为一个接口或抽象类。
依赖倒转原则:客户端代码要使用抽象类编程,而不是使用具体类编程。在依赖倒转原则中,以抽象方式耦合两个类之间的关系是实现依赖倒转原则的关键。依赖注入是传递对象之间依赖关系的指导思想。依赖注入将一个类的对象传入另一个类时,应当传入其父类对象,在程序运行中再通过子类对象覆盖父类对象。
螺旋模型:在快速原型模型和瀑布模型结合起来,在其中增加了风险分析。

A:什么是软件?什么是软件工程?软件工程常见的名词并解释?
Q:软件:程序是按照一系列特定顺序所组织的计算机数据和指令的集合。与程序相关的文档是软件的一部分。软件就是程序+文档。
耦合:模块之间的联系。模块之间联系的越紧密,耦合性就越强,模块独立性就也越差。
内聚:模块内各元素之间的联系。元素之间的联系越紧密,内聚性就越高。

Q:什么是黑盒测试和白盒测试
A: 黑盒测试:只通过研究程序组件的输入和输出来确定程序是否有问题,不用考虑程序内部的逻辑结构和内部特性。又称为功能测试和数据测试。在设计具体的测试用例上,有等价类划分,边界值分析,因果图等方法。因果图用于分析应该为哪些情况设计测试用例。
白盒测试:需要对程序具体代码实现进行分析,了解代码的逻辑,设计测试用例,检测每条分支和路径。常用到的一些标准是
语句覆盖:设计足够多的测试用例,使得程序中每个语句至少能执行一次。
判定覆盖:设计足够多的测试用例,使得程序中每个判定至少都获得一次真值和假值。每个分支至少通过一次。
条件覆盖:设计足够多的测试用例,使每个判断中每个条件的可能取值至少满足一次,但未必能覆盖全部分支。单单仅看即使每个if语句框至少取一次,不考虑组合。
判定/条件覆盖:设计足够多的测试用例,同时满足条件覆盖和判定覆盖。
条件组合覆盖:每个判定框之间相互组合。每个if语句里之间条件逻辑之间相互组合。

数据结构代码手写:
插入排序(done),折半插入排序(done),快速排序(done),归并排序(done),堆排序(done),KMP(done)。

离散数学:
求解线性递推关系的解。

Q:解释ICMP及其原理
A:ICMP是网际控制报文协议,用于在主机,路由器之间传递控制消息。ICMP是使用IP分组,是一种无链接的协议。常使用的命令是ping,用于测试网络是否通畅。

Q:被问到无法回答的问题(计算机网络)
A:(思索一段时间)对不起老师,这个问题我答不上来。但是在计算机网络中我认为有一个地方是数据结构,数据库,计算机网络三门课程的交汇点。(转到DNS系统)

Q:解释DNS域名系统(分布式数据库,联系到存储过程和T-sql代码,联系到b+树和字典序 域名 -> IP)
A:DNS是一个数据库系统,这个系统能够把互联网上的主机名转换为IP地址。这样用户就可以不用去记住主机的IP地址,而是通过主机名去链接它。DNS系统实质上是一个数据库,这个数据库上记载了主机名和ip地址的之间的对应关系。它被设计成分布式数据库系统,并采用客户服务器方式。之所以一个主机名会有多个域,是因为DNS是分布式数据库,为了能够快速检索到准确的对应关系,需要为这个数据库建立索引,而将一个主机名划分成多个域,就是达成这一目的的手段。
DNS查询通常有两种方式,一种是迭代查询,一种是递归查询。DNS的查询请求通常被封装在UDP数据报中。

Q:解释ARP协议(IP -> MAC)
A:ARP协议是用来寻找IP地址所对应的MAC地址,因为最终在实际网络链路上进行传送数据帧时,必须要使用硬件地址。因此仅仅知道IP地址还不能传送数据,需要找到IP地址所对应的MAC地址。当一个主机需要查询一个IP地址所对应的MAC地址时,会在全网进行广播,一旦当目标主机收到该数据帧之后,就会以单播的形式会送自己的MAC地址。

Q:解释DHCP协议
A:DHCP主要是用来给一台新加入计算机网络的主机自动配置IP的地址的协议。这样一台主机就不需要人工配置ip地址,使得主机可以即插即用。当一台新主机联入到网络后,就会立即使用UDP发送广播报文,寻找网络中的DHCP服务器。当DHCP服务器接收到这个信息之后,就会对此进行应答为其分配ip地址。

Q:解释CSMA/CD协议**(联系发散)主要是用于广播信道,仅最大努力交付不可靠**
A:CSMA/CD协议主要用在共享式网络当中,随着交换机的广泛使用,共享式网络转变至交换式网络,这使得CSMA/CD协议逐渐消失。CSMA/CD协议是用来让多台计算机共用一个线路进行通信的协议。CSMA/CD协议要求网络上的计算机在发送数据之前,需要对通信线路进行监听,只有当信道空闲时,主机才能发送数据。因为数据在信道上传播有延迟,所以即便是主机在发送数据时也仍需要不断监听信道。一旦发现别的主机也在向信道上送往数据时,就必须停止发送数据,等待一段时间之后再发送。(截断二进制指数退避算法)
最短帧64B,发送时延 = 传播时延 x 2。争用期51.2 us

Q:停止等待协议(数据链路层通信协议)
A:停止等待协议就是每次发送完数据报之后,必须要等到确认消息之后才能继续发送下一个。在停止等待协议中有一个超时计时器,如果在计时器到期之前都没有收到对方的确认,就会重新发送数据报。

Q:ARQ(用于数据链路层通信)与滑动窗口协议
A:连续ARQ协议是数据链路层的,ARQ的窗口是固定的。
当发送窗口和接收窗口的大小都等于 1时,就是停止等待协议。
  当发送窗口大于1,接收窗口等于1时,就是回退N步协议。
  当发送窗口和接收窗口的大小均大于1时,就是选择重发协议。
  滑动窗口协议中的窗口是可变的,它受限于流量控制与拥塞控制,是接收窗口与拥塞窗口的最小值。
  
Q:解释为什么TCP需要三次握手
A:三次握手是为了避免出现如下所述情况。当客户端发送一个链接请求至服务器端,这个链接请求因某些原因在网络中滞留了很长时间但并未丢失。这对客户端来说,将迟迟收不到服务器端的链接确认消息。若这个等待时间过长,客户端将会自动释放掉这个链接,认为链接无法建立。但是链接请求却能正确达到服务器端,只是时间用了很久。这时候,如果不采用三次握手,即服务器端只要回送确认消息,这个链接就建立了。但是客户端却认为这个链接失效了。这样一来,服务器端将会一直等待永远客户端发送数据,服务器资源就被浪费掉了。

Q:IPv4地址缺乏的解决办法以及IPv4的替代方案以及IPv4和IPv6如何相互通信?
A:IPv4地址缺乏的解决方法是使用CIDR编址,在CIDR中取消了传统IP地址中分类的概。将ip地址划分为前后两个部分,前面的部分就叫做网络前缀,用来指明网络,后面的部分就用来指明主机。通过这样灵活的ip地址划分方式就解决了ipv4地址缺乏的问题。
解决IPv4和IPv6相互通信的方式有两种。一种从硬件上,为每一个路由器都配备ipv4和ipv6协议。这样路由器就能根据ip地址的不同选择不同的协议。另一种是从软件上,只要把ipv6数据报所有部分全部封装进入ipv4的数据报部分。这样ipv6的数据报就能在ipv4的网络上进行传输。

Q:解释虚拟网是什么
A:虚拟网就是利用公用互联网作为n个专用网之间通信载体,虚拟的意思就是表面上机构内的所有计算机看起来好像是一个专用网里交流,但是实际上还是通过了互联网进行交换信息,只是在效果上很像专用网。

Q:解释拥塞控制,和它的具体做法。
A:当一个网络对资源的需求超过了资源所能提供的时候,就会出现网络吞吐量大幅下降的现象。拥塞控制就是为了防止这一现象的产生。拥塞控制可以防止过多的数据注入到网络中,这样就可以使得网络中的路由器和链路不致过载。
拥塞控制:设置一个拥塞窗口,再设置一个拥塞阈值。在tcp报文段中还有一个叫做窗口的字段,这是用来进行流量控制的。在慢开始阶段,每一次确认都会使拥塞窗口增大。当拥塞窗口增大至拥塞阈值时,这时将采用拥塞避免算法。拥塞窗口每一个传输轮次只会增大一。
出现超时:重新设置拥塞阈值为拥塞窗口的一半,并将拥塞窗口置为1.
连续收到3个ack:重新发送丢失报文,并重新设置拥塞阈值为拥塞窗口的一半,拥塞窗口=拥塞阈值。

Q:电路交换,报文交换,分组交换**(联系到单周期数据通路和流水线)**
A:电路交换要求建立一条专用线路。报文交换与分组交换不需要建立专用线路,采用存储转发的方式转发。区别在于数据报的粒度大小。

计算机网络OSI体系结构

物理层:频分复用,时分复用,码分复用。
数据链路层:ARQ协议,CSMA/CD协议
网络层:IP,CIDR,RIP,OSPF,BGP,ICMP,VPN,NAT
运输层:TCP,UDP,拥塞控制,三次握手
应用层:DNS,DHCP,

物理层作用:因为物理的传输媒体有很多,像是双绞线,同轴电缆,光纤等。为了能使这些不同的传输媒体之间能够相互传输信号,需要对他们的一些物理特征进行规定。像是规定电气特性,功能特性,机械特性等。

数据链路层作用:在物理层服务之上,在数据链路层实体之间建立链路链接,传输以帧为单位的数据包。使用流量控制和差错控制,使得有差错的物理链路,变成无差错的数据链路。

网络层:通过IP地址,将离散的MAC地址抽象形成拓扑图结构。多个MAC地址会对应着同一个IP网络号,一个网络号对应一个图顶点。在这之上就能图结构之上,实现路由选择,分组转发和拥塞控制,流量控制等。

Q:协议与服务
A: 网络层向上为传输层提供无链接,尽最大努力交付的数据服务
传输层向上为应用层提供端到端的可靠传输服务,流量控制,差错控制等。

Q:问到合肥印象(引导话题至移动IP通信)
A:对合肥的印象就是很心疼。因为我手机号在省内有无线流量,平时就经常开着流量看视频。这下出了省就给忘了,昨下午用流量看了一部经济类的纪录片,然后今天早上手机就欠费了。自己还是学计算机的,上课时还讲过移动IP通信过程,这一到实际生活中就给忘了。

移动通信略
802.11 mac三地址数据帧
802.3

Q:堆排vs快排,平衡二叉树vs b+树
A:就堆排序来讲,在调整堆的时候,总是需要频繁地访问父结点i,和它的孩子结点2i和2i+1。当i增大的时候,i与2i之间距离也会增大。一旦i和2i的距离大过了cache容量,那么就会cache不命中,那么这时候就需要去访问内存。并且在一个有虚拟内存的操作系统上,当i和2i之间的距离大过了一页的容量,且2i所在页面又正好不在物理内存中,这时候需要从磁盘上读取数据。但反观快速排序,总是连续的访问数据,空间局部性十分良好。
我们知道操作系统磁盘管理的基本单位是盘块,而文件系统的基本单位是簇。即便是只需要一个簇上的一个字节也需要读入整个簇。B+树中之所以一个结点会有多个关键字,一方面是为了能让一个结点充满一个簇,不出现浪费。另一方面是为了减少树的高度。反观平衡二叉树,虽然在算法层面查找一个关键字所需时间是long2n,但是他实际物理存储是极其不规范的。逻辑上相邻的位置,在物理存储上却很远。虽然比较次数少了,但是i/o读写却增多了。这使得平衡二叉树的实际效率不如b+树。同时数据库经常需要进行范围查找,而在平衡二叉树和b树上进行范围查找时,是极其不方便的,因为他们只能随机查找,只有b+树支顺序查找。

Q:IP地址与面向对象分析
A:首先我认为他们都提供了一种分析和处理复杂系统的思路,较之于早期直接使用mac地址进行通信,ip将多个mac地址映射到同一个网络号。将一个网络也就是mac地址的集合,作为系统分析的基本要素。同理较之于早期的结构化分析,面向对象分析将多个过程与数据结构集合形成对象,将对象作为系统分析的基本要素。不再关注数据的流向,而是关注对象与对象之间的通信。

Q:什么是第一范式
A:第一范式要求元祖的每个属性只含有一个值,若不满足第一范式,若在以后新增属性时,将出现更新异常。例子,(学号,课程),课程含有多个值。

Q:什么是BCNF
A:非平凡函数依赖:若x->y,Y不为x的子集,那么就称x->y是非平凡函数依赖。
平凡函数依赖:若x->y,但y是x的子集,那么就称x->y是平凡函数依赖。
部分函数依赖:若x->y,但存在x的真子集x1,使得x1->y,那么就称这个是部分函数依赖。
传递函数依赖:若x->y,y->z,则有x->z,那么就称这个为传递函数依赖。
在第一范式的基础之上,若关系中的所有非平凡函数依赖的左边,都是候选码,那么这个关系就是BCNF

Q:如何测试出90%的bug
A:我会使用白盒测试法中的条件组合覆盖设计尽可能多的测试用例,来测试程序。

Q:什么是概要设计
A:按照业务功能,将功能分解为不必再分解的的模块,使得模块达到高内聚,低耦合,每个模块完成一定的功能,为一个或多个父模块服务,也接受一个或多个子模块的服务。然后将这些模块的调用关系形成软件结构图。

Q:用例图作用
A:用例图,是用来描述人们如何使用一个系统,保证在不揭示系统内部构造的前提下,描述系统的业务功能。用例图被用来获取客户的需求。但用例图是静态的,因此需要活动图来动态的描述业务流程。

Q:活动图的作用
A:活动图用来描述业务用例实现的工作流程,在活动图使用垂直的线,可以划分出泳道。一条泳道就表明某个部分必须要完成的职责。

Q:什么是类图?
A:从泳道图识别出具体的实现类以及该类所需要完成的操作,这个类就需要完成泳道所要求的职责。但类图是静态的模型,无法表示对象之间的交互。因此就需要顺序图,来描述对象与对象之间的交互动态模型。

Q:什么是顺序图
A:顺序图描述了对象的生命周期,对象与对象之间的交互关系。

Q:为了能够从一个更高的角度去描述一个系统,就需要将多个类图组织起来,形成包图,然后确立包图与包图之间的关系,从而形成整个系统的体系结构。

Q:什么是数据字典
A:数据字典是给数据流图上的每个成分加以定义和说明,主要目的是为了程序员与用户沟通交流。

A:结构化分析,通过顶层数据流图与用户交流,DFD图仅描述功能,通过此与用户沟通交流。然后对顶层数据流图逐步求精。但是数据流图是静态的。因此需要状态转换图,描述系统工作

Q:什么是面向对象分析
A:需求->业务用例图->活动图(可以变形为泳道图,泳道就是一个矩形,要求矩形内对象必须要完成的操作)->从图中识别出类,形成类模型->确定类模型中对象与对象之间的交互模型(顺序图)->类模型与类模型形成包图->包图与包图之间形成系统体系结构。

Q:什么是结构化分析
A:数据流模型(描述系统中数据处理的过程,关系数据的流动和数据的转换)->从数据流图中识别出模块->形成模块与模块之间的关系(软件结构图)->为每个模块设计算法与数据结构(流程图,盒图,PAD图,HIPO图,判定表与判定树,PDL)

Q:RAID0与交叉存储器
A:我认为他们都体现了流水线化的思想。为了加快数据传输率,RAID0与交叉存储器都使用冗余的存储体,将原本连续的数据进行切割,然后分别存储在不同存储体中。在RAID0中是通过条带化的方法,而在交叉存储器中通过将物理地址中的体号字段置于低位,从而将连续的物理地址映射到不同存储体中。然后这样一来,就能以流水线的方式去读取存储内容。

Q:解释RAM,ROM,掩摸ROM,PROM,EPROM,EEROM,FLASH
A:RAM随机读写存储器,又可以分为SRAM和DRAM。DRAM会发生漏电现象,这使得DRAM需要不停的补充电荷,称补充电荷为刷新。而SRAM不需要刷新,但它的集成度低。主存常用DRAM构成,高速缓存cache通常用SRAM构成。
ROM是只读存储器,其中的信息不会因为去掉电源而丢失,再次加电时存储信息依然存在。
PROM,是可以编程的只读存储器但仅能编程一次。
EPROM,是可以擦除重写的只读存储器,用紫外线擦存储内容,用加电的方法写入内容。
EEPROM,是电可擦除重写的只读存储器,EEPROM可以使用电擦除存储内容,不需要放置于特殊的擦除器中,在电脑上就能擦除。常用于银行卡
FLASH,也是EEPROM,只不过它的擦除和写入速度很快,为强调其速度快所以才称它为FLASH,常见的有U盘,MP4等

Q:cpu寻址方式
A:隐含寻址,立即数寻址,直接寻址,简介寻址,寄存器寻址,寄存器间址,相对寻址,基址寻址,变址寻址。
为什么要对寄存器编号,是为了进行寄存器寻址。
8086十六位cpu,可寻址2^ 20的地址空间。使用段+偏移的方式寻址2^20地址空间

Q:I/O端口与I/O接口
A:在一些寄存器如数据寄存器,状态寄存器,控制寄存器,命令寄存器之上制定控制I/O设备I/O控制逻辑就形成了I/O接口。I/O接口是对I/O设备的抽象,它屏蔽了I/O设备的机械特性,数据格式等细节。I/O接口中的数据,状态,控制寄存器为I/O设备与总线之间提供了3中I/O信息的传输通道,将这些传输通道称为I/O端口。
I/O端口编址,独立编址和统一编址。

Q:解释中断向量
A:中断向量就是中断服务程序的入口地址。在8086中,有一部分内存区域被固定为中断向量存放的位置,称为中断向量表。中断向量占4B,被分为两个部分,一个部分是段基值,另一个部分是段偏移。CS(段寄存器)和IP(段偏移)。形成物理实际地址的方式是CS寄存器左移4位,然后加上段偏移,就形成了物理地址。

Q:什么是8086的实模式和保护模式(联系发散到x86指令集,intel向下兼容金手铐)
A:给定一个基地址,进程能够不加以限制的访问64kb连续的空间。通过改变段寄存器的内容,一个进程可以随心所欲地访问内存中的任何一个单元,而丝毫不受限制。不能对一个进程的内存访问加以限制,也就谈不上对其他进程以及系统本身的保护。

Q:什么是芯片组
A:芯片组主要是指主板上的南桥芯片,北桥芯片和bios芯片等。北桥芯片是cpu用来与主存,显卡,南桥芯片进行通信的通道。南桥芯片内部则集成了许多I/O设备控制器,像硬盘,键盘等,所有外设的数据都会在南桥芯片中集合,然后送外北桥芯片,再到达cpu。bios芯片是一个只读存储器,用于开机过程中各种硬件设备的初始化和检测。在计算机刚启动时,无法从硬盘中获取数据,因为内存没有任何能够启动并处理硬盘的服务程序代码。bios芯片中的代码就会经过南桥,北桥,送至cpu中,并开始处理。
随着技术的发展,现在cpu已经不需要通过北桥去访问主存,北桥中的主存控制器被移到cpu的内部结构中,这样大大提高了数据传输率。后来显卡的pcie控制器也被移动至cpu内部,这样北桥大部分主要功能都被移动至cpu内部,北桥也没有存在的意义,将北桥中剩下的功能合并至南桥芯片中。

Q:简单工厂模式与工厂模式的区别
A:简单工厂模式集中了所有产品的创建逻辑,当系统需要扩展时,将不得不修改工厂的代码,这是因为在简单工厂模式中负责创建对象的是一个具体工厂类。若对工厂进行抽象,将工厂做为接口,将对象的创建交付给实现接口的具体工厂类,这就是工厂模式。这使得系统需要扩展时不需要修改客户端原有代码,只需增添新的工厂即可。

Q:解释单例模式
A:一个使用单例模式设计的类,在整个程序生命周期里,它只能创建一个对象。具体做法就是将该类的构造函数申明为私有,并声明一个静态私有类对象,对外只提供一个静态的工厂方法,用于构造该类对象。因为没有抽象层,所以单例模式很难进行扩展。

Q:适配器模式
A:适配器模式有类适配器和对象适配器。若客户端代码针对一个Target接口或类进行编码,当系统发生变化,要求target提供不一样的操作时,这时候就可以使用适配器模式。设置一个适配器类和一个适配者类,在适配者类中实现特殊操作,然后通过适配器类将转换Target的操作替换为适配者类中实现的操作。这样就可以不用修改客户端代码,达成新需求,完全符合开闭原则。使用适配器模式要求目标类中的方法应为虚函数,因为适配器要通过继承去覆盖原方法。

Q:什么是桥接模式
A:在一个抽象类中,声明一个接口成员,通过设值注入的方式,为这个接口成员赋予具体实现类,这就是桥接模式。

Q:什么是组合模式
A:设置一个抽象元素类,再设置一个容器类,这个容器类继承于抽象元素类,同时容器类申明一个父类集合对象,这个集合对象能够收集所有派生于父类的对象。若在抽象元素类中声明了对元素的增删改查操作,那么这个组合模式就是透明组合模式。若在抽象类中没有声明对元素的增删改查操作,而是在容器类中增添了增删改查操作,这样的组合模式就是安全的组合模式。

Q:解释继承和装饰者模式的区别**(装饰者模式与组合模式的区别)**
A:设有一个接口类A,再设一个实现接口类A的具体类B,在类B中声明了有一个接口类A的对象,并通过设值注入为这个对象赋予值,称这个类为抽象装饰者类。可以通过继承抽象装饰者类派生新的方法。这样一来,凡是所有实现接口类A的对象,都可以将自身传递到具体装饰者类中,然后就可以调用具体装饰者类中新增的方法。继承是静态的,客户端代码不能控制改变方法和时机。而装饰者模式是动态的,可以在程序运行过程中按需添加功能。

Q:外观模式
A:略

Q:什么是代理模式
A:给某一个对象提供一个代理,并由代理对象控制对原对象的引用,这就是代理模式。抽象主题角色申明了代理对象与被代理对象的共同接口,在客户端代码中要求使用抽象主题角色来编码。代理对象内部包含了对被代理对象的引用,被代理对象中实现了真实的业务代码,而代理对象仅仅只是引用。

Q:什么是命令模式
A:命令模式的核心思想就是将一个命令封装为一个对象,调用者与被调用者之间不存在直接引用,而是调用者通过命令类间接的引用被调用者的方法。在调用者类中声明抽象命令类,并通过设值注入具体命令类。通过这样的方式,就能使调用者与被调用者之间完全解耦,因此调用者可以对应不同的被调用者。

Q:什么是组合命令模式
A:组合命令模式是组合模式和命令模式的结合。为抽象命令类新增一个容器类,这样就可以达到命令的批处理。

Q:什么是迭代器模式
A:将聚合对象中的数据操作从其中分离出来,形成一个单独数据操作类,这样一来就可以不用暴露这个聚合对象的内部表示,这样就被称做迭代器模式。聚合类就仅仅只存储数据,不对外提供访问这些数据的具体方法,迭代器类则负责实现访问数据的具体方法。

Q:什么是观察者模式**(桥接模式与观察者模式区别)**
A:系统中有观察者与被观察目标,观察者监听观察目标,一旦当观察目标发生改变,那么观察者将收到消息通知,根据目标变化自动作出相应动作,这就是观察者模式。设置一个抽象目标类,和一个观察者接口,在这个抽象目标类里声明一个观察者集合。抽象目标类应具有attach与detach操作,attach用于注册观察者,而detach用于撤销观察者。在目标类的编码中要求通知每一个观察者。

Q:各类排序算法最坏最好比较次数
A:直接插入排序(稳定):
比较次数最小n-1,0次移动。
比较次数最大(n+2)(n-1)/2,(n+4)(n-1)/2次移动
直接插入排序(稳定):
最好0次移动,最坏(n+4)(n-1)/2次移动
移动次数不变,仅比较次数减少
冒泡排序(稳定):
比较次数最小n-1次,最多n(n-1)/2次。
简单选择排序(稳定):
比较次数总需要n(n-1)/2次
最小需要0次移动,最多需要3(n-1)次移动
快速排序(不稳定)
最好o(nlog2n),最坏o(n^2)
堆排序(不稳定)
最坏最好都是o(nlog2^2)
归并排序(稳定)
最坏最好都是o(nlog2^2)

按稳定划分:仅快排与堆排是不稳定的,除此之外都是稳定的
按情况划分:堆排,归并,最好最坏都是o(nlog2^2),简单选择最好最坏比较次数都是n(n-1)/2次
特殊记忆:(n+2)(n-1)/2,(n+4)(n-1)/2

Q:结构化分析与面向对象分析的区别
A:在分析设计同一个系统上,结构化设计与面向对象设计的视角尺度不一样。结构化分析视角尺度大,大到认真仔细观察系统中的每一个过程。仔细观察数据在过程与过程之间的流向。面向对象分析视角尺度小,概略观察系统中的对象。概率观察对象与对象之间消息的传递。在一个大型系统会存在十分多的过程,如果仍不能以对象这个更高的视角去审视系统,那么搭建维护一个大型系统是十分困难的。

Q:单片机与CPU的区别
A:单片机不仅包含了cpu,还有内存,各类I/O接口等,看起来就像是一个小型的计算机系统。

Q:交叉存储器(物理)与RAID
A:RAID0与交叉存储器都需要将一个连续的数据切分,然后将它分布的存储在不同的存储体中。在RAID0中这样的操作被称为条带化,在交叉存储器中则是通过将物理地址中的“体号”字段放置于低位,从而将连续的物理地址映射到不同存储体中。一旦一个连续的数据被离散的存储在不同的存储体中时,这时候读取数据就能够以流水线的形式连续的读取,多个存储体同时并行工作极大的增加了数据传输率。但是这样做风险也是极高的,在RAID0系统中,虽然读取速度很快,但是任何一个磁盘损坏,会使整个系统失效。因此RAID0以后的系统,为了增加数据的安全性,通常系统中会有一份完整的数据库备份。这样RAID系统中任意一个磁盘损坏只需要更换损坏的磁盘,RAID系统就能够自动的重建数据。

Q:cache映射方式
A:直接映射与组相联映射地址结构相同,区别在于cache结构,直接映射的cache每一个块号只能装入一个内存块 ,组相联映射的cache按组划分,组内是全相连映射。全相联映射。
cache替换算法仅在组相联映与全相联映射中使用。

Q:流水线冒险
A:结构冒险(指令访问内存冲突取指令,寄存器写冲突寄存器读),数据冒险(数据更新不一致,旁路),控制冒险

Q:微程序控制器与硬布线
A:硬布线,组合电路逻辑直接产生电路信号控制cpu。微程序控制器将一条指令所需要产生的控制信号,存于控制存储器中。一条指令对应着一个微程序,微程序由多个微指令组成,微指令产生控制信号。微程序控制器就像是cpu内部中的cpu,它有普通cpu一样的结构和工作原理,取指,译指,运行等等。
微指令产生控制信号,微指令的编码方式有很多。一种最简单的方式就是一个位对应一个控制信号,这样直接编码就无须译码,信号产生速度极快,但是指令会很长。因此也有译码编码方式。

Q:CF与OF
A:CF借/进位标志,CF = Cin 异或 Cout,cin是减法进一。加法时CF=1表示有进位,减法时CF=0表示有借位。OF = Cn 异或 Cn-1,Cn是最高位进位,Cn-1是n-1的进位。有进位的时候不一定有溢出,有溢出的时候不一定有进位。4位无符号数3+5。4位符号数-2+(-4)。

Q:什么是半加器和全加器
A:半加器 = 一个异或门+一个与门。半加器只有两个输入,无法计算进位。全加器 = 两个半加器。全加器有三个输入,比半加器多了一个进位输入。

Q:行波进位加法器与超前进位加法器
A:行波进位加法器是将多个全加器串联而成,高位运算总需要等待低位云散全加器的进位输出,因此速度很慢。超前进位加法器,通过计算可以求得高位的进位输出。例如一个4位超前进位加法器,一旦知道了最低位的三个输入,就能并行计算出每四位的进位输入。因此设置一个超前进位逻辑,这个逻辑为每一个全加器提供进位输入。因为超前进位逻辑的计算是并行的,能够同时提供进位输入,因此高位运算便不再需要等待低位运算。

Q:程序装入方式
A:绝对装入方式,逻辑地址与物理地址相同。
可重定位装入方式,逻辑地址与物理地址不同,在程序被装入后再修改其指令地址,以及指令中的数据地址。装入后便不能移动位置。
动态运行时的装入方式。

Q:内存保护方案
A:cpu中设置上下限寄存器,采用重定位寄存器和界地址寄存器。

Q:程序链接方式
A:静态连接,编译后的各个小模块直接拼成一个大模块,将这个大模块称为“可执行文件”,以后都不再拆开作为一个整体调度加载运行。
装入时动态连接,在装入一个目标模块时,若发生了一个外部模块调用,将引起装入程序去找出相应的某个目标模块,并将它装入内存,然后修改模块中的地址。
运行时动态连接,在执行过程中,当发现一个被调用模块未装入内存时,OS立刻去寻找该模块,然后装入内存并连接到调用者模块上。

Q:作业与进程的区别
A:作业是用户需要计算机完成的某项任务,是要求计算机所做工作的集合。一个作业至少有一个进程组成。进程是执行作业中某一任务的实体,完成一个作业通常需要多个任务,系统资源以进程为单位分配。

Q:什么是微内核
A:微内核是操作系统的子集,它包含了操作系统最基本核心的功能。而将一些诸如负责虚拟存储器管理,I/O设备管理这些功能模块从操作系统本身中剥离,将他们作为操作体系中的服务进程,这些进程为操作系统提供服务。微内核是基于客户端/服务器模式的操作系统。

Q:模拟信号,数字信号,基带信号,带通信号
A: 模拟信号是连续的类似于正弦波一样,数字信号是离散的脉冲信号。
基带信号,数字信号经过调制后再传输(曼切斯特编码,差分曼切斯特)。
带通信号,数字信号经过调制后再传输(调幅,调频,调相)。

Q:扩展以太网
A:在物理层上扩展以太网,使用转发器扩展以太网地理范围。在数据链路层上扩展以太网,使用网桥和交换机

Q:ppp协议
A:与某个ISP进行通信时使用的协议

语法分析与上下文无关文法(CFG)
在上下文无关文法中一个句子可以对应着多个派生。去掉派生顺序,仅仅只保留“替换”,那么就能形成派生树(CFG-only)。
二义性例子:
Gexp1:E->E+T
T->TF
Gexp2:E->E+E|E/E|E
E
Gexp1和Gexp2。文法Gexp2有二义性,但文法Gexp1却没有。我认为出现这样的原因是因为在Gexp2中将所有运算符的优先级视为一样的。而在Gxp1中能够表达运算符的优先级的原因是在于对不同优先级运算操作的分批定义。例如在Gexp1中将加法和减法这两个运算优先级相同的运算定义为由同一个语法变量产生,而乘法和除法这两个运算优先级相同的运算为由另一个语法变量产生,并且这两个语法变量有先后次序关系,要想产生乘法操作必须先产生加或减操作。但是在Gexp2中所有的运算操作都被定义由同一个语法变量E产生。所有运算操作都是相等级别的,在第一步便可以选取任意的产生式来产生同一个句子,这样便造成了二义性。同时这部分内容提到关于如何判定一个文法是否为二义性是一个不可解的问题。

词法分析

相关理论问题:
NFA与DFA等价,都能识别相同的语言。
构造与NFA等价的DFA。
Q:DFA(determinisitic finite automaton)与NFA(non-determinisitic)的区别
A:区别在于状态转移函数,DFA的状态转移函数都只有一个状态与之对应,f(q,a) =p。而NFA的状态转移函数可能会对应多个状态f(q,a)={p1,p2,p3,p4….pn}。

词法分析就是采用正则文法。
FA是正则语言的识别器,FA识别右线形文法。FA与3型文法等价。
构造识别右线形文法的自动机FA。每一个语法变量就是一个状态,每次吃掉一个就移动到下一个状态。(顺着吃)
构造识别左线形文法的自动机FA。(反着吃,形如A->w这种需要构造新状态)

句法分析

相关理论问题:
CFG转GNF,PDA的状态转移函数f (q,a,Z) = {(p1,r1),(p2,r2)},左递归消除。
直接左递归消除
A->Aa1 A -> b1
A ->b1 = A -> b1B
B -> a1
B -> a1B
间接左递归消除,化简为直接左递归。

LL(1)
first集,follow集,select集。这些集合在计算时,都按语法变量计算。难点在于空串e,按语法变量依次计算。
step1. 先计算first集,使用first集求解follow集。
step2. 对生成式A->a(其中a为语法变量),select(A->a),依赖于firsrt(a),如果firsrt(a)中不含有e,那么select(A->a) = firsr(a)。否则,select(A->a) = {firsr(a) - e} + follow(a)。特殊的,对于生成式A->e。select(A->e) = follw(A)
step3. 求出select集之后,在select集之上有递归分析法和非递归分析法。
step4. 出错处理将每个语法变量的follow集填入到预测表中,并标记为synch,表项中为synch的单元将出栈同时报错。

option1. 递归分析法:为每一个语法变量书写一段识别程序,按照生成式书写递归程序。当一个语法变量有多个select集合时候,例如select(S->AaS) = {a},select(S->BbS) = {c,b},select(S->d) = {d}。这些都是语法变量S的情况,应该将将这些集合在一个函数体ParseS(){}里面。若当前字符是a,那么就应该按照S->AaS编写程序。
option2. 非递归分析法:将select集合形成预测表,将所有终结符形成列,语法变量作为行。设置栈,每次将生成式的右部压入栈。

LR(0)
ACTION-GOTO表。ACTION-GOTO表有两个表项一个ACTION,一个GOTO表。GOTO表的单元项是状态。ACTION的单元项是动作,其中动作有Sn与Rn动作,Sn动作即使移入并转移到n号状态。Rn动作即是使用n号生成式规约,每一次规约过后,需要查看GOTO表进行状态的跳转。

step1:将文法改造成为增广文法
step2:寻找等价项目。https://www.icourse163.org/learn/HIT-1002123007?tid=1205983229#/learn/content?type=detail&id=1210383437&sm=1

LR(0)中存在归约/移进冲突。E->T. 和 E->T.*。究竟是移进,还是规约?

Q:为什么需要中间代码
A:汇编器使用中间代码将其最终翻译成为机器语言,之所以需要中间代码的是因为这样做就能够屏蔽掉具体机器的指令集,同一种中间代码能够被多种不同机器的汇编器翻译成目标代码。能够在中间代码的基础之上,进行与机器无关的代码优化。

printf(“%020d”,i),用于设置宽度为20,不够补0
for(j = 1; j ++ < 4;j ++) ,虽然比较结果为false,但是j仍然需要自增,比较结果并不影响j的自增。
a[10-10],先运算括号内,然后再取值
scanf(“i=%d”,&i),在输入的时候,要求按照格式依次输入。
scanf()在使用指针时,不需要加上&
scnaf在对指针所指向的区域赋值的时候,总会清空掉上一次赋值
%只能作用于整数。
将数组名指向一个字符串是错误的,只能用指针指向
strcmp(str1,str2)
若str1=str2,则返回零;
若str1 若str1>str2,则返回正数

main(int abc,char **arg)

++和- -的优先级大于* (* ++ptr).age,先++再*

宏可以定义在函数任何一个位置

a+ 若文件存在,打开文件,并指向它的末尾。不存在,则创建文件。

r表可读,r+表可读写文件不存在,不会建立文件

w 打开只写文件,若文件存在,则文件长度清零,即文件内容会消失,若文件不存在则建立该文件
w+ 打开可读写文件,若文件存在,则文件长度清零,即文件内容会消失,若文件不存在则建立该文件

记住规则,a是附加,w是写,r是读。+号表示可读可写,若文件不存在时,只有r不会建立文件。w和a都要建立文件,w直接无脑暴力覆盖文件。

如果EOF返回值为1,说明达到了文件的末尾。

char * fgets(char * s, int n,FILE *stream);
从stream中读取n-1个字符。

int putchar(int ch);
int puts(const char *string);
一个输出字符,一个输出字符串。

按’\0’确定结尾,如果没有’\0’,将会出错
strlen,puts,

char *strcat(char *dest, const char *src);
功能:将src字符串连接到dest的尾部,‘\0’也会追加过去

fpus(char *s,FILE *fp)
成功则返回非负数,否则返回EOF

getch 与getchar。getchar:等待用户回车之后,读取缓冲区内容。getch,按一个字符立即响应。

fopen打开错误,则返回null

你可能感兴趣的:(计算机研究生复试面试题目)