一. 选择题
- 从逻辑上可以把数据结构分为( )两大类
A. 动态结构、静态结构
B. 顺序结构、链式结构
C. 线性结构、非线性结构 ✅
D. 初等结构、构造型结构
答:C
解:数据结构可以从逻辑结构和存储结构两个方面分。
-
逻辑结构分为线性结构和非线性结构两大类
-
存储结构分为顺序结构和链式结构两大类
- 下面关于算法的说法正确的是( )
A. 算法的时间复杂度一般与算法的空间复杂度成正比
B. 解决某问题的算法可能有多种,但肯定采用相同的数据结构
C. 算法的可行性是指算法的指令不能有二义性
D. 同一个算法,一般情况下实现语言的级别越高,执行效率越低。✅
答:D
解:算法具有五个特征:
- 有穷性:一个算法必须总是在执行有穷步之后结束,且每一步都在有穷时间内完成
- 确定性:算法中每一条指令必须有确切含义。不存在二义性。相同的输入必然有相同的输出
- 可行性:一个算法是可行的。即算法描述的操作都是可以通过已经实现的基本运算执行有限次来实现
- 输入:一个算法有零个或多个输入,这些输入取自于某个特定对象的集合
- 输出:一个算法有一个或多个输出,这些输出是同输入有着某些特定关系的量
语言级别越高,实现越复杂,效率越低。
- 在发生非法操作时,算法能够做出适当处理的特性称为( )
A. 正确性
B. 健壮性 ✅
C. 可读性
D. 可移植性
答:B
解:评价一个好的算法有以下几个标准:
- 正确性(Correctness):算法应满足具体问题的需求
- 可读性(Readability):算法应该易读。以有利于读者对程序的理解。
- 健壮性(Robustness):算法应具有容错处理。当输入非法数据时,算法应对其作出反应,而不是产生莫名其妙的输出结果。
- 效率与存储量需求:效率指的是算法执行的时间;存储量需求指算法执行过程中所需要的最大存储空间。一般这两者与问题的规模有关。
二. 判断题
- 数据的逻辑结构是指数据的各数据项之间的逻辑关系( )
答:❌
解:结构定义中的“关系”描述的是数据元素之间的逻辑关系,因此又称为数据的逻辑结构(p5)
- 数据元素:对应一个结点
- 数据项:对应结点(结构体)中的一个域
- 顺序存储方式的优点是存储密度大,且插入、删除运算效率高( )
答:❌
解:
顺序存储结构和链式存储结构的区别
- 链表存储结构的内存地址不一定是连续的,但顺序存储结构的内存地址一定是连续的;
- 链式存储适用于在较频繁地插入、删除、更新元素时,而顺序存储结构适用于频繁查询时使用。
顺序存储结构和链式存储结构的优缺点
- 空间上 顺序比链式节约空间。是因为链式结构每一个节点都有一个指针存储域。
- 存储操作上: 顺序支持随机存取,方便操作
- 插入和删除上: 链式的要比顺序的方便(因为插入的话顺序表也很方便,问题是顺序表的插入要执行更大的空间复杂度,包括一个从表头索引以及索引后的元素后移,而链表是索引后,插入就完成了)
- 数据的逻辑结构说明数据元素之间的次序关系,它依赖于数据的存储结构( )
答:❌
解:数据元素之间的关系叫做结构(structure),可以看作是从具体问题抽象出来的数学模型,与计算机无关,与数据的存储无关,也叫做逻辑结构
- 算法的优劣与描述算法的语言无关,但与所用的计算机性能有关( )
答:❌
解:一般从算法的计算时间与所需存储空间来评价一个算法的优劣,撇开软硬件等有关因素,可以认为一个特定算法“运行工作量”的大小,只依赖于问题的规模(通常用n表示),或者说,它是问题规模的函数。
- 算法必须有输出,但可以没有输入( )
答:☑
解:算法的五大特性之二:
- 输入:一个算法有零个或多个输入,这些输入取自于某个特定对象的集合。(可以没有输入)
- 输出:一个算法有一个或多个输出,这些输出是同输入有着某些特定关系的量。(一定要有输出)
三. 简答题
一、 分析程序段中带“#”语句的执行频度,并给出程序段的时间复杂度
- 第一小题
j=1; k=0;
while(j<=n-1){
j++;
k+=j; //#
}
答:执行频度为 ,时间复杂度为
解:
循环体共运行了 次。
- 第二小题
设n是偶数
for(i=1, s=0; i<=n; i++){
for(j=2*i; j<=n; j++){
s++; //#
}
}
答:执行频度为 ,时间复杂度为
解:
内层循环每次从 2、4、6... 开始加到 n ,首项是 n - 1 ,末项是 1 ,项数是 n/2
- 第三小题
k=0;
for(i=0; i<n; i++){
for(j=i; j<n; j++){
k++; //#
}
}
答:执行频度为 ,时间复杂度为
解:
内层循环每次从 1、2、3... 开始加到 n ,首项是 n ,末项是 1 ,项数是 n
- 第四小题
k=0;
for(i=0; i<n; i++){
for(j=1; j<n; j<<=1){
k++; //#
}
}
答:执行频度为 ,时间复杂度为
解:
外层循环执行 n 次
内层循环每次执行 次
二、有的情况下,算法中基本操作重复执行的次数还随问题的输入数据集不同而不同。假定对包含1、2、3、4、5共5个元素的序列(即n=5)做冒泡排序,请举例说明何时会出现以下情况:
- 任何元素都无需移动;
答:完全顺序时,即序列为
1 2 3 4 5
- 某元素会一度朝着远离期最终位置的方向移动;
答:当一个元素之前有若干比他大的元素时,该元素会往前移动,如果初始位置在最终位置左边,相当于远离最终位置;若是右边有比他小的元素,就会往后移动,如果初始位置在最终位置右边,相当于远离最终位置(假定按非递增序列排序),例如序列为
5 4 1 2 3
- 某元素的初始时已位于最终位置,却需要参与n-1次交换;
答:当元素个数为奇数个时,中间的那个元素已经位于最终位置,但需要参与 n - 1 次交换,即序列为
4 5 3 1 2
- 所有元素都需要参与n-1次交换。
答:完全逆序时,即序列为
5 4 3 2 1
三、阅读高质量C++/C编程指南,电子版文档:www.doc88.com/p-210659243…
- 头文件的作用是什么,头文件中为什么有 ifndef/define/endif结构的预处理块
答:
头文件的作用是(1)用户只需要按照头文件中的接口声明来调用库功能,而不用关心库功能如何(2)头文件能加强类型安全检查;
使用预处理块是为了防止头文件被重复引用
- 引用和指针有何区别?下面代码中的Test函数的语句GetMemory(str, 200)并没有使str获取期望的内存,str依旧是NULL,请问是为什么,应该如何修改?
答:
- 引用传入函数的就是参数在函数外本身的地址,对引用操作就相当于对原变量操作;指针传入函数的是函数外部变量的地址,在函数内部可以通过
*来取指向原变量内存地址的值来操作原变量- 因为传入的是指针变量
str本身,在函数内是该指针变量的一个副本,分配完内存后只是将函数内的p赋为了申请出内存的地址,而函数外部的str还是NULL;想要让str获得应有的值,应该通过传引用或者传指向str的指针来操作
- 函数体内的局部变量在函数结束时会自动消亡,那么函数体内动态申请的内存是否会自动释放?
答:
- 不会自动释放。因为 malloc 申请的内存在堆区,指针变量释放了,但申请的内存并没有释放。
四、在调试程序时如果一个循环在执行100次后会出现问题,应如何设置断点进行调试?在调试程序时如果需要在被监控变量的值发生改变时停止执行进行分析,应如何设置?
答:
- 使用 GDB 的
b location if cond创建普通断点,条件为当 n 大于 100 后暂停程序。- 使用 GDB 的
watch cond创建观察断点,表达式的值改变时暂停程序。
四. 编程题
最大子序列求和问题,分别采用PPT中求最大子序列和的算法1、算法2、算法4求以下两个分别包含100个整数 int100.txt 和1000个整数 int1000.txt的最大连续子序列和
要求如下:
- 编写代码完成测试数据文件的读取
- 分别采用三种算法求最大连续子序列和
- 记录三种算法的运行时间
作业代码:
运行结果: