数据结构第二课 | 顺序表(详解)

简介: 数据结构第二课 | 顺序表(详解)

前言:Hello!大家好,我是@每天都要敲代码,上次我们讲了数据结构第一课时间复杂度和空间复杂度;不明白的小伙伴可以学习一遍时间复杂度和空间复杂度传送门;今天让我们开始一起学习数据结构第二课啦-----线性表;在学习线性表之前,我们要先弄清楚它的概念,下面让我们一起来看看吧!


概念:


线性表:线性表是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛

使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串....

解释:线性表在逻辑上是线性结构,也就是连续的一条直线。但是在物理结构上并不一定是

连续的,线性表在物理上存储时,通常以【数组】和【链式结构】(链表)的形式存储

数组空间是连续的,链表空间是不连续的。


顺序表实现:顺序表是用一段【物理地址连续】的存储单元【依次存储数据元素】的线性结构,一般情况下采用数组存储。在数组上完成数据的增删改查。

顺序表一般可以分为:

                  1.静态顺序表:适应定长数组存储。

                  2.动态顺序表:使用动态开辟的数组存储


静态链表的形式很简单,但是容量的大小其实是写死了,不太实用;我们先写出静态链表感受一下吧:


静态顺序表:


08b490dc7b024866a89b846641d7e3c6.png



我们先对顺序表进行初始化,那么传参怎么办呢?传值还是传址?它要改变原来的数据,当然是传址啦;初始化有两种方法,自己选择一种适合自己使用就可以;


第二步我们就把相对简单的打印函数写出来了;


第三步我们就进行尾插,在插入的时候我们就发现了静态顺序表的弊端,我们首先要进行判满,满了就不能插了,只能手动进行扩容,扩小了造成来回扩容,很麻烦;扩大了又会造成浪费,那么该怎么办?我们不妨写成动态顺序表的形式;所以下面的函数接口我就不在写了;直接写成动态顺序表的形式吧!!!


动态顺序表:


对于动态顺序表我们就把常用的接口函数都写出来吧,虽然稍微有点复杂,不要怕,我们一个一个接口函数来解决:


1.先创建顺序表:struct SqList


包括存储数据的数组arr,用malloc创建出来、有效数据的个数sz、容量capacity;下面一起来实现吧:

0e71cf63afea4cdbb0b6693bf6d5e6b3.png


2.进行初始化:SqListInit


我们同样也需要传址!!!在写初始化接口函数之前,我们首先要思考,要初始化什么?怎么初始化?


第一种初始化方式:首先我们要肯定要用malloc先动态申请空间,申请空间的大小就是上面定义的宏常量INIT_MAX的大小;值得注意的是malloc开辟空间是以字节为单位开辟的;之后还是把sz的大小初始化为0,容量capacity的大小初始化为INIT_MAX的大小。


第二种初始化方式:当然你也可以像航哥一样,才开始把ps->arr=NULL,ps->sz=0,  ps->capacity = 0;我们插入的时候直接realloc进行扩容;这里就需要老铁对malloc和realloc有一定的了解了,我们思考一下,当realloc初始传一个空指针,是不是相当于malloc的作用呢?不妨自己去尝试一下吧!并且写成这种形式,我们在直接用reallo直接扩容之前,要把capacity初始化一个值,不然(倍数*capacity=0)就永远为0了;我们一般扩容为原来的两倍。


下面两种方式的扩容都给出来,选择自己习惯的就好;我是比较偏向第一种方式,所以读这篇博客还是按照第一种初始化方式去理解:


第一种方式初始化:

255b0e8f12fa4b6e857e50403ca8df27.png


第二种方式初始化和扩容:

08f2d19c397d4da2baf1894e8eb05c19.png


3.打印函数:SqListPrint


同样我们先把相对简单的打印函数写出来,以后需要直接调用这个函数就行:

4837fb46e71843df93d8290d24c46bd3.png


4.尾插函数:SqListPushBack


扩容函数:SqListExpasion


   在尾插之前我们需要先判断是否需要扩容,看ps->sz == ps->capacity;满足我们就需要扩容,而且在哪里插入都需要先判断是否需要扩容;我们不妨封装成一个函数,下面在使用直接调用就行,避免代码冗余;尾插我们在直接插入就行了,不需要数据的移动,很简单:


1e2654c7f8ad44d1b05541f00e7ba46d.png



是否扩容成功呢?我们定义的初始capacity=4,我们不如来多输入几个数来测试一下:

959c7e262a074a6f982fab2b3ee8c539.png

能正常打印出来,说明我们已经扩容成功了!!!


5.头插函数:SqListPushFront


同样在头插之前我们需要先判断是否需要扩容;头插就不像尾插那么简单直接在后面插入数据;头插需要往后移元素,把下标为0的位置留给新插入的数据;那么怎么移动呢?当然是从后面开始移动啦!从前面数据会被覆盖!!!

48503899f21c410a965ec6d49085ce2b.png


头插两个数据11、12看运行结果:

2e9977726a5f4330a87c6544b1f16166.png

正常打印,说明头插成功。


6.尾删函数 SqListPopBack


对于尾删也很简单,直接让ps->sz--访问不到最后一个元素就可以了:


9298292adadd4db5a4951020609c0619.png


下面我们尾删两个数试试:

0f1b35d7494f4f34b034ac73777977a3.png

发现9、10已经打印不出来了,尾删成功。


7.头删函数 SqListPopFront


对于头删,也要先判断是否为空表;我们同样也要移动元素,从最前面开始,把数据一个个往前移;然后在把ps->sz--就可以啦:这里可以再回过头来去看一下头插函数里面的移动元素和这里头删函数移动元素的区别,对比着学习!!


23a13264351f4f7892f6c706cdf288a4.png


下面头删两个元素,打印试试看:


2c9cb9785b7840a58ffe9f3691152835.png

正常删除头两个元素12和11,头删除成功。


8.修改:SqListModify


查找:SqListFind

在修改数据之前,我们肯定要先进行查找,根据数据的下标进行修改操作,所以不妨先封装一个查找的函数SqListFind;根据这个查找函数找下标,然后在传参进行修改


677a2b663db44fb89d9d0ec814c30f55.png


我们不妨修改一个元素试试,比如:把3改为300:

22dcf80288f4483eb671f3472337c551.png

从这里可以看出,完全是没问题的。


9.任意位置插入:SqListInsert


在任意位置插入;你可以有两种理解,


一种直接给你下标pos,就把数据插入到pos里;比如:我们直接给出下标pos=1的位置插入,这时我们插入之前就要判断pos下标是不是越界;直接用assert(pos<ps->sz)断言就可以。


另外一种理解你可以根据给出的具体数据,调用SqListFind查找函数返回的下标pos,来进行插入;这时返回的下标除了找不到是-1,其它的肯定返回的是合法的值,所以不用越界判断也是可以的。


这里我们只实现第一种理解:


d51490db7b3e476785a7a7e7ec6f37d6.png


我们不妨在下标为0的元素前面插入100;看运行结果:


df3f25acaf6843359c6388f73c10a13e.png

从这里可以看出,完全是没问题的。


10.任意位置删除:SqListDelete


同样删除也是和任意位置插入一样,有两种理解;我们还是只实现第一种理解,我们随意给定一个下标就可以删除这个下标的元素:


872d452579734b46b9c5c5344db66156.png

我们不妨删除下标为1的数据;看运行结果:

e1cc63a1ee784a9ca8291d384f6ce857.png

从这里可以看出,完全是没问题的,1被删除了。


11.销毁:SqListDestory


image.png

所有具体代码:

cdc4abb1df6b4675bfa2ec9b0ea3a741.png


补充题目1: 原地移除元素

补充题目2:合并两个有序数组


这两道题目是航哥数据结构补充的两道题目;我们在以前的博客里已经做过这两道题目,这里就不在说了,感兴趣的小伙伴,不妨看看我的另外两篇博客,专门详解了这两道题目:传送门1<原地移除元素>     传送门2<合并两个有序数组>


总结:


当然你可以模仿通讯录那样写一个详细的菜单,这里就留给老铁们自己动手写一写!今天的数据结构之顺序表就学完了,希望对您有所收获;等你完全一口气能写出这个顺序表,不妨就尝试把这个当成小项目来写;创建SqList.h:用来存放函数的声明、头文件的引用、结构体的定义、常量的定义等放在这里面;创建SqList.c来写具体函数的实现;创建tect.c来写主函数、以及各个函数的调用等。



9fa039b87657464c8f98ced96557cca0.jpg


相关文章
|
26天前
|
存储 算法 程序员
【数据结构】C语言实现顺序表万字详解(附完整运行代码)
【数据结构】C语言实现顺序表万字详解(附完整运行代码)
39 0
|
28天前
|
存储 编译器
数据结构:顺序表详解
数据结构:顺序表详解
37 0
|
存储 索引
数据结构--动态顺序表
数据结构--动态顺序表
|
1月前
|
存储 消息中间件 算法
数据结构从入门到精通——顺序表
顺序表是一种常见的线性数据结构,它使用一段连续的存储单元依次存储数据元素。这种数据结构的特点是逻辑上相邻的元素在物理存储位置上也相邻,因此可以快速地访问表中的任意元素。 顺序表的实现通常依赖于数组,数组是一种静态的数据结构,一旦创建,其大小就是固定的。这意味着在顺序表中插入或删除元素可能会导致空间的浪费或不足。例如,如果在一个已经满了的顺序表中插入一个新元素,就需要重新分配更大的数组空间,并将原有元素复制到新数组中,这是一个相对耗时的操作。
54 0
|
3月前
|
存储 算法 C语言
数据结构 | 顺序表专题
数据结构 | 顺序表专题
|
1月前
|
存储 编译器
数据结构之顺序表的实现(详解!附完整代码)
数据结构之顺序表的实现(详解!附完整代码)
37 1
|
1月前
|
存储
【数据结构——顺序表的实现】
【数据结构——顺序表的实现】
|
1月前
|
存储
【数据结构】顺序表
【数据结构】顺序表
|
1月前
|
存储 C语言
【数据结构】顺序表的学习
【数据结构】顺序表的学习
|
1月前
|
存储
数据结构之顺序表及其实现!
数据结构之顺序表及其实现!