2017年-2021年 软件工程程序设计题(算法题)实战_c语言程序设计&&数据结构程序设计分析

文章目录

2017年

1.c语言程序设计部分


第一题 略

第二题 大循环累加,小循环求阶乘

第三题 没什么好说的,甚至数据都给你了

2.数据结构程序设计部分

问题1分析:

给定了结构体,多了一个频度的数据成员。

locate函数的本质就是插入函数,本质就是查找完然后平移动

本题是双向链表带头结点

代码如下:

c 复制代码
typedef struct BiTNode
{
    Elemtype data;
    struct BiTNode *lLink;
    struct BiTNode *rLink;
    int frep;
    
}BiTNode,*BiTree;

//假设 该双向链表是 18 ,23 ,15 ,24,4个结点构成

void Locate(Elemtype x,BiTree &head)
{
    //先找到这个结点
    BiTNode *cur=head->rLink;
    while(cur!=NULL)
    {
        if(cur->data==x) break; //cur就指向x点
        
        cur=cur->rLink;
    }
    cur->frep++; //频度+1
    int target_frep=cur->frep; //记录目标频度
    BiTNode *pre=cur->lLink; //记录当前的cur的前一个元素,往前找
    
    while(pre!=head)  //如果pre没有找到,将移动到头结点后面
    {
        if(pre->frep==target_frep)break; //找到了,此时pre指向的就是跟它频度相同的点
        pre=pre->lLink;
    }
    
    //开始插入操作
    //将cur插入到pre的后面
    //先将cur去掉
    cur->lLink->rLink=cur->rLink;
    cur->rLink->lLink=cur->lLink;
    
    //将cur加入到pre后面
    cur->rLink=pre->rLink;
    pre->rLink=cur;
    cur->lLink=pre;
    cur->lLink=pre;
}

问题2:就是堆排序

堆排序需要实现swap交换操作

堆排序的调整函数中,需要传入的参数是,树结点的数组int a[],一共的结点数length,和标记当前指向的结点i(largest)

c 复制代码
void swap(int *a,int *b)
{
    int t=*a;
    *a=*b;
    *b=t;
}

void headify(int a[],int length,int i)
{
    int largest=i;
    int lchild=2*i+1;
    int rchlid=2*i+2;
    
    if(lchild<length&&a[lchild]>largest) largest=lchild;  //注意不要忘记左孩子不能超过长度范围
    
    if(rchlid<length&&a[rchlid]>largest) largest=rchlid;
    
    if(largest!=i)
    {
        swap(&a[i], &a[largest]);
        headify(a, length, largest);
    }
    
}


void headsort(int a[],int length)
{
    //每一个叶子结点都要调整一遍,才能建立初始堆
    
    for(int i=length/2-1;i>=0;i--)
    {
        headify(a, length, i);
    }
}

2018年

1.c语言程序设计部分

都很基本和经典,没什么好说的

2.数据结构程序设计部分

问题1:力扣上面那道重排链表

c 复制代码
typedef  int Elemtype;
typedef struct ListNode
{
    Elemtype data;
    struct ListNode *next;
}ListNode;


void sort(ListNode *head)
{
    ListNode *fast=head;
    ListNode *slow=head;
    
    while(fast->next!=NULL&&fast->next->next!=NULL)
    {
        slow=slow->next;
        fast=fast->next->next;
    }
    ListNode *cut_off=slow;
    ListNode *cur=slow->next;  //把slow后面的那个结点存起来
    cut_off->next=NULL;
    
    
    //开始反转后一个链表
    ListNode *pre=NULL;
    while(cur!=NULL)
    {
        ListNode *p=cur->next; //存储cur指向的下一个结点
        cur->next=pre;
        pre=cur;
        cur=p;
    }   //循环结束后cur==NULL,此时pre指向反转后的第一个结点
    
    
    //开始链接
    ListNode *l1=head;
    ListNode *l2=pre;
    
   
    
    while(l1&&l2)
    {
        ListNode *n1=l1->next;
        ListNode *n2=l2->next;
        l1->next=l2; l2->next=n1;
        l1=n1;l2=n2;
    }
}

问题2:就是BFS记录层数,然后当找到这个结点的时候直接返回即可

BFS模版

BFS模版描述如下

创建一个队列,初始化一个队列

如果根节点不为空,将根节点加入到队列中

大循环如果队列不为空,则定义一个空指针,存储出队列的元素

将队列头出队,接下来,如果当前结点存在左孩子,或者右孩子,则将左右孩子加入到队列中。
假如,需要统计层数,则在大循环中,先计算当前层的结点数,利用循环队列计算当前队列的元素个数,这个就是每层的结点数

根据这个就可以确定结点的所在层数

结构体如下:

c 复制代码
typedef int Elemtype;
typedef struct BiTNode
{
    Elemtype data;
    struct BiTNode *lLink;
    struct BiTNode *rLink;
    
}BiTNode,*BiTree;

代码如下:

c 复制代码
int  BFS(BiTree T,Elemtype p) //函数返回值int,返回结点的层数
{
    Queue q;
    initqueue(&q); //初始化一个队列
    
    if(T!=NULL) enqueue(T,q); //将T结点入队
    
    int layer=1; //假定根节点为第一层
   while(is_empty(q))  //如果队列不为空则,进入循环
   {
       int size=(q.rear-q.front+queue_size)%queue_size; //计算当前循环队列中队列的个数
       
       for(int i=0;i<size;i++)
       {
           BiTNode *pNode=NULL;
           dequeue(q,&p); //将队列中的队头取出,将该节点的地址赋给p
           if(pNode->data==p) return layer;
           
           if(pNode->lLink!=NULL) enqueue(T->lLink,q);
           if(pNode->rLink!=NULL) enqueue(T->rLink,q);
       }
       layer++; //上一层全部出队,层数加一
   }
}

2019年

1.c语言程序设计部分

问题1:不用多说,送分题

问题2: 通过%4d %2d 画图设计出适合的形式

c 复制代码
void table()
{
    int i, j;

       // 打印表头
       printf("  "); // 表头的左上角空白
       for (i = 1; i <= 9; i++) {
           printf("%4d", i); // 每个数字占4个字符宽度,保持对齐
       }
       printf("\n");
       
  

       // 打印加法表
       for (i = 1; i <= 9; i++) {
           // 打印行号
           printf("%2d", i); // 打印每行的行号和分隔符

           // 打印加法结果
           for (j = 1; j <= 9; j++) {
               printf("%4d", i + j); // 计算i + j并保持对齐
           }
           printf("\n"); // 每行结束后换行
       }

}


2.数据结构程序设计部分

1.写出二叉链表定义,并编写算法求二叉链表两个结点相距最远的距离。(一个节点到另一个节点所经历的分支个数)

问题分析:求两个结点之间路径最长的路径长度,通常叫做二叉树的直径,某一个点到它的叶子结点,该点到这个点,所经过的点肯定都不是最长的距离,假如这个点,既含有左子树,又含有右子树,左子树的叶子结点到右子树的叶子结点肯定比左子树到根结点的路径要长。
解决方法:考虑DFS

通过先序遍历,将二叉树左右子树的深度返回给他的根结点,同时也不要忘记比较二叉树左子树的深度+右子树的深度是否大于max{左子树的深度或者右子树的深度}
模版:求树的深度模版

c 复制代码
 int MAX=0;
int depth(struct TreeNode* root)
{
     if(root==NULL) return 0; //如果子树为空,返回0

    int left_length=depth(root->left);
    int right_length=depth(root->right);

     int max=0;
    if(left_length>right_length) max=left_length;
    else max=right_length;
    if(left_length+right_length>MAX)MAX=left_length+right_length;

    return max+1; //加深本身该结点的深度
}

int diameterOfBinaryTree(struct TreeNode* root) {
    MAX=0; //注意在leetcode中MAX是局部变量,用的时候必须初始化为0
   depth(root);
   return MAX;
}

2.已知长度为n的线性表A采用顺序存储结构。

(1)写出线性表A的结构体

(2)设计一个时间复杂度为O(n),空间复杂度为O(1)的算法,将值为x的全部元素移动到A的后半部分

问题分析:

由于空间复杂度要求为1,所以不能添加新的存储空间,只能在原有的存储空间上移动,从前往后找值为x的数,从后往前找不为x的数,然后交换,采用静态存储结构即可完成该操作

c 复制代码
typedef int ElemType;
#define MAXSIZE 1000
typedef struct seqlist
{
    Elemtype data[MAXSIZE];
    int length;
}seqlist;

void swap(Elemtype *a,Elemtype *b)
{
    int t=*a;
    *a=*b;
    *b=t;
}
void move(seqlist &seq,Elemtype x)
{
    int left=0;  //定义一个左指针
    int right=seq.length-1;  //定义一个右指针
    
    for(left=0;left<seq.length;left++)  //左指针都扫过一遍之后结束
    {
         if(seq.data[left]==x)  //如果左指针找到了x
         {
             while (seq.data[right==x]) {
                 right--;
             }  //得到了后面一个不等于x的值
             swap(&seq.data[left], &seq.data[right]);
         }
    }
}

2020年

1.C语言程序设计部分

1.请编写程序计算多项式s=1/1+1/(1+2)+...+1/(1+...+n),其中n由键盘进行输入

经典简单题目省略

2.数据结构程序设计部分

问题1:对于循环链表,左移k位之后,就是循环链表中第k+1个结点将会称为链表中第一个数据结点,所以只需要将头指针指向第k个结点,就能实现左移k的操作

问题二:就是BFS,计算一下最大值

2021年

1.C语言程序设计部分

1.银行账户信息包括:用户ID,姓名,密码,余额,写出账户信息结构体,并将数据存储在元素个数不超过90的结构体数组中,设计程序计算余额的平均值,并将余额大于平均值的账户信息输出打印。

2.输入一个数m,请编写程序计算sum=1-1/2^2^-1/3^2^-...-1/m^2^

都是比较经典的算法设计

2.数据结构程序设计部分

1.设计算法在有序单链表中删除重复元素e,使得单链表删除e后依然有序。

c 复制代码
typedef int Elemtype;
typedef struct ListNode
{
    Elemtype data;
    struct ListNode *next;
}ListNode;

//该问题中,传入的单链表不含头结点
void delete_repeatnode(ListNode *&L)
{
    ListNode *pre=L;  //pre指向第一个结点
    ListNode *cur=L->next;  //指向第一个结点的后一个的指针,假如后一个和前一个相等,就把这后一个删除
    
    while(cur!=NULL)
    {
        if(cur->data==pre->data) //删除后一个
        {
            pre->next=cur->next;  //只有删除的时候pre指针才发生变化,否则不动
        }else
        {
            pre=pre->next;
        }
        
        cur=cur->next;
    }
}

2.设计算法在二叉排序树中查找第k大的结点

二叉排序树遍历模版-中序遍历得到有序序列,注意保存它的结点地址

补一个代码刨析:

这道题很明显是二叉排序树的中序遍历问题,找到第k个结点

由于返回值是指针类型,在写遍历模版的时候,要把返回值存下来

处理返回值的关键在于根节点的处理,根节点(子树根节点)是怎么返回的,这是关键。

通过思考来补全整个结果,找到这个结点后,不往下遍历了,else右子树,假如答案是在某个右子树中,return也把答案传回去,而且该循环结束

假如答案是在某个左子树中,return之后,接下来的操作都是没有意义的,甚至还会继续执行遍历右子树,最后会返回一个空,所以必须扼杀于此,所以判断是否找到了,如果找到了,就直接返回,不执行后面的操作。

c 复制代码
BiTNode * funtion_k(BiTree T,int *k) //输入的输出的树的根节点,和第k大,返回值是第k大的结点指针
{
    if(T==NULL)return NULL;
    
    BiTNode *left_result=funtion_k(T->lchild, k);
    if(left_result!=NULL)return left_result;//或者if(*k==0)return left_result;
  
  
    
    (*k)--;
    if(*k==0)
    {
        return T;
    }else
    {
        return funtion_k(T->rchild, k);
    }
    
}
相关推荐
是小Y啦8 分钟前
leetcode 739.每日温度
java·算法·leetcode
aa.173580334 分钟前
剖析淘宝猫粮前五十店铺:销售策略、产品特点与用户偏好
开发语言·python·算法·数据挖掘
水之魂20181 小时前
leetcode哈希表(二)-两个数组的交集
算法·leetcode·散列表
Bug退退退1231 小时前
LeetCode18.四数之和
java·数据结构·算法
EQUINOX11 小时前
LeetCode 第141场双周赛个人题解
算法·leetcode·职场和发展
九圣残炎1 小时前
【从零开始的LeetCode-算法】3200. 三角形的最大高度
java·算法·leetcode
长潇若雪1 小时前
扫雷(C 语言)
c语言·开发语言·经验分享
一个不喜欢and不会代码的码农1 小时前
设计一个尽可能高效的划分算法,满足|n1-n2|最小且|S1-S2|最大
数据结构·算法·排序算法
ImAlex1 小时前
【OpenCV】OpenCV指南:图像处理基础及实例演示
算法
CharlesC++2 小时前
一元n次多项式加法【数据结构-链表】
数据结构·链表