电子科大信软互+班 程算II 2022春机考真题(含答案)

目录

基本情况

具体题目

1 线性表1

2 线性表2

3 栈

4 二叉树

5 树

6 图

7 排序

自我练习

声明


基本情况

对应课程:程序设计与算法基础II(数据结构与算法基础)

考试时间:3小时

题型:函数题

考试年级:2021级

每个题目均会完整给出 一、已知条件   二、任务描述   三、编码要求 (包括提示) 三个部分;

第四部分为编者的答案,可能不是最优,欢迎探讨。


具体题目

1 线性表1

(题目编号:176)

一、已知条件

有线性表的存储结构表示如下:

#define MAXLEN  128

typedef struct {
    int elem[MAXLEN]; //存储数据的数组。下标从0开始。
    unsigned len;     //数组中数据的个数
} list;

二、任务描述

请设计一个算法,其功能是:

  • 在一个给定的线性表中,移除所有能被指定正整数整除的元素
  • 操作完成后的线性表中保留的元素呈连续存储的状态

三、编码要求

1. 算法函数原型

void remove_elem(list *L, unsigned f);
  • 功能:在线性表L中移除所有能被f整除的元素。
  • 参数:
    L:指向线性表的指针。线性表可能为空。
    f:整除因子。测试用例保证f不小于2。
  • 返回值:无

2. 编码约束

  • 时间复杂度:O(L->len)
  • 空间复杂度:O(1)

四、参考答案

/*
 * 完成人 :***
 * 完成时间:***
 * 系统评分:100
 */


#include "176.h" //本题所需头文件,请勿删除!
/* 
 * 功能:
 *      在线性表L中移除所有能被f整除的元素。
 * 参数:
 *      L:指向线性表的指针。线性表可能为空。
 *      f:整除因子。测试用例保证f不小于2。
 * 返回值:
 *      无
 */
void remove_elem(list *L, unsigned f) {
    //TODO
   
    int tmp[1000]={0};
    int cou=0;
    for(int i=0;i<L->len;i++){
        if(L->elem[i]%f!=0)
            tmp[cou++]=L->elem[i];
    }
    for(int i=0;i<cou;i++){
        L->elem[i]=tmp[i];
    }
    L->len=cou;
    return;
}

2 线性表2

(题目编号:177)

一、已知条件

有单链表表示的线性表结构定义如下:

//定义节点类型
typedef struct _node {
    int data;           //数据域
    struct _node *next; //指针域
} node;

//定义单链表类型
typedef struct {
    node *head;      //头指针
    unsigned len;    //链表中的节点数量
} list;


现已知有两个上述类型的线性表La和Lb,二者在某个结点处融合在一起。如图 q2.png 所示:

提示:该图只是一个示例,La不一定总是比Lb长;两个链表都可能为空。

二、任务描述

请设计一个算法,计算两个链表共享结点的数量。

三、编码要求

1. 算法函数原型

int list_shared(list *La, list *Lb);
  • 功能:计算并返回线性表La和Lb的共享结点的数量
  • 参数:La和Lb都是指向线性表的指针
  • 返回值:La和Lb共享结点的数目

2. 编码约束

  • 时间复杂度:O(max(La->len, Lb->len))
  • 空间复杂度:O(1)

四、参考答案

/*
 * 完成人 :***
 * 完成时间:***
 * 系统评分:100
 */


#include "177.h" //本题所需头文件,请勿删除!
/* 
 * 功能:
 *      统计两个线性表中共享结点的个数。
 * 参数:
 *      La和Lb:指向线性表的指针。
 * 返回值:
 *      La和Lb共享结点的数目。
 */

//答案一(编者答案)
int list_shared(list *La, list *Lb) {
    //TODO
    if(La->head==NULL||Lb->head==NULL) return 0;
    node* p,*q;
    p=La->head;
    q=Lb->head;
    while(p->next!=NULL){
        p=p->next;
    }
    while(q->next!=NULL){
        q=q->next;
    }
    if(p!=q) return 0; 
    p=La->head;
    q=Lb->head;
    //int num=0;
    while(p!=q){
       if(p->next==NULL){
            p=La->head;
       }
       else{
            p=p->next;
       }

       if(q->next==NULL){
            q=Lb->head;
       }
       else{
            q=q->next;
       }
   
    }
    int cou=1;
    while(p->next!=NULL){
        p=p->next;
        cou++;
    }
    return cou;
}

//答案二(某同学答案)
//个人认为这个答案不满足时间复杂度要求,但是仍然通过
int list_shared(list *La, list *Lb) {
    node *p = La->head,*q = Lb->head;

    if(p==NULL||q == NULL)  return 0;


    int cnt = 0;

    for(;p!=NULL;p = p->next)
    {
        for(;q!=NULL;q = q->next)
            {
                if(p == q)
                {
                    cnt++;
                    break;
                }
            }

        q = Lb->head;
    }
    return cnt;
}

3 栈

(题目编号:178)

一、已知条件

有一个递归函数如下:

void reverse() {
    char c = getchar();
    if (c == '.') return;
    
    reverse();
    putchar(c);
}

其功能是将输入的字符序列(以'.'结尾)倒序输出(不包括'.')。例如:
输入:abc123.
输出:321cba

另有可用的接口函数如下:

void push(stack *S, char x);    //将字符x压入栈S。S是指向栈的指针
char pop(stack *S);             //弹栈,返回S栈顶数据
bool empty(stack * S);          //测试栈S是否为空。如果为空,返回true,否则返回false

二、任务描述

请设计一个算法,利用栈,消除reverse()中的递归,但功能不变。

三、编码约束

1. 算法函数原型:

void reverse(stack *S);
  • 功能:将输入的字符序列倒序输出。输入以'.'结尾
  • 参数:S是指向栈的指针。栈S已经初始化
  • 返回值:无

2. 编码约束

  • 时间复杂度:无特别要求
  • 空间复杂度:O(1)(不计栈空间)

提示:常量空间复杂度意味着,除了使用栈和单个变量,你不能定义类似于数组这样的辅助存储。

四、参考答案

/*
 * 完成人 :***
 * 完成时间:***
 * 系统评分:100
 */


#include "178.h" //本题所需头文件,请勿删除!
/* 
 * 功能:
 *      将输入的字符序列(以'.'结尾)倒序输出。
 * 参数:
 *      S是指向栈的指针。栈S已经初始化。
 * 返回值:
 *      无。
 */
void reverse(stack *S) {
    //TODO 输入字符请用getchar()
    
    
    char c = getchar();
    while(c!='.'){
        push(S,c);
        c=getchar();
    }
    
    while(!empty(S)){
        char x=pop(S);
        if(x=='.') continue;
        else{
            putchar(x);
        }
    }
    return;
    
    


}

4 二叉树

(题目编号:179)

一、已知条件

设有两棵二叉树t1和t2。如果t2是t1左右翻转得到,如图 q4.png 所示:


那么称二叉树t1和t2互为镜像

二叉树的存储结构如下:

typedef struct _btree_node {
    char tag;   //二叉树结点的字符标签
    struct _btree_node *left, *right; //左子树和右子树
} btree_node, *btree;

二、任务描述

请设计一个算法,实现一棵二叉树的镜像翻转。

三、编码约束

1. 算法函数原型:

btree mirror(btree tree);
  • 功能:生成二叉树tree的镜像二叉树,返回镜像二叉树的根结点指针
  • 参数:tree是指向源二叉树根结点的指针
  • 返回值:指向二叉树tree的镜像二叉树根结点的指针

2. 编码约束

  • 时间复杂度:无特别要求
  • 空间复杂度:无特别要求

 四、参考答案

/*
 * 完成人 :***
 * 完成时间:***
 * 系统评分:100
 */


#include "179.h" //本题所需头文件,请勿删除!
/*
 * 生成二叉树tree的镜像二叉树
 * 参数
 *      tree:源二叉树的根结点指针
 * 返回值
 *      镜像二叉树的根结点指针
 */

btree mirror(btree tree) {
    //TODO
    if (tree == NULL)  return NULL;
    btree left = mirro(tree->left);
    btree right = mirro(tree->right);
    tree->left = right;
    tree->right = left;
    return tree;

    
    
}

5 树

(题目编号:180)

一、已知条件

设有如图 q5-1.png 的一棵树:


那么这棵树的 层次遍历 顺序就是:ABFGCDHE

如果这样的树的存储结构用如下 孩子-兄弟 表示法:

typedef struct csnode {
    char data;              //结点的字符标签
    struct csnode *first;   //指向结点的第一个孩子结点
    struct csnode *sibling; //指向结点的下一个兄弟结点
} csnode, *cstree;

利用以上存储结构的树可以形象地示意为图 q5-2.png:


其中,土黄色结点是其双亲结点的第一个孩子。

另有可用的 队列 操作的接口如下:

bool queue_enter(queue *Q, void *v); //数据v进队Q。参数Q是指向队列的指针,v的类型是任意类型指针。
void* queue_leave(queue *Q); //数据出队。该数据是函数的返回值,其类型是任意类型指针。
bool queue_empty(queue *Q); //测试队列Q是否为空,如果为空返回真,否则返回假。

再有访问树结点的函数如下:

void visit(cstree node);

其功能是输出结点node的字符标签。

二、任务描述

请设计一个算法,实现树的层次遍历

三、编码要求

1.算法函数原型

void layer(cstree root, queue *Q);
  • 功能:对树tree进行层次遍历。遍历到某个结点node时,调用visit(node)来访问该结点

    提示:如果是空树,则遍历没有输出。

  • 参数:
    root: 指向树根结点的指针
    Q: 指向已初始化的队列的指针
  • 返回值:无

2. 编码约束

  • 时间复杂度:无特别要求
  • 空间复杂度:无特别要求

四、参考答案

/*
 * 完成人 :***
 * 完成时间:***
 * 系统评分:100
 */


#include "180.h" //本题所需头文件,请勿删除!
/*
 * 功能
 *      层次遍历树
 * 参数
 *      root:树的根结点指针
 *      Q:    队列指针。队列Q已经初始化了
 * 返回值
 *      无
 */
void layer(cstree root, queue *Q) {
    //TODO
    if(root==NULL)return;
    queue_enter(Q,root);
    while(!queue_empty(Q)){
        cstree p=(cstree)queue_leave(Q);
        visit(p);
        
        if(p->first!=NULL){
            queue_enter(Q,p->first);
            cstree tmp=p->first->sibling;
            while(tmp!=NULL){
                queue_enter(Q,tmp);
                tmp=tmp->sibling;
            }
        }
        
         
    }
    return;
}

6 图

(题目编号:181)

一、已知条件

设有两张 有向图 G1和G2,如图 q6-1.png 所示。


二者有一些 字符标签相同 的顶点(例中是B和D)。

现定义两张 图的焊接(weld) 是将二者的 标签相同的顶点合并,融合成一张图,其余顶点和边不变,如图 q6-2.png 所示。

有向图 用 邻接表 表示,结构如下:

//定义最大顶点数量
#define MAX_VERTEX_NUM 20

typedef struct _arc_node {
    int adjvex;          //该弧指向顶点在顶点向量中的序号
    struct _arc_node *nextarc; //指向下一条弧的指针
} arc_node;

typedef struct vertex_node {
    char tag;   //顶点字符标签
    arc_node *firstarc; //指向该顶点第一条弧的指针
} vertex_node;

typedef struct Graph {
    vertex_node vertex[MAX_VERTEX_NUM]; //顶点向量。下标从0开始。
    int vexnum, arcnum; //图的顶点数和弧数
} adjlist;

用上述数据结构描述的有向图G2的存储结构可以用图 q6-3.png 所示意:

另有根据结点字符标签 v 定位该结点在 图G 顶点向量中的 序号 的函数:

int locate_vertex(adjlist* G, char v);

例如:locate_vertex(G2, 'F')返回的结果是3

二、任务描述

焊接算法分为几个子算法,其中除了合并边(弧)的子算法,其余都已经完成。
现请设计一个算法,实现焊接算法的子算法:合并两张图的边(弧)。

三、编码要求

  1. 算法函数原型:

    void merge_arcs(adjlist *G1, adjlist *G2);
    
    • 功能:将图G2的边(弧)合并到G1中,即将G2中所有的边复制到G1中;G2保持不变
      如果两张图中只要有一张为空图(即顶点数为0),那么算法不做任何操作,即G1和G2保持不变。
    • 参数:G1和G2都是指向图的指针。
    • 返回值:无

    注意:请用采用头插法处理链表的插入!

  2. 编码约束

  • 时间复杂度:无特别要求
  • 空间复杂度:无特别要求

提示:对图G2中顶点向量中的每一个顶点i,首先定位其在图G1顶点向量中的位置j,然后遍历i的邻接点链表,将其中每一个结点复制出一个副本(即生成新结点),再把副本(新结点)采用头插法插入到顶点j的邻接点链表中

四、参考答案

编者没做出来此题,故略

7 排序

(题目编号:182)

一、已知条件

有一个乱序的正整数数组,其长度为n,其中元素值在 1~m 之间。已知

  • n和m都不太大
  • n 小于 m
  • 元素没有重复值,即数组中没有两个数是相同的
  • 数组下标从0开始

二、任务描述

请设计一个算法,对上述数组进行从小到大升序排序。
注:1. 不能用基数排序。2. 不能为m预估一个预设值

三、编码要求

  1. 算法函数原型
    void xsort(unsigned *a, unsigned n);
    
  • 功能:将指定数组进行从小到大升序排序。如果数组长度为0,则函数什么都不做。
  • 参数:
    a:待排序数组
    n:数组长度。注意:长度可能为0。
  • 返回值:无
  1. 编码约束
  • 时间复杂度:O(m)
  • 空间复杂度:无特别要求

提示:利用数组中无重复值的特点,将数据散列到一个长度为m的一维数组中(这里hash(K)=K),然后再依次收集到原数组中。注意:m的值未知,须编码求得。

四、参考答案

使用的是提示的哈希排序

/*
 * 完成人 :***
 * 完成时间:***
 * 系统评分:100
 */


/*
 * 功能:
 *      将指定数组进行从小到大升序排序。如果数组长度为0,则函数什么都不做。
 * 参数:
 *      a:待排序数组
 *      n:数组长度。注意:长度可能为0。
 * 返回值:
 *      无
 */
#include<stdlib.h>
void xsort(unsigned *a, unsigned n) {
    //TODO
    if(n==0) return ;
    unsigned m=0;
    for(int i=0;i<n;i++){
        if(m<a[i]) m=a[i];
    }
    unsigned hash[m+1];
    for(int i=0;i<=m;i++){
        hash[i]=0;
    }
    for(int i=0;i<n;i++){
        hash[a[i]]=a[i];
    }
    int k=0;
    for(int i=0;i<=m;i++){
        if(hash[i]!=0){
            a[k++]=hash[i];
        }
    }
    return;
    
}


自我练习

1. 登录icoding,点击左侧的开始编程

点击左侧栏的开始编程
点击左侧栏的开始编程

2. 新建一个标签页,网址栏输入 https://icoding.run/ide/question/xxx/1

注意:上方网址的xxx更换为icoding题目编号,题目编号为上方的题目序号下面的黄帝文字,如第一题的编号为176.要练习哪个题就对应那个题目编号

3. 这个新建的标签页出现如下图像时

 回到icoding,刷新,即可看到作答页面。


声明

本文章仅供学习使用。严禁作其他用途。

  • 12
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谨慎谦虚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值