耕耘 :C、C++、嵌入式技术领域
🔥我的个人主页
❄️个人专栏:《C语言专栏》 《嵌入式专栏》 《数据结构专栏》
✨**不要等待机会,而要创造机会!**✨
📽博主简介:
✨✨一位热爱生活的阳光大男孩.✨✨
前言
本文系统讲解C语言中顺序表的实现,涵盖线性表概念、静态与动态顺序表的区别,重点展示动态顺序表的结构设计与核心操作:初始化、尾插/头插、尾删/头删、任意位置插入与删除、查找等。通过SeqList.h、SeqList.c和测试文件test.c完整演示了增删改查功能,强调内存管理、边界判断与错误处理,为数据结构学习提供清晰实践范例。
文章目录
- 前言
- 1. 线性表
- 2. 顺序表
- 2.1 概念与结构
- 2.2 分类
- 2.2.1 静态顺序表
- 2.2.2 动态顺序表
- 2.3 动态顺序表的实现
- 2.3.1顺序表代码下载链接
- 2.4 顺序表算法题
- 2.4.1 移除元素
- 2.5 顺序表问题与思考
- 结语
1. 线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是⼀种在实际中⼴泛使 ⽤的数据结构,常⻅的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就说是连续的⼀条直线。但是在物理结构上并不⼀定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储。
2. 顺序表
2.1 概念与结构
概念:顺序表是⽤⼀段物理地址连续的存储单元依次存储数据元素的线性结构,⼀般情况下采⽤数组存储。
那顺序表和数组的区别?
顺序表的底层结构是数组,对数组进行封装,实现了常⽤的增删改查等接⼝,这就是顺序表。
2.2 分类
2.2.1 静态顺序表
概念:使⽤定⻓数组存储元素(缺陷:空间是定值,空间给少了不够⽤,给多了造成空间浪费)
//静态顺序表typedefintSLDataType;//方便后面修改数组类型#defineN7;typedefstructSeqList{SLDataType*a[N];//定常数组intsize;// 有效数据个数}SL;2.2.2 动态顺序表
// 动态顺序表 -- 按需申请typedefintSLDataType;//方便后面修改数组类型typedefstructSeqList{SLDataType*a;//可增容intsize;// 有效数据个数intcapacity;//空间容量}SL;2.3 动态顺序表的实现
定义一个头文件’‘SeqList.h’’
#include<stdio.h>#include<stdlib.h>#include<assert.h>#include<string.h>//定义动态顺序表的结构typedefintSLDatatype;//定义数组类型,方便后期修改typedefstructSeqList{SLDatatype*arr;intsize;//有效数据的个数intcapacity;//空间容量}SL;//顺序表初始化voidSLIint(SL*ps);//扩容voidSLCheckCapacity(SL*ps);//打印顺序表voidSLPrint(SL*ps);//尾插voidSLPushBsck(SL*ps,SLDatatype x);//x为数组类型,方便修改//头插voidSLPushFront(SL*ps,SLDatatype x);//尾删voidSLPopBack(SL*ps);//头删voidSLPopFront(SL*ps);//指定位置插?voidSLInsert(SL*ps,intpos,SLDatatype x);//指定位置删除voidSLErase(SL*ps,intpos);//查找元素voidSLFind(SL*ps,SLDatatype x);在定义一个函数文件SeqList.c
#include"SeqList.h"//初始化voidSLIint(SL*ps){ps->arr=NULL;ps->size=ps->capacity=0;}//扩容voidSLCheckCapacity(SL*ps){//判断空间是否足够if(ps->size==ps->capacity){intnewCapacity=ps->capacity==0?4:2*ps->capacity;//增容一般是成倍数扩容(一般是2倍,可控)//realloc第二个参数,单位是字节SLDatatype*tmp=(SLDatatype*)realloc(ps->arr,newCapacity*sizeof(SLDatatype));if(tmp==NULL){perror("realloc fail!");exit(1);}ps->arr=tmp;//扩容后的新数组ps->capacity=newCapacity;//扩容后的大小}}//打印顺序表voidSLPrint(SL*ps){for(inti=0;i<ps->size;i++){printf("%d ",ps->arr[i]);}printf("\n");}//尾插voidSLPushBsck(SL*ps,SLDatatype x){//判断空间是否足够SLCheckCapacity(ps);//开始插入ps->arr[ps->size++]=x;}//头插voidSLPushFront(SL*ps,SLDatatype x){assert(ps!=NULL);//防止传空指针//判断空间是否足够SLCheckCapacity(ps);//开始插入//将顺序表中所有数据向后移动一位for(inti=ps->size;i>0;i--){ps->arr[i]=ps->arr[i-1];//先移动后面的数据}ps->arr[0]=x;//把数据放在第一位++ps->size;}//尾删voidSLPopBack(SL*ps){assert(ps&&ps->size);--ps->size;}//头删voidSLPopFront(SL*ps){assert(ps&&ps->size);for(inti=0;i<ps->size-1;i++){ps->arr[i]=ps->arr[i+1];}--ps->size;}//任意位置插入voidSLInsert(SL*ps,intpos,SLDatatype x){assert(ps);assert(pos>=0&&pos<=ps->size);SLCheckCapacity(ps);//判断空间是否足够//pos后面的数据整体向后移动一位for(inti=ps->size;i>pos;i--){ps->arr[i]=ps->arr[i-1];}ps->arr[pos]=x;//插入数据++ps->size;}//指定位置删除voidSLErase(SL*ps,intpos){assert(ps);assert(pos>=0&&pos<=ps->size);//pos之后整体向前移动一位for(inti=pos;i<ps->size-1;i++){ps->arr[i]=ps->arr[i+1];}--ps->size;}//查找元素voidSLFind(SL*ps,SLDatatype x){intn=1;for(inti=0;i<ps->size;i++){if(ps->arr[i]==x){n=0;printf("找到了%d\n",ps->arr[i]);}}if(n==1){printf("没有找到%d\n",x);}}在定义一个测试文件test.c
#include"SeqList.h"//初始化应用voidtest01(){SL sl;//建一个空表SLIint(&sl);//初始化}//尾插应用voidtest02(){SL sl;//建一个空表SLIint(&sl);//初始化SLPushBsck(&sl,1);//插入数据SLPushBsck(&sl,2);SLPushBsck(&sl,3);SLPushBsck(&sl,4);SLPrint(&sl);//打印}//头插应用voidtest03(){SL sl;//建一个空表SLIint(&sl);//初始化SLPushFront(&sl,1);//插入数据SLPushFront(&sl,2);SLPushFront(&sl,3);SLPushFront(&sl,4);SLPrint(&sl);//打印}//尾删应用voidtest04(){SL sl;//建一个空表SLIint(&sl);//初始化SLPushBsck(&sl,1);//插入数据SLPushBsck(&sl,2);SLPushBsck(&sl,3);SLPushBsck(&sl,4);SLPrint(&sl);//打印SLPopBack(&sl);//尾删一次SLPrint(&sl);//打印SLPopBack(&sl);//尾删两次SLPrint(&sl);//打印SLPopBack(&sl);//尾删三次SLPrint(&sl);//打印}//头删应用voidtest05(){SL sl;//建一个空表SLIint(&sl);//初始化SLPushBsck(&sl,1);//插入数据SLPushBsck(&sl,2);SLPushBsck(&sl,3);SLPushBsck(&sl,4);SLPrint(&sl);//打印SLPopFront(&sl);//尾删一次SLPrint(&sl);//打印SLPopFront(&sl);//尾删两次SLPrint(&sl);//打印SLPopFront(&sl);//尾删三次SLPrint(&sl);//打印}//任意插入的应用voidtest06(){SL sl;//建一个空表SLIint(&sl);//初始化SLPushBsck(&sl,1);//插入数据SLPushBsck(&sl,2);SLPushBsck(&sl,3);SLPushBsck(&sl,4);SLPrint(&sl);//打印//任意插入SLInsert(&sl,1,100);//在第二位插入数据100SLPrint(&sl);//打印}//任意删除的应用voidtest07(){SL sl;//建一个空表SLIint(&sl);//初始化SLPushBsck(&sl,1);//插入数据SLPushBsck(&sl,2);SLPushBsck(&sl,3);SLPushBsck(&sl,4);SLPrint(&sl);//打印//任意删除SLErase(&sl,1);//删除下标为1的元素SLPrint(&sl);//打印}//查找元素voidtest08(){SL sl;//建一个空表SLIint(&sl);//初始化SLPushBsck(&sl,1);//插入数据SLPushBsck(&sl,2);SLPushBsck(&sl,3);SLPushBsck(&sl,4);SLPrint(&sl);//打印//查找指定元素SLFind(&sl,1);//找元素1SLFind(&sl,100);//找元素100}intmain(){//想测试哪个就放开哪个test01();//初始化应用//test02();//尾插应用//test03();//头插入应用//test04();//尾删入应用//test05();//头删入应用//test06();//任意插入应用//test07();//任意插入应用//test08();//查找元素return0;}2.3.1顺序表代码下载链接
顺序表链接下载
2.4 顺序表算法题
2.4.1 移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。
假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:
更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。返回 k。
示例 1:
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2,,]
intremoveElement(int*nums,intnumsSize,intval){//定义两个变量intdst=0,src=0;while(src<numsSize){//src值和val比较if(nums[src]!=val){nums[dst]=nums[src];dst++;}src++;}returndst;}2.5 顺序表问题与思考
• 中间/头部的插⼊删除,时间复杂度为O(N)
• 增容需要申请新空间,拷⻉数据,释放旧空间。会有不⼩的消耗。
• 增容⼀般是呈2倍的增⻓,势必会有⼀定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插⼊了5个数据,后⾯没有数据插⼊了,那么就浪费了95个数据空间
结语
愿你收获满满,点赞、收藏、转发三连不断,好运常伴!
完.