2-7 运用顺序表实现多项式相加

分数 7

作者 胡艳梅

单位 成都理工大学

本题要求输入两个一元多项式,然后输出它们的和(相加后得到的一元多项式)

输入格式:

输入一个整数n(表示输入组数),然后依次输入每一组数据:
输入一个整数A(表示多项式的项数,小于100),然后输入A对整数,每一对整数表示对应项的指数和系数。

输出格式:

对每一组输入,在一行中输出得到的一元多项式。

输入样例:

在这里给出一组输入。例如:

2
5
0 2
1 4
5 7
7 10
8 19
4
0 3
2 6
4 19
5 -9
3
0 3
4 7
8 2
3
0 -3
5 9
7 21

输出样例:

在这里给出相应的输出。例如:

5x^0+4x^1+6x^2+19x^4-2x^5+10x^7+19x^8
7x^4+9x^5+21x^7+2x^8

邪修

屏幕截图 2025-10-16 092502

ddf86f2ced00b93b61ecb282cdf3d7e2

解析

#include <stdio.h>
#include <stdlib.h>

typedef struct {
int exp;
int coeff;
}Term;

#define MAXSIZE 100

int readPloy(int n , Term *poly)
{
int len = 0;
int i;
for (i = 0; i < n; i++)
{
int e , c;
scanf("%d %d", &e , &c);
if (c == 0)
{
continue;
}

int found = 0;
int j;
for (j = 0; j < len; j++)
{
if (poly[j].exp == e)
{
poly[j].coeff += c;
if (poly[j].coeff == 0)
{
if (j != len - 1)
{
poly[j] = poly[len - 1];
}
len--;
}
found = 1;
break;
}
}
if (!found)
{
poly[len].exp = e;
poly[len].coeff = c;
len++;
}
}
return len;
}

int mergePoly(Term *p1, int len1, Term *p2, int len2, Term *res)
{
int resLen = 0;
int i = 0, j = 0;
for (i = 0; i < len1; i++)
{
res[resLen++] = p1[i];
}
for (i = 0; i < len2; i++)
{
int e = p2[i].exp;
int c = p2[i].coeff;
int found = 0;
for(j = 0; j < resLen; j++)
{
if (res[j].exp == e)
{
res[j].coeff += c;
if(res[j].coeff == 0)
{
if (j != resLen - 1)
{
res[j] = res[resLen - 1];
}
resLen--;
}
found = 1;
break;
}
}
if (!found)
{
res[resLen].exp = e;
res[resLen].coeff = c;
resLen++;
}
}
return resLen;
}

int compare(const void *a, const void *b)
{
Term *t1 = (Term *)a;
Term *t2 = (Term *)b;
return t1->exp - t2->exp;
}

void printPoly(Term *poly, int len)
{
if (len == 0)
{
printf ("\n");
return;
}
printf ("%dx^%d", poly[0].coeff, poly[0].exp);
int i;
for (i = 1; i < len; i++)
{
if (poly[i].coeff > 0)
{
printf ("+%dx^%d", poly[i].coeff, poly[i].exp);
}
else
{
printf ("-%dx^%d", -poly[i].coeff, poly[i].exp);
}
}
printf ("\n");
}

int main()
{
int n;
scanf("%d", &n);
while (n--)
{
Term p1[MAXSIZE], p2[MAXSIZE], res[MAXSIZE];
int len1, len2, resLen;

int A1;
scanf("%d", &A1);
len1 = readPloy(A1, p1);

int A2;
scanf("%d", &A2);
len2 = readPloy(A2, p2);

resLen = mergePoly(p1, len1, p2, len2, res);

qsort(res, resLen, sizeof(Term), compare);

printPoly(res, resLen);
}
return 0;
}

解释这段代码

这段代码的核心功能是用顺序表(数组)实现两个一元多项式的相加,整体逻辑遵循 “读取多项式→合并同类项→排序→格式化输出” 的流程。下面从「数据结构」「核心函数」「主流程」三个层面,逐部分详细拆解代码逻辑。

一、整体框架与数据结构

在写具体功能前,首先要定义 “如何存储多项式的项”,并限制数组大小(避免内存越界),这是代码的基础。

1. 结构体 Term:存储多项式的单个项

多项式的每一项都包含两个关键信息:指数(exp)系数(coeff),用结构体可以将这两个属性 “打包” 成一个整体,方便数组存储(顺序表的核心就是 “数组存相同类型元素”)。

typedef struct {
int exp; // exponent:项的指数(如 x^3 的 exp=3)
int coeff; // coefficient:项的系数(如 5x^2 的 coeff=5)
} Term;
  • 例:项 4x^1 对应的 Term{exp=1, coeff=4};项 -9x^5{exp=5, coeff=-9}

2. 宏 MAXSIZE:限制顺序表的最大容量

题目明确 “多项式项数小于 100”,因此用宏定义数组的最大长度为 100,确保存储每个多项式(p1/p2)和结果(res)时不会越界。

#define MAXSIZE 100

二、核心函数解析

代码共封装了 4 个功能函数,分别负责 “读多项式”“合并多项式”“排序”“输出”,每个函数各司其职,最后在主函数中串联起来。

1. 函数 readPoly:读取多项式并预处理(合并同类项 + 去零项)

功能

输入一个多项式的 “项数 n” 和 “n 对(指数 + 系数)”,将其存储到顺序表(Term *poly)中,同时完成两个关键预处理:

  • 跳过系数为 0 的项(系数为 0 的项对多项式无意义,如 0x^2 可直接忽略);
  • 合并同类项(指数相同的项,系数相加,如 2x^0 + 3x^0 = 5x^0)。

参数与返回值

  • 参数 1:int n → 输入的 “原始项数”(可能包含同类项或零系数项);
  • 参数 2:Term *poly → 指向存储多项式的数组(顺序表),最终会存入预处理后的有效项;
  • 返回值:int len → 预处理后多项式的 “有效项数”(无同类项、无零系数项)。

内部逻辑(逐行拆解)

int readPloy(int n , Term *poly)
{
int len = 0; // 有效项数,初始为0(还没存任何有效项)
int i;
// 循环读取n个原始项(每轮读1对“指数e+系数c”)
for (i = 0; i < n; i++)
{
int e , c;
scanf("%d %d", &e , &c); // 读当前项的指数e和系数c

// 预处理1:跳过系数为0的项(无意义)
if (c == 0)
{
continue;
}

int found = 0; // 标记是否找到同类项(初始为“未找到”)
int j;
// 遍历已存储的有效项,检查是否有同类项(指数相同)
for (j = 0; j < len; j++)
{
if (poly[j].exp == e) // 找到同类项(指数e相同)
{
poly[j].coeff += c; // 系数相加(合并同类项)

// 特殊情况:合并后系数为0,需移除这项
if (poly[j].coeff == 0)
{
// 用最后一个有效项覆盖当前项(避免数组留空)
if (j != len - 1)
{
poly[j] = poly[len - 1];
}
len--; // 有效项数减1(相当于移除了这项)
}
found = 1; // 标记为“已找到同类项”
break; // 无需继续找,跳出循环
}
}

// 预处理2:未找到同类项,将当前项作为新有效项存入数组
if (!found)
{
poly[len].exp = e; // 存指数
poly[len].coeff = c; // 存系数
len++; // 有效项数加1
}
}
return len; // 返回有效项数
}

示例(结合输入样例)

输入第一组多项式的第一个原始项:5 项(0 2/1 4/5 7/7 10/8 19

  • 0 2:c≠0,无同类项 → 存 poly[0] = {0,2},len=1;
  • 1 4:c≠0,无同类项 → 存 poly[1] = {1,4},len=2;
  • 后续项均无同类项,最终 len1=5p1 数组存 5 个有效项。

2. 函数 mergePoly:合并两个多项式(核心相加逻辑)

功能

将两个预处理后的多项式 p1(有效项数 len1)和 p2(有效项数 len2)相加,结果存入 res 数组,核心是再次合并同类项(因为 p1p2 可能有相同指数的项)。

参数与返回值

  • 参数 1:Term *p1 → 第一个多项式的顺序表;
  • 参数 2:int len1 → 第一个多项式的有效项数;
  • 参数 3:Term *p2 → 第二个多项式的顺序表;
  • 参数 4:int len2 → 第二个多项式的有效项数;
  • 参数 5:Term *res → 存储结果多项式的顺序表;
  • 返回值:int resLen → 结果多项式的有效项数。

内部逻辑(逐行拆解)

int mergePoly(Term *p1, int len1, Term *p2, int len2, Term *res)
{
int resLen = 0; // 结果的有效项数,初始为0
int i = 0, j = 0; // 循环变量(i遍历p1,j遍历res)

// 步骤1:先将第一个多项式p1的所有有效项,直接存入结果res
for (i = 0; i < len1; i++)
{
res[resLen++] = p1[i]; // 复制p1的第i项到res,有效项数加1
}

// 步骤2:处理第二个多项式p2的每一项,与res中的项合并同类项
for (i = 0; i < len2; i++)
{
int e = p2[i].exp; // 当前p2项的指数
int c = p2[i].coeff; // 当前p2项的系数
int found = 0; // 标记是否在res中找到同类项

// 遍历res中已有的有效项,检查同类项
for(j = 0; j < resLen; j++)
{
if (res[j].exp == e) // 找到同类项(res中有指数e的项)
{
res[j].coeff += c; // 系数相加(p2的系数加到res的系数上)

// 特殊情况:合并后系数为0,移除这项
if(res[j].coeff == 0)
{
if (j != resLen - 1) // 用最后一项覆盖当前项
{
res[j] = res[resLen - 1];
}
resLen--; // 有效项数减1
}
found = 1; // 标记“已找到”
break; // 跳出循环,处理p2的下一项
}
}

// 若res中无同类项,将p2的当前项作为新项存入res
if (!found)
{
res[resLen].exp = e;
res[resLen].coeff = c;
resLen++;
}
}
return resLen; // 返回结果的有效项数
}

示例(结合输入样例)

p1 有 5 项(0 2/1 4/5 7/7 10/8 19),p2 有 4 项(0 3/2 6/4 19/5 -9):

  • 步骤 1:res 先存入 p1 的 5 项,resLen=5
  • 步骤 2 处理 p20 3:res 中有 exp=0 的项(系数 2)→ 2+3=5,res [0].coeff=5;
  • 处理 p25 -9:res 中有 exp=5 的项(系数 7)→7+(-9)=-2,res [2].coeff=-2;
  • 其他 p2 项(2 6/4 19)无同类项,存入 res;
  • 最终 resLen=7,res 数组有 7 个有效项。

3. 函数 compare:排序规则函数(给 qsort 用)

功能

qsort 是 C 标准库的通用排序函数,需要自定义 “如何比较两个元素”。这里的规则是按多项式项的指数升序排列(如示例输出的指数顺序:0→1→2→4→5→7→8)。

参数与返回值

  • 参数 1/2:const void *a / const void *b → 指向两个待比较的 Term 元素(qsort 要求参数为无类型指针,兼容任意数据类型);
  • 返回值:
    • 若返回 正数a 对应的元素应排在 b 后面;
    • 若返回 负数a 对应的元素应排在 b 前面;
    • 若返回 0:两者顺序随意。

内部逻辑

int compare(const void *a, const void *b)
{
// 强制转换:将无类型指针转为Term类型指针(才能访问exp/coeff)
Term *t1 = (Term *)a;
Term *t2 = (Term *)b;
// 按指数升序:t1的exp小 → 返回负数 → t1排在前面
return t1->exp - t2->exp;
}
  • 例:比较 t1={1,4}(exp=1)和 t2={2,6}(exp=2)→ 1-2=-1(负数)→ t1 排在 t2 前面,符合升序。

4. 函数 printPoly:格式化输出多项式

功能

将排序后的结果多项式 res,按题目要求的格式输出(如 5x^0+4x^1+6x^2+19x^4-2x^5+10x^7+19x^8),核心是处理符号

  • 第一项无前置符号(如 5x^0 不写 +5x^0);
  • 正数项前置 +(如 +4x^1);
  • 负数项前置 -,且系数取绝对值(如 -2x^5 不写 +-2x^5)。

参数

  • 参数 1:Term *poly → 待输出的多项式顺序表;
  • 参数 2:int len → 多项式的有效项数。

内部逻辑

void printPoly(Term *poly, int len)
{
// 边界情况:无有效项(理论上不会出现,因题目输入有项)
if (len == 0)
{
printf ("\n");
return;
}

// 输出第一项:无前置符号
printf ("%dx^%d", poly[0].coeff, poly[0].exp);

// 输出后续项(从第2项开始)
int i;
for (i = 1; i < len; i++)
{
if (poly[i].coeff > 0) // 系数为正:前置+
{
printf ("+%dx^%d", poly[i].coeff, poly[i].exp);
}
else // 系数为负:前置-,系数取绝对值
{
printf ("-%dx^%d", -poly[i].coeff, poly[i].exp);
}
}
printf ("\n"); // 所有项输出完后换行(每组结果占一行)
}

示例(结合输入样例)

res 排序后有 7 项:{0,5}/{1,4}/{2,6}/{4,19}/{5,-2}/{7,10}/{8,19}

  • 第一项输出 5x^0
  • 第二项 4>0 → 输出 +4x^1
  • 第五项 -2<0 → 输出 -2x^5
  • 最终拼接为示例第一行输出。

三、主函数 main:串联所有功能(流程控制)

主函数是代码的 “入口”,负责按题目输入格式读取数据,调用上述函数完成 “读→合并→排序→输出” 的完整流程。

内部逻辑(逐行拆解)

int main()
{
int n;
scanf("%d", &n); // 读“输入组数”n(如示例输入n=2)

// 循环处理每组数据(n组,处理完一组n减1,直到n=0)
while (n--)
{
// 定义3个顺序表:p1(第一个多项式)、p2(第二个)、res(结果)
Term p1[MAXSIZE], p2[MAXSIZE], res[MAXSIZE];
int len1, len2, resLen; // 三个多项式的有效项数

// 步骤1:读第一个多项式
int A1;
scanf("%d", &A1); // 读第一个多项式的原始项数(如示例A1=5)
len1 = readPloy(A1, p1); // 调用readPoly预处理,获有效项数len1

// 步骤2:读第二个多项式
int A2;
scanf("%d", &A2); // 读第二个多项式的原始项数(如示例A2=4)
len2 = readPloy(A2, p2); // 预处理,获有效项数len2

// 步骤3:合并两个多项式(相加)
resLen = mergePoly(p1, len1, p2, len2, res);

// 步骤4:按指数升序排序
qsort(res, resLen, sizeof(Term), compare);
// qsort参数说明:
// res:待排序数组首地址;resLen:元素个数;
// sizeof(Term):每个元素的字节大小;compare:排序规则函数

// 步骤5:格式化输出结果
printPoly(res, resLen);
}
return 0;
}

整体流程总结(以示例输入为例)

  1. n=2(2 组数据);
  2. 第一组数据:
    • A1=5 → 调用 readPolylen1=5
    • A2=4 → 调用 readPolylen2=4
    • 调用 mergePolyresLen=7
    • 调用 qsort 排序;
    • 调用 printPoly 输出第一行结果;
  3. 第二组数据:重复上述步骤,输出第二行结果;
  4. 循环结束,程序退出。

四、关键细节与边界处理

  1. 去零项readPoly 跳过输入的零系数项,mergePoly 移除合并后系数为 0 的项,确保输出无多余项;
  2. 同类项合并readPoly 处理单个多项式的同类项,mergePoly 处理两个多项式间的同类项,避免重复项;
  3. 排序正确性compare 确保指数升序,符合题目输出格式;
  4. 符号处理printPoly 区分第一项和后续项的符号,避免格式错误(如多余的 +-);
  5. 内存安全:用 MAXSIZE 限制数组大小,避免数组越界(因题目项数 < 100,MAXSIZE=100 足够)。

五、代码验证(结合示例输入输出)

输入样例:

2
5
0 2
1 4
5 7
7 10
8 19
4
0 3
2 6
4 19
5 -9
3
0 3
4 7
8 2
3
0 -3
5 9
7 21

代码处理后输出:

5x^0+4x^1+6x^2+19x^4-2x^5+10x^7+19x^8
7x^4+9x^5+21x^7+2x^8

与题目示例输出完全一致,说明代码逻辑正确。

2-8 合并有序数组

分数 7

作者 伍建全

单位 重庆科技大学

给定2个非降序序列,要求把他们合并成1个非降序序列。假设所有元素个数为N,要求算法的时间复杂度为O(N)。

输入格式:

输入有4行。
第1行是一个正整数m,表示第2行有m个整数,这些整数构成一个非降序序列,每个整数之间以空格隔开。第3行是一个正整数n,表示第4行有n个整数,这些整数也构成一个非降序序列,每个整数之间以空格隔开。

输出格式:

把第2行的m个整数和第4行的n个整数合并成一个非降序序列,输出这个整数序列。每个数之间隔1个空格。

输入样例:

6
1 3 6 6 8 9
4
2 4 5 7

输出样例:

1 2 3 4 5 6 6 7 8 9 

解析

#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;

typedef struct LNode {
ElemType data;
struct LNode *next;
} LNode, *LinkList;

typedef struct SqList {
ElemType *data;
int length;
} SqList;

void createList(LinkList L, int len) {
LNode *tail = L; // 尾指针,始终指向最后一个节点(初始为头节点)
for (int i = 0; i < len; i++) {
LNode *p = (LNode *)malloc(sizeof(LNode));
scanf("%d", &p->data);
p->next = NULL; // 新节点的next置空
tail->next = p; // 尾节点的next指向新节点
tail = p; // 尾指针后移到新节点(保持尾部)
}
}

int main() {
LinkList L1 = (LNode *)malloc(sizeof(LNode));
L1->next = NULL;
LinkList L2 = (LNode *)malloc(sizeof(LNode));
L2->next = NULL;

int n;
scanf("%d", &n);
createList(L1, n);

int m;
scanf("%d", &m);
createList(L2, m);

SqList L3;
L3.length = n + m;
L3.data = (ElemType *)malloc(sizeof(ElemType) * L3.length);
int k = 0;

LNode *p1 = L1->next;
LNode *p2 = L2->next;

while (p1 != NULL && p2 != NULL) {
if (p1->data <= p2->data) {
L3.data[k++] = p1->data; // 存储p1的值,索引递增
p1 = p1->next; // p1后移
} else {
L3.data[k++] = p2->data; // 存储p2的值,索引递增
p2 = p2->next; // p2后移
}
}

while (p1 != NULL) {
L3.data[k++] = p1->data;
p1 = p1->next;
}

while (p2 != NULL) {
L3.data[k++] = p2->data;
p2 = p2->next;
}

for (int i = 0; i < L3.length; i++) {
printf("%d ", L3.data[i]);

}

// 释放内存(简化:实际需遍历链表释放每个节点,此处省略)
free(L1);
free(L2);
free(L3.data);

return 0;
}

2-9 在顺序表 list 中查找元素 x

分数 7

作者 陈越

单位 浙江大学

请编写程序,将 n 个整数存入顺序表,对任一给定整数 x,查找其在顺序表中的位置。

输入格式:

输入首先在第一行给出正整数 n(≤104);随后一行给出 n 个 int 范围内的不重复的整数,数字间以空格分隔;最后一行给出待查找的元素 x,也是 int 范围内的整数。

输出格式:

在一行中输出 x 在顺序表中的位置,即数组下标。如果没找到,则输出 -1。注意数组下标从 0 开始。

输入样例 1:

5
1 2 3 4 5
4

输出样例 1:

3

输入样例 2:

5
4 3 6 8 0
1

输出样例 2:

-1

解析

#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct SqList
{
ElemType *elem;
int length;
int listsize;
} SqList;
#define MAXSIZE 10000
int main()
{
int n;
scanf ("%d", &n);
SqList L;
L.elem = (ElemType *)malloc(sizeof(ElemType) * MAXSIZE);
L.length = n;
L.listsize = MAXSIZE;
int i;
for (i = 0; i < n; i++)
{
scanf("%d", &L.elem[i]);
}
int m;
scanf ("%d",&m);
int flag = -1;
int locate;
for (i = 0; i < n; i++)
{
if (L.elem[i] == m) {
flag = 1;
locate = i;
break;
}
}
if (flag == -1) {
printf ("-1");
return 0;
}
else {
printf ("%d",locate);
return 0;
}
}

2-10 在顺序表 list 的第 i 个位置上插入元素 x

分数 8

作者 陈越

单位 浙江大学

请编写程序,将 n 个整数存入顺序表,对任一给定整数 x,将其插入顺序表中指定的第 i 个位置。注意:i 代表位序,从 1 开始,不是数组下标。

输入格式:

输入首先在第一行给出正整数 n(≤104);随后一行给出 n 个 int 范围内的整数,数字间以空格分隔;最后一行给出插入位置 i 和待插入的元素 x,均为 int 范围内的整数。

输出格式:

分以下几种情况输出:

  • 如果顺序表中已经有 104 个元素了,则不能插入,在一行中输出句子 错误:表满不能插入。
  • 如果插入的位置不合法,则不能插入,在一行中输出句子 错误:插入位置不合法。
  • 无论是否插入成功,都在一行中顺序输出表中的元素,每个元素后面跟一个空格。

输入样例 1:

5
1 2 3 4 5
3 8

输出样例 1:

1 2 8 3 4 5 

输入样例 2:

5
4 3 6 8 0
0 1

输出样例 2:

错误:插入位置不合法。
4 3 6 8 0

解析

#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct SqList {
ElemType *data;
int length;
int size;
}SqList;
#define MAXSIZE 10000
int main() {
int n;
scanf ("%d",&n);
SqList L;
L.data = (ElemType *)malloc(sizeof(ElemType) * MAXSIZE);
L.length =n;
int i;
for (i = 0; i < n; i++) {
int k;
scanf ("%d", &k);
L.data[i] = k;
}
int k;
scanf ("%d", &k);
int a;
scanf ("%d", &a);
if (n == 10000) {
printf ("错误:表满不能插入。\n");
}
else if (k <= 0 || k > n + 1) {
printf ("错误:插入位置不合法。\n");
}
else {
for (i = L.length - 1; i >= k - 1; i--) {
L.data[i + 1] = L.data[i];
}
L.data[k - 1] = a;
L.length++;
}
for (i = 0; i < L.length; i++) {
printf ("%d ", L.data[i]);
}
return 0;
}

2-11 从顺序表 list 中删除第 i 个元素

分数 8

作者 陈越

单位 浙江大学

请编写程序,将 n 个整数存入顺序表,对任一指定的第 i 个位置,将这个位置上的元素从顺序表中删除。注意:i 代表位序,从 1 开始,不是数组下标。

输入格式:

输入首先在第一行给出正整数 n(≤104);随后一行给出 n 个 int 范围内的整数,数字间以空格分隔;最后一行给出删除位序 i,为 int 范围内的整数。

输出格式:

如果删除的位置不合法,则不能删除,在一行中输出句子 错误:不存在这个元素。。无论是否删除成功,都在一行中顺序输出表中的元素,每个元素后面跟一个空格。

输入样例 1:

5
1 2 3 4 5
3

输出样例 1:

1 2 4 5 

输入样例 2:

5
4 3 6 8 0
0

输出样例 2:

错误:不存在这个元素。
4 3 6 8 0

解析

#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
#define MAXSIZE 10000
typedef struct SqList {
ElemType *data;
int length;
}SqList;
int main() {
int n;
scanf ("%d", &n);
SqList L;
L.data = (ElemType *)malloc(sizeof(ElemType) * MAXSIZE);
L.length = n;
int i;
for (i = 0; i < n; i++) {
scanf ("%d", &L.data[i]);
}
int k;
scanf ("%d", &k);
if (k <= 0 || k > L.length) {
printf ("错误:不存在这个元素。\n");
}
else {
for (i = k - 1; i < L.length - 1; i++) {
L.data[i] = L.data[i + 1];
}
L.length--;
}
for (i = 0; i < L.length; i++) {
printf ("%d ", L.data[i]);
}
free(L.data);
return 0;
}

2-12 线性表循环右移

分数 8

作者 陈越

单位 浙江大学

给定顺序表 A=(a1,a2,⋯,a**n),请设计一个时间和空间上尽可能高效的算法将该线性表循环右移指定的 m 位。例如,(1,2,5,7,3,4,6,8) 循环右移 3 位(m=3) 后的结果是 (4,6,8,1,2,5,7,3)。

输入格式:

第一行输入 n ( 1≤n≤105)、mm≥0);第二行输入 n 个整数。所有数字在 int 型整数范围内,同行数字间以空格分隔。

输出格式:

输出循环右移 m 位以后的整数序列。数字间以 1 个空格分隔,行首尾不得有多余空格。

输入样例:

6 2
1 2 3 4 5 6

输出样例:

5 6 1 2 3 4

解析

#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
#define MAXSIZE 100000
typedef struct {
ElemType *data;
int length;
int size;
}SqList;

void Reverse(SqList *L , int left, int right)
{
while (left < right)
{
ElemType temp = L->data[left];
L->data[left] = L->data[right];
L->data[right] = temp;
left++;
right--;
}
}
int main()
{
SqList L;
L.data = (ElemType *)malloc(MAXSIZE * sizeof(ElemType));
int n;
int x;
scanf("%d %d" , &n , &x);
L.length = n;
L.size = MAXSIZE;
int i;
for (i = 0; i < n; i++)
{
scanf("%d", &L.data[i]);
}
x = x % n;
Reverse(&L , 0 , n - x -1);
Reverse(&L , n - x, n - 1);
Reverse(&L , 0 , n - 1);
for (i = 0; i < n; i++)
{
printf("%d", L.data[i]);
if (i != n - 1)
{
printf(" ");
}
}
free(L.data);
return 0;
}

2-13 约瑟夫环

分数 9

作者 李廷元

单位 中国民用航空飞行学院

N个人围成一圈顺序编号,从1号开始按1、2、3…顺序报数,报p者退出圈外,其余的人再从1、2、3开始报数,报p的人再退出圈外,以此类推。
请按退出顺序输出每个退出人的原序号。

输入格式:

输入只有一行,包括一个整数N(1<=N<=3000)及一个整数p(1<=p<=5000)。

输出格式:

按退出顺序输出每个退出人的原序号,数据间以一个空格分隔,但行尾无空格。

输入样例:

在这里给出一组输入。例如:

7 3

输出样例:

3 6 2 7 5 1 4

超时代码

#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct SqList {
ElemType *data;
int length;
}SqList;
int main() {
int n, m;
scanf ("%d %d",&n,&m);
SqList L;
L.data =(ElemType *)malloc(sizeof(ElemType)*n);
int i;
for (i = 0; i < n; i++) {
L.data[i] = i + 1;
}
int index = 0;
int count = 0;
int out = 0;
int is_first = 1;
while (out < n) {
if (L.data[index] == -1) {
index++;
index %= n;
continue;
}
count++;
if (count == m) {
if (is_first) {
printf ("%d", L.data[index]);
is_first = 0;
}
else {
printf (" %d", L.data[index]);
}
L.data[index] = -1;
count = 0;
out++;
}
index++;
index %= n;
}
free(L.data);
return 0;
}

你的代码超时是因为用顺序表模拟遍历的时间复杂度太高(O (n×m)),当 n 和 m 较大时(比如 n=3000、m=5000),需要反复跳过已退出的元素(-1),无效循环次数太多。解决办法是改用数学递推法,直接计算每个退出者的位置,时间复杂度降至 O (n),彻底避免超时。

一、超时原因分析

你的现有逻辑是 “逐个遍历数组找下一个报数到 m 的人”,核心问题在于:

  • 每次找目标都要遍历整个数组,遇到已退出的元素(-1)还要跳过,相当于每次操作都要 “扫一遍” 剩余元素;
  • 当 n=3000、m=5000 时,总循环次数可能达到 3000×5000=15,000,000 次,远超时间限制,导致超时。

二、优化方案:约瑟夫环数学递推法

约瑟夫环有成熟的数学递推公式,核心思路是直接计算每次退出者的位置,无需遍历数组。具体原理如下:

  1. 假设当前剩余t个人(初始 t=n),从位置pos开始报数(初始 pos=0,位置从 0 开始计数,方便取模);
  2. 本次退出者的位置 = (pos + m - 1) % tm-1是因为报数从 1 开始,需转换为 0-based 索引);
  3. 输出该位置对应的原序号(+1,因为题目序号从 1 开始);
  4. 更新下一轮的起始位置pos为本次退出者的位置(下一轮从退出者的下一个人开始报数,取模后自动处理环形)。

1-1 求链式表的表长

分数 3

作者 陈越

单位 浙江大学

本题要求实现一个函数,求链式表的表长。

函数接口定义:

int Length( List L );

其中List结构定义如下:

typedef struct LNode *PtrToLNode;
struct LNode {
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode List;

L是给定单链表,函数Length要返回链式表的长度。

裁判测试程序样例:

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct LNode *PtrToLNode;
struct LNode {
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode List;

List Read(); /* 细节在此不表 */

int Length( List L );

int main()
{
List L = Read();
printf("%d\n", Length(L));
return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

1 3 4 5 2 -1

输出样例:

5

解析

int Length( List L ) {
PtrToLNode p = L;
int length = 0;
while (p != NULL) {
p = p->Next;
length++;
}
free (p);
return length;
}

直接使用PtrToLNode建一个p指针,指向L

  • PtrToLNode p = L 声明指针 p,使其指向链表的头节点,避免类型错误。
  • 循环遍历:当 p 不为空时,说明当前节点有效,计数加 1,然后移动 p 到下一个节点(p = p->Next)。
  • p 为空时,说明已遍历完所有节点,返回计数结果。

1-2 单链表逆转

分数 4

作者 陈越

单位 浙江大学

本题要求实现一个函数,将给定的单链表逆转。

函数接口定义:

List Reverse( List L );

其中List结构定义如下:

typedef struct Node *PtrToNode;
struct Node {
ElementType Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */

L是给定单链表,函数Reverse要返回被逆转后的链表。

裁判测试程序样例:

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
ElementType Data;
PtrToNode Next;
};
typedef PtrToNode List;

List Read(); /* 细节在此不表 */
void Print( List L ); /* 细节在此不表 */

List Reverse( List L );

int main()
{
List L1, L2;
L1 = Read();
L2 = Reverse(L1);
Print(L1);
Print(L2);
return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

5
1 3 4 5 2

输出样例:

1
2 5 4 3 1

解析

List Reverse(List L) {
if (L == NULL || L->Next == NULL) {
return L;
}

List prev = NULL;
List current = L;
List next = NULL;

while (current != NULL) {
next = current->Next; // 保存下一个节点
current->Next = prev; // 反转指针
prev = current; // 前移prev
current = next; // 前移current
}

return prev; // prev现在是新的头节点
}

图片解析

屏幕截图 2025-10-16 220233