一、判断题
1-6 TFTFTF
判断题主要考察队列、链表、栈的基础知识,以下是相关的基础知识整理:
-
队列(Queue):
- 队列是一种先进先出(First In First Out,FIFO)的数据结构,类似于现实生活中排队的情况。
- 主要有两个基本操作:入队(enqueue)和出队(dequeue)。
- 入队操作将元素添加到队列的末尾,出队操作则移除队列头部的元素。
- 队列通常用于实现广度优先搜索(BFS)等算法。
-
链表(Linked List):
- 链表是一种由节点组成的数据结构,每个节点包含数据和指向下一个节点的指针。
- 链表分为单向链表、双向链表和循环链表等形式。
- 相比数组,链表的插入和删除操作更为高效,但访问元素需要从头节点依次遍历。
- 链表常用于需要频繁插入和删除操作的场景。
-
栈(Stack):
- 栈是一种后进先出(Last In First Out,LIFO)的数据结构,类似于一摞盘子。
- 栈主要有两个基本操作:入栈(push)和出栈(pop)。
- 入栈操作将元素压入栈顶,出栈操作则移除栈顶的元素。
- 栈常用于递归算法、表达式求值、括号匹配等场景。
二、单选题
1-6 DBCACB
-
CD-ROM是(D.)只读光盘。 CD-ROM是Compact Disc Read-Only Memory的缩写,意思是只读光盘。它的数据一经录制就无法更改,因此属于只读存储器。
-
若指针p指向结构体变量data,即有p = &data; ,则对结构体成员a的正确引用是(B.)(*p).a。 当指针p指向结构体变量data时,通过指针p访问结构体成员a应该使用(*p).a的方式。
-
封装成结构体类型的关键字是(C.)struct。 在C语言中,用于封装成结构体类型的关键字是struct。
-
在包含 n 个数据元素的顺序表中,访问第 i(1≤i≤n) 个数据元素的时间复杂度为 O(1) 是(A.)选项。 顺序表是一种数据结构,若要访问第 i(1≤i≤n) 个数据元素,由于顺序表是按照下标存储数据的,所以可以直接通过下标访问,时间复杂度为O(1)。
-
以下哪一种编程语言是脚本语言(C.)Python。 Python是一种脚本语言,它的源代码可以直接被解释器执行,而不需要编译成机器码。
-
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;
}
代码思路:
-
首先定义了一个结构体
struct node
,表示链表节点,其中包括整型数据成员data
和指向下一个节点的指针next
。 -
然后定义了三个函数
main()
、chuangzao()
和mergelists()
。 -
chuangzao()
函数用来创建链表。它通过循环不断读取输入的整数,直到遇到 -1 结束,然后将这些整数依次存储在链表节点中,并返回链表的头指针。 -
mergelists()
函数用来合并两个有序链表。它通过比较两个链表当前节点的值,选择较小的值构造新的节点,并按照非降序的方式连接起来。最终返回合并后链表的头指针。 -
在
main()
函数中,首先调用chuangzao()
两次分别创建两个链表head1
和head2
,然后调用mergelists()
函数将这两个链表合并为一个新的链表head
。 -
最后,如果合并后的链表为空,则输出 "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;
}
大致思路:
-
进入一个while循环,不断读取输入存入tem中,如果输入成功则条件成立。
-
a += tem;
:将tem的值累加到a中,更新动态和。 -
cout << "," << a;
:输出当前的动态和a。 -
循环继续执行,每次读取一个新的数字,更新动态和,并输出动态和。当输入结束或者遇到文件结束符时,循环结束
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;
}
主要思路:
- 声明了变量 n 表示输入数列的长度,st[N] 为栈,top 表示栈顶指针。
- 在 while 循环内部,如果栈不为空且栈顶元素大于等于当前输入的 x,则将栈顶元素弹出,直到栈为空或栈顶元素小于 x 为止。
- 如果栈不为空,输出栈顶元素,表示当前 x 左边第一个比它小的数;否则输出 -1,表示不存在比它小的数。
- 将当前输入的 x 入栈。
- 循环结束后,输出完整的结果。
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;
}
以下是代码的思路解释:
- 通过 cin 读取 n 和 m 的值,表示初始猴子数量和报数的数目。
- 进入 while 循环,当输入的 n 和 m 均为 0 时跳出循环。
- 声明了一个大小为 MAX 的数组 arr,并初始化为 1,表示所有猴子初始状态均未被淘汰。
- 使用 sum 变量记录未被淘汰的猴子数量,cur 表示当前报数的位置,count 用来计数报数的次数。
- 进入 while 循环,当未被淘汰的猴子数量大于 1 时,继续进行报数淘汰的过程。
- 在循环内部,如果当前位置的猴子未被淘汰,则进行报数操作,如果恰好报到 m 次,则淘汰该猴子,同时未被淘汰的猴子数量减一。
- 循环结束后,再次循环数组找出最后剩下的未被淘汰的猴子,输出其编号即为猴王的编号。
主要是3个变量的维护,
sum(统计剩余猴子数量)
count(报数)
cur(指向所有猴子,包括已经淘汰的)
对于这个圈,用数组来代替,数组下标对应猴子的编号,数组元素存1或者0(1未淘汰,0淘汰)
然后循环不停走(直到只剩一只猴子),当cur指向的是已经淘汰的,那么count不计数(相当于不报数),否则就count++(报数),报完发现count恰好到m了,就把cur指向的元素置0(淘汰),并且count置0(剩下猴子重新报数),并且sum--(淘汰一只)。
最后注意cur一直往后走,走到数组末尾时重新从0开始(因为是个循环的圈)