当前位置: 首页 > ai >正文

信息学奥赛CSP-J模拟阅读程序1(链表)

题目:给定一个程序,请根据给定的程序回答下列判断题与选择题

#include<bits/stdc++.h>
using namespace std;
struct node {int d;node *nxt;
};
int isPrime(int x) {if(x==1)	return 0;for(int i=2;i<x;i++) if(x%i==0)return 0;return 1;
}
int main()
{int n;cin >> n;node *h = new node;node *q = h;for(int i=1;i<=n;i++) {node *p = new node;p->d = i;p->nxt = NULL;q->nxt = p;q = p;}q = h->nxt;node *p = h;while(q!=NULL) {if(isPrime(q->d)) {p->nxt = q->nxt;q = q->nxt;}else  {p = p->nxt;q = q->nxt;}}for(q=h->nxt;q!=NULL;q=q->nxt)cout << q->d << " ";cout << endl;return 0;
}

一、判断题

1、本程序用到了双向链表的技术。(    )

2、将第10行i<x改为i*i<=x,程序运行输出结果不会改变。(    )

3、将第24行p->nxt=NULL,改为p->nxt=NIL,程序运行输出结果不会改变。(    )

4、将第31行if(isPrime(q->d))改为if(!isPrime(q->d)),程序运行输出结果会改为打印1到n之间的所有质数。(    )

二、选择题

1、若输入10,则输出(    )

A. 1 4 6 8 9 10

B. 2 3 5 7

C. 4 6 8 9 10

D. 1 2 3 5 7

2、若输入2024,则输出的数字总数为(    )

A. 1716

B. 1717

C. 1718

D. 1719


三、程序解读        

在这里,我将把代码分片,重点讲述每一片代码块的功能,最后将其串联起来阐述整个程序所实现的功能与注意事项。

struct node {int d;node *nxt;
};

        定义一个结构体,包含两个成员变量,分别为整型数字d和结构体指针nxt,d用来存储当前该节点的数字,而nxt用来存储当前节点下一个节点的地址,用来指向当前节点的下一个节点。 

int isPrime(int x) {if(x==1)	return 0;for(int i=2;i<x;i++) if(x%i==0)return 0;return 1;
}

         判断x是否为质数,如果是,该函数返回1,否则返回0。注意,此处判断质数的方法是最原始、最暴力的方法,直接从2判断到x-1,因为质数的定义是:只能被1和本身整除的数称为质数,那么就意味着,2~x-1但凡有某个数能够把x整除,那么x就不是质数。

int n;
cin >> n;
node *h = new node;
node *q = h;
for(int i=1;i<=n;i++) {node *p = new node;p->d = i;p->nxt = NULL;q->nxt = p;q = p;
}
q = h->nxt;
node *p = h;

         n代表链表的具有n个节点,其中一开始的时候,h指向头节点,q也指向头节点。接下来使用一个for循环构造单链表,例如当n=6时,链表情况如下图所示,其中绿色代表头节点,蓝色代表真正的数据节点。

        当for循环结束后,让q指向第1个节点,p指向头节点,如下图所示。 

while(q!=NULL) {if(isPrime(q->d)) {p->nxt = q->nxt;q = q->nxt;}else  {p = p->nxt;q = q->nxt;}
}

         我们重点来解析一下这段代码,可以代入具体的例子 n = 6。

        第一轮循环:q指向第1个节点,即q!=NULL,执行while循环,首先判断q指向的节点数据是否为质数,此时q指向第1个节点,第1个节点的数据值为1,发现不是质数,执行else代码块语句,让p指针指向原来p指针所指向节点的下一个节点,让q指针指向原来q指针所指向节点的下一个节点,即p指向第1个节点,q指向第2个节点,如下图所示

        第二轮循环,q指向第2个节点,即q!=NULL,执行while循环,首先判断q指向的节点数据是否为质数,此时q指向第2个节点,第2个节点的数据值为2,发现是质数,执行if代码块中的语句,让原来p指向的节点的指针域存储原来q指向节点的下一个节点的地址,紧接着让q本身指向自己指向的下一个节点。然后让q指针指向原来q指针指向的节点的下一个节点。如下图所示:

        第三轮循环,q指向第3个节点,即q!=NULL,执行while循环,首先判断q指向的节点数据是否为质数,此时q指向第3个节点,第3个节点的数据值为3,发现是质数, 指向if代码块中的语句,根据上一轮循环的讲解,此时p、q指针的指向情况如下图所示:

        第四轮循环,q指向第4个节点,即q!=NULL,执行while循环,首先判断q指向的节点数据是否为质数,此时q指向第4个节点,第4个节点的数据值为4,发现不是质数,执行else代码块中的语句, 根据第一轮循环的讲解,此时p、q指针的指向情况如下图所示:

        第五轮循环,q指向第5个节点,即q!=NULL,执行while循环,首先判断q指向的节点数据是否为质数,此时q指向第5个节点,第5个节点的数据值为5,发现是质数,执行if代码块中的语句,同理,此时p、q指针的指向情况如下图所示: 

        第六轮循环,q指向第6个节点,即q!=NULL,执行while循环,首先判断q指向的节点数据是否为质数,此时q指向第6个节点,第6个节点的数据值为6,发现不是质数, 执行else代码块中的语句,同理,此时p、q指针的指向情况如下图所示:

        此时q==NULL,while条件成立,退出循环! 

for(q=h->nxt;q!=NULL;q=q->nxt)cout << q->d << " ";

         当while循环结束后,链表的整体情况如下图所示:

        只要q不等于NULL,那么就一直输出每个节点的数据,因此输出结果为1 4 6。 

        将程序放入编译器中编译并且运行,得到验证结果如下图所示:

        相信大家听完上述的讲解之后,能够大概猜测出此此程序的用处 — 没错,它的作用就是使用链表来筛选出所有非质数数据。如上所述的这种数据结构为们称之为单链表它属于线性数据结构,其中每个节点包含指向下一个节点的指针,如果要进行数据的查找,只能从第1个节点开始从头往后查找,效率较低


四、答案解读

判断题:

1、本程序用到了双向链表的技术。(    )

答案:错误

解析:该题考察单链表和双链表的概念,我们先来看一幅图,你就能够从宏观上看出单链表和双链表的区别。

        根据观察,我们发现 ,双链表的每一个节点都有两个指针,一个指向前面的节点(前驱节点),另一个指向后面的节点(后继节点)。且双链表既可以从表头(第一个节点)向后遍历,也可以从表尾(最后一个节点)向前遍历,对于双链表来说,它在进行插入和删除操作时可以更方面地定位节点,因此我们可以给出双链表的准确定义:双链表是一种线性数据结构,它是单链表的扩展。与单链表不同,双链表中的每个节点不仅包含指向下一个节点的指针(后继指针),还包含指向前一个节点的指针(前驱指针)。这种双向链接的特性使得双链表在某些操作上比单链表更灵活

2、将第10行i<x改为i*i<=x,程序运行输出结果不会改变。(    )

答案:正确

解析:我们知道,对于任意一个正整数都可以表示为:n = p*q,假设p<=q,且p、q两个数据当中,其中p是小于等于根号n的,而q是大于等于根号n的。

        这样子讲好像很抽象对不对,那我们来举例子,例如,对于36,36可以表示为两个数字相乘的式子有如下那么几个:

36 = 1 * 36

36 = 2 * 18

36 = 3 * 12

36 = 4 *  9

36 = 6 * 6 

        在此处,p的取值有1、2、3、5、6,q的取值为36、18、12、9、6。我们会发现p的取值都是小于等于根号36=6的,而q的取值都是大于等于根号36=6的,那意味着什么呢? — 若在2~根号n范围内没有n的因数,那么n必然是质数,若在这个范围内存在因数,那么n就不是质数。例如对于n=36,在2~根号36=6之间存在36的因数,那么36不是质数,而对于17而言,在2~根号17=4之间没有17的因数,那么17一定是一个质数。因此在进行范围判断的时候,可以不必从2判断到n-1,而是从2判断到根号n即可,因为如果n有因数,那么必然有因数是小于或等于根号n的,这样子可以提高程序的效率。

        因此可以将i<x修改为i*i<=x。此时i不必增加到n-1了,只需要让其增加到根号n即可,此时i*i<=x等价于i<=根号x

3、将第24行p->nxt=NULL,改为p->nxt=NIL,程序运行输出结果不会改变。(    )

答案:错误

解析:送分题啊,你不要做成送命题了。在C++中,NULL等价于0,同时如果将其赋值给指针变量,那么代表当前指针不指向任何地址空间。若改成NIL,会出现编译错误,C++根本不认识这个单词的含义。

4、将第31行if(isPrime(q->d))改为if(!isPrime(q->d)),程序运行输出结果会改为打印1到n之间的所有质数。(    )

答案:正确

解析:if(isPrime(q->d))当该条件成立(是质数)那么就跳过当前的质数节点,如果对其结果进行取反,那么就是当该条件不成立(不是质数),整体条件成立,跳过当前非质数节点。因此此时会筛选出所有的非质数节点,程序验证结果如下图所示:

选择题:

1、若输入10,则输出(    )

A. 1 4 6 8 9 10

B. 2 3 5 7

C. 4 6 8 9 10

D. 1 2 3 5 7

答案:A

解析:本程序的作用是使用链表筛选出1~n所有的非质数节点,且输出每一个节点的值。因此当输入10,输出的结果为1、4、6、8、9、10。

2、若输入2024,则输出的数字总数为(    )

A. 1716

B. 1717

C. 1718

D. 1719

答案:C

解析:题目实际上问的是1~2024,有多少个非质数,那我们转换一下思路,用总的数字,减去1~2024的质数个数,得到的就是1~2024的非质数总数。问题来了,1~2024的质数个数怎么计算呢?暴力算需要很长的时间,1~2024共有306个质数,那么非质数个数有2024-306=1718个。这题我是用程序验证的,因为觉得很费时,没有手动从头算,不然就只能靠平时的积累了,比如平时有背过1~2000的质数个数,那这个时候就会轻松一些。

 

http://www.xdnf.cn/news/13377.html

相关文章:

  • 2024睿抗-03
  • Oracle 的 FORCE_LOGGING 特性
  • ISO/IEC 14443 防碰撞协议 Type A Type B
  • 第26节 Node.js 事件
  • 爱普生 SG-9101CB以展频调制技术突破 EMI 难题​
  • 51la查看https统计,悟空统计助力高效运营
  • 系统集成自动化流程编排流实现 if-else 条件分支(一)
  • AIGC方案-java实现视频伪动效果
  • el-table-v2修改表头、单元格、表格整体的宽度、高度样式
  • Web 架构之微服务拆分原则与反模式
  • 网页组件强制设置右对齐
  • 基于拓扑的信任评级实现的车载异常检测框架
  • 从零实现一个红队智能体
  • linux内核编译问题记录
  • 润乾报表display value expression使用介绍
  • Redis GEO 52 位整数的经纬分布
  • 【基于阿里云上Ubantu(x86-64)系统部署配置K8s】
  • Docker环境安装Kafka、Flink、ClickHouse镜像
  • 海外打车代驾app评价系统框架搭建
  • 获取RadioButton的text,更换textview的text
  • C++笔记-C++11(二)
  • 【Unity优化】提高热更新和打包速度
  • Centos与RockLinux设置静态ip
  • 数据库管理与高可用-PostgreSQL日常维护
  • MongoDB入门指南:环境安装与基本操作
  • QGIS新手教程4:相交、缓冲区与合并操作详解(含实战案例)
  • 多头与空头:市场博弈的两面
  • 【2025最新】Adobe Illustrator下载保姆级安装教程(附官方下载链接)
  • ThinkPad 交换 Ctrl 键和 Fn 键
  • Uncaught (in promise) TypeError: Cannot read properties of null (reading ‘xxx’)