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

数据结构之顺序表:一款优秀的顺序存储结构

在这里插入图片描述

🌈这里是say-fall分享,感兴趣欢迎三连与评论区留言
🔥专栏:《C语言从零开始到精通》、《C语言编程实战》、《数据结构与算法》
💪格言:做好你自己,你才能吸引更多人,并与他们共赢,这才是你最好的成长方式。


前言:

到目前为止C语言所有知识点我们已经学习完了,有一些不常用的知识点这里就不再继续拓展,从这篇博客开始,我们正式走入一个新的专栏:《数据结构与算法》,本篇我们就来了解一下:顺序表(本顺序表基于C语言)


文章目录

  • 前言:
  • 正文:
    • 1. 什么是顺序表?
    • 2. 顺序表分类
      • 2.1 静态顺序表
      • 2.2 动态顺序表
    • 3. 动态顺序表的实现
      • 3.1 头文件
      • 3.2 源文件(函数)
      • 3.3 源文件(测试)


正文:

1. 什么是顺序表?

在数据结构中,顺序表是一种线性表的存储结构,它通过连续的存储空间来存储元素,使得表中的元素在逻辑上的相邻关系在物理存储位置上也相邻。

  • 核心特点:
  1. 物理存储连续所有元素依次存放在一片连续的内存空间中,例如数组就是典型的顺序表实现。
  2. 元素按索引访问由于存储连续,可通过首地址 + 索引偏移量直接计算任意元素的地址,因此支持随机访问(时间复杂度为 O (1))。
  3. 容量固定或动态扩容
    静态顺序表:初始化时确定容量,后续不可更改(易溢出)。
    动态顺序表:容量可随元素数量增长自动扩容(如复制旧数据到新的更大空间)。

2. 顺序表分类

2.1 静态顺序表

定义:

#define num 100  //num是改变数组大小的,但只能使用前改变
struct StaticSeqList
{int arr[num];//这里是一个定长数组int size;//size用来记录已有的元素个数
};

总的来说静态顺序表其实和一般数组是很类似的

2.2 动态顺序表

定义:

struct seqlist
{sltype* arr;//这是一个指针,可以开辟空间int size;//记录已有元素个数int capacity;//用来记录开辟空间长度
};

与静态顺序表不同,动态顺序表实际上和柔性数组一样,可控制数组大小

3. 动态顺序表的实现

下面带大家写一下这个顺序表:
其中主要是包含函数源文件的写法

3.1 头文件

想要实现一个顺序表首先肯定得先定义他,这里我们在添加我们需要的头文件以后定义一个动态顺序表

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int sltype;//为数组元素类型进行重定义,方便以后修改
typedef struct seqlist
{sltype* arr;//这是一个指针,可以开辟空间int size;//记录已有元素个数int capacity;//用来记录开辟空间长度
}sl;//用sl这个名字对动态顺序表进行重定义

以下是我们需要进行的函数的声明,为了方便我们一般把他们放到头文件中


//检查空间
void SLcheckcapacity(sl* ps);
//顺序表的初始化
void SLinit(sl* ps);
//顺序表的销毁
void SLdestory(sl* ps);
//顺序表的尾插
void SLappend(sl* ps, sltype x);
//顺序表的打印
void printsl(sl* ps);
//顺序表的头插
void SLprepend(sl* ps, sltype x);

3.2 源文件(函数)

下面就是我们的函数定义了,这里以注释和插叙的方式给大家解释

#include"Seqlist.h"//将头文件放入源文件中
  • 初始化

这里是对动态顺序表的初始化,在主函数中我们首先创建一个类型为sl的叫sl1的动态顺序表,然后对它进行初始化

	//初始化试验sl sl1;SLinit(&sl1);
//顺序表初始化
void SLinit(sl* ps)
{ps->arr = NULL;ps->size = 0;ps->capacity = 0;
}

有没有人想过这里传参为什么传地址而不是传值?

  1. 实际上传值的话他会在函数内部创建一份形参(动态顺序表的拷贝)而无法实际修改真实的动态顺序表,而且创建这些形参时也会产生额外的内存占用
  2. 动态顺序表内部的成员实际上都是依靠指针来访问的,直接传地址来修改更合理
  • 销毁

这里我们先不对顺序表进行任何操作,我们先来试着销毁刚才已经初始化的顺序表

//顺序表的销毁
void SLdestory(sl* ps)
{assert(ps != NULL);//注意这里需要检查顺序表指针是否为空,使用assert宏来控制它free(ps->arr);//在使用中我们会申请动态内存这个时候就需要释放内存ps->arr = NULL;//释放内存以后将顺序表内的舒徐全部置空或者置零方式内存泄漏ps->size = ps->capacity = 0;
}
  • 插入操作_尾插
//顺序表的尾插
void SLappend(sl* ps ,sltype x)//这里定义时将地址传来,再将要插入的数据传入函数
{assert(ps != NULL);//插入之前,检查空间是否足够SLcheckcapacity(ps);//检查空间我们紧跟尾插讲解ps->arr[ps->size] = x;//确保没有问题以后将最后一个空间放上我们要插入的数据ps->size++;//不要忘记同步实际使用空间
}
  • 检查空间

检查空间大小时候我们考虑两种情况:①.还没有开辟空间;②已经开辟空间,但空间不够了需要扩容

//检查空间
void SLcheckcapacity(sl* ps)
{assert(ps != NULL);if (ps->capacity == ps->size)//实际使用的空间马上要超过总空间了,这个时候扩容{sltype newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//定义一个新的实际空间准备使用//这里用条件操作符如果为开辟空间就赋值为4,如果已有空间就翻倍sltype* tmp = realloc(ps->arr, newcapacity * sizeof(sltype));//防止是空指针,我们先将开辟的新地址给一个临时变量if (tmp == NULL)//判断是否为空指针{//如果是的话则报错perror("realloc fail");exit(1);}ps->arr = tmp;//检查完以后给原来的空间真正扩容ps->capacity = newcapacity;//不要忘记同步实际空间数}
}
  • 顺序表打印

//打印顺序表
void printsl(sl* ps)
{assert(ps != NULL);//每个函数使用前为防止传入空指针都要检查是否为空sltype i = 0;for (i = 0;i < ps->size ;i++){printf("%d ", ps->arr[i]);//用循环的方式将顺序表内容打印出来}printf("\n");//增加换行符保证结构清楚
}
  • 头插

//顺序表的头插
void SLprepend(sl* ps, sltype x)
{assert(ps != NULL);//先判断空间SLcheckcapacity(ps);//已有元素向后移动int i = 0;for (i = ps->size;i > 0 ; i--)//注意,为防止数据覆盖,这里是后面的元素先移动{ps->arr[i] = ps->arr[i-1];//最后一次移动是[0]的元素移动到[1]}ps->arr[0] = x;//将元素放入首个位置ps->size++;//size增加1
}
  • 头删

实际上头删和尾插是很类似的,都需要移动元素,保证顺序表的线性结构

//顺序表的头删
void delete_head(sl* ps) //删除只需要传入指针地址就好了
{assert(ps != NULL);assert(ps->size);//在保证数据表不为0时候才能删除int i = 1;for (i = 1;i <= ps->size ; i++)//注意这里i一开始需要是1,因为第一个位置是0//头删在移动数据的过程中不用担心数据覆盖所以可以直接移动{ps->arr[i - 1] = ps->arr[i];//最后只需要移动size次就好了}ps->size--;//删除以后size--
}
  • 尾删

//顺序表的尾删
void delete_tail(sl* ps)
{assert(ps);//这是一种上方的简便写法assert(ps->size);//在保证数据表不为0时候才能删除ps->size--;
}

3.3 源文件(测试)

#include"Seqlist.h"int main()
{//初始化试验sl sl1;SLinit(&sl1);//尾插试验SLappend(&sl1,5);printsl(&sl1);//头插试验SLprepend(&sl1, 4);printsl(&sl1);SLprepend(&sl1, 3);printsl(&sl1);SLprepend(&sl1, 2);printsl(&sl1);SLprepend(&sl1, 1);printsl(&sl1);//头删试验delete_head(&sl1);printsl(&sl1);//尾删试验delete_tail(&sl1);printsl(&sl1);//尾插试验SLappend(&sl1, 0);printsl(&sl1);//销毁试验SLdestory(&sl1);return 0;
}

下面是测试结果:

在这里插入图片描述

  • 以上就是顺序表的全部实现方法了
    完整代码放在gitee仓库,有需要请自行查看

  • 本节完…
http://www.dtcms.com/a/515983.html

相关文章:

  • 如何将联系人从iPhone转移到iQOO
  • 广州营销型网站成都网站建设app开发
  • 个体户做网站有用吗外链工厂
  • LVDS系列32:Xilinx 7系 ADC LVDS接口参考设计(三)
  • TPS62402DRCR双通道同步降压DC-DC转换器 TI德州仪器 降压转换器 芯片解析
  • 项目实践4—全球证件智能识别系统(Qt客户端开发+FastAPI后端人工智能服务开发)
  • 下载asp网站哪里有免费网站可以看
  • 公司网站怎么做才高大上wordpress好用的模板
  • <自用文 重装 Windows 11 后> ssh-agent 配置
  • web网页开发,在线%考试,教资,题库%系统demo,基于vue,html,css,python,flask,随机分配,多角色,前后端分离,mysql数据库
  • SQL入门:别名使用完全指南
  • 有什么做兼职的好的网站吗网站和服务器的关系
  • 湘潭建网站网站版式分类
  • 基于Flask的志愿者管理系统
  • .NET实现多任务异步与并行处理的详细步骤
  • stripe 支付对接
  • 项目引入DeepSeek对话【前端】
  • 前端解决弹性容器设置“flex: 1”但内部的表格设置“text-overflow: ellipsis”却无法正常显示省略号的问题
  • 科大讯飞星火科技文献大模型 Spark-Scilit-X1-13B 在 GitCode 开源,助力科研智能化革新!
  • 网站建设较好的公司wordpress自定义类型模板
  • 国外设计网站d开头的免费的国产cad
  • k8s pod优雅下线实践
  • KeyValuePair 与 Dictionary
  • javascript `designMode`
  • Claude Code - AWS Skills
  • 照明灯具-图形识别更方便
  • 成都网站建设询q479185700上快网站版面
  • 【Linux】Centos替代方案
  • 猿辅导MySQL面试常见问题解析(一)
  • 【开题答辩全过程】以 基于大数据抖音用户行为分析的可视化大屏为例,包含答辩的问题和答案