当前位置: 首页 > news >正文

【数据结构与算法(C语言版)】从 0 实现 线性表之顺序表(代码实现增删查功能全解析)

文章目录

      • 一、引言:什么是顺序表?
      • 二、环境准备
      • 三、核心模块 1:顺序表的结构定义
          • 3.1 结构定义代码
          • 3.2 代码解析
      • 四、核心模块 2:顺序表的初始化
          • 4.1 初始化原理
          • 4.2 初始化代码(含 main 函数调用)
      • 五、辅助模块:顺序表打印(调试必备)
          • 5.1 代码示例
          • 5.2 代码解析
      • 六、核心模块 3:顺序表插入元素
          • 6.1 插入原理
          • 6.2 插入代码
          • 6.3 插入效果
      • 七、核心模块 4:顺序表删除元素
          • 7.1 删除原理
          • 7.2 代码示例
          • 7.3 关键注意点
      • 八、核心模块 5:顺序表查询元素
          • 8.1 查询原理
          • 8.2 代码示例
      • 九、完整代码与运行结果
          • 9.1 完整代码
          • 9.2 运行结果
            • 初始顺序表:
            • 插入后顺序表:
            • 删除后顺序表:
      • 十、总结与注意事项

一、引言:什么是顺序表?

在开始写代码前,我们先搞懂一个基础问题:顺序表是什么?
顺序表是线性表的「顺序存储结构」,本质是用数组存储数据,同时用一个变量记录当前存储的元素个数(长度)。它的核心特点是:
元素在内存中连续存储,支持「随机访问」(通过下标快速定位元素,时间复杂度 O (1));
插入、删除元素时需要移动后续元素,时间复杂度 O (n)。
本文将基于 C 语言,从 0 开始实现顺序表的初始化、插入、删除、查询四大核心功能(对应题目需求),每一步都附带原理讲解和代码解析,零基础也能跟着学会。

二、环境准备

  • 编译器:任意 C 语言编译器(如 GCC、Dev-C++、VS2022);
  • 头文件:需包含 2 个核心头文件:
    • stdio.h:用于输入输出(如打印顺序表、报错信息);
    • stdlib.h:用于动态内存分配(malloc)和释放(free)。

三、核心模块 1:顺序表的结构定义

要实现顺序表,首先得定义它的「数据结构」—— 用结构体封装数组和长度,让代码更模块化。

3.1 结构定义代码
#include<stdio.h>
#include<stdlib.h>// 1. 定义顺序表的最大容量(宏定义:方便后续修改,无需到处改代码)
#define MaxSize 50// 2. 定义元素类型(typedef:后续想存其他类型,只需改这里,增强可移植性)
typedef int ElementType;// 3. 定义顺序表结构体
typedef struct SequenceList{ElementType data[MaxSize];  // 存储元素的数组int length;                 // 当前元素个数(长度)
} SqList;  // 结构体别名,后续用SqList代替struct SequenceList
3.2 代码解析
  1. #define MaxSize 50
    定义顺序表的最大容量为 50(静态顺序表,容量固定)。如果后续需 要更大的容量,直接修改50即可,无需修改其他代码。
  2. typedef int ElementType
    给int起别名ElementType。如果未来想让顺序表存储float或char,只需把int改成float,所有使用ElementType的地方会自动适配,不用逐个修改数组和函数参数。
    结构体成员说明:
  3. data[MaxSize]
    核心数组,用来存实际数据(如整数 1、2、3);
    length:记录当前有多少个有效元素(比如存了 5 个元素,length=5),避免每次遍历都要查数组全部元素。

四、核心模块 2:顺序表的初始化

初始化是使用顺序表的第一步 —— 给顺序表分配内存,并设置初始数据(如从数组导入初始值)。

4.1 初始化原理
  • 用malloc动态分配结构体内存(对比静态分配,动态分配更灵活,避免栈溢出);
  • 检查内存分配是否成功(malloc失败会返回NULL,必须处理,否则会崩溃);
  • 导入初始数据(如把{1,2,3,4,5}存入顺序表),并设置初始长度。
4.2 初始化代码(含 main 函数调用)
// 初始化顺序表(从数组导入初始数据)
// 动态分配初始化 顺序表
int main() {SqList* L = (SqList*)malloc(sizeof(SqList));if(L == NULL) {printf("memory allocation failed!\n");return -1;}ElementType temp_arr[] = {1 ,2, 3, 4, 5};int temp_len = sizeof(temp_arr) / sizeof(ElementType);for(int i = 0; i < temp_len; i++) {L -> data[i] = temp_arr[i];}L -> length = temp_len;// 后续操作(插入、删除、查询)...return 0;
}

五、辅助模块:顺序表打印(调试必备)

为了直观看到顺序表的内容,我们需要一个打印函数 —— 遍历顺序表,输出每个元素的位置和值。

5.1 代码示例
void loop_print(SqList arr) {printf("--------------------------------divide line-----------------------------------");for(int i = 0; i < arr.length; i++) {printf("[%d].\t %d\n", i + 1, arr.data[i]);}
}
5.2 代码解析
  • i + 1的作用:数组下标从 0 开始,但人类习惯 “第 1 个元素”“第 2 个元素”,所以打印时用i + 1表示位置。
  • 只遍历length个元素:避免打印数组中未使用的 “垃圾值”(如data[5]及以后的内存,未赋值时是随机值)。

六、核心模块 3:顺序表插入元素

插入功能是顺序表的核心操作之一 —— 在指定位置插入一个元素,需要先移动后续元素,再插入新值。

6.1 插入原理
  1. 合法性检查:确保插入位置合法(不能小于 1,也不能大于当前长度 + 1)、顺序表未满、指针非空;
  2. 元素后移:从最后一个元素(下标length-1)开始,到插入位置的下标,逐个向后移动 1 位(避免覆盖元素);
  3. 插入元素:在目标位置存入新元素;
  4. 更新长度:length加 1(元素个数增加)。
6.2 插入代码
/*** 顺序表插入元素* @param list:            顺序表对象* @param add_position:    添加的元素位置* @param add_element:     需要添加的元素* @return                 success: 1; failed: -1*/
int insert_sequence_list(SqList* list, int add_position, ElementType add_element) {if (list == NULL) {return -1;}if(! (add_position >= 1 && add_position <= list-> length + 1)) {return -1;}if(list -> length >= MaxSize) {return -1;}for(int i = list -> length; i >= add_position; i--) {list -> data[i] = list -> data[i- 1];}list -> data[add_position - 1] = add_element;list -> length++;return 1;
}
6.3 插入效果

初始顺序表:[1,2,3,4,5](length=5)
插入后顺序表:[1,99,2,3,4,5](length=6)

七、核心模块 4:顺序表删除元素

删除功能与插入类似,需要先记录被删元素,再移动后续元素覆盖被删位置。

7.1 删除原理
  1. 合法性检查:确保删除位置合法(1~length)、顺序表非空、指针非空、接收被删元素的指针非空;
  2. 记录被删元素:先把删除位置的元素值存入del_element(方便后续使用);
  3. 元素前移:从删除位置的下标开始,到最后一个元素的前一位,逐个向前移动 1 位;
  4. 更新长度:length减 1(元素个数减少)。
7.2 代码示例
/*** 顺序表删除元素* @param list:          顺序表对象* @param del_position: 删除元素的位置* @param del_element:   删除的元素* @return               delete success: 1, delete failed: -1;*/
int delete_sequence_list(SqList* list, int del_position, ElementType* del_element) {if(list == NULL) {return -1;}if(del_position < 1 || del_position > list -> length) {return -1;}if(del_element == NULL) {return -1;}// 将删除的位置元素值赋值给我们需要记录的变量*del_element = list -> data[del_position - 1];for(int i = del_position - 1; i < list -> length; i++) {list -> data[i] = list -> data[i + 1];}list -> length--;return 1;
}
7.3 关键注意点

为什么先记录被删元素?如果先移动元素,被删位置的元素会被后续元素覆盖,无法再获取被删值 —— 这是初学者常见的坑,必须先记录再移动!
删除效果:插入后顺序表:[1,99,2,3,4,5](length=6)
删除第 3 位后:[1,99,3,4,5](length=5),被删元素为 2。

八、核心模块 5:顺序表查询元素

查询功能即「顺序查找」—— 遍历顺序表,找到目标元素后返回其位置(1-based),未找到返回 - 1。

8.1 查询原理
  1. 合法性检查:确保顺序表非空、指针非空;
  2. 遍历顺序表:逐个对比元素值与目标值;
  3. 返回结果:找到则返回位置(下标 + 1),未找到返回 - 1
8.2 代码示例
/*** 根据元素查找对应的位置并返回* @param list:         顺序表对象* @param find_element: 需要查找的元素* @return:             find success: element position, find failed: -1;*/
int find_sequence_list_element(SqList list, ElementType find_element) {if(list.length == 0) {return -1;}for(int i = 0; i < list.length; i++) {if(list.data[i] == find_element) {return i + 1;  // 返回的是位置而非索引。}}return -1;
}

九、完整代码与运行结果

9.1 完整代码
// Created by LiuJinTao on 2025/9/17.   【代码主题】:001 - 顺序表(Sequence List)
#include<stdio.h>
#include<stdlib.h>#define MaxSize 50typedef int ElementType;
typedef struct SequenceList{ElementType data[MaxSize];int length;
} SqList;int insert_sequence_list(SqList* list, int add_position, ElementType add_element);
int delete_sequence_list(SqList* list, int del_position, ElementType* del_element);
int find_sequence_list_element(SqList list, ElementType find_element);
void loop_print(SqList arr);int main() {// 动态分配初始化 顺序表SqList* L = (SqList*)malloc(sizeof(SqList));if(L == NULL) {printf("memory allocation failed!\n");return -1;}ElementType temp_arr[] = {1 ,2, 3, 4, 5};int temp_len = sizeof(temp_arr) / sizeof(ElementType);for(int i = 0; i < temp_len; i++) {L -> data[i] = temp_arr[i];}L -> length = temp_len;ElementType add_element = 99;ElementType del_element;int add_position = 2;int del_position = 3;loop_print(*L);// 插入操作int insert_result = insert_sequence_list(L, add_position, add_element);if(insert_result == -1) {printf("sequence list insert element failed!\n");} else {printf("sequence list insert element(%d) - position(%d) success!\n", add_position, add_element);}// 删除操作int delete_result = delete_sequence_list(L, del_position, &del_element);if(delete_result == -1) {printf("delete sequence list failed!");loop_print(*L);} else {printf("delete sequence list success! element = %d\n", del_element);loop_print(*L);}loop_print(*L);// 查询元素int find_result = find_sequence_list_element(*L, add_element);if(find_result) {printf("find element success!:\n");printf("element position = %d\n", find_result);  // 2} else {printf("don't find element!\n");}free(L);return 0;
}/*** 顺序表插入元素* @param list:            顺序表对象* @param add_position:    添加的元素位置* @param add_element:     需要添加的元素* @return                 success: 1; failed: -1*/
int insert_sequence_list(SqList* list, int add_position, ElementType add_element) {if (list == NULL) {return -1;}if(! (add_position >= 1 && add_position <= list-> length + 1)) {return -1;}if(list -> length >= MaxSize) {return -1;}for(int i = list -> length; i >= add_position; i--) {list -> data[i] = list -> data[i- 1];}list -> data[add_position - 1] = add_element;list -> length++;return 1;
}/*** 顺序表删除元素* @param list:          顺序表对象* @param del_position: 删除元素的位置* @param del_element:   删除的元素* @return               delete success: 1, delete failed: -1;*/
int delete_sequence_list(SqList* list, int del_position, ElementType* del_element) {if(list == NULL) {return -1;}if(del_position < 1 || del_position > list -> length) {return -1;}if(del_element == NULL) {return -1;}// 将删除的位置元素值赋值给我们需要记录的变量*del_element = list -> data[del_position - 1];for(int i = del_position - 1; i < list -> length; i++) {list -> data[i] = list -> data[i + 1];}list -> length--;return 1;
}/*** 根据元素查找对应的位置并返回* @param list:         顺序表对象* @param find_element: 需要查找的元素* @return:             find success: element position, find failed: -1;*/
int find_sequence_list_element(SqList list, ElementType find_element) {if(list.length == 0) {return -1;}for(int i = 0; i < list.length; i++) {if(list.data[i] == find_element) {return i + 1;  // 返回的是位置而非索引。}}return -1;
}void loop_print(SqList arr) {printf("--------------------------------divide line-----------------------------------");for(int i = 0; i < arr.length; i++) {printf("[%d].\t %d\n", i + 1, arr.data[i]);}
}
9.2 运行结果
初始顺序表:

[1]. 1
[2]. 2
[3]. 3
[4]. 4
[5]. 5

插入后顺序表:

[1]. 1
[2]. 99
[3]. 2
[4]. 3
[5]. 4
[6]. 5

删除成功!被删元素:2

删除后顺序表:

[1]. 1
[2]. 99
[3]. 3
[4]. 4
[5]. 5
查询结果:元素99在位置2

十、总结与注意事项

  1. 动态内存必须释放:用malloc分配的内存,最后一定要用free释放,避免内存泄漏;
  2. 参数合法性校验不能少:空指针、位置越界、表满 / 表空等情况,都要加判断,提高代码健壮性;
  3. 1-based 与 0-based 转换:人类习惯用 1 开始的位置,数组下标从 0 开始,转换时注意位置-1;
  4. 插入 / 删除的元素移动方向:插入从后往前移,删除从前往后移,避免覆盖元素。

如果想进一步提升,可以尝试添加「修改元素」「清空顺序表」「动态扩容(突破 MaxSize 限制)」等功能,巩固对顺序表的理解!

Created by LiuJinTao

http://www.dtcms.com/a/391120.html

相关文章:

  • MethodSignature signature = (MethodSignature) joinPoint.getSignature()
  • CN2香港服务器是否适合SEO优化?
  • 查看电脑IP地址、修改IP操作,查询本地网络使用的公网IP,判断路由器是否有公网IP,内网IP又怎么让外网上访问
  • 合成孔径雷达干涉测量InSAR:从星载与地基系统原理到多领域应用实战,涵盖数据处理、地形三维重建、形变监测与案例解析
  • Activity 之间跳转时,生命周期的变化
  • SortableItem拖拽组件里的Popconfirm失效
  • [吾爱原创] 图片尺寸调整-支持批量、多格式、缩小、放大、保留元数据、无损质量、最小体积、预览
  • 【C语言】C 语言文件操作全解析:从基础到进阶
  • 《工作流落地篇:工作流中涉及到的主要数据库表》
  • 实验二理解 Java 语言的基本结构和程序设计方法
  • 【开题答辩全过程】以 基于Java的社区医疗预约系统的设计与实现为例,包含答辩的问题和答案
  • 以虚筑实,虚拟仿真技术浇筑水利工程人才培养的数字基座
  • 拟声 0.79.1 | 高颜值,拟态风格,B站歌曲,可下载,可搜索歌词
  • 团体程序设计天梯赛-练习集 L1-038 新世界
  • 【MySQL】约束类型
  • AXI4 DDR读写测试
  • 一个.h .hpp 笔记
  • MongoDB数据类型学习笔记
  • STM32实现USB的CDC+MSC+AUDIO的USB复合设备
  • x265静态编译win10--
  • STM32学习-Keli仿真
  • LeetCode hot 100 解题思路记录(一)
  • 01-搭建后端django项目
  • 深入探索卷积神经网络:从基础到高级架构(一)
  • 【大数据社科交叉方向会议】第六届大数据与社会科学国际学术会议(ICBDSS 2025)
  • 计算机网络 知识点梳理及讲解(二)物理层:编码调制、传输媒体、信道复用、宽带接入等
  • 学习嵌入式的第三十八天——ARM——概述
  • 初级会计【备考】
  • Windows系统忘记用户名密码怎么办
  • 市场部绩效考核关键指标与市场分析