习题纠错04

发布时间 2023-09-01 21:11:09作者: 优秀还天籁

2、在C语言的定义和调用中,下面描述正确的是() //答案B
A
函数的定义可以嵌套,但函数的调用不可以嵌套。
B
函数的定义不可以嵌套,但函数的调用可以嵌套。
C
函数的定义和函数调用都可以嵌套。
D
函数的定义和调用都不可以嵌套。//C语言的语法规定,函数的定义必须出现在全局作用域中,也就是在其他函数的外部。这意味着函数定义不能嵌套在其他函数的内部。
//函数的嵌套定义可能会导致语法歧义和编译器难以处理的复杂性。
//如果允许函数嵌套定义,那么在函数内部嵌套的函数可能无法正确地访问外部函数的局部变量和参数,也会增加编译器的复杂性和实现的困难。
//拓展:所谓的函数是用于封装的可重用的代码,for循环只是一种控制结构。

对于以下代码,
char* p=new char[100];
说法正确的是() //答案D
A
p和new出来的内存都在栈上
B
p和new出来的内存都在堆上
C
p在堆上,new出来的在栈上
D
p在栈上,new出来的在堆上//指针变量p本身是在栈上分配的,它存储了堆上分配的内存块的地址。
//而通过new分配的内存块是在堆上分配的,它的生命周期不受函数作用域的限制,需要手动释放(使用delete[])来避免内存泄漏。
//拓展:指针变量本身也是一种局部变量,存储内存地址,存储在栈中。

对于下面代码段输出为() //答案是B
int x = 1, y = -1;
printf("%d\n", (x-- & ++y));
A 1
B 0
C -1
D 2 //这道题不难,只是需要知道的是& 用于获取地址或执行位运算的按位与操作。
//&& 用于执行逻辑与操作,并且具有短路特性。& 用于获取地址或执行位运算的按位与操作。
//两者的操作对象不同:按位与操作 (&):按位与操作是对两个操作数的每个对应位执行逻辑与操作,针对的是二进制的位。
//逻辑与操作 (&&):逻辑与操作是对两个条件进行逻辑与操作,针对的是布尔值或条件表达式。
//短路特性:按位与操作 (&):按位与操作不具有短路特性,即无论第一个操作数的值是什么,都会计算第二个操作数。
//逻辑与操作 (&&):逻辑与操作具有短路特性。如果第一个条件为假(0),则不会计算第二个条件,因为无论第二个条件的结果如何,整个表达式都将为假(0)

//拓展:整数类型的数据在内存中以二进制形式表示,可以直接进行位操作。
//而浮点数类型的数据使用浮点数表示法(如IEEE 754标准),包含有符号位、指数位和尾数位,不适合直接进行位操作。

下面代码会输出什么()//答案是c
class A {
public:
int m;
void print() {cout << "A\n";}
};

int main() {
A *pa = 0;
pa->print();
}
A、什么都没输出
B、A
C、编译报错
D、其余选项都错//在给定的代码中,pa 是一个指向类 A 的指针,并被初始化为 0(空指针)。然后,通过空指针 pa 调用了 print() 函数。
//但是由于pa 是一个空指针,它并不指向任何有效的对象或实例。在尝试通过空指针调用成员函数时,会导致未定义行为(undefined behavior)。

下面代码运行的结果是: 答案是 -1
int main() {
char x = 0xFFFF;
printf("%d\n",x--);
}//这里需要注意的是,关于截断的概念,当将一个大于类型表示范围的值赋给该类型变量时,会发生截断(truncation),只保留最低有效字节的值
//例如,0xFFFF赋值给char,就会发生截断,保留最低的一个有效字节的值,也就是八位二进制位,也就是11111111,还有需要注意的就是如果该变量的类型是有符号的
//那么截断之后的最高位便是符号位,如果是无符号数,那就不需要。
//还需要注意的点就是计算机中存储的数据是以补码形式存储的,但是输出时需要将补码转成原码,例如上面的11111111,转成原码为-1.

运行时的C程序,下列哪些变量在内存中的stack区域的有() //答案是BD
int a = 0;
char *p1;
int main(void) {
int b;
char s[] = "abc";
char *p2;
char *p3 = "123456";
static int c =0;
p1 = (char *)malloc(10);
free(p1);
return 0;
}
A、a
B、b
C、c
D、s
E、p1//这里需要注意的是,p1,a、c这些都是存储在data中的,b、s、p2、p3是存储在stack中的,malloc出来的是在堆中的。

执行下列语句后,y的值是()//答案是1
int x, y;
x=y=1;
++x || ++y;//这里需要注意的是,'||'和'&&'操作符是有短路特性的,‘||’中只要左侧为非零那么就会停止,‘&&’只要左侧为0那就停止。

下面四个选项中,均是正确的数值常量或字符常量的选项是()答案是D
A、0.0 0f 8.9e ‘&'
B、"a" 3.9e-2.5 lel ‘\”’
C、’3' 011 0xff00 0a
D、+001 0xabcd 2e2 //这里需要注意的是:A选项,8.9e后面的e必须跟整数,8.9和8.9e0是等价的,8.9e0也就是表示8.9*10的0次方。
//B选项中的“a”表示的是字符串常量,而不是字符常量。c选项中的0a是不合法的,以0开头的表示是八进制,八进制中没有a。

从一个数据文件中读入以换行符结束的一行字符串的函数为( )//答案是B
A、gets()
B、fgets()
C、getc()
D、fgetc()//拓展:char* gets(char str)的作用是函数用于从标准输入(键盘)读取字符串,但它有严重的隐患即缓冲区溢出。
//它无法检查输入的长度,因此如果输入的字符串超过了目标字符数组的大小,就会导致数据写入到其他内存区域,可能引发程序崩溃或安全漏洞。
//char
fgets(char* str, int size, FILE* stream);str,存储读取的字符串,size,读取的最大字符数,包括"\n",所以实际读取的size-1;
//stream,文件流指针,通常是stdin。
//int getc(FILE *stream);从指定文件中读取一个字符,并且返回对应字符的ASCII值作为整数值,如果到达文件末尾,则返回EOF。
//fgetc()和getc()作用是相同的。

4.在32位机器中,如下代码:
void example(char acWelcome[]){
printf("%d", sizeof(acWelcome));
return;
}
void main(){
char acWelcome[] = "Welcome to Huawei Test";
example(acWelcome);
return;
}
的输出是 //答案是B
A.0
B.4
C.23
D.24//这边需要注意的是,数组作为函数的参数是会退化为函数指针的,因为需要传递数组的大小,这边题目中,数组名变成了example()函数的参数
//所以,退化为函数指针,那么大小根据操作系统来定。
//拓展的是:一个数组int a[10],a和&a[0]都表示的是这个数组的第一个元素的地址,也就是数组的首地址,而&a,则表示的是整个数组的地址
//所以说要是想打印出23,那么则需要使用语句printf("%d",sizeof(&a));

4.广义表K=(m,n,(p,(q,s)),(h,f)),则head[tail[head[tail[tail(K)]]]]的值为( )//答案是B
A、s
B、q
C、p
D、h//这里需要注意的是在数据结构领域,广义表是一种扩充了线性表(即常见的列表)的数据结构。广义表可以包含其他广义表作为元素,因此是一种递归的数据结构。这也就是这个问题中的广义表 K 包含其他广义表(如(p,(q,s))和(h,f))作为元素。
//head操作是获取广义表的第一个元素;tail是删除第一个元素,并返回剩余部分。

解析XML时,需要校验节点是否闭合,如必须有与之对应,用()数据结构实现比较好//答案是D
A、链表
B、树
C、队列
D、栈//这里需要注意的是栈是一种后进先出(LIFO)的数据结构,可以用来跟踪节点的打开和关闭。
//当解析XML时,遇到一个开始标签(如),将该标签入栈。当遇到一个结束标签(如),则需要检查栈顶的元素是否与当前结束标签匹配。
//如果匹配,则将栈顶的元素出栈,表示该节点已经闭合。如果不匹配,则说明XML文档存在错误。

广义表运算式 Tail(((a,b),(c,d)))的操作结果是()。
A、(c,d)
B、c,d
C、((c,d))
D、d //这里需要注意的是A和c选项,因为tail操作是需要得到的是一个广义表,所以,需要加括号,head操作是获得得到一个元素,就不要加括号了

在单链表中,要将s所指结点插入到p所指结点之后,其语句应为() //答案是D
A、s->next=p+1; p->next=s;
B、(p).next=s; (s).next=(p).next
C、s->next=p->next; p->next=s->next;
D、s->next=p->next; p->next=s; //这里需要注意的是,对于A中的p+1在链表中是无法实现的,这样无法访问到下一个元素,对于B选项,
//对于B选项,(
p).next这个的写法和p->next的语法是一样的。但是B错在前一句是正确的,但是后一句话却会造成循环

线性表的链接实现有利于()运算 //答案是A
A、插入
B、读表元素
C、查找
D、定位//这里需要注意的是
//插入:链表可以在 O(1) 时间复杂度内完成插入操作,只要我们已经有了要插入位置的节点的引用。这是因为插入只需要改变几个指针的指向,不需要像数组那样移动元素。
//读表元素:在链表中,如果我们想读取一个特定的元素,我们通常需要从头节点开始,逐个节点地遍历,这是一个 O(n) 的操作。相比之下,数组可以在 O(1) 时间内读取任意位置的元素。
//查找:无论是链表还是数组,我们都需要遍历元素来查找特定的值,所以查找操作对于两者来说都是 O(n) 的操作。
//定位:定位通常意味着找到满足特定条件的元素的位置。链表需要从头到尾遍历以定位元素,这是一个 O(n) 的操作。而数组可以在 O(1) 时间内通过索引定位到任意位置的元素。

在顺序表中,只要知道_______,就可在相同时间内求出任一结点的存储地址。 //答案是D
A 基地址
B 结点大小
C 向量大小
D 基地址和结点大小//这里需要注意的是基地址和结点大小的概念
//基地址是顺序表在内存中的起始地址。也就是说,基地址是顺序表的第一个元素(即索引为0的元素)的内存地址。
//结点大小是指顺序表的每个元素占用的内存大小。

//关联数组:所谓的关联数组是指关联数组是一种存储键值对的数据结构,其中每个键都是唯一的,并映射到一个值。

某带链的队列初始状态为 front=rear=NULL 。经过一系列正常的入队与退队操作后, front=rear=10 。该队列中的元素个数为( ) //答案是A
A 1
B 0
C 1或0
D 不确定//这里需要注意的是,该题目中是带链的队列。当队列为空决定条件是front和rear等于NULL,或者就front等于NULL
//而front和rear等于时,但是并不是指向为NULL,所以该队列中的元素个数是1个

若某线性表最常用的操作是存取任一指定序号的元素和在最后进行插入和删除运算,则利用()存储方式最节省时间。 //答案是A
A 顺序表
B 双链表
C 带头结点的双循环链表
D 单循环链表 //这里需要注意的是,对于顺序表,存取任一指定序号元素的时间复杂度是O(1),在最后插入删除也是O(1)
//对于其他的选项,查询任意指定序号的元素的时间复杂度就为O(n),如若有指向链尾的指针的,那么时间复杂度就是O(1),若没有指向链尾的指针为O(n)

下列叙述中正确的是( )。 //答案是D
A
每一个结点有两个指针域的链表一定是非线性结构
B
所有结点的指针域都为非空的链表一定是非线性结构
C
循环链表是循环队列的链式存储结构
D
线性结构的存储结点也可以有多个指针 //这里需要注意的是。对于A选项要是是双链表的话,有两个指针域,但是它是线性结构,所以A是错误的
//对于B选项所有结点的指针域都为非空的话,也还是线性链表
//对于C选项,链表是链表,队列是队列,完全是不一样的

3.某一系统功能,需要一次性加载N(N在1000左右)个随机数,后续只对该集合进行遍历。最宜采用哪种结构存放? //答案是C
A
Hash表
B
二叉树
C
链表
D
图 //这里需要注意的是,题目中所需要的是只是对该集合进行遍历,对于Hash表进行查找时是十分的方便的,但是在遍历时却不是最优的
//对于二叉树的话,在复杂度相同的情况下,需要更多的额外空间来存储指向子节点的指针。此外,创建和维护一个平衡的二叉树需要花费更多的时间和计算资源。
//对于链表的话在此场景,只需要一次性加载数据,然后进行遍历操作,链表的效率十分高且操作简单。
//对于图的话,图是用于模拟网络关系的复杂数据结构,对于简单的遍历操作来说,显然过于复杂。

以下几种方式当中,稀疏矩阵压缩的存储方法是:() //答案是AD
A
三元组
B
二维数组
C
散列
D
十字链表 //这里需要注意的是AD,对于A选项的话,三元组可以节省很多空间,但是涉及矩阵运算的话,便需要移动大量的数据
//而其中的十字链表表示法的话,可以避免大量元素的移动,十字链表的结构为
//row col value 其中的row表示行,col表示列,value表示其中的值,down是指向同一列中的下一节点,right表示指向同行的下一个节点
// down right

线性表的链式存储结构既方便其存取操作,也方便其插入与删除操作,这种说法()//这样的说法是错误的,存取操作,相对于顺序表,就没那么方便了

有一个单向链表,头指针和尾指针分别为p,q,以下哪项操作的复杂度不受队列长度的影响? //答案是ACD
A
删除头部元素
B
删除尾部元素
C
头部元素之前插入一个元素
D
尾部元素之后插入一个元素 //这里需要注意的是对于其他的ACD选项的话,删除头部元素以及头部元素之前插入一个元素只需要移动头节点,时间复杂度是O(1),在尾部元素之后
//插入一个元素,只需要将最后一个元素的指针指向要插入的元素,然后将尾指针指向他,时间复杂度为O(1),但是B选项删除尾部元素,需要得到尾部指针的前一个节点,将其指针指向为NULL
//所以这样的话,就需要进行遍历,那么时间复杂度就变成了O(n);

线性表是具有 n 个()的有限序列(n>0) //答案是C
A 表元素
B 字符
C 数据元素
D 数据项//表元素可能是指组成表的个体元素,但这个定义并不特定于线性表
//B选项,线性表不仅仅只有字符,还有许多的数据类型
//D选项,数据项是指一个数据对象中的最小单位,例如一个记录中的一个字段。
//C数据元素包含一个或多个数据项,所以应该选c。

某单链表有5个元素,设单链表的节点结构为(data,next),5个元素的data依次为(1、2、3、4、5),
已知指针q指向节点3,指针p指向节点4,那么下面操作能将链表变为data依次为(1、2、3、5)的是____。 //答案是F
(其中temp为节点类型指针,默认指向NULL)
A q=p->next;
B p=q->next;
C p->next=q->next;
D q->next=p->next; delete q;
E p->data=p->next->data; p->next=p->next->next; delete p->next;
F temp = p->next; p->next=temp->next; p->data=temp->data; delete temp;temp=NULL;//这里需要注意的是
//E选项和F选项,对于E选型中的p->next=p->next->next,由于p->next->next,这个指针所指向的地址是不确定的,以及节点5是没有释放的,所以E是错误的
//所以F选项是正确的

设数据结构 B=(D, R) ,其中
D={ a, b, c, d, e, f }
R={ (a, b ) , (b, c ) , (c, d ) , (d, e), (e, f), (f, a) }
该数据结构为( )。 //答案是A
A 非线性结构
B 循环队列
C 循环链表
D 线性结构//B=(D,R)表达式中,B表示数据结构,D表示数据元素,R这个二元组表示的是数据元素的前后件关系
//所谓的线性结构有两个条件:1、有且只有一个根节点 2、每个非根节点有且只有一个前件,有且只有一个后件,这样的数据结构是线性结构,上述的题目中
//没有根节点,所以这是非线性结构

//顺序存储密度高,链式密度低的原因是:顺序存储,通常在内存中占据一段连续的空间,数据元素紧密地排列在一起。而链式存储除了实际的数据外,每个元素还需要额外的空间来存储指针。
//这意味着,相比顺序存储结构,链表需要更多的内存空间来存储同样数量的数据。

数据结构中的算法是对待特定问题求解步骤的一种描述,它是指令有限的序列,其中每一条指令表示一个或多个操作,算法一般具有如下哪些特点 //答案是ABC
A 确定性
B 可行性
C 有穷性
D 鲁棒性//这里需要注意的是算法的特性
//①有穷性 一个算法必须保证有限步之后结束 ②确定性 算法中每一条指令必须有确切的含义 ③可行性 算法中所有操作都必须通过已经实现的操作进行运算
//④输入 一个算法有0个或多个输入 ⑤输出 一个算法有一个或多个输出

将N条长度均为M的有序链表进行合并,合并以后的链表也保持有序,时间复杂度为() //答案是A
A O(N * M * logN)
B O(N*M)
C O(N)
D O(M) //优先队列可以用多种方式实现,例如通过数组、链表、堆或者二叉搜索树等。其中,堆(特别是二叉堆)是一种非常高效的优先队列实现方式,
//因为它可以在O(logN)的时间复杂度内插入和删除元素,同时在O(1)的时间复杂度内找到最大或最小的元素。
//每个节点都会被添加到优先队列中和从优先队列中移除一次,操作的时间复杂度是O(logN),总共有N * M个节点,所以总的时间复杂度是O(N * M * logN)。

便于插入和删除的容器是() //答案是ACD
A list
B vector
C map
D set//这里需要注意的是vector底层是数组,支持快速随机访问
//2:list 底层数据结构为双向链表,支持快速增删 3:map、set都是STL关联容器,支持快速增删

在表头和表尾都可能有元素被插入的情况下,在单循环链表中设置尾指针比设置头指针好//因为如果要在表尾插入一个元素,没尾指针就需要
//遍历整个链表,所以时间复杂度为O(n)。

用邻接表表示图进行深度优先遍历时,通常是采用()来实现算法的。 //答案是A
A 栈
B 队列
C 树
D 图//这里需要注意的是栈是一种后进先出(Last-In-First-Out,LIFO)的数据结构,它可以保存待访问的节点。
//在深度优先遍历中,从起始节点开始,将其入栈,然后按照一定规则选择一个未访问的相邻节点,将其入栈,继续深入探索。
//当无法继续深入时,回溯到前一个节点,从栈中弹出一个节点,继续探索其他路径,直到栈为空,遍历结束。
//广度优先遍历的话是依靠队列

判断下列说法是否正确:F=(a,F)是一个递归的广义表,它的深度是1,长度是2。( )//答案是B
A 正确
B 错误 //这里需要注意的是长度和深度的概念
//广义表是由n个元素组成的序列,n是广义表的长度。 广义表的深度: 广义表中括号的最大层数叫广义表的深度。
//这里长度为2,但是由于是递归,所以深度为无穷

将两个长度为 len1 和 len2 的升序链表,合并为一个长度为 len1+len2 的降序列表,采用 归并算法,在最坏情况下,比较操作的次数与( )最接近 .//答案是A
A len1+len2
B len1*len2
C min(len1,len2)
D max(len1,len2)//这里需要注意的是
//在最坏的情况下,需要先比较len1个元素,在对len1个元素进行比较之后,还需要将len2个元素与len1中的元素进行比较,
//所以,最坏的情况下的话,应该是len1+len2。

设链式栈中结点的结构为(data ,link),且top是指向栈顶的指针,若想在链式栈的栈顶插入一个由指针s所指的结点,则应执行( )操作。 //答案是C
A
top->link=s;
B
s->link=top->link; top->link=s;
C
s->link=top; top=s;
D
s->link=top; top=top->link;//这里需要注意的是
//A选项 :栈顶的下一个节点指向s,原栈中数据丢失。错误
//B选项 :相当于把s放到了top节点后当作第二节点。错误
//C选项 :s的link指向原top,新的top指向s。正确
//D选项 :把s放到头节点之前,再更新头节点为原第二节点,s和原top丢失。错误

下列哪些容器可以使用数组,但不能使用链表来实现? //答案是D
A 队列
B 栈
C 优先级队列
D Map或者Dict//这里需要注意的是
//Map(映射)Dict(字典),都是一种基于键值对的数据结构,它需要支持通过键来查找对应的值。
//在使用数组实现时,可以使用哈希函数将键映射到数组的索引位置,通过数组来存储键值对。这样可以实现较快的查找操作,时间复杂度为O(1)。
//而使用链表实现时,需要遍历链表来查找对应的键值对,时间复杂度为O(n)。因此,使用数组实现的Map或Dict可以提供更高效的查找操作。

关于单向链表,以下说法正确的有()//答案是ABD
A
单向链表中指向头结点的指针First,可用于单向链表的判空依据
B
单向链表中指向头结点的指针First,可用于定位所有其他结点的位置
C
已知操作节点地址的情况下,单向链表插入,删除的时间复杂度小于查找的时间复杂度
D
单向链表允许在非表头进行插入或删除操作 //c选项错在,对于已经知道操作节点地址的情况下,可以直接依靠
//这个地址直接查找访问到该节点,那么时间复杂度也就是O(1),和插入、删除一致

设有一组初始记录关键字序列为(34,76,45,18,26,54,92),则由这组记录关键字生成的二叉排序树的深度(根的深度为1)为()。//答案是A
A 4
B 5
C 6
D 7
//BST构造的时候,如果根节点为空,则首先序列的第一个作为根节点,然后第二个与根节点比较:小的放到左边,大的放到右边;
//根节点不为空的时候,待插入的节点跟根节点比较:小的往左子树去比较,大的往右子树去比较。
//比较过程中,待插入节点只作为某节点的左或右节点插入,而不会变动之前的节点位置。

有A,B,C,D,E五个字符,出现的频率分别为2,5,3,3,4,由A,B,C,D,E生成的最优二叉树中,该树的带权路径长是多少()//答案是C
A 35
B 49
C 39
D 45//这里需要注意的是
//最优二叉树,也就是它的wpl值最小时,也就是权值越大的叶节点越靠近根节点、权值越小的叶节点越远离根节点,
//在计算该树的带权路径的时候,也就是将每个节点的权与从根节点出发到该节点之间的路径长度的乘积之和(路径长度也就是,线的条数)

一棵有n个结点的二叉树,按层次从上到下、同一层从左到右顺序存储在一维数组A[1..n]中,则二叉树中第i个结点(i从1开始用上述方法编号)的右孩子在数组A中的位置是()
//答案为D
A A[2i](2i <= n)
B A[2i + 1](2i + 1 <= n)
C A[i - 2]
D 条件不充分,无法确定//这里需要注意的是
//在按照层次存储的二叉树中,左孩子的位置可以确定,因为它是按顺序存储的,紧跟在当前节点后面。
//但是右孩子的位置无法直接通过索引计算得出,因此无法确定右孩子的位置。
//这是因为按层次存储的二叉树在数组中并没有严格的规律来确定右孩子的位置,需要额外的信息或者其他数据结构来确定右孩子的位置。
//例如:
1
/
2 3
/ \
4 5 6

关于二叉树,下面说法正确的是()//答案为BD
A 二叉树中至少有一个节点的度为2
B 一个具有1025个节点的二叉树,其高度范围在11到1025之间
C 对于n个节点的二叉树,其高度为n*log(n)
D 二叉树的先序遍历是EFHIGJK,中序遍历为HFIEJKG,该二叉树的右子树的根为G
//对于c选项的话,高度取决于树的形状