√一、单项选择题
1. 以下不属于存储结构是____。
A.栈
B.线索树
C.哈希表
D.双链表
!栈是一种数据结构,不是存储结构
2. 以下算法的时间复杂度为____。
void fun(int n)
{
int i = 1;
while (i <= n)
i = i * 3;
}
A.
B.
C.
D.
3. 在含有n个节点的单链表中查找第i个节点的平均时间复杂度是____。
A.
B.
C.
D.
4. 设栈S和队列Q的初始状态均为空,元素a,b,c,d,e,f,g依次进入栈S。若每个元素出栈后立即进入队列Q,且7个元素出列的顺序是b,d,c,f,e,a,g,则栈S的容量至少是____。
A. 1
B. 2
C. 3
D. 4
5. 已知循环队列存储在一维数组A[0…n-1]中,且队列非空时front和rear分别指向队头元素和队尾元素。若初始时队列空,且要求第一个进入队列的元素存储在A[0]处,则初始时front和rear的值分别是____。
A. 0,0
B. 0,n-1
C. n-1,0
D. n-1,n-1
6. 一个n×n的对称矩阵A,如果采用以列优先(即以列序为主序)的压缩方式存放到一个一维数组B中,则B的容量为____。
A.
B.
C.
D.
7. 若一棵3次树中有a个度为1的节点,b个度为2的节点,c个度为3的节点,则该树中有____个叶子节点。
A.1+2b+3c
B.a+2b+3c
C.2b+3c
D.1+b+2c
8. 一个无向连通图中有16条边,所有顶点的度均小于5,度为4的顶点有3个,度为3的顶点有4个,度为2的顶点有2个,则该图有____个顶点。
A.10
B.11
C.12
D.13
9. 一个表示工程的AOE网中的关键路径____。
A.必须是唯一的
B.可以有多条
C.可以没有
D.以上都不对
10. 用邻接矩阵表示图,对于求从某源点到其余各顶点的Dijkstra算法,在图的顶点数为10时计算时间约为10ms,则在图的顶点数为40时计算时间约为____ms。
A.10
B.80
C.160
D.200
- 不论图采用邻接矩阵还是采用邻接表来存储,使用Dijkstra算法求单元最短路径问题的时间复杂度均为,当顶点数量变为原来的4倍时,计算时间为原的4²=16倍
11. 设有100个元素的有序表,用折半查找时,成功时最大的比较次数是____。
A.25
B.50
C.10
D.7
- 折半查找的时间复杂度为
12. 在含有27个节点的二叉排序树上,查找关键字为35的节点,则依次比较的关键字有可能是____。
A.28,36,18,46,35
B.18,36,28,46,35
C.46,28,18,36,35
D.46,36,18,26,35
13. 采用递归方式对顺序表进行快速排序,下列关于递归次数的叙述中,正确的是____。
A. 递归次数与初始数据的排列次序无关
B. 每次划分后,先处理较长的分区可以减少递归次数
C. 每次划分后,先处理较短的分区可以减少递归次数
D. 递归次数与每次划分后得到的分区处理顺序无关
- 快速排序的递归次数与元素的初始排列有关。如果每一次划分后两个区域所包含的元素个数几乎相同时,此时的递归次数少;如果划分后分区不平均,则递归次数多。但快速排序的递归次数与分区处理顺序无关,即先处理较长的分区或先处理较短的分区都不影响递归次数。
- 此外,可以形象地把快速排序的递归调用过程用一个二叉树描述,先处理较长或较短分区,可以想象为交换某一递归结点处的左右子树,这并不会影响树中的分支数。
14. 数据序列{8,9,10,4,5,6,20,1,2}只能是____算法的两趟排序后的结果。
A.简单选择排序
B.冒泡排序
C.直接插入排序
D.堆排序
15. 对一组数据(84,47,25,15,21)排序,数据在排序过程中的变化如下:
(1)84,47,25,15,21
(2)21,47,25,15,84
(3)15,21,25,47,84
(4)15,21,25,47,84
则所采用的排序方法是____。
A.冒泡排序
B.快速排序
C.堆排序
D.直接插入排序
- 冒泡排序(2)中第一个元素应该为序列中的最小值
直接插入排序(2)中第一个元素应该为47
16. 将中缀表达式转换为等价的后缀表达式的过程中要利用堆栈保存运算符。对于中缀表达式A-(B+C/D)×E,当扫描读到操作数E时,堆栈中保存的运算符依次是() 。
A.- ×
B.- ( ×
C.- +
D.- ( +
- 先将中缀表达式转换为后缀表达式:A B C D / + E × -
当扫描到中缀中的E时,后缀中E之后还有× -,并且×应该在栈顶,-应该在栈底
17. 若一台计算机具有多个可以并行运行的CPU,就可以同时执行相互独立的任务,则下列排序算法中,适合并行处理的是() 。
l.选择排序 Ⅱ.快速排序 Ⅲ.堆排序 Ⅳ.基数排序 Ⅴ.归并排序 Ⅵ.希尔排序
A.lI、V和VI
B. l、Ⅲ和Ⅴ
C.ll、Ⅲ、IV和V
D.l、ll、Ⅲ、IV和V
- 并行处理可以理解为:把一个大问题分解为多个小问题,然后分别进行处理。
18. 相比邻接矩阵,下列算法使用邻接表效率更高的是()
l.拓扑排序 Ⅱ.广度优先搜索 Ⅲ.深度优先搜索 V.普里姆(Prim)算法
A.Ⅱ、Ⅲ
B.Ⅰ、Ⅱ
C.Ⅰ、Ⅱ、Ⅲ、Ⅳ
D.Ⅱ
19. 含有16个结点的平衡二叉树最大深度为()
A.4
B.5
C.6
D.7
- 在含有n个结点的平衡二叉树的最大深度为,这个公式的根节点不算高度,所以结果要加1→
或者使用公式,其中。计算可得(此时已经多于16个结点)
20. 由4个结点可以构造出( )种不同的二叉排序树。
A.4
B.6
C.10
D.14
- 求解该题即与卡特兰数相关,将n=4代入公式,求得共有14种不同情况
二、问答题
1. 若已知一棵完全二叉树(所有节点值均不同)的先序、中序或后序遍历序列中的一种,能够唯一确定这棵二叉树吗?如果能,请以其中一种遍历序列来说明构造该二叉树的过程。如果不能,并举一个反例予以说明。
- 能够。因为任一种遍历序列中含有节点个数n,当n已知时就可以确定完全二叉树的形态,以给定先序遍历序列a1a2…an为例,由该完全二叉树形态得到的先序遍历序列b1b2…bn,则bi=ai,这样就可以唯一构造这棵二叉树。
- !若是完全二叉树,只有先序、中序或后序遍历序列中的一种,能够唯一确定这棵二叉树;若不是完全二叉树,只有一种遍历序列不能唯一确定一棵二叉树。
2. 简述堆和二叉排序树的区别。
- 以小根堆为例,堆的特点是双亲结点的关键字必然小于等于孩子结点的关键字,而两个孩子结点的关键字没有次序规定。而二叉排序树中,每个双亲结点的关键字均大于左子树节点的关键字,每个双亲结点的关键字均小于右子树结点的关键字,也就是说,每个双亲节点的左、右孩子的关键字有次序关系。这样,当对两种树执行中序遍历后,二叉排序树会得到一个有序的序列,而堆则不一定能得到一个有序的序列。
3. 对于一个堆栈,若其入栈序列为1,2 3. n,不同的出入栈操作将产生不同的出栈序列。其出栈序列的个数正好等于结点个数为n的二叉树的个数,且与不同形态的二叉树一一对应。请简要叙述一种从堆栈输入(固定为1,2,3., n)/输出序列对应一种二叉树形态的方法,并以入栈序列1,2,3(即n=3)为例加以说明。
- 关键点:二叉树的前序遍历序列作为入栈序列,那么对应的出栈序列为中序遍历序列。
即要根据先序遍历结果和中序遍历结果来唯一确定一棵二叉树,代码实现参考→点击!具体算法实现
三、算法设计题
1. 用单链表来存储集合,并假设这样的单链表中的节点递增有序,设计一个尽可能高效的算法求两个集合A和B的并集C。设A、B中分别有m和n个元素,分析你设计的算法的时间和空间复杂度。
- 点击 !参考第七题(2)
2. 假设二叉树采用二叉链存储结构进行存储,假设每个节点值为单个字符且所有节点值不同,设计一个算法,输出二叉树b中第k层的所有节点值,并分析你所设计算法的时间复杂度。
- 该算法可采用先序/中序/后序/层次遍历
点击! 层序遍历思想参考第九题
使用先序遍历求第k层所有结点代码如下:
void Prekth(BiTNode* t, int k,int h)
{
if (t != NULL)
{
if (h == k) printf("%c ", t->data);
Prekth(t->lchild, k, h + 1);
Prekth(t->rchild, k, h + 1);
}
}
Prekth(t, 3, 1);
3. 图的邻接表是一种图的链式存储结构,请给出邻接表的完整类型定义。采用你所设计的邻接表作为存储结构,设计一个算法,求出无向图G的连通分量个数。
- 此处提供两种解决此问题的方法:
①使用并查集点击!使用并查集求无向图的连通分量数
②使用深度/(广度)优先遍历算法
VertexType visited[50] = { 0 };
int count = 0;
void DFS(MGraph g, int i) //深度优先遍历
{
visited[i] = true;
for (int j = FirstNeighbor(g, g.Vex[i]); j >= 0; j = NextNeighbor(g, g.Vex[i], g.Vex[j]))
{
if (!visited[j])
{
visited[j] = true;
DFS(g, j);
}
}
}
void DFS_Traverse(MGraph g, VertexType x)
{
int i, j;
for (i = 0; i < g.vexnum; i++)
{
visited[i] = false; //访问数组初始化
if (g.Vex[i] == x) j = i; //寻找顶点x的数组下标
}
DFS(g, j); //从顶点x开始进行访问
count++;
for (i = 0; i < g.vexnum; i++)
if (!visited[i])
{
DFS(g, i);
count++; //每次调用DFS后,连通分量数增加
}
}
运行结果:
4. 在数组中,某个数字减去它右边的数字得到一个数对之差。求所有数对之差的最大值。例如,在数组{2,4,1,16,7,5,11,9}中,数对之差的最大值是11,是16减去5的结果。
- 算法思想:①先遍历一遍数组,找到数组中最大值的位置index
②根据最大值的位置,分三种情况进行分析:
int FindPairNum(int a[], int num)
{
int i, j, max = a[0], min, index = 0;
for (i = 1; i < num; i++) //遍历查找数组中的最大值
if (a[i] >= max) //如果存在多个相同的次大值,保留最后出现的那个
{
max = a[i]; //更新最大值
index = i; //最大值的数组下标
}
if (index == num - 1) //最大值在末尾的情况
{
max = a[0]; //把第一个元素看作是最大值
for(j = 1; j < num-2; j++) //遍历查找数组中的次大值
if (a[j] > max) max = a[j]; //此时的max为次大值
return max - a[index]; //a[index]为最大值
}
else if (index == 0) //最大值在开头的情况
{
min = a[0]; //把第一个元素看作是最小值
for (j = 1; j < num; j++) //遍历查找数组中的最小值
if (a[j] < min) min = a[j];
}
else
{
min = a[index+1]; //把最大值的下一位作为最小值
for (j = index + 1; j < num; j++) //从最大值的下一位开始遍历,查找数组中的最小值
if (a[j] < min) min = a[j];
}
return max - min;
}
运行结果:
时间复杂度:
此题还可以采用分治法/动态规划,时间复杂度为
如果使用暴力解法,直接双重嵌套循环,时间复杂度为