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

C语言顺序表:从零开始,解锁数据结构之门!

目录

引言

一、什么是顺序表?

二、静态顺序表

2.1、定义

2.2、代码实现

2.3、静态顺序表的缺点

三、动态顺序表

3.1、定义

3.2、代码实现

四、动态顺序表的操作

4.1、动态顺序表的初始化

4.2、尾插法

4.3、头插法

4.4、尾删法

4.5、头删法

4.6、删除指定位置的数据

4.7、指定位置之前插入数据

4.8、查找

4.9、销毁

结语


引言

“Hello, world!” 也许是你接触编程的第一句代码。但要成为一名合格的程序员,仅仅会写代码是不够的。深入理解数据结构,才能驾驭复杂的数据、设计高效的算法,构建出强大的软件。今天,我们将一起踏上数据结构的探索之旅,从最基础、也是最常用的数据结构——顺序表开始。它像一颗基石,构筑了许多高级数据结构的根基。准备好了吗?拿起你的C语言编译器,让我们一起揭开顺序表的神秘面纱!

一、什么是顺序表?

顺序表,是使用一段连续的存储空间存储数据元素的线性表。其不管在逻辑结构上还是物理结构上,数据的存储都是连续紧挨着的。

二、静态顺序表

2.1、定义

静态顺序表,顾名思义,它的大小是一定的,不可改变的。常见的静态顺序表就是数组,但是这不够严谨,因为我们只知道静态顺序表的大小,却不知道它的有效元素的个数,因此我们使用结构体来表示静态顺序表,动态顺表也是同样的。

2.2、代码实现

typedef int SLDataType;
#define N 7//静态顺序表
typedef struct SeqList
{SLDataType arr[N];  //顺序表主体int size;   //有效元素个数
}SL;

注意:

(1)对 int 重新命名为 SLDateType 是为了方便后续修改顺序表的元素类型,如果 int 要替换成 long ,只需要在第一行替换即可。同理,N也是如此。

(2)对结构体重新命名也是为了方便代码后续编写,当然,你也可以单独命名:

typedef SqeList SL;

这二者的重命名方式是等价的

2.3、静态顺序表的缺点

静态顺序表的大小是不可更改的,空间小了不够用,空间大了又浪费内存,具有非常大的局限性。而为了解决这个问题,我们可以使用动态顺序表。

三、动态顺序表

3.1、定义

动态顺序表本质和静态顺序表一样,都是一段连续的存储空间存储数据元素的线性表。不同的是,动态顺序表可以随时调整自己的大小来满足需求,比静态顺序表更加灵活

3.2、代码实现

typedef int SLDataType;typedef struct SeqLsit
{SLDataType* arr;   //顺序表主体,后面会开辟空间int size;    //顺序表的有效元素个数int capacity;  //顺序表的容量
}SL;

动态顺序表由于大小随时变化,因此,它比静态顺序表多了一个参数:容量。

四、动态顺序表的操作

4.1、动态顺序表的初始化

//初始化
void SLInitial( SL* ps)
{ps->arr = NULL;ps->size = 0;ps->capacity = 0;
}

注意:初始化的方式不唯一!

4.2、尾插法

//尾插法
void SLinend(SL* ps ,SLDataType x)
{assert(ps);if (ps->size == ps->capacity){int new_capacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//增容SLDataType* str = (SLDataType*)realloc(ps->arr,sizeof(SLDataType) * new_capacity);if (str == NULL){perror("realloc");exit(1);}ps->arr = str;ps->capacity = new_capacity;}ps->arr[ps->size++] = x;
}

首先要判断传入的 ps 是不是空指针?用assert来检查,该函数包含在 <assert.h> 中

在插入之前,需要判断该顺序表的容量是否足够?如果容量足够,则直接插入即可;如果用量不够,需要扩容。一般我们扩容选择扩容到当前容量的2倍或者3倍。扩容的代码形式有很多种,不一定非要跟笔者一致。

在插入完成后,记得要把容量和有效元素个数进行更新!

4.3、头插法

//头插法
void SLin_Head(SL*ps , SLDataType x)
{assert(ps);if (ps->size == ps->capacity){int new_capacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SLDataType* str = (SLDataType*)realloc(ps->arr, sizeof(SLDataType) * new_capacity);if (str == NULL){perror("realloc");exit(1);}ps->arr = str;ps->capacity = new_capacity;}for (int i = ps->size; i > 0; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[0] = x;ps->size++;
}

同样的,需要检查 ps 是否为空,然后再判断是否需要增容?可以把判断是否增容这部分代码写成一个函数,方便后续使用。

4.4、尾删法

//尾删法
void SLDete_end(SL* ps)
{assert(ps && ps->size);ps->size--;
}

除了需要判断 ps 是不是 NULL ,还需要判断 该线性表中有没有元素,没有元素还怎么删呢,对吧?

这里需要注意的是,不能使用 free,对最后一个元素进行 free 处理,这样做会语法报错!free 只能释放完整的空间!

4.5、头删法

//头删法
void SLDete_head(SL* ps)
{assert(ps && ps->size);for (int i = 0; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}

用后面的元素对前一个元素进行覆盖即可,最后不要忘了有效个数的更新

4.6、删除指定位置的数据

//删除指定位置的数据
void SLDete_specify(SL* ps, int pose)
{assert(ps && ps->size);assert(pose >= 0 && pose < ps->size);for (int i = pose; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}

指定位置后面的元素依次向前覆盖

4.7、指定位置之前插入数据

//指定位置之前插入数据
void SLin_specify_f(SL* ps, int pose, SLDataType x)
{assert(ps);assert(pose >= 0 && pose < ps->size);if (ps->size == ps->capacity){int new_capacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SLDataType* tmd = (SLDataType*)realloc(ps->arr, sizeof(SLDataType) * new_capacity);if (tmd == NULL){perror("realloc");exit(1);}ps->arr = tmd;ps->capacity = new_capacity;}for (int i = ps->size; i > pose; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pose] = x;ps->size++;
}

同样,涉及到添加数据,就需要判断是否需要增容

4.8、查找

//查找
int SLSeek(SL* ps, SLDataType x)
{assert(ps);for (int i = 0; i < ps->size; i++){if (ps->arr[i] == x){return i;}}return -1;
}

4.9、销毁

void SLdestory(SL* ps)
{assert(ps);if (ps->arr)free(ps->arr);ps->arr = NULL;ps->size = ps->capacity = 0;
}

这里释放完后记得将其归空,避免野指针,同时,size和capacity也要置0

结语

恭喜你!你已经掌握了C语言顺序表的核心知识。它虽然是基础,但却是通往数据结构世界的大门。通过实践和不断思考,你会发现顺序表远不止这些。希望这篇博客能激发你对数据结构的兴趣,继续探索更深层次的知识。记住,编程的乐趣在于不断学习和挑战。现在,就拿起你的编译器,把这些知识变成你自己的吧! 下次,我们将会一起探索链表,敬请期待!

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

相关文章:

  • YOLO系列pt导出不同onnx方法
  • Renren框架DistributeLock排他锁实现详解
  • 企业内网系统:从传统开发到智能赋能的进化之路
  • 安达发|医疗器械行业APS自动排单:智能化生产管理的未来之路
  • useRef跨渲染周期存储
  • 数据结构 --- 队列
  • 10.Docker安装mysql
  • chatgpt是怎么诞生的,详解GPT1到GPT4的演化之路及相关背景知识
  • dexie 前端数据库封装
  • 使用快捷键迅速校准多个通道 | IPEmotion
  • 软件技术:柯里化
  • 《PyQt6-3D应用开发技术文档》
  • 仿豆包智能输入框实现
  • python基础25_某大网校(下)处理json数据以及保存题库
  • 安全访问云端内部应用:用frp的stcp功能解决SSH转发的痛点
  • Linux驱动开发(platform 设备驱动)
  • 老题新解|矩阵转置
  • AI驱动的业务系统智能化转型:从非结构化到结构化的智能转换
  • 【STM32 学习笔记】FLASH闪存
  • pytorch学习-12循环神经网络(基础篇)
  • 机器视觉之激光码检测系统
  • 【世纪龙科技】学测-汽车信息化综合实训考核平台(机电方向)
  • 数字孪生系统如何助力汽车零部件企业实现虚拟智控
  • RedisJSON 内存占用剖析与调优
  • Lua嵌入式爬虫实现步骤
  • 【Linux系统】冯诺依曼体系结构 | 初识操作系统
  • 生产者、消费者问题(C语言、POSIX)
  • 测试覆盖标准-条件覆盖-短路求值
  • 全新开源AI知识库系统!PandaWiki一键构建智能文档,支持AI问答、创作与搜索!
  • [特殊字符] 05_Jenkins 部署前端项目实现自动化部署