顺序表实现代码解析与学习笔记

一、顺序表基础概念

顺序表是线性表的一种顺序存储结构,它使用一段连续的内存空间(数组)存储数据元素,通过下标直接访问元素,具有随机访问的特性。其核心特点是:元素在内存中连续存放,逻辑顺序与物理顺序一致。

二、代码结构说明

本次实现包含 3 个文件,分工如下:

  • arraylist.h:定义顺序表结构体及相关操作函数的声明

  • arraylist.c:实现顺序表的核心操作函数

  • main.c:测试顺序表的各项功能

三、核心结构体解析

arraylist.h中定义了顺序表的结构体:

typedef struct{​int capacity;    // 顺序表的容量(最大可存储元素数)​int last;        // 最后一个元素的下标(-1表示空表)​int \*data;       // 指向存储元素的数组(堆内存)​} ArrayList;

  • capacity:记录当前顺序表的最大容量(数组长度)

  • last:通过下标管理实际元素数量(元素个数 = last + 1)

  • data:动态数组指针,实际存储元素的内存空间

四、核心函数实现解析

1. 初始化函数 init_list

 ArrayList \*init\_list(int cap) {​if (cap <= 0) return NULL;  // 容量必须为正数​ArrayList \*list = malloc(sizeof(ArrayList));​if (list) {​list->data = calloc(cap, sizeof(int));  // 分配数组内存并初始化为0​if (list->data == NULL) {​free(list);  // 数组内存分配失败时,释放结构体​return NULL;​}​list->capacity = cap;​list->last = -1;  // 初始化为空表​return list;​}​return NULL;​}

  • 功能:创建并初始化顺序表,分配结构体和数组内存

  • 关键:参数校验(容量 > 0)、内存分配失败的容错处理

2. 插入函数 insert(头插法)

 bool insert(ArrayList \*list, int data) {​if (list == NULL) return false;​// 满表时扩容(2倍扩容)​if (is\_full(list) && !expand\_list(list)) return false;​// 元素后移(从最后一个元素开始)​for (int i = list->last; i >= 0; i--) {​list->data\[i+1] = list->data\[i];​}​// 插入新元素到表头(下标0)​list->data\[0] = data;​list->last++;  // 更新最后元素下标​return true;​}

  • 特点:采用头插法(新元素插入到表头位置)

  • 扩容逻辑:当表满时调用expand_list扩容为原容量的 2 倍

  • 时间复杂度:O (n)(需要移动所有现有元素)

3. 扩容函数 expand_list(静态辅助函数)

 static bool expand\_list(ArrayList \*list) {​if (list == NULL) return false;​int new\_cap = list->capacity \* 2;  // 2倍扩容策略​int \*new\_data = realloc(list->data, sizeof(int) \* new\_cap);​if (new\_data == NULL) return false;​list->data = new\_data;​list->capacity = new\_cap;​// 初始化新增内存(可选操作)​for (int i = list->last + 1; i < new\_cap; i++) {​list->data\[i] = 0;​}​return true;​}

  • 关键:使用realloc重新分配内存,避免内存泄漏

  • 扩容策略:简单采用 2 倍扩容(实际应用中可根据需求优化,如 1.5 倍扩容减少内存浪费)

4. 删除函数 remove_data

 bool remove\_data(ArrayList \*list, int data) {​if (!list || is\_empty(list)) return false;​// 查找第一个匹配元素的位置​int pos = -1;​for (int i = 0; i <= list->last; i++) {​if (list->data\[i] == data) {​pos = i;​break;​}​}​if (pos == -1) return false;  // 未找到元素​// 元素前移(覆盖被删除元素)​for (int i = pos; i < list->last; i++) {​list->data\[i] = list->data\[i+1];​}​list->last--;  // 更新最后元素下标​return true;​}

  • 功能:删除第一个匹配的元素

  • 步骤:查找位置 → 元素前移 → 更新下标

  • 时间复杂度:O (n)(最坏情况需要移动 n-1 个元素)

5. 销毁函数 destroy

 void destroy(ArrayList \*list) {​if (list == NULL) return;​if (list->data != NULL) {​free(list->data);  // 先释放数组内存​list->data = NULL;  // 避免悬挂指针​}​free(list);  // 再释放结构体内存​list = NULL;​}

  • 关键:先释放内部动态数组,再释放结构体,避免内存泄漏

  • 注意:置空指针(list->data = NULL)防止后续误操作

五、测试流程解析(main.c)

  1. 初始化顺序表:创建容量为 3 的顺序表

  2. 测试插入功能:插入 5 个数据(10、20、30、40、50)

  • 插入前 3 个数据时,容量为 3(未扩容)

  • 插入第 4 个数据时,表满触发扩容(容量变为 6)

  1. 遍历输出:打印当前顺序表的所有元素(头插法下,元素顺序为 50、40、30、20、10)

  2. 测试删除功能:依次删除 30、10、50、12(12 不存在)

  3. 销毁顺序表:释放所有分配的内存

六、学习笔记总结

  1. 顺序表优缺点

  • 优点:随机访问(通过下标直接访问,时间复杂度 O (1))

  • 缺点:插入 / 删除中间元素时需要移动大量元素(时间复杂度 O (n));容量固定(需手动扩容)

  1. 头插法特点

  • 新元素始终插入到表头,插入顺序与元素存储顺序相反(如插入 10→20→30,存储为 30、20、10)

  • 每次插入都需移动所有现有元素,适合元素数量少的场景

  1. 扩容策略思考

  • 2 倍扩容:减少扩容次数,但可能浪费内存

  • 1.5 倍扩容:平衡扩容次数和内存浪费,更适合实际应用

  • 扩容时使用realloc,可能触发内存拷贝(原有内存不足时)

  1. 内存管理要点

  • 动态内存分配后必须检查是否成功(NULL判断)

  • 释放内存时需先释放内部资源(如data数组),再释放外部结构体

  • 释放后指针置空,避免悬挂指针导致的野指针操作

通过以上代码实现,可以清晰理解顺序表的基本操作原理及内存管理细节,为学习更复杂的数据结构奠定基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/92345.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/92345.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/92345.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Oracle篇】Oracle Data Pump远程备份技术:直接从远端数据库备份至本地环境

&#x1f4ab;《博主主页》&#xff1a;    &#x1f50e; CSDN主页__奈斯DB    &#x1f50e; IF Club社区主页__奈斯、 &#x1f525;《擅长领域》&#xff1a;擅长阿里云AnalyticDB for MySQL(分布式数据仓库)、Oracle、MySQL、Linux、prometheus监控&#xff1b;并对…

Linux系统--文件系统

大家好&#xff0c;我们今天继续来学习Linux系统部分。上一次我们学习了内存级的文件&#xff0c;下面我们来学习磁盘级的文件。那么话不多说&#xff0c;我们开始今天的学习&#xff1a; 目录 Ext系列⽂件系统 1. 理解硬件 1-1 磁盘、服务器、机柜、机房 1-2 磁盘物理结构…

KUKA库卡焊接机器人氩气节气设备

在焊接生产过程中&#xff0c;氩气作为一种重要的保护气体被广泛应用于KUKA库卡焊接机器人的焊接操作中。氩气的消耗往往是企业生产成本的一个重要组成部分&#xff0c;因此实现库卡焊接机器人节气具有重要的经济和环保意义。WGFACS节气装置的出现为解决这一问题提供了有效的方…

远程连接----ubuntu ,rocky 等Linux系统,WindTerm_2.7.0

新一代开源免费的终端工具-WindTerm github 27.5k⭐ https://github.com/kingToolbox/WindTerm/releases/download/2.7.0/WindTerm_2.7.0_Windows_Portable_x86_64.zip 主机填写你自己要连接的主机ip 端口默认 22 改成你ssh文件配置的端口 输入远程的 用户名 与密码 成功连接…

笔试——Day32

文章目录第一题题目思路代码第二题题目&#xff1a;思路代码第三题题目&#xff1a;思路代码第一题 题目 素数回文 思路 模拟 构建新的数字&#xff0c;判断该数是否为素数 代码 第二题 题目&#xff1a; 活动安排 思路 区间问题的贪⼼&#xff1a;排序&#xff0c;然…

超高车辆如何影响城市立交隧道安全?预警系统如何应对?

超高车辆对立交隧道安全的潜在威胁在城市立交和隧道中&#xff0c;限高设施的设计通常考虑到大部分正常通行的货车和运输车辆。然而&#xff0c;一些超高的货车、集装箱车或特殊车辆如果未经有效监测而进入限高区域&#xff0c;就可能对道路设施造成极大的安全隐患。尤其在立交…

解决 MinIO 上传文件时报 S3 API Requests must be made to API port错误

在使用 MinIO 进行文件上传时&#xff0c;我遇到了一个比较坑的问题。错误日志如下&#xff1a; io.minio.errors.InvalidResponseException: Non-XML response from server. Response code: 400, Content-Type: text/xml; charsetutf-8, body: <?xml version"1.0&quo…

linux_https,udp,tcp协议(更新中)

目录 https 加密类型 对称加密 非对称加密 加密方案 只用对程加密 只用非对程加密 双方都是用非对程加密 非对称对称加密 非对称对称加密证书 流程图 校验流程图 udp udp协议格式 特点 UDP缓冲区 tcp tcp协议格式 32位序号及确认序号 4位首部 6位标志位 1…

web端-登录页面验证码的实现(springboot+vue前后端分离)超详细

目录 一、项目技术栈 二、实现效果图 ​三、实现路线 四、验证码的实现步骤 五、完整代码 1.前端 2.后端 一、项目技术栈 登录页面暂时涉及到的技术栈如下: 前端 Vue2 Element UI Axios&#xff0c;后端 Spring Boot 2 MyBatis MySQL JWT Maven 二、实现效果图…

疯狂星期四文案网第33天运营日记

网站运营第33天&#xff0c;点击观站&#xff1a; 疯狂星期四 crazy-thursday.com 全网最全的疯狂星期四文案网站 运营报告 今日访问量 今日搜索引擎收录情况 必应收录239个页面&#xff0c;还在持续增加中&#xff0c;已经获得必应的认可&#xff0c;逐渐收录所有页面 百度…

客户端利用MinIO对服务器数据进行同步

MinIO 是一款高性能、开源的对象存储服务&#xff0c;专为海量数据存储设计&#xff0c;兼容 Amazon S3 API&#xff08;即与 AWS S3 协议兼容&#xff09;&#xff0c;可用于构建私有云存储、企业级数据湖、备份归档系统等场景。它以轻量、灵活、高效为核心特点&#xff0c;广…

WPF 双击行为实现详解:DoubleClickBehavior 源码分析与实战指南

WPF 双击行为实现详解:DoubleClickBehavior 源码分析与实战指南 文章目录 WPF 双击行为实现详解:DoubleClickBehavior 源码分析与实战指南 引言 一、行为(Behavior)基础概念 1.1 什么是行为? 1.2 行为的优势 二、DoubleClickBehavior 源码分析 2.1 类定义与依赖属性 2.2 双…

零知开源——基于STM32F103RBT6的TDS水质监测仪数据校准和ST7789显示实战教程

✔零知开源是一个真正属于国人自己的开源软硬件平台&#xff0c;在开发效率上超越了Arduino平台并且更加容易上手&#xff0c;大大降低了开发难度。零知开源在软件方面提供了完整的学习教程和丰富示例代码&#xff0c;让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品&…

luogu P3387 【模板】缩点

原题链接 原题再现 题目描述 给定一个 n 个点 m 条边有向图&#xff0c;每个点有一个权值&#xff0c;求一条路径&#xff0c;使路径经过的点权值之和最大。你只需要求出这个权值和。 允许多次经过一条边或者一个点&#xff0c;但是&#xff0c;重复经过的点&#xff0c;权…

P1119 灾后重建【题解】

P1119 灾后重建 题目背景 B 地区在地震过后&#xff0c;所有村庄都造成了一定的损毁&#xff0c;而这场地震却没对公路造成什么影响。但是在村庄重建好之前&#xff0c;所有与未重建完成的村庄的公路均无法通车。换句话说&#xff0c;只有连接着两个重建完成的村庄的公路才能通…

Horse3D引擎研发笔记(二):基于QtOpenGL使用仿Three.js的BufferAttribute结构重构三角形绘制

在Horse3D引擎的研发过程中&#xff0c;我们致力于构建一个高效、灵活且易于扩展的3D图形引擎。在本篇博客中&#xff0c;我们将详细记录如何基于QtOpenGL框架&#xff0c;使用仿Three.js的BufferAttribute结构&#xff0c;重构三角形绘制流程。通过这一过程&#xff0c;我们希…

MCU程序段的分类

程序的下载&#xff08;烧录到存储器中&#xff09;通常是按照程序文件分段&#xff08;Code段、RO_data段、RW_data段、ZI_data段&#xff09;的方式存储的&#xff0c;但运行时内存的布局会按照程序进程分段&#xff08;TEXT段、DATA段、BSS段、堆栈段&#xff09;进行组织。…

综合项目记录:自动化备份全网服务器数据平台

一、项目背景与需求1.1项目概述该项目共分为2个子项目&#xff0c;由环境搭建和实施备份两部分组成1.2项目总体需求企业内部有一台web服务器&#xff0c;内部数据很重要&#xff0c;现需要为该web服务器数据做备份&#xff0c;这样在数据丢失时可以恢复。要求如下&#xff1a;每…

联合索引全解析:一棵树,撑起查询的半边天

目录 一、为什么联合索引是MySQL性能优化的“王牌”&#xff1f; &#xff08;一&#xff09;索引的基本结构&#xff1a;从聚簇到非聚簇 1. 聚簇索引&#xff08;Clustered Index&#xff09; 2. 非聚簇索引&#xff08;Secondary Index&#xff09; &#xff08;二&…

vue开发的计算机课程页面

课程信息展示页面设计与实现我将设计一个美观且实用的课程信息展示页面&#xff0c;重点展示计算机网络应用课程的相关信息。设计思路使用卡片式布局清晰展示课程各模块信息采用科技感配色方案&#xff0c;符合计算机网络课程主题添加动画效果增强用户体验响应式设计确保在各种…