《数据结构》习题2

一、单项选择题

  1. 以下数据结构中___属非线性结构。
    A.栈
    B.串
    C.队列
    D.平衡二叉树

  2. 以下算法的时间复杂度为___。

void func(int n)
{
    int i = 0, s = 0;
    while (s <= n)
    {
        i++;
        s = s + i;
    }
}

A. O ( n ) O(n) O(n)
B. O ( n ) O(\sqrt n) O(n )
C. O ( n l o g 2 n ) O(nlog_2^n) O(nlog2n)
D. O ( l o g 2 n ) O(log_2^n) O(log2n)

  • 该程序片段的功能是一直累加直到数值大于n,此时有 1 + 2 + 3 + . . . + x → ( 1 + x ) x 2 ≤ n → x ≈ n 1+2+3+...+x \rightarrow\frac{(1+x)x}{2}≤n\rightarrow x≈\sqrt n 1+2+3+...+x2(1+x)xnxn
  1. 在一个双链表中,删除p所指节点(非首、尾节点)的操作是___。
    A.p->prior->next=p->next;p->next->prior=p->prior;
    B.p->prior=p->prior->prior;p->prior->prior=p;
    C.p->next->prior=p;p->next=p->next->next;
    D.p->next=p->prior->prior;p->prior=p->prior->prior;

  2. 设n个元素进栈序列是1、2、3、…、n,其输出序列是 p 1 、 p 2 、 … 、 p n p_1、p_2、…、p_n p1p2pn,若 p 1 = 3 p_1=3 p1=3,则 p 2 p_2 p2的值为___。
    A.一定是2
    B.一定是1
    C.不可能是1
    D.以上都不对

  3. 在数据处理过程中常需要保存一些中间数据,如果要实现后保存的数据先处理,则应采用___来保存这些数据。
    A.线性表
    B.栈
    C.队列
    D.单链表

  • 先进先出选队列;后进先出选栈
  1. 中缀表达式a*(b+c)-d的对应的后缀表达式是___。
    A.a b c d * + -
    B.a b c +* d -
    C.a b c * + d -
    D.- + * a b c d

  2. 设栈s和队列q的初始状态都为空,元素a、b、c、d、e和f依次通过栈s,一个元素出栈后即进入队列q,若6个元素出队的序列是b、d、c、f、e、a,则栈s的容量至少应该存多少个元素?
    A.2
    B.3
    C.4
    D.5

  • 第一个入队(出栈)元素为b,在出栈之前,栈中有a、b两个元素;第而个入队(出栈)元素为d,在出栈之前,栈中有a、c、d三个元素…以此类推,栈中暂存的元素不会多于三个
  1. 设循环队列中数组的下标是0~N-1,其队头队尾指针分别为f和r(f指向队首元素的前一位置,r指向队尾元素),则其元素个数为___。
    A.r-f
    B.r-f-1
    C.(r-f)%N+1
    D.(r-f+N)%N

  2. 若将n阶上三角矩阵A按列优先顺序压缩存放在一维数组 B [ 1.. n ( n + 1 ) 2 ] B[1..\frac{n(n+1)}2] B[1..2n(n+1)]中,A中第一个非零元素 a 1 , 1 a_{1,1} a1,1存于B数组的 b 1 b_1 b1中,则 a i , j a_{i,j} ai,j应存放到 b k b_k bk中的非零元素 a i , j a_{i,j} ai,j(1≤i≤n,1≤j≤i)的下标i、j与k的对应关系是___。
    A. i ( i + 1 ) 2 + j \frac{i(i+1)}{2}+j 2i(i+1)+j
    B. i ( i − 1 ) 2 + j \frac{i(i-1)}{2}+j 2i(i1)+j
    C. j ( j + 1 ) 2 + i \frac{j(j+1)}{2}+i 2j(j+1)+i
    D. j ( j − 1 ) 2 + i \frac{j(j-1)}{2}+i 2j(j1)+i

  • 假设取5×5的矩阵,按照列优先存放,如果要满足i≥j的条件,则 b 10 b_{10} b10 a 4 , 4 a_{4,4} a4,4 b 14 b_{14} b14 a 4 , 5 a_{4,5} a4,5 b 15 b_{15} b15 a 5 , 5 a_{5,5} a5,5,带到选项逐个验证
  1. 一棵结点个数为n的m(m≥3)次树中,其分支数是___。
    A.nh
    B.n+h
    C.n-1
    D.h-1
  • 除根结点外,每一个结点头上都会连有一条线(即分支),因此分支数比结点数少一个,并且分支数与高度h无关
  1. 设森林F对应的二叉树为B,B中有m个节点,其根节点的右子树的节点个数为n,森林F中第一棵树的节点个数是___。
    A.m-n
    B.m-n-1
    C.n+1
    D. 条件不足,无法确定
  • 森林转换为二叉树时,先把每颗单独的森林转化为二叉树(此时根结点均无右孩子,只有左孩子),然后依次把它们连在前一棵二叉树的根结点的右孩子上。因此,第一颗森林的结点数就是整颗二叉树的左子树中的结点数,而右子树中的结点数则是剩余森林结点的总和
  1. 一棵二叉树的先序遍历序列为ABCDEF,中序遍历序列为CBAEDF,则后序遍历序列为___。
    A.CBEFDA
    B.FEDCBA
    C.CBEDFA
    D.不确定

  2. 在一个具有n个顶点的有向图中,构成强连通图时至少有___条边。
    A.n
    B.n+1
    C.n-1
    D.n/2

  3. 对于有n个顶点的带权连通图,它的最小生成树是指图中任意一个___。
    A.由n-1条权值最小的边构成的子图
    B.由n-1条权值之和最小的边构成的子图
    C.由n-1条权值之和最小的边构成的连通子图
    D.由n个顶点构成的极小连通子图,且边的权值之和最小

  4. 对于有n个顶点e条边的有向图,求单源最短路径的Dijkstra算法的时间复杂度为___。
    A. O ( n ) O(n) O(n)
    B. O ( n + e ) O(n+e) O(n+e)
    C. O ( n 2 ) O(n^2) O(n2)
    D. O ( n e ) O(ne) O(ne)

  • Dijkstra—— O ( n 2 ) O(n^2) O(n2)
  • Floyd—— O ( n 3 ) O(n^3) O(n3)
  • Kruskal—— O ( e l o g 2 e ) O(elog_2^e) O(elog2e)
  • Prim—— O ( n 2 ) O(n^2) O(n2)
  1. 一棵深度为k的平衡二叉树,其每个非叶子节点的平衡因子均为0,则该树共有___个节点。
    A. 2 k − 1 − 1 2^{k-1}-1 2k11
    B. 2 k − 1 2^k-1 2k1
    C. 2 k − 1 + 1 2^{k-1}+1 2k1+1
    D. 2 k − 1 2^k-1 2k1

每个非叶子节点的平衡因子均为0,说明它是一棵满二叉树
在这里插入图片描述
平衡因子:某结点的左子树与右子树的高度(深度)差即为该结点的平衡因子(一定是左边-右边)。平衡二叉树上所有结点的平衡因子只可能是 -1,0或1。

  1. 对线性表进行折半查找时,要求线性表必须___。
    A.以顺序方式存储
    B.以链接方式存储
    C.以顺序方式存储,且节点按关键字有序排序
    D.以链表方式存储,且节点按关键字有序排序

  2. 假设有k个关键字互为同义词,若用线性探测法把这k个关键字存入哈希表中,至少要进行___次探测。
    A.k-1
    B.k
    C.k+1
    D.k(k+1)/2

  3. 以下排序算法中,某一趟排序结束后未必能选出一个元素放在其最终位置上的是___ 。
    A.堆排序
    B.冒泡排序
    C.直接插入排序
    D.快速排序

  • A:堆排序每趟总能选出一个最大值或者最小值位于根结点。
    B:冒泡排序总是两两比较选出一个最小值位于数组前面。
    C:直接插入排序不一定会位于最终的位置,因为不确定后面插入的元素对于前面的元素是否产生影响。
    D:快排选出的枢轴在一趟排序中就位于了它最终的位置
  1. 以下排序方法中,___不需要进行关键字的比较。
    A.快速排序
    B.归并排序
    C.基数排序
    D.堆排序
  • 基数排序不基于比较和移动

二、问答题
22. 已知一棵度为m的树中有 n 1 n_1 n1个度为1的节点, n 2 n_2 n2个度为2的节点,…, n m n_m nm个度为m的节点,问该树中有多少个叶子节点?

  • 设叶子结点有 n 0 n_0 n0个,则 n 0 + n 1 + n 2 + . . . + n m = 0 ⋅ n 0 + 1 ⋅ n 1 + 2 ⋅ n 2 + . . . + m ⋅ n m + 1 n_0+n_1+n_2+...+n_m=0·n_0+1·n_1+2·n_2+...+m·n_m+1 n0+n1+n2+...+nm=0n0+1n1+2n2+...+mnm+1
    n 0 = 1 ⋅ n 2 + 2 ⋅ n 3 + . . . + ( m − 1 ) ⋅ n m = ∑ i = 2 m ( i − 1 ) ⋅ n i + 1 n_0=1·n_2+2·n_3+...+(m-1)·n_m=\sum_{i=2}^{m}(i-1)·n_i+1 n0=1n2+2n3+...+(m1)nm=i=2m(i1)ni+1
  1. 设数据集合D={1,12,5,8,3,10,7,13,9},试完成下列各题:
    (1)依次取D中各数据,构造一棵二叉排序树bt;
    (2)如何依据此二叉树bt得到D的一个有序序列;
    (3)画出在二叉树bt中删除12后的树结构。

在这里插入图片描述

  • 中序遍历二叉树,可以得到递增有序的序列
  • 删除结点12,可以让12的前驱结点(10)代替,也可以让后继结点(13)代替。图中给的是以前驱结点代替的示意图,如果使用后继结点代替,则将12改成13,删除结点13即可。
  1. 一个有n个整数的数组R[1…n],其中所有元素是有序的,将其看成是一棵完全二叉树,该树构成一个堆吗?若不是,请给一个反例,若是,请说明理由。
  • 该数组一定构成一个堆,递增有序数组构成一个小根堆,递减有序数组构成一个大根堆。
    以递增有序数组为例,假设数组元素为 k 1 、 k 2 、 … 、 k n k_1、k_2、…、k_n k1k2kn是递增有序的,从中看出下标越大的元素值也越大,对于任一元素ki,有 k i < k 2 i , k i < k 2 i + 1 ( i < n 2 ) ) k_i<k_{2i},k_i<k_{2i+1}(i<\frac n2)) ki<k2iki<k2i+1(i<2n),这正好满足小根堆的特性,所以构成一个小根堆。

三、算法设计题

  1. A = ( a 1 , a 2 , … , a n ) , B = ( b 1 , b 2 , … , b m ) A=(a_1,a_2,…,a_n),B=(b_1,b_2,…,b_m) A=(a1,a2,,an)B=(b1,b2,,bm)是两个递增有序的线性表(其中n、m均大于1),且所有数据元素均不相同。假设A、B均采用带头节点的单链表存放,设计一个尽可能高效的算法判断B是否为A的一个子序列,并分析你设计的算法的时间复杂度和空间复杂度。

[!点击] 参考第16题

  • 时间复杂度为O(m+n),空间复杂度为O(1)
int SubSeq(LinkList* A, LinkList* B)
{
	LinkList* p = A->next, * q = B->next;
	while (p != NULL && q != NULL) //找两个单链表中第一个值相同的结点
	{
		if (p->data < q->data) p = p->next;
		else if (p->data > q->data) q = q->next;
		else break;
	}
	while (p != NULL && q != NULL && p->data == q->data)
	{	//当两者值相等时同步后移
		p = p->next;
		q = q->next;
	}
	if (q == NULL) return 1; //当B中结点比较完毕返回1
	else return 0; //否则返回0	
}
  1. 假设二叉树b采用二叉链存储结构存储,试设计一个算法,输出该二叉树中从根节点出发的第一条最长的路径长度,并输出此路径上各节点的值。并分析你设计的算法的时间复杂度和空间复杂度。

点击! 参考链接中的第五题

  • 本算法的时间复杂度为O(n),空间复杂度为O(n)

四、附加题

假设一个图G采用邻接表作为存储结构,设计一个算法,判断该图中是否存在回路。

  • 使用拓扑排序判断图中是否存在回路:
int Indegree[MaxVertexNum] = { 0 }; //全局变量,统计各顶点的入度
bool HasCycle(AdjGraph g)
{
	int i, j, count = 0;
	for (i = 0; i < g.vexnum; i++) 
		Indegree[i] = CountInDegree(g, g.adjlist[i].data); //将每个顶点的入度存入一维数组中
	for(i = 0; i < g.vexnum; i++) //双重循环查找入度为0的顶点
		for (j = 0; j < g.vexnum; j++)
		{
			if (Indegree[j] == 0)
			{
				count++; //如果某个结点入度为0,则计数值增加
				Indegree[j] = -1; //访问过的顶点入度标为-1
				printf("%c ", g.adjlist[j].data); //输出该结点的值
				ArcNode* p = g.adjlist[j].firstarc;
				while (p != NULL)
				{
					Indegree[p->adjvex]--; //该顶点相连的其他顶点入度减1
					p = p->nextarc; //指针后移
				}
			}
		}
	if (count == g.vexnum) return false; //输出的数据个数如果等于顶点数,说明不存在回路
	else return true; //否则说明存在回路
}

运行结果:

  • 此算法没有使用栈,因此需要反复遍历记录顶点入度的数组,因此时间复杂度为O(|V|²)。如果借助栈来实现(将入度为0的顶点放入栈中,便于读取),可以使时间复杂度降低到O(|V|+|E|)。
  • 借助栈实现的代码参考→邻接矩阵&邻接表法的拓扑排序
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值