【数据结构】顺序表的学习

前言:在之前我们学习了C语言的各种各样的语法,因此我们今天开始学习数据结构这一个模块,因此我们就从第一个部分来开始学习"顺序表"。

💖 博主CSDN主页:卫卫卫的个人主页 💞
👉 专栏分类:数据结构 👈
💯代码仓库:卫卫周大胖的学习日记💫
💪关注博主和博主一起学习!一起努力!
在这里插入图片描述


目录

  • 顺序表
    • 动态顺序表
      • 顺序表的初始化
      • 顺序表的销毁
      • 顺序表的空间容量检查
      • 顺序表的打印
      • 顺序表的尾增
      • 顺序表的头增
      • 顺序表的头删
      • 顺序表的尾删
      • 顺序表的选择插入
      • 顺序表的删除数据
      • 顺序表数据的查找
    • 练习


顺序表

  1. 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
  2. 顺序表一般可以分为两个部分,静态顺序表(使用定长数组存储元素)和动态顺序表(使用动态开辟的数组存储)。
  3. 静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

动态顺序表

首先我们创建一个结构体,去实现数据的动态存储。
在这里插入图片描述

代码如下:

typedef int SLDataype;//定义整型,方便后面进行数据的更改typedef struct SeqList //动态顺序表的开辟
{SLDataype* a;int size; //记录多少个有效数据int capacity; //记录空间有多大
}SL;

接下来我们就实现一个个接口来实现顺序表的基本功能

顺序表的初始化

顺序表的初始化十分简单,只需要将开辟的指针置为空指针,有效数据清零,空间容量清零即可。
代码如下:

void SLInit(SL* ps1)//顺序表的初始化
{assert(ps1);ps1->a = NULL;//将指针置为空指针ps1->size = 0;//数据清零ps1->capacity = 0;//容量清零
}

顺序表的销毁

同理,顺序表的销毁,只需要判断所开辟的空间是否已经是被释放了,和被置为空指针了,如果不是,就把所开辟的空间释放和数据清零即可。
代码如下:

void SLDestory(SL* ps1)//顺序表的销毁
{if (ps1->a != NULL)//判断该指针是否为空指针{free(ps1->a);//释放该指针所开辟的空间ps1->a = NULL;//置为空指针ps1->size = 0;//数据清零ps1->capacity = 0;//容量清0}
}

顺序表的空间容量检查

我们想要实现在所开辟的空间中,增加数据,就不可避免的需要去检查所开辟的空间的容量是否充足,如果不充足,我们就需要去增容,那该增加多少呢?增加太多,会导致空间的浪费,太少又会导致不断的扩容,这是一个双向的问题,因此这也没有什么十分固定的答案,通常来讲,一般增容一倍即可。

代码思路:在检查空间的时候,我们应该考虑传过来的指针是否是空指针,即是否是初始化后的顺序表,但realloc函数是可以对空指针进行扩容的,但是我们为了防止扩容失败,应该开辟一个新的结构体指针来接收这块空间,在开辟成功后重新覆盖回去。

代码实现:

void SLCheckCapacity(SL* ps1)//检查空间
{if (ps1->size == ps1->capacity)//判断记录的数据个数,与空间容量释放相同,相同的时候即空间满了,需要增容{int newCapacity = ps1->capacity == 0 ? 4 : ps1->capacity * 2;//判断开辟的空间是否是初始化的空间,如果是就让他容量为4,如果不是就开辟当前空间的两倍SLDataype* tmp = (SLDataype*)realloc(ps1->a, sizeof(SLDataype) * newCapacity);//创建一个新的结构体指针,在他的后面扩容,放在开辟失败后原本的数据也不见了//realloc 可以对空指针进行扩容if (tmp == NULL){perror("realloc fail");return;}ps1->a = tmp;//将开辟后面的指针传给原本的地址ps1->capacity = newCapacity;//更新容量}
}

顺序表的打印

void SLPrint(SL* ps1)
{for (int i = 0; i < ps1->size; i++)//变量开辟的数据{printf("%d ", ps1->a[i]);//直接打印}printf("\n");
}

顺序表的尾增

代码思路:因为前面我们提到了size是有效数据的个数,也是指向的数组的最后一个元素的后一个的位置,因此只需要在此位置赋值即可,然后再让size往后偏移一位。

代码实现:

void SLPushBack(SL* ps1, SLDataype x)//尾增
{SLCheckCapacity(ps1);//检查空间容量ps1->a[ps1->size] = x;//因size指向的是数组最后一个元素的后一个元素,因此只需要直接在此位置赋值即可ps1->size++;//size继续指向后一个元素
}

现在我们实现了四个小的接口,忙活了这么久,我们来见一下效果,好歹听个响是吧。
效果图:

void TestSL1()//测试函数
{SL s1;//创建动态顺序表SLInit(&s1);//初始化顺序表SLPushBack(&s1, 2);//尾增数据SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPrint(&s1);//打印数据SLPushBack(&s1, 5);SLPushBack(&s1, 6);SLPrint(&s1);//打印数据SLDestory(&s1);//销毁顺序表
}int main()
{TestSL1();return 0;
}

在这里插入图片描述


顺序表的头增

代码实现思路:我们记录数据的最后一个位置为end,最后一个数据后面的一个数据位置为end+1,让end依次往后覆盖,然后end–直到end到起始位置即停止循环,具体思路如下图:
在这里插入图片描述
代码实现:

void SLPushFront(SL* ps1, SLDataype x)//头增
{SLCheckCapacity(ps1);//先检查数据//挪动数据int end = ps1->size - 1;//记录最后一个位置while (end >= 0)//end到起始位置时即覆盖完成{ps1->a[end + 1] = ps1->a[end];//将数据依次往后覆盖--end;}ps1->a[0] = x;//将数据赋值给起始位置就可以实现头增ps1->size++;//size++
}

当然了,不能白忙活,我们来测试一下这个函数,来看看效果如何

void TestSL2()
{SL s1;//创建动态顺序表SLInit(&s1);//初始化顺序表SLPushBack(&s1, 2);//尾增数据SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPrint(&s1);//打印尾增的数据printf("上面是尾增的数据\n");printf("------------------------------\n");printf("下面是头增的数据\n");SLPushFront(&s1, 20);//头增的数据SLPushFront(&s1, 10);SLPushFront(&s1, 0);SLPushFront(&s1,9);SLPrint(&s1);//打印头增的数据SLDestory(&s1);//销毁顺序表
}int main()
{//TestSL1();TestSL2();return 0;
}

在这里插入图片描述


顺序表的头删

代码思路:我们记录一个起始位置即数组的第二个元素记录为begin,让他往前面一个数据begin-1覆盖,然后再放入循环中不断覆盖,当运行到size的位置的时候停止循环具体思路如下图:
在这里插入图片描述
代码如下:

void SLPopFront(SL* ps1)//头删
{assert(ps1->size > 0);//判断传过来是是不是为空数据int begin = 1;//将起始位置置为1while (begin < ps1->size)//再起始位置等于size时即覆盖完成{ps1->a[begin - 1] = ps1->a[begin];//后面覆盖前面++begin;}ps1->size--;//size减减
}

当然,我们依然来听个响,听听声音,效果图如下:


void TestSL3()
{SL s1;//创建动态顺序表SLInit(&s1);//初始化顺序表SLPushBack(&s1, 2);//尾增数据SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPushFront(&s1, 20);//头增的数据SLPushFront(&s1, 10);SLPushFront(&s1, 0);SLPushFront(&s1, 9);SLPrint(&s1);//打印原本的数据printf("上面是原本的数据\n");printf("--------------------------------------\n");printf("下面是删除后的数据\n");SLPopFront(&s1);//头删数据SLPopFront(&s1);SLPopFront(&s1);SLPrint(&s1);//打印删除后的数据SLDestory(&s1);//销毁顺序表
}int main()
{//TestSL1();//TestSL2();TestSL3();return 0;
}

在这里插入图片描述


顺序表的尾删

代码思路:我们可以通过前面的打印函数可以知道,我们是通过打印到size前面的一个下标来访问所有的元素,因此我们只需要让size往前面走一个,就可以把尾部的元素删除,可以看下图思路:
在这里插入图片描述

代码实现:

void SLPopBack(SL* ps1)//尾删
{//空if (ps1->size == 0)//判断删除的是否为空{return;}ps1->size--;//size--即可
}

我们依然来测试一下我们函数,看看效果是否成功实现,代码和效果图如下:

void TestSL4()
{SL s1;//创建动态顺序表SLInit(&s1);//初始化顺序表SLPushBack(&s1, 2);//尾增数据SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPushFront(&s1, 20);//头增的数据SLPushFront(&s1, 10);SLPushFront(&s1, 0);SLPushFront(&s1, 9);SLPrint(&s1);//打印原本的数据printf("上面是原本的数据\n");printf("--------------------------------------\n");printf("下面是删除后的数据\n");SLPopBack(&s1);//尾删数据SLPopBack(&s1);SLPrint(&s1);//打印删除后的数据SLDestory(&s1);//销毁顺序表
}int main()
{//TestSL1();//TestSL2();//TestSL3();TestSL4();return 0;
}

在这里插入图片描述


顺序表的选择插入

代码思路:选择插入,即将一个值,任意插入到顺序表中的范围内,当然了口头总是不太好说清,我们对着下图来进行一一分析,我们可以记录一个end坐标记录数据的尾部,然后将值一一覆盖,pos为我们想要出入数据的位置,例如下图,当end走到pos的位置的时候,即可停止覆盖,这有点类似与我们前面的头删,将值pos之后的值全部往后挪动了一位,然后将最后重复的值被想插入的值覆盖即可。
在这里插入图片描述

代码实现:

void SLInsert(SL* ps1, int pos, SLDataype x)//插入数据
//pos是下标,size是数据个数,看作下标的话,他是最后一个数的下一个位置
{assert(ps1);//判断传来的值是否是空指针assert(pos >= 0 && pos <= ps1->size);//插入的值必须是再范围内(可以包括尾增)SLCheckCapacity(ps1);//检查空间// 挪动数据int end = ps1->size - 1;//找到尾坐标while (end >= pos){ps1->a[end + 1] = ps1->a[end];//将值一一覆盖,类似于头删--end;}ps1->a[pos] = x;//赋值ps1->size++;
}

我们依然来看看函数的效果是否实现,测试代码和效果图如下:

void TestSL5()
{SL s1;//创建动态顺序表SLInit(&s1);//初始化顺序表SLPushBack(&s1, 2);//尾增数据SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPushFront(&s1, 20);//头增的数据SLPushFront(&s1, 10);SLPushFront(&s1, 0);SLPushFront(&s1, 9);SLPrint(&s1);//打印原本的数据printf("上面是原本的数据\n");printf("--------------------------------------\n");printf("下面是选择插入后的数据\n");SLInsert(&s1, 3, 99);SLInsert(&s1, 1, 2);SLPrint(&s1);//打印选择插入后的数据SLDestory(&s1);//销毁顺序表
}
int main()
{//TestSL1();//TestSL2();//TestSL3();//TestSL4();TestSL5();return 0;
}

在这里插入图片描述


顺序表的删除数据

代码思路:删除数据和选择插入的概念其实大差不差,首先也应当判断传过来的数是否是空指针,删除的数据在不在数据范围内,然后我们再通过图文来进行分析,如下图,先把删除的位置记录下来,当然了,和前面同理依次往前面覆盖,再打印的时候直接将size往前移一位即可把最后重复的值给去掉,达到顺序表的删除的功能。
在这里插入图片描述
函数代码:

void SLErase(SL* ps1, int pos)//删除数据
{assert(ps1);assert(pos >= 0 && pos < ps1->size);int begin = pos + 1;//记录删除数据后的位置while (begin < ps1->size){ps1->a[begin - 1] = ps1->a[begin];//依次覆盖++begin;}ps1->size--;
}

代码实现和函数实现效果图如下:

void TestSL6()
{SL s1;//创建动态顺序表SLInit(&s1);//初始化顺序表SLPushBack(&s1, 2);//尾增数据SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPushFront(&s1, 20);//头增的数据SLPushFront(&s1, 10);SLPushFront(&s1, 0);SLPushFront(&s1, 9);SLPrint(&s1);//打印原本的数据printf("上面是原本的数据\n");printf("--------------------------------------\n");printf("下面是选择插入后的数据\n");SLErase(&s1, 3);//删除数据SLErase(&s1, 1);//删除数据SLPrint(&s1);//打印选择插入后的数据SLDestory(&s1);//销毁顺序表}int main()
{//TestSL1();//TestSL2();//TestSL3();//TestSL4();//TestSL5();TestSL6();return 0;
}

在这里插入图片描述


顺序表数据的查找

代码思路:顺序表数据的查找就过于简单了,我们只需要遍历数据,看看是否有对应的值,有则返回该数的下标,没有则返回**-1**。代码如下:

int SLFind(SL* ps1, SLDataype x)//顺序表数据的查找
{assert(ps1);//判断传来的数据是否是空指针for (int i = 0; i < ps1->size; i++)//遍历数组{if (ps1->a[i] == x)return i;//找到即返回坐标i}return -1;//没找到返回-1
}

函数测试与效果图:

void TestSL7()
{SL s1;//创建动态顺序表SLInit(&s1);//初始化顺序表SLPushBack(&s1, 2);//尾增数据SLPushBack(&s1, 3);SLPushBack(&s1, 4);SLPushFront(&s1, 20);//头增的数据SLPushFront(&s1, 10);SLPushFront(&s1, 0);SLPushFront(&s1, 9);SLPrint(&s1);//打印原本的数据printf("上面是原本的数据\n");printf("--------------------------------------\n");printf("下面是选择插入后的数据\n");printf("该数的下标是:%d\n",SLFind(&s1, 2));SLDestory(&s1);//销毁顺序表
}
int main()
{//TestSL1();//TestSL2();//TestSL3();//TestSL4();//TestSL5();//TestSL6();TestSL7();return 0;
}

在这里插入图片描述
讲到这里,关于顺序表的基本内容实现全部讲完了,接下来我们来看一题目练习一下把!


练习

题目链接:
在这里插入图片描述

思路分析:看到这个题,大家都会想到一个很通俗易懂的方法,就是开辟一个辅助数组,将所有的数放进去,然后进去排序,当然我们今天是不讲这个方法的,因为这个方法的时间复杂度过于高。我们看到这个是一个非递减顺序,可以知道最大的数都放在了后面,因此我们可以将两个数中最后的元素拿出来依次比较,然后将较大的放在nums1中的最后面,依次类推,放到最后自然而然的可以将所有数进行排序,那怎么去实现它呢?看图说话,如下图,我们记录一个坐标i1i2分别记录下两个数组中的最后一个元素,然后依次进行比较,如果i1中的数较大就放在下标j的位置,反之则把i2放进去,且如果nums1中走完了,nums2还没有,就只需要将nums2中的数据单独拿出来,放再j所在的位置即可。
在这里插入图片描述
代码实现如下:

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{int i1 = m - 1;//记录第一个数组的尾坐标int i2 = n - 1;//第二个数组尾坐标int j = m + n - 1;//记录总元素的坐标while(i1 >= 0 &&  i2 >= 0){if(nums1[i1] > nums2[i2]){nums1[j--] = nums1[i1--]; }else{nums1[j--] = nums2[i2--];}}while(i2 >= 0){nums1[j--] = nums2[i2--];}
}

运行结果:
在这里插入图片描述


结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。


🫵🫵🫵 祝各位接下来好运连连 💞

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

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

相关文章

windows和docker环境下springboot整合gdal3.x

链接: gdal官网地址 gdal gdal的一个用c语言编写的库&#xff0c;用于处理地理信息相关的数据包括转换&#xff0c;识别数据&#xff0c;格式化数据以及解析 同时提供第三方语言的SDK包括python&#xff0c;java上述需要编译后使用 java是需要使用jni接口调用实现方法在wind…

mysql---存储引擎

目录 mysql---存储引擎 功能&#xff1a; mysql的存储引擎分类 MYISAM和INNODB做个对比 MYISAM 在磁盘上有三个文件&#xff1a; MYISAM的特点&#xff1a; 支持的存储格式: INNODB innodb的特点 使用场景&#xff1a; 三个文件&#xff1a; 行锁 表锁 排他锁 …

uniapp原生插件之安卓文件操作原生插件

插件介绍 安卓文件操作原生插件&#xff0c;读写文件&#xff0c;文件下载等&#xff0c;支持读取移动设备路径等外部存储设备路径&#xff0c;如U盘路径 插件地址 安卓文件操作原生插件 - DCloud 插件市场 超级福利 uniapp 插件购买超级福利 详细使用文档 uniapp 安卓文…

互联网医院|湖南互联网医院|智慧医疗改善就医服务

互联网医院系统&#xff0c;是指利用互联网技术和远程医疗技术&#xff0c;提供在线就诊、咨询、诊断和治疗等医疗服务的一种医疗模式。互联网医院系统实际上与医院的HIS系统很相似&#xff0c;是侧重服务于线上问诊的专业HIS&#xff0c;包含传统HIS的基本模块&#xff0c;如挂…

VS Code 开发 Spring Boot 类型的项目

在VS Code中开发Spring Boot的项目&#xff0c; 可以导入如下的扩展&#xff1a; Spring Boot ToolsSpring InitializrSpring Boot Dashboard 比较建议的方式是安装Spring Boot Extension Pack&#xff0c; 这里面就包含了上面的扩展。 安装方式就是在扩展查找 “Spring Boot…

【工具】【IDE】Qt Creator社区版

Qt Creator社区版下载地址&#xff1a;https://download.qt.io/archive/qt/ 参考&#xff1a;https://cloud.tencent.com/developer/article/2084698?areaSource102001.8&traceIduMchNghqp8gWPdFHvSOGg MAC安装并配置Qt&#xff08;超级简单版&#xff09; 1.安装brew&…

精品Python手机选购决策数据的分析与可视化大屏购物商城-爬虫

《[含文档PPT源码等]精品基于Python的手机选购决策数据的分析与可视化-爬虫》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;python 使用框架&#xff1a;Django …

2023-mac rz sz 安装

之前安装过一次&#xff0c;没问题&#xff0c;这次按照之前教程装了就不管上传下载都会卡住&#xff1b; step1: brew install lrzsz step2&#xff1a;在/usr/local/bin 路径下配置两个sh,之前从网上找到的直接用都不对&#xff0c;下面这个是调试过的正式可用的 iterm2…

堆叠注入 [GYCTF2020]Blacklist1

打开题目 判断注入点 输入1&#xff0c;页面回显 输入1 页面报错 输入 1 # 页面正常&#xff0c;说明是单引号的字符型注入 我们输入1; show databases; # 说明有6个数据库 1; show tables; # 说明有三个表 我们直接查看FlagHere的表结构 1;desc FlagHere&#xff1b;# 发…

『PyQt5-基本控件』| 16 什么是屏幕坐标系?

16 什么是屏幕坐标系? 1 什么是屏幕坐标系?2 相关概念3 代码实现4 获取窗口坐标4.1 直接获取4.2 通过坐标系获取4.3 获取Frame坐标1 什么是屏幕坐标系? 2 相关概念 屏幕坐标系,即窗口相对于屏幕的坐标。屏幕左上角坐标称为原点坐标(0,0);窗口的坐标,即窗口的左上角相对…

uniapp在APP端使用swiper进行页面不卡顿滑动

uniapp在APP端使用swiper进行页面会卡顿&#xff0c;主要是渲染的数据有点多&#xff0c;这里只渲染三个数据就不好那么卡顿了&#xff0c;每次滑动后更新数据 <view><swiper change"changePoint" circular :disable-touch"disableTouch"><…

速卖通新卖家有必要测评吗?

大家都知道通过测评可以提升产品的转化率&#xff0c;提升产品的销量&#xff0c;那么做速卖通的卖家有必要测评吗&#xff1f; 测评就是类似于国内电商的补单&#xff0c;而一个类目里面竞争很大很卷的话&#xff0c;不去补销量来提升产品的权重&#xff0c;凭借着平台给的自…

静态链表的定义与实现(数据结构与算法)

1. 静态链表 用数组的方式实现的链表 单链表&#xff1a; 各个结点在内存中星罗棋布、散落天涯 静态链表&#xff1a;分配一整片连续的内存空间&#xff0c; 各个结点集中安置。 1.1 静态链表的优点 不需要像动态链表那样频繁地进行内存分配和释放&#xff0c;可以节省内存…

2010年408计网

下列选项中, 不属于网络体系结构所描述的内容是&#xff08;C&#xff09;A. 网络的层次B. 每层使用的协议C. 协议的内部实现细节D. 每层必须完成的功能 本题考查网络体系结构的相关概念 再来看当今世界最大的互联网&#xff0c;也就是因特网。它所采用的TCP/IP 4层网络体系结…

Java自学第2课:Java语言基础知识要点

1 Java主类结构 任务&#xff1a;创建新项目名为item&#xff0c;包名为number&#xff0c;类名为first。 1.1 包声明 不指定包时&#xff0c;默认就是工程名&#xff0c;指定后&#xff0c;类文件可以分类了&#xff0c;是这意思吧。包就大概等于一个文件夹。而且在类文件中…

PS学习笔记合集

2.一些快捷键 一、放大快捷键 Ctrl&#xff1a;在画布中点击一次&#xff0c;即可放大一次&#xff0c;可多次点击。 CtrlShift&#xff1a;在画布中点击一次&#xff0c;即可放大到适合窗口大小。 CtrlAlt&#xff1a;在画布中点击一次&#xff0c;即可放大到适合窗口大小&a…

爱写bug的小邓程序员个人博客

博客网址: http://www.006969.xyz 欢迎来到我的个人博客&#xff0c;这里主要分享我对于前后端相关技术的学习笔记、项目实战经验以及一些技术感悟。 在我的博客中&#xff0c;你将看到以下主要内容&#xff1a; 技术文章 我将会分享我在学习前后端技术过程中的一些感悟&am…

基于单片机的可穿戴个人健康监测仪-智能手环

收藏和点赞&#xff0c;您的关注是我创作的动力 文章目录 概要 一、方案的设计与论证2.1设计任务及要求2.2 模块技术和方法综述2.3 设计可能遇到的困难 二、 系统总体框架3.1 硬件设计 三 软件部分4.1 主程序流程框 四、 结论五、 文章目录 概要 近几年智能化的不断发展&#…

JavaEE平台技术——预备知识(Web、Sevlet、Tomcat)

JavaEE平台技术——预备知识&#xff08;Web、Sevlet、Tomcat&#xff09; 1. Web基础知识2. Servlet3. Tomcat并发原理 1. Web基础知识 &#x1f192;&#x1f192;上个CSDN我们讲的是JavaEE的这个渊源&#xff0c;实际上讲了两个小时的历史课&#xff0c;给大家梳理了一下&a…

计算机组成与结构-计算机体系结构

计算机体系结构 指令系统 Flynn分类法 SISD&#xff08;单指令流单数据流&#xff09; 结构 控制部分&#xff1a;一个处理器&#xff1a;一个主存模块&#xff1a;一个 代表 单处理器系统 SIMD&#xff08;单指令流多数据流&#xff09; 结构 控制部分&#xff1a;一个处理…