一套试卷——数据结构(2020数据结构B)
一、简答题(本大题共 4 小题,每小题 5 分,总计 20 分)
1.
2.
3.
4.
二、应用题(本大题共 8 小题,总计 80 分)
5.
6.
7.
8.
9.
10.
11.
12.
三、算法阅读题(本大题共 2 小题,每小题 10 分,总计 20 分)
13.
14.
void S(int a[], int n) {int i, j, m, k;for (i = 1; i < n; i++) { // 从第二个元素开始(下标1),直到最后一个元素m = a[i]; // 取出当前待插入的元素j = 0;// 在已排序部分 a[0..i-1] 中查找插入位置// 找到第一个 >= m 的元素的位置 jwhile (j < i && m < a[j]) {j++;}// 将 j 到 i-1 的元素后移一位for (k = i; k > j; k--) {a[k] = a[k - 1];}// 插入 m 到位置 ja[j] = m;} }(1) 功能:
这是一种插入排序的变种,但查找插入位置的方式是从已排序部分的开头往后找第一个
a[j] <= m的位置,然后插入。由于它总是把较小的数往后移,最终结果是降序排列(因为插入位置 j 是第一个小于等于 m 的位置,m 会插在它前面,导致大的数在前)。
(2) 最终序列:
{6, 5, 4, 3, 2, 1}(3) 时间复杂度:
两层循环,比较和移动次数都是 O(n²)
平均/最坏时间复杂度:O(n²)
四、算法设计题(本大题共 3 小题,每小题 10 分,总计 30 分)
15.
#include <stdio.h> #include <stdlib.h>typedef struct LinkList {int data;struct LinkList* next; } LinkList;// 在倒数第 i 个结点之前插入 x void insert_x(LinkList* L, int x, int i) {if (L == NULL || i <= 0) return;// 1. 计算链表长度 n(不包括头结点)int n = 0;LinkList* p = L->next;while (p != NULL) {n++;p = p->next;}// 2. 检查 i 是否合法if (i > n) return; // 倒数第 i 个不存在// 3. 找到正数第 (n - i) 个结点(即倒数第 i 个的前驱)int pos = n - i; // 要移动的步数(从头结点开始)p = L;for (int j = 0; j < pos; j++) {p = p->next;}// 4. 插入新结点LinkList* newNode = (LinkList*)malloc(sizeof(LinkList));newNode->data = x;newNode->next = p->next;p->next = newNode; }
16.
// 定义队列结构体 typedef struct {int items[MAX_N]; // 存储队列元素的数组int front; // 队头指针,指向队列第一个元素int rear; // 队尾指针,指向队列最后一个元素的下一个位置 } Queue;// 初始化队列 void initQueue(Queue &q) {q.front = 0; // 初始化队头指针为0q.rear = 0; // 初始化队尾指针为0 }// 入队操作 void enqueue(Queue &q, int value) {q.items[q.rear] = value; // 将元素放入队尾位置q.rear = (q.rear + 1) % MAX_N; // 队尾指针循环后移,实现环形队列 }// 出队操作 int dequeue(Queue &q) {int value = q.items[q.front]; // 获取队头元素q.front = (q.front + 1) % MAX_N; // 队头指针循环后移return value; }// 判断队列是否为空 int isEmpty(Queue &q) {return q.front == q.rear; // 队头队尾指针相等时队列为空 }// 模拟报数淘汰过程 void simulateExitOrder(int n) {Queue q; // 创建队列initQueue(q); // 初始化队列// 将1到n的编号依次入队for (int i = 1; i <= n; i++) {enqueue(q, i);}int k = 1; // 报数值,从1开始int result[MAX_N]; // 存储离开顺序的数组int idx = 0; // 结果数组的索引// 当队列不为空时循环处理while (isEmpty(q) == false) {int person = dequeue(q); // 队首出队if (k % 2 != 2) { // 报数为奇数result[idx++] = person; // 记录离开顺序} else { // 报数为偶数enqueue(q, person); // 重新入队,放到队尾}k++; // 报数值递增}// 输出最终的离开顺序printf("离开顺序:");for (int i = 0; i < n; i++) {printf("%d ", result[i]);}printf("\n"); }
17.
void countLetters(const char *str) {int count[26] = {0}; // 用于存储26个小写字母出现次数的数组int length = strlen(str);// 遍历字符串中的每个字符for (int i = 0; i < length; i++) {char currentChar = str[i]; // 当前字符// 判断是否为小写字母if (currentChar >= 'a' && currentChar <= 'z') {int index = currentChar - 'a'; // 计算该字母在数组中的索引count[index] = count[index] + 1; // 对应字母计数加1}}// 统计不同字母的种类数int distinctCount = 0;for (int i = 0; i < 26; i++) {if (count[i] > 0) {distinctCount++;}}// 输出结果printf("一共出现了 %d 个字母,分别为:", distinctCount);for (int i = 0; i < 26; i++) {if (count[i] > 0) {printf("%c, ", 'a' + i);}}printf("\n次数分别为:");for (int i = 0; i < 26; i++) {if (count[i] > 0) {printf("%d, ", count[i]);}}printf("\n"); }// int index = currentChar - 'a';的作用: // 'z'=122,122-97=25,这样可以将字母映射到 0~25 的整数, //可以用数组统计每个字母的出现次数。
































