当前位置:文档之家› 复旦大学考研计算机961真题答案针对回忆版

复旦大学考研计算机961真题答案针对回忆版

17 18年两年答案说一下:由于学校封题,所以只有回忆版,软工细节无法复现所以我们只能尽量写出更多东西2017年第一部分数据结构1.向量相对于数组有什么优缺点?优点:(1)可以动态增长长度(2)数组在内存中分配的连续空间,多次分配释放后会有内存碎片,而vectors 是动态增长的,不是连续的,所以不会出现内存碎片,还有vector的迭代器能防止出现类似数组愈界等等。

(3)数组不允许拷贝和赋值,即不能将数组的内容拷贝到其他数组作为其初始值,但是vector可以。

缺点:(1)在内部进行插入删除,效率较低。

(2)只能在末端进行pop和push。

(3) 当动态长度超过默认分配大小后,要整体重新分配、拷贝和施放。

2.二叉树计算叶子节点算法,时间复杂度。

(可使用任一程序设计语言或伪代码,建议先用自然语言描述算法)。

答:主要思想:采用递归算法,先序遍历二叉树的每个结点,如果结点没有左子树和右子树,则叶子结点个数加1。

代码:Int CountOfLeaf ( BiTree T) //求二叉树叶子结点个数{if(!T) return 0;if (T->lchild==NULL&&T->rchild==NULL)count++; //如果没有左右孩子,则为叶子结点CountOfLeaf ( T->lchild); //遍历左子树CountOfLeaf ( T->rchild);//遍历右子树return count;}int main( BiTree T)int count=0; //全局变量count表示叶子结点的个数CountOfLeaf (T);//求二叉树叶子结点个数return count;}时间复杂度为O(n)2.几乎逆序的数组排序用什么排序算法?写出算法,时间复杂度。

答:前提条件:假定数组原始几乎从大到小排列,要将数组从小到大进行排列主要思想:先将数组先原地倒置,然后再将数组进行冒泡排序。

代码:Void Reverse( int a[], n) //逆序函数,将数组中的元素原地倒置{for(i = 0; i < n/2 ;i++){Swap(a[i],a[n - i - 1]);}}void BubbleSort( int a[],int n) //冒泡排序{for(j=0;j<n-2;j++) //将j从0~n-2进行循环{int flag=false; //初始化标志位for(int i=n-1;i>j;i--){if(a[i]<a[i-1]) //如果后面的数小于前面的数,则交换,并修改标志位{swap(a[i],a[i-1]);flag=true;}}if(flag==false)return; //如果标志为false,则一次循环没有移动元素,得出最终数组}}}int sort(int a[],int n){Reverse( a, n); //先将原有数组进行原地逆序BubbleSort(a,n); //再用冒泡排序得出最终结果}时间复杂度:原地逆序的时间复杂度为O(n),冒泡排序在基本有序的情况下时间复杂度也为O(n),因此总的时间复杂度为O(n)。

4.二叉排序树的2种优化方法,并且介绍这两种方法是怎样优化二叉排序树的。

①红黑树本质上是一种二叉查找树,但它在二叉查找树的基础上额外添加了一个标记(颜色),同时具有一定的规则。

这些规则使红黑树保证了一种平衡,插入、删除、查找的最坏时间复杂度都为O(logn)。

②AVL是最先发明的自平衡二叉查找树算法。

在AVL中任何节点的两个子树的高度最大差别为1,所以查找、插入和删除在平均和最坏情况下都是O(log n)。

增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。

第二部分csapp1.Amdahl性能分析定律,硬件优化趋势a为并行计算部分所占比例n为并行处理结点个数S(N):程序在N个处理器(总核心数)相对在单个处理器(单核)中的速度提升比当1-a=0时,(即没有串行,只有并行)最大加速比s=n;当a=0时(即只有串行,没有并行),最小加速比s=1;当n→∞时,极限加速比s→ 1/(1-a),这也就是加速比的上限。

这个公式说明:1.增加处理器数、计算负载分布到更多处理器上,可以提高计算速度2.程序中可并行代码的比例决定你增加处理器(总核心数)所能带来的速度提升的上限2.流水线是怎样提高性能的,会遇到什么问题,解决方法是什么。

(1)指令执行基本分为取指,译码,执行,访存,写回,根据寄存器的特性可以不断的将一个时序过程分解成若干个子过程。

(2)多条指令重叠进行操作,,每个过程都能有效的与其他子进程同时进行。

这样可以提高处理器处理效率,争取在一个时钟周期中完成一条指令。

会遇到的问题:包括数据冒险和控制冒险。

处理数据冒险时:(1)使用暂停来避免冒险,也就是让指令停留在译码阶段,知道其源操作数的指令通过了写回阶段,具体做法是在执行阶段插入一个气泡。

(2)使用转发来避免数据冒险直接将结果值从流水线阶段传到更早点阶段(3)加载和使用数据冒险而处理控制冒险时,在执行阶段中,指令会改变条件码。

我们在下一个周期往译码和处理阶段中插入气泡,并同时取出跳转指令后面的指令,这样就能取消(有时也称为指令排除)那两条预存错误的指令。

3.软件优化至关重要,软件优化一般有哪些方法?1)高级设计。

选择适合的算法和数据结构。

2)基本编码原则。

避免限制优化的因素,这样编译器就能产生高效的代码。

●消除连续的函数调用。

在可能时,将计算移到循环外。

考虑有选择地妥协程序的模块性以获得更大的效率●消除不必要的内存引用。

引入临时变量来保存中间结果。

只有在最后的值计算出来时,才将结果存放到数组或全局变量中。

3)低级优化。

结构化代码以利用硬件功能。

●展开循环,降低开销,并且使进一步的优化成为可能。

●通过使用例如多个累积变量和重新结合等技术,找到方法提高指令级并行。

●用功能性的风格重写条件操作,使得编译采用条件数据传送。

4.什么是高速缓存,存储结构是怎样提高性能的,它和局部性的关系是什么。

什么是高速缓存Cache是一种小容量高速缓冲存储器,由快速的SRAM组成,直接制作在CPU芯片内,速度较快,几乎与CPU处于同一个量级。

存储结构是怎样提高性能的CPU和存储器的性能差距越来越大,存储器的传输速度很大程度限制了处理器的效率,从而引进高速缓存cache,CPU能直接从Cache中取得指令和数据,而不必访问慢速的主存。

它和局部性的关系是什么时间局部性:最近被访问的内容(指令或数据)很快还会被访问。

空间局部性:当前被访问的内容附近的内容很快会被访问。

在CPU和主存之间设置Cache,总是把主存中被频繁访问的活跃程序块和数据块复制到Cache中,良好的时间局部性和空间局部性能提高cache的命中率,减少CPU访存的时间,加快运行5.虚拟内存的作用,通过什么方式提高虚拟内存的性能。

①(作为缓存工具)使用DRAM当做部分的虚拟地址空间的缓存;②(作为内存管理工具)为每个进程提供了统一的线性地址空间③(作为内存保护工具)进程之间不会相互影响;用户程序不能访问内部信息和代码第三部分软件工程1.瀑布过程的特点①瀑布模型是一种文档驱动模型,模型简单;②每个阶段都要提交文档接受审查,有质量保证;③阶段之间有顺序性和依赖性;④推迟实现,先进行逻辑设计再进行物理设计;⑤对需求变更的响应比较困难2.开闭原则的概念一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

3.敏捷宣言是什么个体和交互重于过程与工具可以工作的软件重于详尽的文档客户合作重于合同谈判响应变化重于遵循计划2.一个场景(学生毕业申请系统),画出数据流图顶层、0层、1层。

3.结合传感器说明简述软件测试的作用。

是不是用例越多越好?为什么?不是越多越好,因为虽然理想情况下,测试应对系统中所有可能的执行路径进行全面的检查。

然而,系统所有可能的执行路径的数目随系统复杂性的增加不断增长,甚至可能达到无止境的程度。

软件企业执行测试的资源与时间有限,因此实现一个复杂系统的百分之百的路径覆盖往往并不现实。

此时,应该根据具体情况采用不同级别的覆盖标准,来达到提高测试效率的目的。

4.白盒测试和黑盒测试在用例设计上的区别。

白盒测试:测试人员将测试对象当作透明的盒子,根据程序内部的逻辑结构及有关信息设计测试用例,检查所有逻辑是否按照预定的要求正确工作。

黑盒测试:测试人员将测试对象看作一个黑盒子,完全不考虑程序内部的逻辑结构和内部特性,只根据需求规格说明书,检查程序的功能是否符合它的功能要求。

2018年考题回忆版第一部分数据结构1.栈的链表实现代码,数组实现与链表性能比较#define MAXSIZE 100//栈的顺式储存类型typedef struct {Elemtype data[MAXSIZE];int top;}SeqStack,*PSeqStack;//栈的初始化PSeqStack initSeqStack(){PSeqStack stack;stack = (PSeqStack)malloc(sizeof(SeqStack));stack->top = -1;return stack;}//判断栈是否为空 1,空;0,非空int emptyStack(PSeqStack stack){if(stack->top == -1){return 1;}else{return 0;}}int pushStack(PSeqStack stack,Elemtype x){//入栈if(stack->top == MAXSIZE-1){return 0;}else{stack->top ++;stack->data[stack->top] = x;return 1;}}int popStack(PSeqStack stack,Elemtype &x){//出栈if(emptyStack(stack)){return 0;}else{x = stack->data[stack->top];stack->top --;return 1;}}struct LinkList{datatype data;struct LinkList *next;};struct stack{datatype data;struct stack *next;};typedef struct stack Stack;//创建栈Stack *s;//初始化栈void init(){s=NULL;}//判断栈是否为空int Empty(){if(s==NULL)return 1;elsereturn 0;}判断栈是否已满了void full(Stack *s){if(s->top==maxsize-1){maxsize++;s->data=(datatype *)malloc(s->data,maxsize);}}//入栈void Push(datatype element){Stack *p = (Stack *)malloc(sizeof(Stack));p->data=element;p->next=s;s=p;}//出栈void Pop(){if(!Empty(s))s=s->next;elseprintf("栈空\n");}用数组和链表实现栈,在出栈和进栈时时间复杂度都为o(1),性能几乎相同。

相关主题