书名:数据结构(C语言描述)(慕课版)
主编:范翠香 罗作民
副主编:宋昕 李晔
啊啊啊啊啊为什么这么快就要期末考了TAT
得知期末手写代码的一瞬间 : ) → ;(
期末复习用,题目手打,答案来自老师:)
爱来自你理曲江校区 ;)
一、客观习题
1.
一般情况下,将递归算法转换成等价的非递归算法应该设置(A)栈
2.
栈和队列的共同点是(C)只允许在特定端点处插入和删除元素
(A)都是先进后出 × 只有栈是先进后出
(B)都是先进先出 × 只有队列是先进先出
3.
若让元素1, 2, 3, 4, 5依次入栈,则出栈顺序不可能出现(C)4, 3, 1, 2, 5的情况
(A)5, 4, 3, 2, 1 →所有元素逐个入栈后逐个出栈即可
(B)2, 1, 5, 4, 3 →1, 2先入栈再依次出栈,剩下3, 4, 5全部入栈后再依次出栈即可
(D)2, 3, 5, 4, 1 →1, 2, 3入栈后出栈2、 3, 4、 5入栈后再依次出栈,最后1出栈即可
4.
设用链表作为栈的存储结构,则退栈操作(B)必须判别栈是否为空
5.
不带头结点的链式栈结点为(data,next),top指向栈顶,若想删除栈顶结点,并将删除结点的值保存到x中,则应执行的操作是(A)x = top->data; top = top->next;
6.
用数组data存储一个有n个元素的栈,初始栈顶位置top为n,则以下能将元素x入栈的正确操作为(C)top--; data[top] = x
7.
由两个栈共享一个数组空间的优势在于(B)节省存储空间,降低上溢发生的概率
8.
设有一个递归算法
则计算n!需要调用该函数的次数为(A)n+1
int fact(int n) // n大于或等于0
{
if (n <= 0)
return 1;
else
return n * fact(n - 1);
}
9.
设循环队列的容量为20,序号从0到19,经过一系列的入队和出队操作后,front=5,rear=10,问队列中有(B)5个元素(采用少用一个元素空间的方式区分队列空和队列满)
知识点:循环队列,元素个数=(rear-front+容量)%容量
其中rear指向队尾元素的后一位置,而不是队尾元素本身
10.
设计一个判别表达式中左、右括号是否配对出现的算法,采用(D)栈数据结构最佳
11.
用链式结构存储的队列,在进行删除运算时(D)头、尾指针可能都要修改
12.
数组Q[n]用来表示一个循环队列,f为当前队列头元素的前一个位置,r为队尾元素的位置。假定队列元素中的个数小于n,计算队列中元素个数的表达式是(D)(n+r-f)%n
13.
最大容量为n的循环队列,队尾指针是rear,队头是front,则队列空的条件是(B)rear==front
14.
最适合用作链队列的链表是(B)带队头指针和队尾指针的单向链表
15.
假设栈初始为空,将中缀表达式a/b+(c*d-e*f)/g 转换为等价的后缀表达式的过程中,当扫描到f时,栈中从栈底到栈顶的元素依次是(B)+(-*
二、简答题
1.
简要说明栈和队列的特点,试各举一个实例说明栈和队列在程序设计中的作用。
栈的特点是先进后出,因此在解决实际问题中涉及先进后出或者后进先出的情况时可以考虑使用栈。例如,求解表达式括号匹配问题时通常使用一个栈,将读到的左括号进栈,每读入一个右括号,判断栈顶是否为左括号,若是,则出栈;否则,表示不匹配。
队列的特点是先进先出。例如,求解操作系统中的作业排队问题时通常使用队列,因为在允许多道程序运行的计算机系统中同时有几个作业运行,若运行的结果都需要通过通道输出,则要按请求输出的先后次序排队。每当通道传输完毕并可以接受新的输出任务,队头的作业先从队列中退出进行输出操作,即出队;只要申请输出的作业都从队尾进入队列,即进队。
2.
假设有a、b、c、d这4个元素依次入栈,其中入栈和出栈操作可以交替进行,试写出所有可能的出栈序列
题表3.1 出栈序列
以a开头 | abcd | abdc | acbd | acdb | adcb |
以b开头 | bacd | badc | bcad | bcda | bdca |
以c开头 | cbad | cbda | cdba | ||
以d开头 | dcba |
3.
什么是队列的上溢现象和假溢出现象?解决假溢出的方法有哪些?
在队列的顺序存储结构中,假设队头指针为front、队尾指针为rear、队的存储空间大小为MaxSize。当有元素进队时,若rear=MaxSize(初始rear=0),则发生队列的上溢现象,不能进行进队操作。若队列中还有剩余空间但元素却不能进入队列,就是队列的假溢出现象,造成这种现象的原因是队列的设计不合理。
解决队列的假溢出方法有以下几种:
1) 建立一个足够大的空间,但这样做会造成空间的使用效率降低;
2) 当出现假溢出时可以采用以下几种方法:
(1)采用平移元素的方法:每当进队一元素时,队列中已有的元素向队头移动一个位置,这种方法对应进队运算得到时间复杂度为O(n);
(2)每当出队一个元素时,依次移动队中的元素,始终使front指针指向队列中的第一个元素位置,这种方法对应出队运算的时间复杂度为O(n);
(3)采用环形队列方式:把队列看成一个首尾相接的环形队列,在环形队列上进行进队或者出队运算时仍然遵循“先进先出”原则,这种方法对应进队和出队运算的时间复杂度为O(1).
4.
利用栈实现将中缀表达式8-(3+5)*(5-6/2)转换成后缀表达式,写出栈的变化过程
栈的变化过程如题表3.2所示,最后生成的后缀表达式求值结果为-8。
题表3.2 栈的变化过程
op栈 | postexp | 说明 |
8# | 将8#存入postexp中 | |
- | 8# | ‘-‘进栈 |
-( | 8# | ‘(‘进栈 |
-( | 8#3# | 将3#存入postexp中 |
-(+ | 8#3# | ‘+‘进栈 |
-(+ | 8#3#5# | 将5#存入postexp中 |
- | 8#3#5#+ | 遇到‘)‘,将‘+‘和‘(‘出栈 |
-* | 8#3#5#+ | ‘*‘进栈 |
-*( | 8#3#5#+ | ‘(‘进栈 |
-*( | 8#3#5#+5# | 将5#存入postexp中 |
-*(- | 8#3#5#+5# | ‘-‘进栈 |
-*(- | 8#3#5#+5#6# | 将6#存入postexp中 |
-*(-/ | 8#3#5#+5#6# | ‘/‘进栈 |
-*(-/ | 8#3#5#+5#6#2# | 将2#存入postexp中 |
-* | 8#3#5#+5#6#2#/- | 遇到‘)‘,将‘/‘‘-‘和‘(‘出栈 |
8#3#5#+5#6#2#/-*- | exp扫描完毕,将栈中所有运算符依次出栈并存入postexp中,得到后缀表达式 |
三、算法设计题
1.![](https://img-blog.csdnimg.cn/b8292640cefd4ed283c4e5192aba7761.jpeg)
1)算法描述:
int Ack(int m,n)
{ //Ack(m,n)的递归算法
if(m==0)
return (n+1); //递归结束
else if(m!=0&&n==0)
return (Ack(m-1,1)); //调用递归函数Ack(m-1,1)
else
return (Ack(m-1,Ack(m,n-1))); //调用递归函数Ack(m-1,Ack(m,n-1))
}
Ack(2,1)的计算过程为:
Ack(2,1)=Ack(1,Ack(2,0)) //因m≠n,n≠0而得
= Ack(1,Ack(1,1)) //因m≠n,n=0而得
= Ack(1,Ack(0,Ack(1,0))) //因m≠n,n≠0而得
= Ack(1,Ack(0,Ack(0,1))) //因m≠n,n=0而得
= Ack(1,Ack(0,2)) //因m=0而得
= Ack(1,3) //因m=0而得
= Ack(0,Ack(1,2)) //因m≠n,n≠0而得
= Ack(0, Ack(0,Ack(1,1))) //因m≠n,n≠0而得
= Ack(0,Ack(0, Ack(0,Ack(1,0)))) //因m≠n,n≠0而得
= Ack(0,Ack(0, Ack(0,Ack(0,1)))) //因m≠n,n=0而得
= Ack(0, Ack(0,Ack(0,2))) //因m=0而得
= Ack(0,Ack(0,3)) //因m=0而得
= Ack(0,4) //因n=0而得
= 5 //因n=0而得
2)算法描述:
int Ackerman(int m, int n)
{ //Ack(m,n)的非递归算法
for(j=0;j<n;j++) akm[0][j]=j+1; //得到Ack(0,n)的值
for(i=1;i<m;i++)
{
akm[i][0]=akm[i-1][1];
for(j=1;j<n;j++)
akm[i][j]=akm[i-1][akm[i][j-1]];
}
return (akm[m][n]);
}
2.
如果允许在循环队列的两端都可以进行插入和删除操作:
(1)写出循环队列的类型定义
(2)写出“从队尾删除”和“从队头插入”的算法
1) 算法描述:
typedef struct
{
QElemType *base; //存储空间的基地址
int front; //头指针
int rear; //尾指针
}SqQueue;
2) 算法描述:
Status EnQueue(SqQueue &Q, QElemType e)
{ //在Q的队头插入新元素e
if(Q.rear==(Q.front-1+M)%M) //判断队满
return ERROR;
Q.base[Q.front]=e; //新元素插入队头
Q.front(Q.front-1+M)%M; //修改队头指针
return OK;
}
Status DeQueue(SqQueue &Q, QElemType &e)
{ //删除Q的队尾元素,用e返回其值
if(Q.front==Q.rear) //判断队空
return ERROR;
e=Q.base[Q.rear]; //保存队尾元素
Q.rear=(Q.rear-1+M)%M; //队尾指针减1
return OK;
}
3.![](https://img-blog.csdnimg.cn/a0552a5186ba4c6e9150466e10f78958.jpeg)
# include<stdio.h>
# define MaxSize 100
void fun1()
{
int i,n,x;
int st[MaxSize],top=-1; //顺序栈和栈顶指针
int qu[MaxSize],front=0,rear=0; //队列和队指针
printf(“n:”);
scanf(“%d”,&n);
for(i=0;i<n;i++)
{
printf(“第%d个车皮编号:”,i+1);
scanf(“%d”,&x);
if(x%2==1) //编号为奇数,则进队
{
qu[rear]=x;
rear++;
printf(“%d进队\n”,x);
}
else //编号为偶数,则进栈
{
top++;
st[top]=x;
printf(“%d进栈\n”,x)
}
}
printf(“出轨操作:\n”);
while(front!=rear) //队列中的所有元素出队
{
printf(“%d出队”,qu[front]);
front++;
}
while(top>=0) //栈中的所有元素出队
{
printf(“%d出栈”,st[top]);
top--;
}
printf(“\n”);
}
int main()
{
fun1();
return 1;
}