顺序表(1) 基础(详解+学习历程)

一、前言

顺序表是数据结构的一种。数据结构是计算机存储、组织数据的一种方式。

数据结构中一种称为线性结构的逻辑结构主要是对线性表的学习,线性表包含顺序表。线性表是对一类事物的集合的统称;

线性表不一定有物理结构,但是一定有逻辑结构;顺序表含有物理结构,也含有逻辑结构;

含有物理结构就是那一类事物实际上是按照一种特定的有序的方式排列,而含有逻辑结构是人为可以想象成这类事物是按照一定顺序排列的。举例(一类事物):有几种水果,它们可以被称为线性表。为什么呢?最开始是杂乱无章地摆放在桌子上面,可知是没有物理结构,但是我们想着这一类事物都是水果,(香蕉、苹果、菠萝、橙子······)我们自然就把他们归为一类并且常常在脑海中把这几种水果按照先后顺序给想象出来,这种可以想象出来的可被赋予一种排列方式的事物的集合我们就说它们具有逻辑结构。

而顺序表是线性表的一种,它这两种结构都具有,是因为顺序表底层是数组。我们知道,数组在内存上面的开辟方式以及地址都是连续的,它本身就是一种物理结构。

顺序表相比于数组,可以更简单地对数据进行增删查改,顺序表分为静态顺序表和动态顺序表,这里介绍动态顺序表。

二、顺序表实现对数据增删查改

首先对注意事项和实现功能的函数有个基本认识

//顺序表#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int SeqDatatype;typedef struct SeqList
{SeqDatatype* arr;int size;int capacity;
}SL;//初始化顺序表
void SeqInit(SL* ps);//销毁顺序表
void SeqDestroy(SL* ps);//顺序表尾插
void SeqPushBack(SL* ps, SeqDatatype x);//申请空间
void SeqCheckSpace(SL* ps);//打印顺序表的元素
void SeqPrint(SL* ps);//顺序表头插
void SeqPushFront(SL* ps,SeqDatatype x);//顺序表尾删
void SeqPopBack(SL* ps);//顺序表头删
void SeqPopFront(SL* ps);//指定位置前插入数据
void SeqInsert(SL* ps, int pos, SeqDatatype x);//删除指定位置的数据
void SeqErase(SL* ps, int pos);//寻找数据(以下标的形式返回)
int SeqFind(SL s,SeqDatatype x);

对上述代码逐行解释 

typedef int SeqDatatype;

 这里将int重定义起了一个别名SeqDatatype,表示这是顺序表里面的数据类型;这样做的原因是简化修改顺序表数据类型的步骤,(例如要改成char类型,这样写就不用在后面的代码里面逐行修改,只用在此行代码将int改为char)

typedef struct SeqList
{SeqDatatype* arr;int size;int capacity;
}SL;

这里是定义顺序表的结构,首先它是动态的,那么就只需要定义SeqDatatype* arr,这样可以在后面需要空间时利用动态开辟函数进行动态开辟(倘若是静态的,那么就要定义为SeqDatatype arr[N])N是一个具体数值,代表你定义的顺序表能存储的数据个数,也就是顺序表的长度,这样写将顺序表长度写死了)

size表示的是当前顺序表的含数据的个数;capacity表示顺序表能够容纳的最大数据个数。

typedef只是将顺序表这个定义基于结构体的数据结构起了一个别名 SL。

1、 初始化顺序表

//初始化
void SeqInit(SL* ps)
{ps->arr = NULL;ps->size = ps->capacity = 0;
}

对顺序表的初始化很简单,将要进行动态开辟的地址先置为NULL ,将顺序表的大小和容量置为0;

2、顺序表的尾插

//尾插
void SeqPushBack(SL* ps, SeqDatatype x)
{assert(ps);SeqCheckSpace(ps);ps->arr[ps->size++] = x;
}

尾插是在顺序表的末尾插入数据,这涉及到顺序表的修改,故传参时需要传地址,x表示要尾插的数据的数值;assert是对传过来的顺序表的地址进行断言,如果传过来的地址是空的,那么就会报错;SeqCheckSpace是一个函数,这个函数的功能就是顺序表容量不够时进行动态开辟的,下面会具体介绍;最后一行代码是先将下标为size处的置为要尾插的数值,我们知道,size相当于是一个数组的大小,但是它同时可以表示为数组最后一个元素之后假象的一个元素的下标(例如arr[10]表示有10个数据,但是第十个数据的下标是9,在尾部添加数据时就要在下标为时的地方添加数据)而后置++表示这个操作结束之后把size的数值加一,这样就可以实时跟进顺序表的大小了;

可是这样空间不够就越界了吗?下面的SeqCheckSpace就是来解决这个问题的

3、容量不够时动态开辟空间

//申请空间
void SeqCheckSpace(SL* ps)
{if (ps->size == ps->capacity){SeqDatatype Newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SeqDatatype* tmp = (SeqDatatype*)realloc(ps->arr, Newcapacity * sizeof(SeqDatatype));if (tmp == NULL){perror("realloc failed");exit(1);}//走到这里说明开辟成功ps->arr = tmp;ps->capacity = Newcapacity;}
}

判断条件是顺序表容量等于大小;这里的动态开辟函数为realloc,但是要创建一个临时变量去接收,这是因为realloc开辟可能会存在失败的情况(后面空间不够,返回NULL) 这个时候若用arr去接收则会使得原顺序表的的存储数据的数组地址被破坏;此时在这里使用一个if条件的判断,如果开辟失败那么就终止,还不会使得顺序表被破坏;如果开辟成功那么就让pa->arr=tmp,最后让链表的容量赋值为Newcapacity;

4、顺序表的头插

//头插
void SeqPushFront(SL* ps, SeqDatatype x)
{assert(ps);SeqCheckSpace(ps);for (int i = ps->size; i >= 1; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[0] = x;ps->size++;
}

顾名思义,头插就是在顺序表的头部插入数据,但是顺序表底层是数组,我们只能直接做像尾插一样在数组后面增加数据的操作,头插却不能;那么怎么做呢?同样的先判断顺序表的大小和容量是否一样,一样则说明要开辟;之后可以依次把数据向后移动一个位置,使得下表为0的位置可以被赋值为x,并且此时还不会造成原数据被覆盖的问题;值得注意的是往后移动是从后面开始移起,若是先移动下标为0的数据,那么下标为1的数据就被覆盖了,此时,再想做后移的操作就无法得到原来数据了。同理,移动数据并且给arr[0]赋值之后让size++,实时跟进;

5、顺序表的尾删

//尾删
void SeqPopBack(SL* ps)
{assert(ps && ps->size);ps->size--;
}

尾删很简单,只需要将size--,这时顺序表的大小就减了1,虽然没有对顺序表的数据有什么直接的操作,但是间接地使得顺序表地最后一个数据无法被访问,相当于在尾部删除了一个数据;值得注意的是,此时的assert断言还要加上ps->size,因为如果顺序表没有数据,就无法进行删除数据的操作。

6、顺序表的头删

//头删
void SeqPopFront(SL* ps)
{assert(ps && ps->size);for (int i = 0; i < ps->size-1; i++){ ps->arr[i] = ps->arr[i + 1];}ps->size--;
}

头删也是采用移动的方式,从第一个数据开始,往前移动,这样使得数据不会被覆盖,最后一个数据虽然还保留着,只需要将size--,这个时候同尾删的道理一样,最后就实现了头删的操作;

7、指定位置前插入数据

//指定位置前插入数据
void SeqInsert(SL* ps, int pos, SeqDatatype x)
{assert(ps);SeqCheckSpace(ps);for (int i = ps->size ; i>pos ; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;ps->size++;
}

pos表示下标,我们要在这个下标前的一个下标的位置插入数据,将从pos起以后的数据都向后移动一个位置,使得pos的位置被空出来,注意是从最后一个数据开始移动起,保证数据不会被覆盖丢失,最后在下标为pos的位置赋值为x,再将size++ ;

8、删除指定位置的数据

//删除指定位置的数据
void SeqErase(SL* ps, int pos)
{assert(ps && ps->arr);assert(pos >= 0 && pos < ps->size);for (int i = pos;i<ps->size-1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}

和头删同理,只不过是改变了移动的起点,但是要注意的是,此时的第二个断言表示删除的数据要在有效下标之间,从pos之后的一个位置起,并且从前往后向前移动一个位置,最后size--;

9、查找顺序表中的数据


//寻找数据
int SeqFind(SL s,SeqDatatype x)
{for (int i = 0; i < s.size; i++){if (x == s.arr[i]){return i;}}return -1;
}

查找数据是通过返回该数据下标是否成功的方式实现的,如果找得到那么就返回这个数据的下标,如果找不到就返回一个非下标值(负数)-1,实现方式是遍历顺序表里面的数据,看有没有等于x的;

完。

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

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

相关文章

Docker 安装迅雷NAS

一、前言 在本文之前&#xff0c;博主在家用服务器 CentOS 上使用的下载方案是 Aria2 和其前端面板 Ariang. 所下载的资源大多数是 BT 资源&#xff0c;奈何 Aria2 对 BT 资源的下载速度实在堪忧&#xff0c;配置 BT 服务器效果不佳且费时。每次都将 BT 资源云添加至迅雷云盘&…

NLP - Softmax与层次Softmax对比

Softmax Softmax是神经网络中常用的一种激活函数&#xff0c;用于多分类任务。Softmax函数将未归一化的logits转换为概率分布。公式如下&#xff1a; P ( y i ) e z i ∑ j 1 N e z j P(y_i) \frac{e^{z_i}}{\sum_{j1}^{N} e^{z_j}} P(yi​)∑j1N​ezj​ezi​​ 其中&#…

Github与本地仓库建立链接、Git命令(或使用Github桌面应用)

一、Git命令&#xff08;不嫌麻烦可以使用Github桌面应用&#xff09; git clone [] cd [] git branch -vv #查看本地对应远程的分支对应关系 git branch -a #查看本地和远程所有分支 git checkout -b [hongyuan] #以当前的本地分支作为基础新建一个【】分支,命名为h…

windows内置的hyper-v虚拟机的屏幕分辨率很低,怎么办?

# windows内置的hyper-v虚拟机的屏幕分辨率很低&#xff0c;怎么办&#xff1f; 只能这么大了&#xff0c;全屏也只是把字体拉伸而已。 不得不说&#xff0c;这个hyper-v做的很烂。 直接复制粘贴也做不到。 但有一个办法可以破解。 远程桌面。 我们可以在外面的windows系统&…

python解析Linux top 系统信息并生成动态图表(pandas和matplotlib)

文章目录 0. 引言1. 功能2.使用步骤3. 程序架构流程图结构图 4. 数据解析模块5. 图表绘制模块6. 主程序入口7. 总结8. 附录完整代码 0. 引言 在性能调优和系统监控中&#xff0c;top 命令是一种重要工具&#xff0c;提供了实时的系统状态信息&#xff0c;如 CPU 使用率、内存使…

0/1背包问题总结

文章目录 &#x1f347;什么是0/1背包问题&#xff1f;&#x1f348;例题&#x1f349;1.分割等和子集&#x1f349;2.目标和&#x1f349;3.最后一块石头的重量Ⅱ &#x1f34a;总结 博客主页&#xff1a;lyyyyrics &#x1f347;什么是0/1背包问题&#xff1f; 0/1背包问题是…

CFS三层内网渗透——第二层内网打点并拿下第三层内网(三)

目录 八哥cms的后台历史漏洞 配置socks代理 ​以我的kali为例,手动添加 socks配置好了&#xff0c;直接sqlmap跑 ​登录进后台 蚁剑配置socks代理 ​ 测试连接 ​编辑 成功上线 上传正向后门 生成正向后门 上传后门 ​内网信息收集 ​进入目标二内网机器&#xf…

小程序分包加载、独立分包、分包预加载等

一、小程序分包加载 小程序的代码通常是由许多页面、组件以及资源等组成&#xff0c;随着小程序功能的增加&#xff0c;代码量也会逐渐增加&#xff0c; 体积过大就会导致用户打开速度变慢&#xff0c;影响用户的使用体验。分包加载是一种小程序优化技术。将小程序不同功能的代…

如果在已经打开的网页里面,我点击了一个链接,这个链接在新的标签页打开,如何能得到新的标签页其返回的数据收发数据。

要在已打开的网页中点击一个链接并在新标签页中打开&#xff0c;然后捕获新标签页中的所有HTTP请求和响应&#xff0c;你可以使用Selenium库结合selenium-wire插件。下面是一个示例代码&#xff0c;展示了如何实现这一功能&#xff1a; python import json from selenium imp…

【微信小程序开发实战项目】——花店微信小程序实战项目(4)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

Nginx的安装与配置 —— Linux系统

一、Nginx 简介 1.1 什么是 Nginx Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;在BSD-like 协议下发行。其特点是占有内存少&#xff0c;并发能力强&#xff0c;事实上nginx的并发能力在同类型的网页服务…

Linux系统部署MongoDB开源文档型数据库并实现无公网IP远程访问

文章目录 前言1. 安装Docker2. 使用Docker拉取MongoDB镜像3. 创建并启动MongoDB容器4. 本地连接测试5. 公网远程访问本地MongoDB容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 &#x1f4a1; 推荐 前些天发现了一个巨牛的人工智能学习网站&am…

现代农业利器:土壤检测仪器的应用与未来

在现代农业发展的浪潮中&#xff0c;土壤检测仪器以其精准、高效的特点&#xff0c;成为了农业生产的得力助手。这些看似不起眼的设备&#xff0c;实际上在保障农产品质量、提高农业生产效率方面发挥着举足轻重的作用。 一、土壤检测仪器&#xff1a;现代农业的“眼睛” 土壤检…

Vector的扩容过程是怎样的

Vector的扩容过程在C中是一个动态调整内存空间以容纳更多元素的过程。这一过程主要发生在向Vector中添加元素时&#xff0c;如果当前Vector的容量不足以容纳新元素&#xff0c;就会触发扩容操作。以下是Vector扩容过程的详细步骤&#xff1a; 扩容机制 判断是否需要扩容&…

记录第一次写脚本

使用csh语言&#xff0c;Linux系统操作的 写和执行csh&#xff08;C Shell&#xff09;脚本不需要额外的软件&#xff0c;只需要一个支持csh的终端环境。 1.检查是否安装了C Shell 在终端terminal运行以下命令 which csh 如果返回路径&#xff0c;比如/bin/csh&#xff0c…

SpringBoot 启动流程六

SpringBoot启动流程六 这句话是创建一个上下文对象 就是最终返回的那个上下文 我们这个creatApplicationContext方法 是调用的这个方法 传入一个类型 我们通过打断点的方式 就可以看到context里面的东西 加载容器对象 当我们把依赖改成starter-web时 这个容器对象会进行…

STM32-HAL-FATFS(文件系统)(没做完,stm32f103zet6(有大佬的可以在评论区说一下次板子为什么挂载失败了))

1STM32Cube配置 1-1配置时钟 1-2配置调试端口 1-3配置uart 1-4配置SDIO&#xff08;注意参数&#xff09;&#xff08;其中他的初始化的异常函数给注释&#xff0c;SD卡文件写了&#xff09; 配置了还要打开中断和DMA可在我的其他文章中看一样的 1-5配置FatFs (只改了图选中…

java中响应式编程:@FunctionalInterface用法实例

在Java中&#xff0c;Function<T, R>接口是Java 8引入的函数式接口之一&#xff0c;主要用来代表一个输入参数并产生一个结果的函数。它是响应式编程和函数式编程风格的重要组成部分&#xff0c;特别是在处理流&#xff08;Stream&#xff09;和异步操作时非常有用。 Fu…

QT c++函数模板与类模板的使用

QT c类模板的使用 #pragma once#include <QtWidgets/QMainWindow> #include "ui_QtWidgetsApplication5.h"class QtWidgetsApplication5 : public QMainWindow {Q_OBJECTpublic:QtWidgetsApplication5(QWidget *parent nullptr);~QtWidgetsApplication5();te…

Arthas实战(4)- 线程死锁问题排查

一、 准备测试应用 新建一个 SpringBoot应用&#xff0c;写一段线程死锁的代码&#xff1a; GetMapping("/threadLock") public void threadLock() {Thread thread1 new Thread(() -> {synchronized (resource1) {System.out.println(Thread.currentThread().g…