话不多说,先上整体动态顺序表实现的代码给大家

SeqList.h

#include <stdio.h> //包含标准输入输出流的头文件
#include <assert.h> //包含断言的头文件
#include <stdlib.h> //包含增容等的头文件typedef int SLDataType; //类型重命名typedef struct SeqList
{SLDataType* a; //定义一个指针变量为了接下来动态内存的开辟int size; //记录顺序表存储元素的个数int capacity; //记录顺序表当前的容量大小(最多能存储多少个数据)
}SL; //结构体重命名void SeqListInit(SL* ps); //顺序表的初始化void SeqListPrint(SL* ps); //顺序表的打印void SeqListDestroy(SL* ps); //顺序表的销毁void SeqListCheckCapacity(SL* ps); //顺序表检查是否增容void SeqListBackPush(SL* ps, SLDataType x); //顺序表的尾插void SeqListBackPop(SL* ps); //顺序表的尾删void SeqListFrontPush(SL* ps, SLDataType x); //顺序表的头插void SeqListFrontPop(SL* ps); //顺序表的头删int SeqListFind(SL* ps, SLDataType x); //顺序表的查找void SeqListInsert(SL* ps, int pos, SLDataType x); //顺序表的任意插入void SeqListErase(SL* ps, int pos); //顺序表的任意位置删除

SeqList.c

#define _CRT_SECURE_NO_WARNINGS 1#include "SeqList.h"void SeqListInit(SL* ps)
{ps->a = NULL;ps->size = ps->capacity = 0;
}  //顺序表的初始化void SeqListPrint(SL* ps)
{int i = 0;for (i = 0; i < ps->size; ++i){printf("%d ", ps->a[i]);}printf("\n");
} //顺序表的打印void SeqListDestroy(SL* ps)
{free(ps->a);ps->a = NULL;ps->size = ps->capacity = 0;
} //顺序表的销毁void SeqListCheckCapacity(SL* ps)
{if (ps->size == ps->capacity){int newcapacity = (ps->capacity == 0 ? ps->capacity = 4 : ps->capacity * 2);SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));if (tmp == NULL){printf("realloc invalid!\n");exit(-1); //退出程序}ps->a = tmp;ps->capacity = newcapacity;}
} //顺序表检查是否增容void SeqListBackPush(SL* ps, SLDataType x)
{//SeqListCheckCapacity(ps); //检查是否需要增容//int end = ps->size;//ps->a[end] = x;//ps->size++;SeqListInsert(ps, ps->size, x);
} //顺序表的尾插void SeqListBackPop(SL* ps)
{粗暴的方式//assert(ps->size > 0);温柔的方式///*if (ps->size <= 0)//{//  printf("SeqListBackPop invalid!\n");//    return;//}*///ps->size--;SeqListErase(ps, ps->size - 1);}//顺序表的尾删void SeqListFrontPush(SL* ps, SLDataType x)
{//SeqListCheckCapacity(ps); //检查是否需要增容//int end = ps->size;//while (end >= 0)//{// ps->a[end] = ps->a[end - 1];//   end--;//}//ps->a[0] = x;//ps->size++;SeqListInsert(ps, 0, x);
} //顺序表的头插void SeqListFrontPop(SL* ps)
{粗暴的方式//assert(ps->size > 0);温柔的方式///*if (ps->size <= 0)//{//  printf("SeqListFrontPop invalid!\n");//   return;//}*///int begin = 0;//while (begin < ps->size)//{//  ps->a[begin] = ps->a[begin+1];//    begin++;//}//ps->size--;SeqListErase(ps, 0);
} //顺序表的头删int SeqListFind(SL* ps, SLDataType x)
{int i = 0;for (i = 0; i < ps->size; ++i){if (ps->a[i] == x){return i;}}return -1;
} //顺序表的查找void SeqListInsert(SL* ps, int pos, SLDataType x)
{SeqListCheckCapacity(ps);//粗暴的方式assert(pos >= 0 && pos <= ps->size);//温柔的方式/*if (pos<0 || pos>ps->size){printf("SeqListInsert invalid!\n");return;}*/int end = ps->size;while (end >= pos){ps->a[end] = ps->a[end - 1];end--;}ps->a[pos] = x;ps->size++;
} //顺序表的任意插入void SeqListErase(SL* ps, int pos)
{//粗暴的方式assert(pos >= 0 && pos < ps->size);//温柔的方式/*if (pos < 0 || pos >= ps->size){printf("SeqListErase invalid!\n");return;}*/int begin = pos;while (begin < ps->size){ps->a[begin] = ps->a[begin + 1];begin++;}ps->size--;
} //顺序表的任意位置删除

test.c

#define _CRT_SECURE_NO_WARNINGS 1#include "SeqList.h"void TestSeqList1()
{SL s1;SeqListInit(&s1);SeqListBackPush(&s1, 0);SeqListBackPush(&s1, 1);SeqListBackPush(&s1, 2);SeqListBackPush(&s1, 3);SeqListBackPush(&s1, 4);SeqListBackPop(&s1);SeqListBackPop(&s1);SeqListBackPop(&s1);SeqListFrontPush(&s1, 2);SeqListFrontPush(&s1, 3);SeqListFrontPush(&s1, 4);SeqListFrontPush(&s1, 5);SeqListFrontPush(&s1, 6);SeqListFrontPop(&s1);SeqListFrontPop(&s1);SeqListFrontPop(&s1);SeqListFrontPop(&s1);SeqListPrint(&s1);
}void TestSeqList2()
{SL s1;SeqListInit(&s1);SeqListInsert(&s1, 0, 0);SeqListInsert(&s1, 1, 1);SeqListInsert(&s1, 2, 2);SeqListInsert(&s1, 3, 3);SeqListInsert(&s1, 4, 4);SeqListErase(&s1, 1);SeqListErase(&s1, 2);SeqListPrint(&s1);SeqListDestroy(&s1);
}int main()
{TestSeqList1();//TestSeqList2();return 0;
}

顺序表

1.基本概念:顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构。(一般情况下采用数组存储,在数组上完成数据的增删查改)

2.分类:静态顺序表(使用定长数组存储元素)和动态顺序表(使用动态开辟的数组存储)

附:
1.楼主使用的是VS2013编译器。

2.在一个比较正式的项目工程里,通常是类似于分为功能定义的头文件、功能实现的源文件以及测试用的源文件。(类似于下图)

3.本篇文章中楼主以动态顺序表的实现为主,静态顺序表的实现大家可以参考动态顺序表的实现。(为了后续方便学习C++中的STL,楼主的变量、函数等的命名风格均是根据C++的命名风格来命名的!)

动态顺序表的实现

SeqList.h

首先包含必要的头文件(包括输入输出、断言、增容等的相关所需的头文件)

我们定义一个结构体类型出来先,成员变量包括一个指针变量、记录该顺序表存了多少个元素的变量以及这个顺序表总容量的变量。(定义指针变量是为了进行动态内存开辟,然后我们可以通过顺序表目前所存储的元素个数和顺序表目前的总容量进行对比判断是否需要增容)同时我们也可以将结构体类型重命名一下,使我们更加地方便进行写代码操作。

对于指针的类型,我们最好采用typedef将某个类型重命名,使用这个重命名来作为指针的类型。(这样的好处是我们根据储存类型的不同,方便修改指针的类型)

同时定义好相应的函数接口。(初始化、销毁以及增删查改等)

注意:表面上我们把size变量理解为记录顺序表存储的元素个数,深层次理解实际上size变量则是代表顺序表(数组)下标当前所在的位置

SeqList.c

初始化、打印、销毁等功能的实现

初始化我们就将该结构体类型变量中的指针变量置空,存储的元素个数和存储的总容量都置0。

打印顺序表的内容就是遍历一遍数组输出即可,简单粗暴!(注意数组的下标是从0开始的)

销毁顺序表是为了防止内存泄露等相关问题的出现,一般我们不使用动态内存开辟的这块空间以后,最好使用free函数将其销毁,并将其置空!

判断是否需要增容功能的实现

需要清楚的是,不管是接下来要实现的尾插、头插以及任意位置的插入操作功能的实现,我们都需要判断是否需要增容。所以,为了方便代码复用,我们将这部分代码封装成一个函数。

当我们的数组已存储的元素个数和我们数组的总容量相等时,这就意味着我们需要增容了。我们先定义一个新的总容量变量根据原先总容量来进行赋值(采用一个三目运算符来进行判断赋值,若原先总容量为0,我们就令它为4,不然就在原来的基础上扩2倍),这个增容的方式你可以根据你个人的爱好来增就行,我只是拿一个相对普遍的增容方式而已,就像一个人吃饭通常吃2碗就可以了,你吃5碗当然也是没有问题的!接着我们定义一个新的指针变量用来增容(我使用的是realloc函数来进行增容的),增容完成后我们需要判断一下返回给我们指针变量的值是否为空,如果为空代表增容失败,这是一个比较严重的错误,所以我们直接用exit函数退出程序;不为空的话就代表增容成功,那么我们就让我们原先的指针也指向这个新指针的位置,原先的总容量变为新的总容量。(很多xdm可能会很疑惑,为什么不在原有的指针上直接进行增容,而还要借助一个新的指针来间接进行增容,因为如果原指针动态内存开辟失败,那么原先的指针也将找不到了!)

尾插功能的实现

首先需要调用判断是否需要增容的函数,防止存储空间未被开辟或者存储空间不足。(后续其他方式插入功能的实现也一样的道理)

尾插比较简单,直接在顺序表末尾的位置进行插入就行。

找到顺序表末尾的位置也就是记录顺序表存储多少个元素的变量所对应的数组下标,完成以后我们的记录顺序表存储多少个元素的变量记得要+1!(记录顺序表存储多少个元素的变量跟我们数组的下标是同步的,都是从0开始,+1代表移动到下一个位置,但是还没有存储元素)


尾删功能的实现

首先需要判断一下我们的顺序表是否有存储元素,如果一个元素都没有存储,怎么进行删除操作呢?我们可以用粗暴的方式(直接断言报错)或者温柔的方式(不满足条件时我们什么都不做),就比如你的娃犯错了你是直接打,还是说两句就不管了一样。当我们是存储了元素以后我们才能进行接下来的删除元素操作。(后续其他方式删除功能的实现一样的道理。)

因为这是尾部删除,简单粗暴,直接让记录顺序表的存储元素个数的变量-1即可完成尾删!


头插功能的实现

第一步还是先要调用判断是否需要增容函数。

根据顺序表的概念我们能明确的知道顺序表是连续存储的,如果目前已经存储了数据,那么我们就要将原有的数据全部往后挪动一个位置,腾出第一个位置给我们进行头插操作!

我们先定义一个变量是目前顺序表存储多少个元素的尾部下标,有了尾部下标的位置,我们紧接着就可以通过一个while循环将我们的顺序表元素依次往后迭代,循环结束以后,我们就将要插入的数据直接插入头部即可,完成以后记录我们存储多少个元素的变量记得要+1!


头删功能的实现

跟尾删功能一样,我们还是需要先做一个简单判断是否能进行接下来的删除操作!

当条件满足时才开始我们接下来的头部删除操作,先定义一个变量在顺序表首元素的位置,即0。通过一个while循环将顺序表中的元素依次往前迭代覆盖,循环结束(即删除完成),我们就将记录顺序表存储元素的个数-1即可!


查找功能的实现

简单粗暴,遍历一遍顺序表,然后依次跟要查找的数据进行对比,找到就返回对应的下标,最后数组都遍历完成后还找不到,就返回-1(代表找不到)即可!

任意位置插入功能的实现

第一步还是需要先判断是否需要增容。

同时我们也需要判断一下任意位置的插入位置是否合理,如果插入到-1的位置或者跳跃间隔插入,这样都是不合理的方式插入,是无法进行我们的插入操作的。
任意位置的插入操作跟头插道理一样,由于顺序表是连续存储的,所以我们需要将部分数据一起往后挪动,为要插入的位置腾出空间来存储。

先定义一个变量是顺序表最后一个元素下标的位置,然后引用一个while循环,将我们目标位置开始的所有元素依次往后迭代挪动,直至达到我们目标插入位置时才停止(包括移动我们目标插入位置的数据),此时再将要插入的数据插入到目标位置即可,完成以后我们记录顺序表存储元素的个数记得还是要+1。


任意位置删除功能的实现

首先我们得需要判断一下我们的删除是否合理(跟上述操作同理,没有元素怎么删?删除的位置不合理怎么删?)

任意位置的删除跟头删一个道理。

定义一个变量是在目标删除位置,通过一个while循环将目标删除位置后面的数据依次往前迭代覆盖(包含目标删除位置),直到我们最后一个元素也完成向前迭代。完成以后记得将我们记录顺序表存储元素的个数-1!


完善升级顺序表
这就是我们最基本的动态顺序表,我们还能将其更加完善一下,比如根据我们任意位置的插入和删除函数,将我们的尾插、尾删、头插以及头删等函数优化下,使代码更好的完成复用!操作非常简单粗暴,只需要分别传对应的顺序表尾部和头部位置给任意位置的插入和删除函数就能实现!

test.c

这个文件主要是用来测试的,建议大家编写边测试,不要写完在测试,以免出现调试了半天都出不来结果,还不知道错哪里,如果是边写边测试我们就能及时知道错误的代码片段在哪个功能实现的位置,不要贪快,“心急吃不了热豆腐!”。
大家可以像我这样写测试用的专门函数,以此为例。


以上便是完整的动态顺序表的讲解!

静态顺序表的实现

跟动态顺序表一样的操作,只不过是不能动态内存开辟而已。(我只是写了简单的定义而已,增删查改的实现参考动态顺序表)

上述便是本篇博客的主要内容

小贴士:
在我们学习学习数据结构的过程中不仅仅是要懂得思想,而是还要懂得将思想表达出来(画图+写代码),这才是最重要的,不然最终只能是纸上谈兵!

下篇链接:数据结构初阶:单链表的实现
分分钟带你拿捏初阶数据结构的单链表

备注:

楼主不才,不喜勿喷,若有错误或需要改进的地方,非常感谢你的指出,我会积极学习采纳。谢谢家人们一直以来的支持和鼓励,我会继续努力再接再励创作出更多优质的文章来回报家人们的。编程爱好的xdm,若有编程学习方面的问题可以私信我一同探讨(我尽力帮),毕竟“众人拾柴火焰高”,大家一起交流学习,共同进步!

2022年3月30日

室友一把王者的时间我拿捏了数据结构——顺序表(C语言版)相关推荐

  1. 室友一把王者的时间——偷偷学会栈与队列

    目录 栈的概念与结构 栈的定义 栈的初始化 栈的销毁 入栈 出栈 获取栈顶元素 获取栈中有效数据的个数 判断栈是否为空 栈的完整代码 Stack.h Stack.c test.c 队列的概念与结构 队 ...

  2. 【纯JavaSE】图书管理系统(带精解注释)舍友一把王者的时间,我完成了一个纯Java的基础入门小项目~

  3. 一把王者的时间,学会generate语句【Verilog高级教程】

    芯片设计验证社区·芯片爱好者聚集地·硬件相关讨论社区·数字verifier星球 四社区联合力荐!近500篇数字IC精品文章收录! [数字IC精品文章收录]学习路线·基础知识·总线·脚本语言·芯片求职· ...

  4. 室友利用一把王者的时间就学会了【C语言结构体内存对齐】

    文章目录 一.什么是结构体内存对齐? 二.结构体的对齐规则 结构体内存对齐规则的具体应用 三.为什么会存在内存对齐 总结 提示:以下是本篇文章正文内容,下面案例可供参考 一.什么是结构体内存对齐? 从 ...

  5. 室友只用了一把王者的时间就入门了「C语言」

  6. 宿友用一把王者的时间入门了【二叉树】,你又懂多少呢?乌拉~~

  7. 一把王者的时间,我就学会了Nginx

    作者 | 步尔斯特 来源 | CSDN博客 Nginx 简介 Nginx("engine x")是一个高性能的 HTTP 和反向代理服务器,特点是占有内存少,并发能力强,事实上 n ...

  8. 一把王者的时间,我就学会了 Nginx

    一.Nginx 简介 Nginx("engine x")是一个高性能的 HTTP 和反向代理服务器,特点是占有内存少,并发能力强,事实上 nginx 的并发能力确实在同类型的网页服 ...

  9. 一把王者的时间带你拿捏计算机中整形提升的问题

    计算机中整形提升讲解 附1: 计算机的底层计算原理 大家猜猜下面程序的运行结果是多少? 如果你的答案是0,那么恭喜你答对了. 解析:那么答案为什么是0呢?接下来我就用计算机底层的计算原理手把手告诉你这 ...

最新文章

  1. 操作系统学习笔记 第三章:处理机调度与死锁(王道考研)
  2. C C++的编译过程详解
  3. iOS 自定义转场动画初探
  4. 我用Python爬虫挣钱的那些事
  5. 不满6位补零 字符串_vb6.0中字符串中不足位数前面补0的方法
  6. 面试官系统精讲Java源码及大厂真题 - 45 Socket 源码及面试题
  7. Android--调用系统照相机拍照与摄像
  8. c++ msflexgrid 使用_丝杠支座组件C
  9. vi/vim使用进阶: quickfix
  10. scala问题解决sbt下载过慢的问题
  11. matlab指派问题论文,数学建模指派问题论文.doc
  12. 什么是脏读、不可重复读、幻读? (数据库相关)
  13. 荣耀4a android art,荣耀4A拆机图解·看真相
  14. 【键盘】jQuery+CSS3模拟键盘事件(精)
  15. x265-10bit的配置
  16. [日常] 面试知识点总结(持续更新)
  17. 行业动态 - Zhaga-D4i 首批认证授予户外照明灯具产品
  18. DLL入口点函数DllMain .
  19. Asterisk AMI 接口整理
  20. 开发定位功能时如何检测手机是否开启虚拟定位?

热门文章

  1. 我还是很喜欢你,像相思藏在树底, 花落是你,花开也是你。
  2. Android设置系统休眠
  3. BSA-Xylan 牛血清白蛋白-木聚糖,血清白蛋白HSA/卵清白蛋白OVA/乳清白蛋白偶联糖
  4. Java基础 - 坦克大战(第五章,坦克移动、与被击中效果功能)
  5. 打印公司员工信息表java,打印模板 java
  6. Python中如何实现im2col和col2im函数(sliding类型)
  7. 风林火山 GHOST XP SP3清爽纯净版V2011_01
  8. 【JoJo的摄影笔记】相机配件之奥义——风林火山
  9. 【程序人生】是的,我离职了!
  10. ripgrep (rg) 如何搜索被忽略或隐藏的文件?