【数据结构】顺序表 | 详细讲解

在计算机中主要有两种基本的存储结构用于存放线性表:顺序存储结构和链式存储结构。本篇文章介绍采用顺序存储的结构实现线性表的存储。

顺序存储定义

线性表的顺序存储结构,指的是一段地址连续的存储单元依次存储链性表的数据元素。

线性表的(^{a_1{}}^{a_2{}}……^{a_n{}})的顺序存储示意图如下:

就比如说,在大学期间,我们同宿舍的有一个同学,人特别老实、热心,我们时常会让他帮我们去图书馆占座,他总是答应,你想想,我们一个宿舍连他共有九个人,这其实明摆着是欺负人的事。他每次一吃完早饭就冲去图书馆,挑一个好地儿,把他的书包里的书,一本一本地按座位放好,若书包里的书不够,他会把他的饭盒、水杯、水笔都用上,长长一排,九个座位硬是被他给占了,后来有一次因占座的事情弄得差点都要打架。

顺序存储方式

线性表的顺序存储结构,说白了,和刚刚的例子一样,就是在内存中找了块地,通过占位的形式,把一定的内存空间给占了,然后把相同数据类型的数据元素依次存放在这块空地中。既然线性表的每个数据元素的类型都相同,所以可以用C语言(其他语言也相同)的一维数组来实现顺序存储结构,即把第一个数据元素存到数组下标为0的位置中,接着把线性表相邻的元素存储在数组中相邻的位置。

线性表中,我们估算这个线性表的最大存储容量,建立一个数组,数组的长度就是这个最大存储容量。随着数据的插入,我们线性表的长度开始变大,不过线性表的当前长度不能超过存储容量,即数组的长度

数据长度与线性表长度区别

注意哦,这里有两个概念“数据的长度”和“线性表的长度”需要区分一下。

数组的长度是存放线性表的存储空间的长度,在静态分配的一维数组中,存储分配后这个量是一般不变的。但在动态分配的一维空间中,是可以实现动态分配数组。

线性表的长度是线性表中数据元素的个数,随着线性表插入和删除操作的进行,这个量是变化的。

地址计算方法

由于我们数数都是从1开始数的,线性表的定义也不能免俗,起始也是1,可C语言中的数组是从0开始的,于是线性表的第i个元素是要存储在数组下标为i-1的位置,即数据元素的序号和存放它的数组下标之间存在对应的关系。

用数组存储顺序表意味着要分配固定长度的数组空间,由于线性表中可以进行插入和删除操作,因此分配的数组空间要大于等于当前线性表的长度。

存储器中的每一个存储单元都有自己的编号,这个编号称为地址。在前一个地址确定好之后,那么后面的位置都是可以计算的。由于每个数据元素,不管它是整形、实型还是字符型, 它都是需要占用一定的存储单元空间的。假设占用的是c个存储单元,那么线性表中第i+1个数据元素的存储位置和第i个数据元素的存储位置满足下列关系(LOC表示获得存储位置的函数)。

LOC(a_{i+1})=LOC(a_{i})+c

所以对于第i个数据元素a_{i}的存储位置可以由a_{1}推算得出:

LOC(a_{i})=LOC(a_{i})+(i-1)*c

地址计算公式,可以随时算出线性表中任意位置的地址,不管它是第一个还是最后一个,都是相同的时间。那么我们对每个线性表位置的存入或者取出数据,对于计算机来说都是相等的时间,也就是一个常数,因此用我们算法中学到的时间复杂度的概念来说,它的存取时间性能为O(1)。具有这一特点的存储结构称为随机存取结构。

顺序表的代码实现分析

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

顺序表一般可以分为:

  1. 静态顺序表:使用定长数组存储元素。
  2. 动态顺序表:使用动态开辟的数组存储。
//顺序表的静态存储
#define N 7
typedef int SLDataType;
typedef struct SeqList
{SLDataType array[N];//定长数组size_t size;        //有效数据的个数
}SL;//顺序表的动态存储
typedef int SLDataType;
typedef struct SeqList
{SLDataType* array; //指向动态开辟的数组size_t size;//有效数据个数size_t capacity;//容量空间的大小
}SL;

其实在平时以及以后的工作环境中,静态存储实践很少,因为不知道需要多少内存空间,N给大了不够用,N给小了浪费。静态顺序表只适合用于确定知道需要存多少数据的场景。所以在现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

顺序表的结构代码

typedef int SLDataType;
//顺序表的动态存储
typedef struct SeqList
{SLDataType* a; //指向动态开辟的数组size_t size;//有效数据个数size_t capacity;//容量空间的大小
}SL;

顺序表的初始化

在这个顺序表中有一个a数组,一个size是指有效数据的个数,一个capacity是容量空间的大小。对于size而言,size是有效数据的个数,而看作下标的话,那便是最后一个元素的下一个下标

在进行初始化是,要对数组以及顺序表结构体中的size以及capacity都进行初始化。

void SLInit(SL* psl)
{psl->a = NULL;psl->size = 0;psl->capacity = 0;
}

顺序表的销毁

起初,顺序表是一个空表,但是经过了一系列的增删改查之后就会存储一些数据,之后我们在销毁这个链表时,这个链表就是有内容的,所以在这里我们需要注意的是,销毁时需要断言一下这个顺序表是否为空,如果是空表的话,那还销毁什么。其次在销毁时,思路也很简单,无非就是让这个顺序表的几个变量都变为0。

void SLDestory(SL* psl)
{assert(psl);if (psl->a != NULL){free(psl->a);psl->a = NULL;psl->size = 0;psl->capacity = 0;}
}

顺序表的遍历打印

遍历打印的思路极其类似于数组的打印,利用下标即可。下标是从零开始的,且size是有效数据的个数即最后一个数据的下一个下标,所以这里的循环条件就是i<size。

void SeqListPrint(SL* psl)
{assert(psl);int i = 0;for (i = 0; i < psl->size; i++){printf("%d ", psl->a[i]);}printf("\n");
}

顺序表的扩容 

因为在刚刚开始的时候,我们初始化size以及capacity都为0,所以为了防止每次扩容都是0,所以利用三目操作符来进行判断,如果这个capacity为0的话,那么就直接扩容4字节,其他的都是扩容它的两倍。

void SLCheckCapacity(SL* psl)
{assert(psl);int Newcapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;SLDataType* tmp = (SLDataType*)realloc(psl->a, Newcapacity * sizeof(SLDataType));if (tmp == NULL){perror("realloc fail\n");}psl->a = tmp;psl->capacity = Newcapacity;
}

顺序表的尾插

在添加数据时,不论是前插后插还是在指定位置插入,我们都需要为其判断是否有足够的空间,也就是判断是否需要扩容。扩容之后将数据插入顺序表中。

void SeqListPushBack(SL* psl, SLDataType x)
{assert(psl);SLCheckCapacity(psl);psl->a[psl->size - 1] = x;psl->size++;
}

这里注意一下,在尾插之后需要将size++。 

顺序表的头插

顺序表的头插相比较尾插就较难一些,因为需要将所有的数据都向后挪动一位。所以得再借助一个指针用来遍历。

void SeqListPushFront(SL* psl, SLDataType x)
{assert(psl);SLCheckCapacity(psl);int end = psl->size - 1;while (end >= 0){psl->a[end+1] = psl->a[end];end--;}psl->a[0] = x;psl->size++;
}

顺序表的尾删

尾删还是比较容易的,无非就是将size--,但是这里还要断言一下确保size是大于零的。

void SeqListPopBack(SL* psl)
{assert(psl);assert(psl->size > 0);psl->size--;
}

顺序表的头删

如果想要头删的那话,就是将后面的元素给覆盖到前一个,从前往后开始。

void SeqListPopFront(SL* psl)
{assert(psl);assert(psl->size > 0);int begin = 1;while (begin <= psl->size - 1){psl->a[begin - 1] = psl->a[begin];begin++;}psl->size--;
}

顺序表的查找

顺序表查找,在这个顺序表中是否有这个数组。其实这个也就是遍历,很简单利用下标。

int SeqListFind(SL* psl, SLDataType x)
{int i = 0;for (int i = 0; i < psl->size; i++){if (psl->a[i] == x){return i;}}
}

顺序表在pos位置插入x的数

这里我们需要断言一下这个是否为有效位置。 

void SeqListInsert(SL* psl, int pos, SLDataType x)
{assert(psl);assert(pos >= 0 && pos <= psl->size);SLCheckCapacity(psl);int end = psl->size - 1;while (end >= pos){psl->a[end + 1] = psl->a[end];end--;}psl->a[pos] = x;psl->size++;
}

顺序表删除pos位置上的值

void SeqListErase(SL* psl, int pos)
{assert(psl);assert(pos >= 0 && pos <= psl->size);int begin = pos + 1;while (begin <= psl->size - 1){psl->a[begin - 1] = psl->a[begin];begin++;}psl->size--;
}

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

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

相关文章

10-Docker-分布式存储算法

01-哈希取余算法分区 哈希取余分区&#xff08;Hash Modulus Partitioning&#xff09;是一种在分布式计算和数据存储中常用的分区策略&#xff0c;其目的是将数据或计算任务分配到多个节点或服务器上&#xff0c;以实现负载均衡和提高性能。这种分区策略的核心思想是使用哈希…

通过商品ID获取到京东商品详情页面数据,京东商品详情官方开放平台API接口,京东APP详情接口,可以拿到sku价格,销售价演示案例

淘宝SKU详情接口是指&#xff0c;获取指定商品的SKU的详细信息。SKU是指提供不同的商品参数组合的一个机制&#xff0c;通过不同的SKU来标识商品的不同组合形式&#xff0c;如颜色、尺寸等。SKU详情接口可以帮助开发者获取指定商品的SKU列表&#xff0c;以及每个SKU的属性、库存…

VirtualBox网络地址转换(NAT),宿主机无法访问虚拟机的问题

问题&#xff1a;NAT模式下&#xff0c;默认只能从内访问外面&#xff0c;而不能从外部访问里面&#xff0c;所以只能单向ping通&#xff0c;虚拟机的ip只是内部ip。 PS&#xff1a;桥接则是与主机公用网卡&#xff0c;有独立的外部ip。 解决&#xff1a;NAT模式可以通过配置 …

第十八章 Swing 程序设计

目录 概述 Swing常用窗体 JFrame 窗体 JDialog 对话框 JOptionPane 小型对话框 1.自定义对话框 2.确认框 3.输入框 4.通知框 常用布局管理器 null绝对布局 FlowLayout 流布局管理器 BorderLayout 边界布局管理器 GridLayout 网络布局管理器 常用面板 JPa…

Servlet作业小练习

一.题目 利用JavaBean实现用户类&#xff0c;包含姓名、性别、爱好&#xff0c;爱好需要用多选框 实现表单1进行获取数据&#xff0c;表单2显示获取结果。 利用Servlet实现逻辑代码 二.实现效果 三.具体实现 1.User实体类 package com.hjj.pojo.hw9;/*** author:嘉佳 Dat…

Halcon的相机内参外参的标定

halcon标定相机内参只能使用方向标定板和圆点标定板。并且方向标定板可也可用性极高。 1.打开halcon的标定助手&#xff0c;选择标定板的描述文件&#xff0c;填写标定板的厚度&#xff0c;根据相机选择像元的尺寸和镜头的焦距。如果已有相机内参&#xff0c;只标定外参&#…

设计模式(3)-结构型模式

结构型模式 结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式&#xff0c;前者采用继承机制来组织接口和类&#xff0c;后者釆用组合或聚合来组合对象。 由于组合关系或聚合关系比继承关系耦合度低&#xff0c;满足“合成复用原则…

计算机网络第4章-通用转发和SDN

引子&#xff1a; 在前面&#xff0c;我们将基于目的地转发的特征总结为两个步骤&#xff1a; 查找目的IP地址&#xff08;匹配&#xff09;&#xff0c;然后将分组发送到有特定输出端口的交换结构&#xff08;“动作”&#xff09;。 但是这种转发特征会带来许多问题&#…

webpack babel

构建工具 简介 当我们习惯了在node中编写代码的方式后&#xff0c;在回到前端编写html、css、js这些东西会感觉到各种的不便。比如&#xff1a;不能放心的使用模块化规范&#xff08;浏览器兼容性问题&#xff09;、即使可以使用模块化规范也会面临模块过多时的加载问题。我们…

【Excel】函数sumif范围中符合指定条件的值求和

SUMIF函数是Excel常用函数。使用 SUMIF 函数可以对报表范围中符合指定条件的值求和。 Excel中sumif函数的用法是根据指定条件对若干单元格、区域或引用求和。 sumif函数语法是&#xff1a;SUMIF(range&#xff0c;criteria&#xff0c;sum_range) sumif函数的参数如下&#xff…

多测师肖sir___接口自动化测试框架(python+request+unittest+ddt)

接口自动化测试框架 一、接口自动化测试框架&#xff08;pythonrequestunittestddt&#xff09; 首先我们新建一个新项目:名称zdh 二、在一个项目中&#xff1a;新建6个包 第一个包conf包用来填写配置参数、地址等 第二个包data 包用来存放测试用例的表格 第三个包report 包用来…

vscode 终端进程启动失败: shell 可执行文件“C:\Windows\System32\WindowsPower

vscode 终端进程启动失败: shell 可执行文件“C:\Windows\System32\WindowsPower 第一次用vscode&#xff0c;然后遇到这个问题&#xff0c;在设置里搜索 terminal.integrated.defaultProfile.windows 将这里的null改成"Command Prompt" 重启就可以了

Spring Cloud学习(五)【Feign 远程调用】

文章目录 RestTemplate方式调用存在的问题Feign的介绍定义和使用Feign客户端Feign 的自定义配置Feign 性能优化Feign 的最佳实践 RestTemplate方式调用存在的问题 先来看我们以前利用RestTemplate发起远程调用的代码&#xff1a; 存在下面的问题&#xff1a; 代码可读性差&am…

jmeter接口自动化部署jenkins教程

首先&#xff0c;保证本地安装并部署了jenkins&#xff0c;jmeter&#xff0c;xslproc 我搭建的自动化测试框架是jmeterjenkinsxslproc ---注意&#xff1a;原理是&#xff0c;jmeter自生成的报告jtl文件&#xff0c;通过xslproc工具&#xff0c;再结合jmeter自带的模板修改&…

5 Paimon数据湖之表数据查询详解

更多Paimon数据湖内容请关注&#xff1a;https://edu.51cto.com/course/35051.html 虽然前面我们已经讲过如何查询Paimon表中的数据了&#xff0c;但是有一些细节的东西还需要详细分析一下。 首先是针对Paimon中系统表的查询&#xff0c;例如snapshots\schemas\options等等这些…

Spring Cloud之多级缓存

目录 传统缓存 多级缓存 JVM进程缓存 Caffeine 缓存驱逐策略 实现进程缓存 常用Lua语法 数据类型 变量声明 循环使用 定义函数 条件控制 安装OpenResty 实现Nginx业务逻辑编写 请求参数解析 实现lua访问tomcat JSON的序列化和反序列化 Tomcat的集群负载均衡 …

stm32超声波测距不准的解决方法(STM32 delay_us()产生1us)

首先要说明一下原理&#xff1a;使用stm32无法准确产生1us的时间&#xff0c;但是超声波测距一定要依赖时间&#xff0c;时间不准&#xff0c;距离一定不准&#xff0c;这是要肯定的&#xff0c;但是在不准确的情况下&#xff0c;要测量一个比较准确的时间&#xff0c;那么只能…

python中的异常与模块

异常 为了能够让代码可以正常的运行下去&#xff0c;不会因为某个语句而让程序崩溃&#xff0c;所以我们就需要使用异常&#xff0c;异常的语法格式如下&#xff1a; try:可能出现异常的语句 except:出现异常之后的处理同时python也是支持捕获指定异常的 try:可能出现异常的…

说说对Fiber架构的理解?解决了什么问题?

一、问题 JavaScript引擎和页面渲染引擎两个线程是互斥的&#xff0c;当其中一个线程执行时&#xff0c;另一个线程只能挂起等待 如果 JavaScript 线程长时间地占用了主线程&#xff0c;那么渲染层面的更新就不得不长时间地等待&#xff0c;界面长时间不更新&#xff0c;会导…

NIO 笔记(二)Netty框架专题

【笔记来自&#xff1a;it白马】 Netty框架 前面我们学习了Java为我们提供的NIO框架&#xff0c;提供使用NIO提供的三大组件&#xff0c;我们就可以编写更加高性能的客户端/服务端网络程序了&#xff0c;甚至还可以自行规定一种通信协议进行通信。 NIO框架存在的问题 但是之…