C语言学习笔记20260630-动态整数序列维护(顺序表综合应用)
一、学习目标
通过"动态整数序列维护"问题,全面掌握顺序表(数组)在增、删、查、改、排序及遍历等核心操作上的综合应用。深入理解数组作为线性表在内存中的连续存储特性,学习如何通过维护 len 变量来动态管理逻辑长度,并掌握顺序表插入操作中的元素后移技巧以及自定义排序算法的实现。
二、问题拆解与核心逻辑
本题要求维护一个初始为空的整数序列,支持多达 8 种操作。核心约束条件为:
- 顺序表模拟 :使用静态数组
arr[MAXN]模拟动态序列,通过变量len记录当前序列的实际元素个数。 - 边界与移动 :在指定位置插入元素时,必须保证后续元素整体后移,防止数据覆盖;在删除或插入时,需严格维护
len的准确性。 - 综合调度 :通过
while(q--)循环配合if-else分支,根据操作码(op)动态调度对应的功能函数。
三、核心功能模块解析与完整代码
3.1 排序模块:冒泡排序的升序与降序实现
排序是顺序表的高级操作。这里采用经典的双层循环冒泡排序,通过改变比较条件(> 或 <)来实现升序或降序。
完整代码实现:
c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define MAXN 10000
// 升序排序,数组+长度作为参数传入
void sortAsc(int arr[], int len)
{
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int t = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = t;
}
}
}
}
// 降序排序
void sortDesc(int arr[], int len)
{
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - 1 - i; j++)
{
if (arr[j] < arr[j + 1])
{
int t = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = t;
}
}
}
}
3.2 核心交互模块:主函数与操作调度
主函数负责读取操作指令,并执行对应的数组操作。其中,**在指定位置插入元素(操作4)**是本题的难点,需要逆序移动元素以腾出空间。
完整代码实现:
c
int main()
{
int arr[MAXN];
int len = 0; // 维护当前序列的逻辑长度
int q;
scanf("%d", &q);
while (q--)
{
int op;
scanf("%d", &op);
if (op == 1)
{
// 末尾添加x:直接赋值到 arr[len],然后长度+1
int x;
scanf("%d", &x);
arr[len++] = x;
}
else if (op == 2)
{
// 删除末尾:逻辑长度-1即可(物理内存无需清空)
len--;
}
else if (op == 3)
{
// 输出下标i:利用数组O(1)随机访问特性
int i;
scanf("%d", &i);
printf("%d\n", arr[i]);
}
else if (op == 4)
{
// 在下标i与i+1之间插入x:即插入到下标 i+1 的位置
int i, x;
scanf("%d%d", &i, &x);
// 元素后移:从最后一个元素开始,依次向后挪一位
for (int j = len; j > i + 1; j--)
{
arr[j] = arr[j - 1];
}
arr[i + 1] = x; // 填入新元素
len++; // 长度+1
}
else if (op == 5)
{
sortAsc(arr, len);
}
else if (op == 6)
{
sortDesc(arr, len);
}
else if (op == 7)
{
printf("%d\n", len);
}
else if (op == 8)
{
// 遍历输出整个序列
for (int j = 0; j < len; j++)
{
if (j > 0)
printf(" ");
printf("%d", arr[j]);
}
printf("\n");
}
}
return 0;
}
四、核心细节与易错点解析
4.1 插入操作的元素后移(操作4)
在顺序表的任意位置插入元素时,必须从后往前 移动元素。代码中的 for (int j = len; j > i + 1; j--) 确保了 arr[len-1] 先移动到 arr[len],以此类推,最终将 arr[i+1] 的位置空出来。如果从前往后移动,会导致后续数据被覆盖。
4.2 逻辑长度 len 的维护
数组的物理大小是固定的(MAXN),但序列的逻辑大小由 len 决定。
- 添加 :
arr[len++] = x;先使用当前len作为下标,再自增。 - 删除末尾 :
len--;仅仅缩减逻辑边界,原arr[len]处的数据依然存在于内存中,但后续操作不再访问它。
4.3 输出格式的控制(操作8)
在输出整个序列时,要求元素之间用空格隔开,且最后一个元素后没有多余空格。代码通过 if (j > 0) printf(" "); 巧妙实现了这一格式控制,避免了复杂的边界判断。
五、总结与工程实践建议
本题是一个典型的顺序表(动态数组)综合应用题。它涵盖了数据结构中线性表最基础的增删查改与排序。在实际工程或更复杂的算法场景中,如果数据量极大且频繁在中间位置插入/删除,静态数组的 O(N) 移动开销会变得难以接受,此时可以考虑使用链表或 C++ STL 中的 std::vector(动态数组)。但在数据规模适中(如本题 q ≤ 7000)且对随机访问有较高要求的场景下,基于数组的顺序表依然是最高效、最简洁的解决方案。