版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
2026年3月GESP编程能力等级认证C++五级真题(含答案和解析)一、单选题(每题2分,共30分)。1.关于单链表、双链表和循环链表,下列说法正确的是()。A.在单链表中,若已知任意结点的指针,则可以在O(1)时间内删除该结点。B.循环链表中一定不存在空指针。C.在循环双链表中,尾结点的next指针一定为nullptr。D.在带头结点的循环单链表中,判定链表是否为空只需判断头结点的next是否指向自身。答案:D。解析:A选项:单链表中若已知任意结点的指针,要删除该结点通常需要知道其前驱结点,找前驱需要从头遍历,时间复杂度为O(n),错误。B选项:如果是不带头结点的循环单链表且为空表,其头指针即为空指针,错误。C选项:循环双链表的尾结点的next指向头结点,而不是nullptr,错误。D选项:带头结点的循环单链表中,当为空链表时,头结点的next恰好指向自己,判断正确。2.双向循环链表中要在结点p之前插入新结点s(均非空),以下指针操作正确的是()。A.s->next=p;p->prev=s;p->next=s;s->prev=p;B.s->prev=p;s->next=p->next;p->next->prev=s;p->next=s;C.s->next=p;s->prev=p->prev;p->prev->next=s;p->prev=s;D.s->next=p;s->prev=nullptr;p->prev=s;答案:C。解析:在双向链表中结点p之前插入结点s,需要修改四个指针的方向且不能丢失原有的前驱结点引用。首先处理新结点s的两端:s->next=p;以及s->prev=p->prev。接着修改原链表中的指针,必须先修改p的原前驱结点的后继:p->prev->next=s;最后修改p的前驱指向新结点:p->prev=s。只有C选项符合此逻辑过程。3.下面函数用“哑结点”统一处理删除单向链表中的头结点与中间结点。横线处应填()。structNode{intval;Node*next;Node(intv):val(v),next(nullptr){}};Node*eraseAll(Node*head,intx){Nodedummy(0);dummy.next=head;Node*cur=&dummy;while(cur->next){if(cur->next->val==x){Node*del=cur->next;______________________deletedel;}elsecur=cur->next;}returndummy.next;}A.cur=cur->next;B.cur->next=del->next;C.del->next=cur->next;D.cur->next=nullptr;答案:B。解析:代码中通过建立哨兵结点dummy,并用指针cur遍历链表。当满足条件cur->next->val==x时,表示cur的下一个结点del即为需要被删除的结点。在单链表中删除del,应当将cur结点的next指针越过被删除的结点,直接指向del->next。因此横线处应填入cur->next=del->next;选项B正确。4.对如下代码实现的欧几里得算法(辗转相除法),执行gcd(48,18)得到的调用序列为()。intgcd(inta,intb){returnb==0?a:gcd(b,a%b);}A.gcd(48,18)->gcd(18,12)->gcd(12,6)->gcd(6,0)B.gcd(48,18)->gcd(30,18)->gcd(12,18)C.gcd(48,18)->gcd(18,30)->gcd(30,6)D.gcd(48,18)->gcd(12,18)->gcd(6,12)答案:A。解析:根据所给的递归代码逻辑,若b!=0,则递归调用gcd(b,a%b)。对于初始调用gcd(48,18),因为18非0,会执行48%18=12,接着进入gcd(18,12);同理下一步为18%12=6,进入gcd(12,6);接着12%6=0,进入gcd(6,0)。当参数b变为0时,达到递归终点并返回6。所以完整过程如A选项所示。5.下面代码实现了欧拉(线性)筛,横线处应填写()。vector<int>euler_sieve(intn){vector<bool>is_composite(n+1,false);vector<int>primes;for(inti=2;i<=n;i++){if(!is_composite[i])primes.push_back(i);for(intj=0;__________________________&&(longlong)i*primes[j]<=n;j++){is_composite[i*primes[j]]=true;if(i%primes[j]==0)break;}}returnprimes;}A.j<=nB.j<sqrt(n)C.j<primes.size()D.j<i答案:C。解析:线性筛的核心原理是利用每个合数最小的质因子将其筛除。算法中内层循环用于遍历目前已经被发现并收集到primes数组中的质数。数组下标j从0开始,为了防止越界,j必须小于质数数组当前的元素个数,即j<primes.size()。该条件保证了程序可以安全地访问primes[j]。所以选C。6.埃氏筛中将内层循环从j=i*i开始而不是j=2*i的主要原因是()。vector<int>eratosthenes_sieve(intn){vector<bool>is_composite(n+1,false);vector<int>primes;for(inti=2;i<=n;i++){if(is_composite[i])continue;primes.push_back(i);for(longlongj=(longlong)i*i;j<=n;j+=i)is_composite[j]=true;}returnprimes;}A.因为2*i一定不是合数B.i*i一定是质数C.小于i*i的i的倍数已被更小质因子筛过D.这样可以把时间复杂度降为O(n)答案:C。解析:在埃氏筛法中,当我们遇到一个素数i时,需要将i的所有倍数标记为合数。对于形如k*i(其中k<i)的倍数,因为k小于i,那么这个数必然存在一个更小的素数因子(k的素因子)。在算法之前的遍历过程中,这个数肯定已经被那个更小的素数筛去了,所以内层循环直接从i*i开始即可避免重复标记。7.下面程序的运行结果为()。boolcheck(intn,inta[],intk,intdist){intcnt=1;intlast=a[0];for(inti=1;i<n;i++){if(a[i]-last>=dist){cnt++;last=a[i];}}returncnt>=k;}intsolve(intn,inta[],intk){std::sort(a,a+n);intl=0;intr=a[n-1]-a[0];while(l<r){intmid=(l+r+1)/2;if(check(n,a,k,mid))l=mid;elser=mid-1;}returnl;}intmain(){inta[]={1,2,8,4,9};intn=5;intk=3;std::cout<<solve(n,a,k)<<std::endl;return0;}A.2B.3C.4D.5答案:B。解析:本题考察经典的“二分答案”模型(最大化最小值)。数组排序后为{1,2,4,8,9},在其中选择k=3个元素使得相邻差值最大。当假定最小距离为3时,可以选择1、4、8(4-1≥3且8-4≥3),满足条件;假定距离为4时,选了1之后只能选8,选不够3个,不满足条件。因此最大满足要求的距离是3,选B。8.在升序数组中查找第一个大于等于x的位置,下面循环中横线应填()。intlowerBound(constvector<int>&a,intx){intl=0,r=a.size();while(l<r){intmid=l+(r-l)/2;if(a[mid]>=x)_____________;elsel=mid+1;}returnl;}A.r=mid;B.r=mid-1;C.l=mid;D.l=mid+1;答案:A。解析:题目要求在升序数组中查找第一个大于等于x的元素位置(即lower_bound)。在二分过程中,如果满足条件a[mid]>=x,说明当前的mid可能是目标位置,或者目标位置在mid的左侧。为了不漏掉这个可能的答案,右边界应该更新为mid,即r=mid。这种二分写法也不会导致死循环。9.关于递归函数调用,下列说法错误的是()。A.递归调用层次过深时,可能会耗尽栈空间导致栈溢出。B.尾递归函数可以通过编译器优化来避免栈溢出C.所有递归函数都可以通过循环结构来改写,从而避免栈溢出。D.栈溢出发生时,程序会抛出异常并可以继续执行后续代码。答案:D。解析:A选项:每次递归都会消耗系统栈内存,层数过深确实会溢出。B选项:尾递归在某些编译器和优化设置下可能被优化为循环,从而减少栈空间消耗,但这不是C++标准强制保证的行为,相比之下D选项明显错误。C选项:依据理论,所有递归问题都可用显式栈配合循环来转换为非递归实现。D选项:在C/C++等语言中,栈溢出通常会导致严重错误(如段错误或进程崩溃),操作系统会强行终止进程,不能通过普通的异常捕获来继续正常执行后续代码,说法错误。10.给定n根木头,第i根长度为a[i]。要切成不少于m段等长木段,求最大可能长度,则横线上应填写()。constintMAXN=100005;longlonga[MAXN];intn,m;boolcheck(longlongx){longlongcnt=0;for(inti=1;i<=n;i++){if(x==0)returntrue;cnt+=a[i]/x;if(cnt>=m)returntrue;}returnfalse;}intmain(){cin>>n>>m;longlongmx=0;for(inti=1;i<=n;i++){cin>>a[i];mx=max(mx,a[i]);}longlongl=1,r=mx;longlongans=0;while(l<=r){longlongmid=l+(r-l)/2;if(check(mid)){ans=mid;______________________}else{______________________}}cout<<ans<<endl;return0;}A.l=mid+1;r=mid-1;B.l=mid-1;r=mid+1;C.l=mid+1;r=mid;D.l=mid;r=mid+1;答案:A。解析:本题依然采用二分答案求最大可能长度。当check(mid)为真时,说明长度为mid是可行的,我们要继续寻找有没有更大的长度。此时记录了最优解ans=mid,因此接下来的搜索范围可以安全地避开mid,转到[mid+1,r],故应填l=mid+1。反之若不可行,则转到[l,mid-1]寻找,填r=mid-1。选A。11.下面代码用分治求“最大连续子段和”,其时间复杂度为()。intsolve(vector<int>&a,intl,intr){if(l==r)returna[l];intmid=l+(r-l)/2;intleft=solve(a,l,mid);intright=solve(a,mid+1,r);intsum=0,lmax=INT_MIN;for(inti=mid;i>=l;i--){sum+=a[i];lmax=max(lmax,sum);}sum=0;intrmax=INT_MIN;for(inti=mid+1;i<=r;i++){sum+=a[i];rmax=max(rmax,sum);}returnmax({left,right,lmax+rmax});}A.O(n2)B.O(nlogn)C.O(logn)D.O(n)答案:B。解析:该算法采用典型的分治思想,将规模为n的问题划分为两个规模为n2的子问题进行递归处理。而合并步骤中,为了计算跨越中点的最大子段和,代码向左和向右分别遍历了一遍当前区间的元素,合并操作的时间开销为O(n)。因此其递归时间复杂度表达式为T(n)=2T(n/2)+O(n),根据主定理得出该算法的时间复杂度为O(nlogn)。12.游戏大赛决赛,两组选手分别按得分从小到大排好队,现在要把他们合并成一个有序排行榜。A组:A={12,35,67,89},B组:B={20,45,55,78},下面是归并合并函数的核心循环,横线处应填入()。inti=0,j=0;vector<int>result;while(i<A.size()&&j<B.size()){if(___________________){result.push_back(A[i++]);}else{result.push_back(B[j++]);}}while(i<A.size()){result.push_back(A[i++]);}while(j<B.size()){result.push_back(B[j++]);}A.A[i]>=B[j]B.A[i]<=B[j]C.i>=jD.i<=j答案:B。解析:这是归并排序中合并两个有序数组的经典过程。题目要求最终合并为从小到大的有序排行榜。因此当遍历时,应当比较A组和B组当前的元素大小,谁小就优先将谁放入结果数组中。为了保证相同元素时原有顺序不改变(稳定性),在A[i]<=B[j]时选取前面数组的元素A[i]并将其对应的指针i后移。选项B符合逻辑。13.有n位同学的成绩已经从小到大排好序,现在对它执行下面这段以第一个元素为pivot的快速排序,请问此次排序的时间复杂度是()。voidquicksort(vector<int>&a,intl,intr){if(l>=r)return;intpivot=a[l];inti=l,j=r;while(i<j){while(i<j&&a[j]>=pivot)j--;while(i<j&&a[i]<=pivot)i++;if(i<j)swap(a[i],a[j]);}swap(a[l],a[i]);quicksort(a,l,i-1);quicksort(a,i+1,r);}A.O(n)B.O(nlogn)C.O(n2)D.O(logn)答案:C。解析:在快速排序中,若总是选取第一个元素作为枢轴(pivot),且给定数组已经是有序状态,那么在每次划分子数组时,pivot右边没有比它小的元素。这会导致划分产生的两个子数组长度极度不平衡,一个是0,另一个是n-1。此时递归树退化成了一条链式结构,递归深度达到n,每层的时间开销依然是O(n),导致总时间复杂度退化为最坏情况O(n2)。14.下面关于排序算法的描述中,不正确的是()。A.冒泡排序和插入排序都是稳定的排序算法B.快速排序和归并排序都是不稳定的排序算法C.冒泡排序和插入排序最好时间复杂度均为O(n)D.归并排序在最好、最坏和平均三种情况的时间复杂度均为O(nlogn)。答案:B。解析:A选项正确,冒泡和插入排序只在相邻元素间操作,不会改变相等元素的相对位置,所以稳定。B选项错误,快速排序中枢轴交换的过程会导致不稳定,但归并排序在合并子数组时严格控制了相等元素的插入顺序,是典型的稳定排序算法。C选项正确,插入排序在已有序时为O(n);冒泡排序若采用“本轮无交换则提前结束”的优化,最好情况为O(n)。在常见教材语境下,冒泡排序最好复杂度通常指优化版,因此C可视为正确。D选项正确,归并排序恒定对半分,时间复杂度固定。15.下面代码实现两个整数除法,其中被除数为一个“大整数”,用字符串表示,除数是一个小整数,用int表示,则横线处应该填写()。intmain(){strings;intb;cin>>s>>b;vector<int>a;for(charc:s){a.push_back(c-'0');}vector<int>c;longlongrem=0;for(inti=0;i<a.size();i++){rem=rem*10+a[i];intq=rem/b;c.push_back(q);______________________}intpos=0;while(pos<c.size()-1&&c[pos]==0)pos++;for(inti=pos;i<c.size();i++){cout<<c[i];}cout<<endl;cout<<rem<<endl;return0;}A.rem/=b;B.rem%=b;C.rem=b;D.rem=q;答案:B。解析:这道题使用数组模拟高精度被除数除以单精度除数的过程。在模拟竖式除法的每一位计算中,需要将“上一位的余数乘10再加上当前位数字”构成本次计算的新被除数rem。将新被除数整除单精度除数b得到当前位的商q,而参与下一位运算的则是本次计算剩下的余数,因此通过rem%=b;获取新余数,B选项正确。二、判断题(每题2分,共20分)。16.有一个存储了n个整数的线性表,分别用数组和单链表两种方式实现。在已知下标(或结点指针)的前提下,数组的随机访问是O(1),而在链表中已知某结点的指针时,在该结点之后插入一个新结点的操作也是O(1)。()。答案:正确。解析:数组的底层是连续的内存空间,支持通过下标直接进行偏移计算获取元素,因此随机访问的时间复杂度是O(1)。在单链表中,如果不考虑查找前驱的时间,仅仅是在已知当前节点p指针的基础上插入新结点s,只需执行s->next=p->next;p->next=s;操作与链表总长度无关,因此复杂度同样也是O(1)。描述正确。17.若数组a已按升序排列,则下面代码可以正确实现“在a中查找第一个大于等于x的元素的位置”。()。intlowerBound(vector<int>&a,intx){intl=0,r=a.size();while(l<r){intmid=(l+r)/2;if(a[mid]>=x)r=mid;elsel=mid+1;}returnl;}答案:正确。解析:这是一个典型的求解下界(lower_bound)的二分查找算法实现。当a[mid]>=x成立时,说明目标位置一定不会大于mid,所以应当把右边界收缩至当前位置即r=mid;当a[mid]<x成立时,说明目标一定严格在mid的右边,因此左边界更新为l=mid+1。该逻辑能正确处理并跳出循环。描述正确。18.快速排序只要每次都选取中间元素作为枢轴,就一定是稳定排序。()。答案:错误。解析:排序算法稳定性的定义是指相等大小的元素在排序后能够保持原有相对顺序不变。快速排序的工作机制决定了它会把元素按照和枢轴的大小关系交换到两侧。不论选取哪个元素作为枢轴,这种远距离位置跳跃式的交换都有可能会打乱原本数值相等的两个元素的先后次序。所以快速排序本质上是不稳定的算法。19.若某算法满足递推式:T(n)=2T(n/2)+O(n),则其时间复杂度为O(nlogn)。()。答案:正确。解析:该递推关系式表明,算法将规模为n的大问题划分为了2个规模为n2的子问题进行求解,且在合并或拆分过程花费了额外的O(n)时间。根据时间复杂度分析的主定理(MasterTheorem)或通过绘制递归树可推导:树的高度为logn,且每一层的操作代价总和均为O(n)。因此最终的时间复杂度为O(nlogn)。描述正确。20.在一个数组中,如果两个元素a[i]和a[j]满足i<j且a[i]>a[j],则a[i]和a[j]是一个逆序对。下面代码可以正确统计数组a区间[l,r]内的逆序对总数。()。longlongcnt=0;voidmerge_count(vector<int>&a,intl,intm,intr){inti=l,j=m+1;while(i<=m&&j<=r){if(a[i]<=a[j])i++;else{cnt+=(m-i+1);j++;}}}答案:错误。解析:该代码只有在[l,m]和[m+1,r]两个区间已经分别有序时,才能正确统计“跨越左右区间”的逆序对数量;但题目说的是统计数组区间[l,r]内的逆序对总数,代码既没有递归统计左右区间内部逆序对,也没有将左右区间合并成有序状态,因此不能正确统计总逆序对。21.根据唯一分解定理,如果大于1的整数不能被任何不超其平方根的质数整除,那么n必定是质数。()。答案:正确。解析:根据数论中的唯一分解定理及素因数分解原理,如果一个大于1的整数n是合数,那么它一定可以分解为至少两个质因子的乘积,且这两个因子中必然至少存在一个较小因子是不大于n的。逆反地推论,如果n没有发现任何小于等于n的质因数来整除它,那就说明n没有除自身外的质因子,因此n一定是素数。描述正确。22.假设数组a的值域范围是D,以下程序的时间复杂度是O(nlogn+nlogD)。()。boolcheck(intn,inta[],intk,intdist){intcnt=1;intlast=a[0];for(inti=1;i<n;i++){if(a[i]-last>=dist){cnt++;last=a[i];}}returncnt>=k;}intsolve(intn,inta[],intk){std::sort(a,a+n);intl=0;intr=a[n-1]-a[0];while(l<r){intmid=(l+r+1)/2;if(check(n,a,k,mid))l=mid;elser=mid-1;}returnl;}intmain(){inta[]={1,2,8,4,9};intn=5;intk=3;std::cout<<solve(n,a,k)<<std::endl;return0;}答案:正确。解析:程序先对数组排序,复杂度为O(nlogn)。随后在距离范围[0,a[n-1]-a[0]]上进行二分。若值域范围为D,则二分次数为O(logD)。每次调用check都需要线性扫描数组,复杂度为O(n)。因此总复杂度为O(nlogn+nlogD)。23.若一个问题满足最优子结构性质,则一定可以用贪心算法得到最优解。()。答案:错误。解析:满足“最优子结构”仅仅是使得问题具备可以使用动态规划或贪心算法进行求解的前提条件。要保证贪心算法真正可以得出全局最优解,该问题还必须满足更严格的“贪心选择性质”,也就是在当前步骤做的每一步局部最优选择,未来一定能导向最终的全局最优。缺乏贪心选择性质时,只有使用动态规划去全局推导才是安全的。描述错误。24.线性筛相比埃氏筛的核心改进在于:埃氏筛中一个合数可能被多个质数重复标记,线性筛通过"每个合数只被其最大质因子筛去"的策略,保证每个合数恰好被标记一次,从而实现O(n)的时间复杂度。()。答案:错误。解析:题目描述前半部分解释埃氏筛法的重复标记缺陷是正确的,并且线性筛(欧拉筛)的初衷也是为了保证每个数只被筛选一次进而实现严格的O(n)时间复杂度。但线性筛的正确实现策略是确保“每个合数只被其最小质因子筛除”而不是最大质因子。概念表述错误,判定为错。25.任何递归程序都可以改写为等价的非递归程序,但改写后的非递归程序一定需要显式地使用栈来模拟递归调用过程。()。答案:错误。解析:递归程序都可以改写为非递归程序,但不一定必须使用“显式栈”,还可以用循环或数学递推等形式。例如递归求阶乘,就可以改写成循环迭代的形式。三、编程题(每题25分,共50分)。26.试题名称:有限不循环小数。时间限制:1.0s。内存限制:512.0MB。题目描述:若1a可化为一个有限的,不循环的小数,则称a请你求出在L到R中终止数的数量。输入格式:输入一行,包含两个整数L,R。输出格式:输出一行,包含一个整数,表示L到R中终止数的数量。输入样例。输出样例。样例解释:在[2,11]终止数有2、4、5、8、10。数据范围:保证l≤L≤R≤106。参考程序。#include<iostream>usingnamespacestd;intmain(){intl,r,ans=0;cin>>l>>r;for(inti=l;i<=r;i++){intt=i;while(t&&t%2==0)t/=2;while(t&&t%5==
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 初中八年级道德与法治《做文明交流的互鉴使者》教学设计
- 2026年市场营销策划能力考核卷一
- 初中八年级道德与法治上册全案教学设计(部编版)
- 协调项目延期交付时间商洽函(6篇)
- 《赋能与革新:优化营商环境的公共价值领导力》教学设计-面向领导干部专题研讨班
- 2026年植树节活动目标小班下学期
- 2026年采摘工会活动方案策划
- 2026年大学生读书活动策划方案
- 2026年国庆节幼儿亲子活动方案策划书
- 2026年高校学生工作案例分析报告
- 亚马逊运营岗位晋升制度
- 2025年初中信息技术会考试题题库及答案
- 2025北京丰台区初一(下)期末语文试题及答案
- 放射性肺纤维化诊疗指南(2025年版)
- DB61∕T 1724-2023 考古工地安全施工规范
- 数据资产评估体系构建与财务应用研究
- 《防腐蚀碳砖标准》
- 2022机电工程安装工艺细部节点做法
- 2025年马原期末考试题库附答案详解(精练)
- 外协价格管理办法
- DB44T 1759-2015 电动汽车充电站运行服务规范
评论
0/150
提交评论