仿真实验室第四次培训题解

文章详细解读了队列、链表、栈的基础知识,涉及C++编程题目的解答,包括链表合并、成绩排序、动态和计算、单调栈以及约瑟夫环问题。展示了如何在实际编程中运用这些数据结构解决实际问题。
摘要由CSDN通过智能技术生成

一、判断题

1-6 TFTFTF

判断题主要考察队列、链表、栈的基础知识,以下是相关的基础知识整理:

  1. 队列(Queue)

    • 队列是一种先进先出(First In First Out,FIFO)的数据结构,类似于现实生活中排队的情况。
    • 主要有两个基本操作:入队(enqueue)和出队(dequeue)。
    • 入队操作将元素添加到队列的末尾,出队操作则移除队列头部的元素。
    • 队列通常用于实现广度优先搜索(BFS)等算法。
  2. 链表(Linked List)

    • 链表是一种由节点组成的数据结构,每个节点包含数据和指向下一个节点的指针。
    • 链表分为单向链表、双向链表和循环链表等形式。
    • 相比数组,链表的插入和删除操作更为高效,但访问元素需要从头节点依次遍历。
    • 链表常用于需要频繁插入和删除操作的场景。
  3. 栈(Stack)

    • 栈是一种后进先出(Last In First Out,LIFO)的数据结构,类似于一摞盘子。
    • 栈主要有两个基本操作:入栈(push)和出栈(pop)。
    • 入栈操作将元素压入栈顶,出栈操作则移除栈顶的元素。
    • 栈常用于递归算法、表达式求值、括号匹配等场景。

二、单选题

1-6 DBCACB

  1. CD-ROM是(D.)只读光盘。 CD-ROM是Compact Disc Read-Only Memory的缩写,意思是只读光盘。它的数据一经录制就无法更改,因此属于只读存储器。

  2. 若指针p指向结构体变量data,即有p = &data; ,则对结构体成员a的正确引用是(B.)(*p).a。 当指针p指向结构体变量data时,通过指针p访问结构体成员a应该使用(*p).a的方式。

  3. 封装成结构体类型的关键字是(C.)struct。 在C语言中,用于封装成结构体类型的关键字是struct。

  4. 在包含 n 个数据元素的顺序表中,访问第 i(1≤i≤n) 个数据元素的时间复杂度为 O(1) 是(A.)选项。 顺序表是一种数据结构,若要访问第 i(1≤i≤n) 个数据元素,由于顺序表是按照下标存储数据的,所以可以直接通过下标访问,时间复杂度为O(1)。

  5. 以下哪一种编程语言是脚本语言(C.)Python。 Python是一种脚本语言,它的源代码可以直接被解释器执行,而不需要编译成机器码。

  6. Python脚本文件的拓展名是(B.).py。 在Python中,通常用.py作为Python脚本文件的文件拓展名。

三、填空题

下面程序段的时间复杂度是

其中,外层循环执行了n次,内层循环执行了m次。在每次内层循环中,都会执行一次赋值操作 A[i][j] = 0。

因此,内层循环的执行总次数为 n * m 次。所以该程序段的时间复杂度为 O(nm)。

简单来说,该程序段的时间复杂度与 n 和 m 的乘积成正比,即 O(nm)。

四、编程题

1、7-1 两个有序链表序列的合并

先上代码:

#include<stdio.h>
#include<stdlib.h>
struct node
{
    int data;
    struct node *next;
};
struct node *chuangzao();
struct node *mergelists(struct node *list1, struct node *list2);
int main ()
{
    struct node *head1,*head2,*head,*p;
    head1=chuangzao();
    head2=chuangzao();
    head=mergelists(head1,head2);
    if(head==NULL)
    printf("NULL");
    else
    for(p=head;p!=NULL;p=p->next)
    {
        printf("%d",p->data);
        if(p->next!=NULL)
        printf(" ");
    }
}
struct node *chuangzao()
{
    struct node *s,*head=NULL,*tail=NULL;
    while(1)
    {
        s=(struct node*)malloc(sizeof(struct node));
        scanf("%d",&s->data);
        if(s->data==-1)
        break;
        s->next=NULL;
        if(head==NULL)
        {
            head=s;
        }
        else
        {
            tail->next=s;
        }
        tail=s;
    }
    return head;
}
struct node *mergelists(struct node *list1, struct node *list2)
{
	struct node	*s,*head=NULL,*tail=NULL;
	while(1)
	{
		if(list1==NULL||list2==NULL)
		break;
        s = (struct node*)malloc(sizeof(struct node));
		if((list1->data)>(list2->data))
		{
			s->data=list2->data;
			s->next=NULL;
            if(head==NULL)
            { 
                head = s;
            }
            else
            {
                tail->next = s;
            }
            tail = s;
            list2=list2->next;
		}
		else
		{
			s->data=list1->data;
			s->next=NULL;
            if(head==NULL)
            { 
                head = s;
            }
            else
            {
                tail->next = s;
            }
            tail = s;
            list1=list1->next;
		}
	}
	if(list1!=NULL)
	tail->next=list1;
	if(list2!=NULL)
	tail->next=list2;
    return head;
}

代码思路:

  1. 首先定义了一个结构体 struct node,表示链表节点,其中包括整型数据成员 data 和指向下一个节点的指针 next

  2. 然后定义了三个函数 main()chuangzao()mergelists()

  3. chuangzao() 函数用来创建链表。它通过循环不断读取输入的整数,直到遇到 -1 结束,然后将这些整数依次存储在链表节点中,并返回链表的头指针。

  4. mergelists() 函数用来合并两个有序链表。它通过比较两个链表当前节点的值,选择较小的值构造新的节点,并按照非降序的方式连接起来。最终返回合并后链表的头指针。

  5. main() 函数中,首先调用 chuangzao() 两次分别创建两个链表 head1head2,然后调用 mergelists() 函数将这两个链表合并为一个新的链表 head

  6. 最后,如果合并后的链表为空,则输出 "NULL";否则,遍历输出合并后链表中的元素,并在每个元素后面添加空格(最后一个元素除外)。

2、7-2 成绩排序 

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct Student {
    string name;
    int score;
};

bool compare(const Student &a, const Student &b) {
    if (a.score != b.score) {
        return a.score > b.score;
    } else {
        return a.name < b.name;
    }
}

int main() {
    int n;
    cin >> n;
    vector<Student> students(n);
    for (int i = 0; i < n; i++) {
        cin >> students[i].name >> students[i].score;
    }

    sort(students.begin(), students.end(), compare);

    for (int i = 0; i < n; i++) {
        cout << students[i].name << " " << students[i].score << endl;
    }

    return 0;
}

 这是一个简单的排序问题,可以使用C++的STL库中的sort函数来实现

代码首先定义了一个结构体Student来存储学生的姓名和分数。然后通过compare函数定义了排序的规则,按照分数从高到低排序,如果分数相同则按照名字的字典序从小到大排序。接着在main函数中读入学生信息,然后使用sort函数进行排序,最后输出排序后的结果。

 3、7-3 数组的动态和

#include<bits/stdc++.h>
using namespace std;
long long a,tem;
int main (){
    cin>>tem;
    a+=tem;
    cout<<tem;
    while(cin>>tem){
        a+=tem;
        cout<<","<<a;
    }
    return 0;
}

大致思路:

  1. 进入一个while循环,不断读取输入存入tem中,如果输入成功则条件成立。

  2. a += tem;:将tem的值累加到a中,更新动态和。

  3. cout << "," << a;:输出当前的动态和a。

  4. 循环继续执行,每次读取一个新的数字,更新动态和,并输出动态和。当输入结束或者遇到文件结束符时,循环结束

4、7-4 单调栈

#include <iostream>
using namespace std;

const int N = 100010;

int n, st[N], top;

int main()
{
    cin >> n;
    while (n--)
    {
        int x;
        scanf("%d", &x);

        while (top && st[top] >= x) top--;
        if (top) cout << st[top] << ' ';
        else cout << -1 << ' ';

        st[++top] = x;
    }
    return 0;
}

主要思路:

  1. 声明了变量 n 表示输入数列的长度,st[N] 为栈,top 表示栈顶指针。
  2. 在 while 循环内部,如果栈不为空且栈顶元素大于等于当前输入的 x,则将栈顶元素弹出,直到栈为空或栈顶元素小于 x 为止。
  3. 如果栈不为空,输出栈顶元素,表示当前 x 左边第一个比它小的数;否则输出 -1,表示不存在比它小的数。
  4. 将当前输入的 x 入栈。
  5. 循环结束后,输出完整的结果。

5、7-5 h0181. 约瑟夫问题 

#include<iostream>
using namespace std;
const int MAX = 305;
int main() {
	int n, m;
	while (cin >> n >> m) {
		if (n == 0 && m == 0) break;
		int arr[MAX] = { 0 };
		for (int i = 1; i <= n; i++) arr[i] = 1;//初始化数组,1未淘汰,0淘汰
		int sum = n, cur = 1, count = 0;//sum记录未淘汰猴数量,cur指向圈内所有猴(包括已经淘汰的),count是报的数
		while (sum > 1) {//不止一只猴时就继续报数淘汰
			if (arr[cur] == 1) {
				count++;//报数
				if (count == m) {//恰好报到m,淘汰该猴
					arr[cur] = 0;
					count = 0;//重新报数
					sum--;//猴数减一
				}
			}
			cur++;
			cur = (cur == n + 1) ? 1 : cur;//cur要循环走,所以指向数组末尾时回到起始
		}
		//循环找最后剩下那只猴
		for (int i = 1; i <= n; i++) {
			if (arr[i] == 1) {
				printf("%d\n", i);//注意输出的是猴的编号
				break;//肯定只有一只猴王,所以输出后直接跳出,争取一点效率。。
			}
		}
	}
	return 0;
}

以下是代码的思路解释:

  1. 通过 cin 读取 n 和 m 的值,表示初始猴子数量和报数的数目。
  2. 进入 while 循环,当输入的 n 和 m 均为 0 时跳出循环。
  3. 声明了一个大小为 MAX 的数组 arr,并初始化为 1,表示所有猴子初始状态均未被淘汰。
  4. 使用 sum 变量记录未被淘汰的猴子数量,cur 表示当前报数的位置,count 用来计数报数的次数。
  5. 进入 while 循环,当未被淘汰的猴子数量大于 1 时,继续进行报数淘汰的过程。
  6. 在循环内部,如果当前位置的猴子未被淘汰,则进行报数操作,如果恰好报到 m 次,则淘汰该猴子,同时未被淘汰的猴子数量减一。
  7. 循环结束后,再次循环数组找出最后剩下的未被淘汰的猴子,输出其编号即为猴王的编号。

主要是3个变量的维护,

sum(统计剩余猴子数量)
count(报数)
cur(指向所有猴子,包括已经淘汰的)
对于这个圈,用数组来代替,数组下标对应猴子的编号,数组元素存1或者0(1未淘汰,0淘汰)

然后循环不停走(直到只剩一只猴子),当cur指向的是已经淘汰的,那么count不计数(相当于不报数),否则就count++(报数),报完发现count恰好到m了,就把cur指向的元素置0(淘汰),并且count置0(剩下猴子重新报数),并且sum--(淘汰一只)。

最后注意cur一直往后走,走到数组末尾时重新从0开始(因为是个循环的圈)

  • 16
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值