1 单选题(每题 2 分,共 30 分)
第1题 与数组相比,链表在( )操作上通常具有更高的效率。
A. 随机访问元素 B. 查找指定元素
C. 在已知位置插入或删除节点 D. 遍历所有元素
解析:答案C。与数组相比,链表在插入和删除操作上通常具有更高的效率。这是因为链表采用非连续的链式存储结构,在插入或删除元素时仅需调整相邻节点的指针,无需移动大量元素;而数组基于连续内存空间,插入或删除需移动后续元素以维持连续性,导致更高时间复杂度。故选C。
第2题 下面C++代码实现双向链表。函数 is_empty() 判断链表是否为空,如链表为空返回 true ,否则返回 false 。横线处不能填写( )。
- // 节点结构体
- struct Node {
- int data;
- Node* prev;
- Node* next;
- };
- // 双向链表结构体
- struct DoubleLink {
- Node* head;
- Node* tail;
- int size;
- DoubleLink() {
- head = nullptr;
- tail = nullptr;
- size = 0;
- }
- ~DoubleLink() {
- Node* curr = head;
- while (curr) {
- Node* next = curr->next;
- delete curr;
- curr = next;
- }
- }
- // 判断链表是否为空
- bool is_empty() const {
- _______________________
- }
- };
A. return head == nullptr; B. return tail == nullptr;
C. return head.data == 0; D. return size == 0;
解析:答案C。要判断双向链表是否空,按第14~18行构造函数,在给定的双向链表实现中,is_empty() 函数可以有多种正确的实现方式。以下是可能的正确填写选项:
- return head == nullptr;
- return tail == nullptr;
- return head == nullptr && tail == nullptr;
- return size == 0;
所以不能用head.data == 0判断。故选C。
第3题 基于上题代码正确的前提下,填入相应代码完善append(),用于在双向链表尾部增加新节点,横线上应填写( )。
- void append(int data) {
- Node* newNode = new Node{data, nullptr, nullptr};
- if (is_empty()) {
- head = tail = newNode; }
- else {
- _______________________
- }
- ++size;
- }
| A. |
|
B. |
|
| C. |
|
D. |
|
解析:答案D。函数名为append,应该是追加,即新节点添加在链表尾部。尾节点的后继指向新节点(tail->next = newNode;),新节点的前驱为尾节点(newNode->prev = tail;),置新节点为尾节点(tail = newNode;)。故选D。
第4题 下列C++代码用循环链表解决约瑟夫问题,即假设n个人围成一圈,从第一个人开始数,每次数到第k个的人就出圈,输出最后留下的那个人的编号。横线上应填写( )。
- struct Node {
- int data;
- Node* next;
- };
- Node* createCircularList(int n) {
- Node* head = new Node{1, nullptr};
- Node* prev = head;
- for (int i = 2; i <= n; ++i) {
- Node* node = new Node{i, nullptr};
- prev->next = node;
- prev = node;
- }
- prev->next = head;
- return head;
- }
- int fingLastSurvival(int n, int k) {
- Node* head = createCircularList(n);
- Node* p = head;
- Node* prev = nullptr;
- while (p->next != p) {
- for (int count = 1; count < k; ++count) {
- prev = p;
- p = p->next;
- }
- _______________________
- }
- cout << "最后留下的人编号是: " << p->data << endl;
- delete p;
- return 0;
- }
| A. |
|
B. |
|
| C. |
|
D. |
|
解析:答案A。这是一个单向循环链表,第28行处要要删除(每次数到第k个的人就出圈)节点p,需要先将p的前驱的后继设为p的后继,然后才能删除p,A.正确。B.p删除后获得p的后继,错误。C.p前驱的后继为p,p删除了链表指向错误。D.删除的是p的后继节点,错误。故选A。
第5题 下列C++代码判断一个正整数是否是质数,说法正确的是( )。
- bool is_prime(int n) {
- if (n <= 1)
- return false;
- if (n == 2 || n == 3 || n == 5)
- return true;
- if (n % 2 == 0 || n % 3 == 0 || n % 5 == 0)
- return false;
- int i = 7;
- int step = 4;
- int finish_number = sqrt(n) + 1;
- while (i <= finish_number) {
- if (n % i == 0)
- return false;
- i += step;
- step = 6 - step;
- }
- return true;
- }
A. 代码存在错误,比如5是质数,但因为 5 % 5 余数是0返回了false
B. finish_number 的值应该是n / 2,当前写法将导致错误
C. 当前 while 循环正确的前提是:所有大于3的质数都符合 6k±1 形式
D. while 循环修改如下,其执行效果和执行时间相同。
- for (int i = 2; i < finish_number; i++) {
- if (n % i == 0)
- return false;
- }
- return true;
解析:答案C。本题中的程序应用了质数的6k±1规则:除了2和3之外的所有质数都可以表示为6k±1的形式,因为若数n能被2或3整除,则n为合数;若数n不能被2或3整除,则其除以6的余数不能是0、2、3、4,只能是1或5(例如5余5、7余1、11余5等),因此必然属于6k±1的形式,C.正确。5因第4行条件成立会返回true,所以A.错误;求质数枚举因数的上限为,而不是n/2,B.错误;原程序只枚举了小于
+1的6k±1形式的数,D.选项程序枚举了2 ~
的所有数,原程序时间会更快一些,D.错误。故选C。
第6题 下列C++代码用两种方式求解两个正整数的最大公约数,说法错误的是( )。
- int gcd0(int big, int small) {
- if (big < small) {
- swap(big, small);
- }
- if (big % small == 0) {
- return small;
- }
- return gcd0(small, big % small);
- }
- int gcd1(int big, int small) {
- if (big < small) {
- swap(big, small);
- }
- for (int i = small; i >= 1; --i) {
- if (big % i == 0 && small % i == 0)
- return i;
- }
- return 1;
- }
A. gcd0()函数的时间复杂度为O(log n)
B. gcd1() 函数的时间复杂度为O(n)
C. 一般说来,gcd0()的效率高于gcd1()
D. gcd1() 中的代码 for (int i = small; i >= 1; --i) 应该修改为 for (int i = small; i > 1; --i)
解析:答案D。A.gcd0()函数为辗转相除法递归求最大公约数,辗转相除法(欧几里得算法)的时间复杂度为O(log(min(a, b))),其中a和b为输入的两个整数,设n=min(a,b),时间复杂度为O(log n),正确;B.gcd1()只有一重循环,时间复杂度为O(n),正确、gcd0()时间复杂度为

最低0.47元/天 解锁文章
622

被折叠的 条评论
为什么被折叠?



