【数据结构】顺序表(c语言实现)(附源码)

🌟🌟作者主页:ephemerals__

🌟🌟所属专栏:数据结构

目录

前言

1.顺序表的概念与结构

2.顺序表的分类

3.顺序表的实现

3.1 结构定义及方法的声明

3.2 方法的实现

3.2.1 初始化

3.2.2 销毁

3.2.3 打印顺序表

3.2.4 检查空间大小,不够则增容

3.2.5 尾插

3.2.6 头插

3.2.7 尾删

3.2.8 头删

3.2.9 指定位置之前插入

3.2.10 指定位置删除 

3.2.11 查找

4.程序全部代码

总结


前言

        在我们学习顺序表之前,先引入一个概念:线性表。那么线性表是什么呢?

线性表,是n个具有相同特性的数据元素的有限序列。线性表在数据结构当中广泛使用。常见的线性表有:顺序表、链表、栈、队列、字符串......线性表在逻辑上是线性结构,也就是说数据元素就像一条线一样串联在一起,但是它的每一个数据元素的地址并不一定是连续的

了解到顺序表是线性表的一种,接下来我们进入正题,开始正式学习顺序表。

1.顺序表的概念与结构

顺序表的概念:顺序表是一段按照连续的内存地址将数据元素依次存储的数据结构。一般情况下,它的底层逻辑是数组。也就是说,顺序表的每个元素的内存地址是连续的

顺序表和数组的区别:虽然顺序表的底层结构是数组,但是我们在实现顺序表的过程中,对数组进行了封装,在数组的基础上增加了对它的一些方法,例如增删查改等操作

2.顺序表的分类

        顺序表可以分为静态顺序表动态顺序表。顾名思义,静态顺序表的大小是固定不变的。它的结构定义如下:

#define N 10typedef int SLDataType;//静态顺序表
typedef struct SeqList
{SLDataType arr[N];//固定大小的数组int size;//有效数据的个数
}SL;

显然,这种结构是有缺陷的。当我们需要存放的数据很多时,它的内存大小是不够的。当存放的数据过少时,又会造成空间的浪费。所以,就有了动态顺序表。动态顺序表的内存大小可以根据数据的数量发生改变。它的结构定义如下:

typedef int SLDataType;//动态顺序表
typedef struct SeqList
{SLDataType* arr;//定义起始指针,后续动态开辟内存空间int size;//有效数据的个数int capacity;//数组的空间大小
}SL;

由于动态顺序表强大的灵活性和实用性,我们平时所谈到的顺序表一般都指的是动态顺序表。接下来我们在以上结构的基础上,一一实现动态顺序表的基本功能

3.顺序表的实现

3.1 结构定义及方法的声明

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int SLDataType;//动态顺序表
typedef struct SeqList
{SLDataType* arr;//定义起始指针,后续动态开辟内存空间int size;//有效数据的个数int capacity;//数组的空间大小
}SL;//初始化
void SLInit(SL* ps);//销毁
void SLDestroy(SL* ps);//打印顺序表
void SLPrint(SL* ps);//检查空间大小,不够则增容
void SLCheckCapacity(SL* ps);//尾插
void SLPushBack(SL* ps, SLDataType n);//头插
void SLPushFront(SL* ps, SLDataType n);//尾删
void SLPopBack(SL* ps);//头删
void SLPopFront(SL* ps);//指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType n);//指定位置删除数据
void SLErase(SL* ps, int pos);//查找
void SLFind(SL* ps, SLDataType n);

以上就是关于顺序表的定义和一些方法的的声明。接下来,我们尝试一一实现这些方法。

3.2 方法的实现

3.2.1 初始化

        初始化时,我们将结构体赋一个初值就可以。代码如下:

//初始化
void SLInit(SL* ps)
{assert(ps);//断言一下,确保传入的不是空指针ps->arr = NULL;ps->capacity = ps->size = 0;
}

初始情况下,arr是一个空指针,结构的空间大小和数据个数都为0。

3.2.2 销毁

        销毁顺序表时,我们将arr的内存释放掉,然后将空间大小和数据个数调整尾0就好了。代码如下:

//销毁
void SLDestroy(SL* ps)
{assert(ps);//防止传空指针if (ps->arr != NULL)//防止多次释放{free(ps->arr);ps->arr = NULL;}ps->capacity = ps->size = 0;
}

3.2.3 打印顺序表

//打印顺序表
void SLPrint(SL* ps)
{assert(ps);//防止传空指针for (int i = 0; i < ps->size; i++)//遍历打印{printf("%d ", ps->arr[i]);}printf("\n");
}

3.2.4 检查空间大小,不够则增容

        在我们插入数据的时候,数据的总数有可能会超出顺序表的空间大小,此时我们就需要检查空间大小,如果不够就需要增容。我们将增容封装为一个函数来实现:

//检查空间大小,不够则增容
void SLCheckCapacity(SL* ps)
{assert(ps);if (ps->capacity == ps->size)//空间大小与数据个数相等则说明空间已满{int NewCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//设定一个新空间大小,第一次增容时大小为4,之后每次以2倍的形式增容SLDataType* tmp = (SLDataType*)realloc(ps->arr, NewCapacity * sizeof(SLDataType));//防止内存丢失,创建局部变量暂时接收起始地址if (tmp == NULL)//内存开辟失败退出程序{perror("realloc");exit(1);}ps->arr = tmp;//将调整好的内存赋值给arrps->capacity = NewCapacity;}
}

3.2.5 尾插

//尾插
void SLPushBack(SL* ps, SLDataType n)
{assert(ps);SLCheckCapacity(ps);//检查空间大小ps->arr[ps->size++] = n;//在下标为size的位置插入元素,然后size自增
}

3.2.6 头插

        在头插的过程中,我们需要先将所有的数据全部后移一位,然后在第一个位置插入数据。

代码如下:

//头插
void SLPushFront(SL* ps, SLDataType n)
{assert(ps);SLCheckCapacity(ps);//检查空间大小for (int i = ps->size; i > 0; i--){ps->arr[i] = ps->arr[i - 1];//所有元素后移一位}ps->arr[0] = n;//第一个位置插入数据ps->size++;//元素个数加1
}

3.2.7 尾删

//尾删
void SLPopBack(SL* ps)
{assert(ps);assert(ps->size);//若数据为空,则不能删除ps->size--;//size自减,则最后一个元素无法被访问到,相当于删除了最后一个元素
}

这里只需要将size自减,使得最后一个元素无法被访问,相当于完成了删除操作。

3.2.8 头删

        头删时,我们将第一个元素之后的所有元素向前移动一位即可。代码如下:

//头删
void SLPopFront(SL* ps)
{assert(ps && ps->size);//合并两个断言语句for (int i = 0; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];//整体向前移动一位,覆盖第一个元素}ps->size--;//元素个数减1
}

3.2.9 指定位置之前插入

        在我们实现指定位置插入时,需要将该位置及之后的所有元素整体向后移动一位,然后再插入元素即可。代码如下:

//指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType n)//这里的参数pos是下标
{assert(ps && pos >= 0 && pos <= ps->size);//确保pos在合理范围内SLCheckCapacity(ps);for (int i = ps->size; i > pos; i--){ps->arr[i] = ps->arr[i - 1];//将pos位置后的元素整体向后移动一位}ps->arr[pos] = n;//插入ps->size++;//元素个数加1
}

3.2.10 指定位置删除

        指定位置删除时,将该位置之后的元素整体向前移动一位,覆盖该元素即可。代码如下:

//指定位置删除数据
void SLErase(SL* ps, int pos)
{assert(ps && ps->size && pos >= 0 && pos < ps->size);//确保pos在合理范围内for (int i = pos; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];//pos之后的元素整体向前移动一位,覆盖pos位置元素}ps->size--;//元素个数减1
}

3.2.11 查找

        查找元素时,我们只需要遍历顺序表,找到符合的元素即可。

//查找
void SLFind(SL* ps, SLDataType n)
{assert(ps);for (int i = 0; i < ps->size; i++)//遍历顺序表{if (ps->arr[i] == n){return i;//匹配成功则返回对应下标}}return -1;//找不到返回-1
}

4.程序全部代码

        程序全部代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int SLDataType;//动态顺序表
typedef struct SeqList
{SLDataType* arr;//定义起始指针,后续动态开辟内存空间int size;//有效数据的个数int capacity;//数组的空间大小
}SL;//初始化
void SLInit(SL* ps);//销毁
void SLDestroy(SL* ps);//打印顺序表
void SLPrint(SL* ps);//检查空间大小,不够则增容
void SLCheckCapacity(SL* ps);//尾插
void SLPushBack(SL* ps, SLDataType n);//头插
void SLPushFront(SL* ps, SLDataType n);//尾删
void SLPopBack(SL* ps);//头删
void SLPopFront(SL* ps);//指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType n);//指定位置删除数据
void SLErase(SL* ps, int pos);//查找
void SLFind(SL* ps, SLDataType n);//初始化
void SLInit(SL* ps)
{assert(ps);//断言一下,确保传入的不是空指针ps->arr = NULL;ps->capacity = ps->size = 0;
}//销毁
void SLDestroy(SL* ps)
{assert(ps);//防止传空指针if (ps->arr != NULL)//防止多次释放{free(ps->arr);ps->arr = NULL;}ps->capacity = ps->size = 0;
}//打印顺序表
void SLPrint(SL* ps)
{assert(ps);for (int i = 0; i < ps->size; i++){printf("%d ", ps->arr[i]);}printf("\n");
}//检查空间大小,不够则增容
void SLCheckCapacity(SL* ps)
{assert(ps);if (ps->capacity == ps->size)//空间大小与数据个数相等则说明空间已满{int NewCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//设定一个新空间大小,第一次增容时大小为4,之后每次以2倍的形式增容SLDataType* tmp = (SLDataType*)realloc(ps->arr, NewCapacity * sizeof(SLDataType));//防止内存丢失,创建局部变量暂时接收起始地址if (tmp == NULL)//内存开辟失败退出程序{perror("realloc");exit(1);}ps->arr = tmp;//将调整好的内存赋值给arrps->capacity = NewCapacity;}
}//尾插
void SLPushBack(SL* ps, SLDataType n)
{assert(ps);SLCheckCapacity(ps);//检查空间大小ps->arr[ps->size++] = n;//在下标为size的位置插入元素,然后size自增
}//头插
void SLPushFront(SL* ps, SLDataType n)
{assert(ps);SLCheckCapacity(ps);//检查空间大小for (int i = ps->size; i > 0; i--){ps->arr[i] = ps->arr[i - 1];//所有元素后移一位}ps->arr[0] = n;//第一个位置插入数据ps->size++;//元素个数加1
}//尾删
void SLPopBack(SL* ps)
{assert(ps);assert(ps->size);//若数据为空,则不能删除ps->size--;//size自减,则最后一个元素无法被访问到,相当于删除了最后一个元素
}//头删
void SLPopFront(SL* ps)
{assert(ps && ps->size);//合并两个断言语句for (int i = 0; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];//整体向前移动一位,覆盖第一个元素}ps->size--;//元素个数减1
}//指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType n)//这里的参数pos是下标
{assert(ps && pos >= 0 && pos <= ps->size);//确保pos在合理范围内SLCheckCapacity(ps);for (int i = ps->size; i > pos; i--){ps->arr[i] = ps->arr[i - 1];//将pos位置后的元素整体向后移动一位}ps->arr[pos] = n;//插入ps->size++;//元素个数加1
}//指定位置删除数据
void SLErase(SL* ps, int pos)
{assert(ps && ps->size && pos >= 0 && pos < ps->size);//确保pos在合理范围内for (int i = pos; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];//pos之后的元素整体向前移动一位,覆盖pos位置元素}ps->size--;//元素个数减1
}//查找
void SLFind(SL* ps, SLDataType n)
{assert(ps);for (int i = 0; i < ps->size; i++)//遍历顺序表{if (ps->arr[i] == n){return i;//匹配成功则返回对应下标}}return -1;//找不到返回-1
}

总结

        以上就是我们顺序表的概念及功能实现。不难发现,它的许多方法都需要遍历数组,时间复杂度为O(N),运行效率不是很高。之后博主将会介绍链表的相关知识和功能,他会弥补顺序表的一些不足。如果你觉得博主讲的还不错,就请留下一个小小的赞在走哦,感谢大家的支持❤❤❤

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

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

相关文章

Nvidia GPU驱动安装报错显卡与驱动不兼容(本身兼容)

最近在公司服务器上遇到了一个特别离谱的问题&#xff0c;就是在本身在nividia官网上面下载的匹配的显卡驱动&#xff0c;安装之后采用下面命令查看驱动显示&#xff1a; $ nvidia-smiNVIDIA-SMI has failed because it couldnt communicate with the NVIDIA driver. Make su…

web服务器搭建练习

练习要求&#xff1a; 搭建一个web服务器&#xff0c;客户端通过www.haha.com访问该网站时能够看到内容:this is haha 完成过程&#xff1a; 1. 创建新ip&#xff0c;重启ens [rootlocalhost ~]# nmtui [rootlocalhost ~]# nmcli connection up ens1602.创建目录&#xff0…

Java面试八股之Spring boot的自动配置原理

Spring boot的自动配置原理 Spring Boot 的自动配置原理是其最吸引人的特性之一&#xff0c;它大大简化了基于 Spring 框架的应用程序开发。以下是 Spring Boot 自动配置的基本原理和工作流程&#xff1a; 1. 启动类上的注解 Spring Boot 应用通常会在主类上使用 SpringBoot…

微信支付v3

查看证书序列号 引用&#xff1a;https://wechatpay-api.gitbook.io/wechatpay-api-v3/chang-jian-wen-ti/zheng-shu-xiang-guan https://myssl.com/cert_decode.html # 查看证书序列号openssl x509 -in apiclient_cert.pem -noout -serial 微信支付java <dependency>…

sql-libs通关详解

1-4关 1.第一关 我们输入?id1 看回显&#xff0c;通过回显来判断是否存在注入&#xff0c;以及用什么方式进行注入&#xff0c;直接上图 可以根据结果指定是字符型且存在sql注入漏洞。因为该页面存在回显&#xff0c;所以我们可以使用联合查询。联合查询原理简单说一下&…

中间层 k8s(Kubernetes) 到底是什么,架构是怎么样的?

你是一个程序员&#xff0c;你用代码写了一个博客应用服务&#xff0c;并将它部署在了云平台上。 但应用服务太过受欢迎&#xff0c;访问量太大&#xff0c;经常会挂。 所以你用了一些工具自动重启挂掉的应用服务&#xff0c;并且将应用服务部署在了好几个服务器上&#xff0c;…

自动驾驶-机器人-slam-定位面经和面试知识系列06之C++STL面试题(02)

这个博客系列会分为C STL-面经、常考公式推导和SLAM面经面试题等三个系列进行更新&#xff0c;基本涵盖了自己秋招历程被问过的面试内容&#xff08;除了实习和学校项目相关的具体细节&#xff09;。在知乎和牛客&#xff08;某些文章上会附上内推码&#xff09;也会同步更新&a…

达梦数据库激活

SSH登录 192.168.0.148 账号&#xff1a;root 密码&#xff1a;xxx 1.上传 dm.key 文件到安装目录 /bin 目录下 cd /home/dmdba/dmdbms/bin rz -E dm.key2.修改 dm.key 文件权限 chown -R dmdba.dinstall dm.key3.打开数据库工具&#xff0c;新建查询&#xff0c;输入 cd /…

Macbook - MacOS14连接WIFI但无法打开部门网页或应用

现象&#xff1a; 遇到MacBook部分网页可以打开&#xff0c;部分网页不行。包括应用也是同个现象&#xff0c;重启路由器连接手机热点也无法解决。 解决方案&#xff1a; 系统设置/网络/位置&#xff0c;默认是【自动】&#xff0c;添加并选择新的位置即可解决。&#xff08;具…

实验2-1-5 输出带框文字

#include<stdio.h> int main(){printf("************\n");printf(" Welcome \n");printf("************\n");}

2024年【危险化学品生产单位安全生产管理人员】最新解析及危险化学品生产单位安全生产管理人员考试总结

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 危险化学品生产单位安全生产管理人员最新解析参考答案及危险化学品生产单位安全生产管理人员考试试题解析是安全生产模拟考试一点通题库老师及危险化学品生产单位安全生产管理人员操作证已考过的学员汇总&#xff0c;…

基于JSP的毕业生就业信息管理系统

你好&#xff0c;我是专注于信息系统开发的码农小野&#xff01;如果你对毕业生就业信息管理有需求&#xff0c;欢迎联系我。 开发语言&#xff1a;JSP 数据库&#xff1a;MySQL 技术&#xff1a;JSP技术 SSM框架 工具&#xff1a;Eclipse、Maven、Navicat 系统展示 首页…

nhdeep电子档案长期保存系统

nhdeep电子档案长期保存系统&#xff0c;用于导入管理系统中的著录项信息&#xff0c;并安装档案相关规范&#xff0c;转换为适合长期保存的电子文件格式和封装包结构&#xff0c;进行管理和存储。 著录信息列表页面&#xff0c;用于导入著录项&#xff0c;挂接原文文件&#…

【漏洞复现】CmsEasy crossall_act.php SQL注入漏洞

漏洞描述 CmsEasy存在SQL注入漏洞,通过文件service.php加密SQL语句执行即可执行任何SQL命令 免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得利用网络从事危害国家安全、荣誉和利益,未经授权请勿利用文章中的技术资…

protobuf2.5升级protobuf3.14.0

这个升级搞得心力憔悴&#xff0c;我VS2010升级到了VS2017&#xff0c;所有的库都要编译一下&#xff0c;想着顺便把其他的三方库也升级了。搞了好几天&#xff0c;才升级完&#xff0c;因为不仅要搞windows还要搞linux版本各种库的升级。hpsocket的升级&#xff0c;jsoncpp的升…

LLM 大语言模型显存消耗估计与计算

LLM 大语言模型显存消耗估计与计算 1. LLM 大语言模型开发流程 在大模型&#xff08;如 LLaMA-7B、GPT-3 等&#xff09;的开发、训练、微调、推理和部署过程中&#xff0c;各个阶段的流程都涉及多个复杂的步骤。以下是详细的流程描述&#xff0c;涵盖训练和微调的区别&#…

机器学习 第7章-贝叶斯分类器

机器学习 第7章-贝叶斯分类器 7.1 贝叶斯决策论 贝叶斯决策论(Bayesian decision theory)是概率框架下实施决策的基本方法。对分类任务来说&#xff0c;在所有相关概率都已知的理想情形下&#xff0c;贝叶斯决策论考虑如何基于这些概率和误判损失来选择最优的类别标记。下面我…

Transformer,注意力机制。

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

流媒体服务器二:RTMP协议详解 以及 RTMP学习到什么程度算是合格?

一个问题&#xff1f; 在上一节我们使用SRS搭建了RTMP环境&#xff0c;那么在企业开发中&#xff0c;是否使用第三方的RTMP服务器&#xff08;例如上一节的SRS&#xff09;就可以了呢&#xff1f;或者说&#xff1a;作为一个音视频开发人员&#xff0c;就会配置就OK了呢&#…