数据结构:线性表顺序存储结构———顺序表

目录

顺序表的定义

初始化线性表

销毁线性表

求线性表的长度

判断是否为空表

插入数据元素

逻辑序号与物理序号的区别

删除数据元素

输出线性表

 按序号求线性表中的元素

按元素值查找

整体上创建顺序表

顺序表实验


线性表的顺序存储是把线性表中的所有元素按照其逻辑顺序依次存储到从计算机存储器中指定存储位置开始的一块连续的空间。

说直白点就是在内存中找了一块地,通过占位的形式,把一定的内存空间给占了,把你要存的数据元素按照顺序存进这块空间。仔细想想存进一维数组里是不是挺契合的,数组下标从0开始存第一数据,依次往后存,这样就保证了相邻数据元素存在了相邻的位置。

顺序表的定义

#include <stdio.h>
#define MaxSize 100
typedef  char ElemType;
typedef struct
{ElemType data[MaxSize];int length;
}SqList;

typedef struct{ ............} SqList ;是指把结构体类型名struct重命名为SqList,SqList是等价于struct的,SqList是类型名;

如果没有typedef,直接struct {.......}SqList,那么SqList是结构体变量,不是类型名。

开头定义了typedef char ElemType;,其实就是把char用ElemType表示了,ElemType其实就是char。

而#define MaxSize 100等价于,MaxSize=100;

所以ElemType data[MaxSize]其实就是一个大小为100,类型为char的数组,char data[100],用来存放数据元素

length是这个顺序表已经存了多少元素

初始化线性表

void InitList(Sqlist*& L)
{L = (SqList*)malloc(sizeof(SqList));L->length = 0;
}

用malloc函数给结构体SqList顺序表分配一个空间 ,以方便给顺序表存元素,结构体指针L去接收这片新开辟空间的首地址,结构体指针L访问结构体内部成员int length将其初始化为0。为什么顺序表长度length为0呢,这个length其实代表的是顺序表已经存了多少个元素,此时没有元素,所以为0,后续增加元素和删除元素操作会改length的值。

这个SqList *&L其实是结构体指针SqList *L,为什么会写得这么奇怪呢SqList*& L,这个&不是取地址的意思,而是引用的意思。c语言里传值传参,形参的改变不会影响实参,通过引用可以在函数内部修改指针L所指向的结构体,而不是仅仅修改指针本身的值。但是需要注意的是c语言没有引用,引用是c++里面的,所以有些纯c语言编译器可能会报错。

同样纯c语言编译器中,可以通过用二级指针SqList **L接收L这个指针变量的地址,这时也可以在函数内部修改指针L所指向的结构体。

销毁线性表

在上面操作中可以知道malloc分配了空间给线性表存元素,用指针L去接收,现在要销毁线性表怎么操作。直接把这一片空间全部销毁就行了,free(L)意思就是释放了L所指向的空间。

void DestroyList(SqList*& L)
{free(L);
}//销毁顺序表

求线性表的长度

 结构体SqList里成员length记录的就是线性表的长度直接输出就可以了

void lengtht(SqList*L)
{return L->length;
}

判断是否为空表

依旧要用到length,length代表的是顺序表已经存了多少个元素,增加元素和删除元素操作会改length的值。 删除就是length--,增加就是length++。如果为空表要么就是一个也没插进去,此时保持初始化length=0;要么就是全删完了,length--一直到length为0。

所以直接判断length是不是等于0就行

bool ListEmpty(SqList* L)
{if (L->length == 0){return 0;}elsereturn 1;
}

其实也可以直接写成这样

bool ListEmpty(SqList* L)
{return (L->length==0);
}

 返回的是布尔(bool)值,如果为真返回0,如果为假返回1。不支持c99标准的c语言编译器使用bool函数会报错。

插入数据元素

逻辑序号与物理序号的区别

我们日常生活中,数数都是从1开始的,比如排队买东西,排在首尾的就是第1位。而数组是从0开始的,排在首位的是第0位,而不是第1位。

bool ListInsert(SqList*& L, int i, ElemType e)
{if (i<1 || i>L->length + 1 || L->length == MaxSize)return false;i--;for (int j = L->length; j > i; j--)L->data[j] = L->data[j - 1];L->data[i] = e;L->length++;return true;
}

 bool ListInsert(SqList*& L, int i, ElemType e) 是指在第i个位置上插入元素e,这个i要注意是逻辑序号,对应数组0

1.首先要考虑这个位置是不是合适,它可以在第一个位置上插进去,也可以在最后的位置插进去,也就是length+1的位置

2.所以合理的范围应该是1<=i<=length+1,同时也应该注意存数据是往数组data[MaxSize]里存,数组是定长MaxSize大小的,超过MaxSize就越界了

写成代码就是这样了  if (i<1 || i>L->length + 1 || L->length == MaxSize)
                                      return false;  

如果在这个范围内那应该怎么存呢,举个例子现在有个一个长队买东西王二,李明,张三,李四,王五,我要插队插在李明后面张三前面,该怎么办。张三李四王五挨个往后退就能空出个位置让我插了

i--是将逻辑序号转变为了物理序号,毕竟是要存到数组里,所以还是用数组下标的物理序号好一点

for (int j = L->length; j > i; j--)
        L->data[j] = L->data[j - 1];

王二,李明,张三,李四,王五 这五个人对应的数组下标为0,1,2,3,4

从后往前挪动,此时L->length=5, L->data[5]=L->data[4]这就是把王五往后面挪了一个位置,从数组下标为4的位置放到下标为5的位置。

重复上述操作,数组下标为2的地方就空出来了,L->data[i] = e;把值写进去,然后length加1就行
                                                                               L->length++;

length是指数组里现在存了多少个元素

这是在中间插的,如果是在开头开始插,那么后面所有的都得往后挪,也是适用于这个循环的,要挪动后面n个元素,此时是最坏的情况

如果是在最后一个位置插元素,那么就直接L->data[i] = e;   L>length++; 

删除数据元素

bool ListDelete(SqList*& L, int i)
{if (i<1 || i>L->length || L->length == MaxSize){return false;}for (int j = i; j < L->length; j++){L->data[j] = L->data[j+1];}L->length--;return true;
}

删除数据元素与插入数据元素类似,都是不能超过1<=i<=length+1这个范围

所以i<1 || i>L->length || L->length == MaxSize过了这个范围,直接返回false就行

怎么做到删除呢,其实就是把后项的数据直接覆盖前一项的数据,然后把length减1就行,而不是释放i这个位置的空间。for (int j = i; j < L->length; j++)
                                     {
                                           L->data[j] = L->data[j+1];
                                       }
                                       L->length--;

从i开始,用i后面的数据覆盖i这个位置的数据

有些书上可能会把代码写成这样

bool ListDelete(SqList*& L, int i, ElemType &e)
{if (i<1 || i>L->length || L->length == MaxSize)return false;i--;e = L->data[i];for (int j =i; j<L->length; j++){L->data[j - 1] = L->data[j];}L->length--;return true;
}  

为什么要用e去保存要删除的值呢,使用e来记录删除的元素值的原因是为了给调用者提供该元素的值。在某些情况下,当从顺序表中删除一个元素时,可能会需要知道该元素的值,例如在需要检查被删除元素是否满足特定条件的情况下。通过将删除的元素值赋给e,函数调用者可以获得该值并进行进一步的处理或使用

如果你用不到的话,用上一个代码也行,不过考试还是用下面那个完整的代码

输出线性表

void DispList(SqList* L)
{if (ListEmpty(L))return;for (int i = 0; i < L->length; i++){printf("%c", L->data[i]);printf("\n");}
}

先判断是不是空,如果是空就return空,剩下的就是打印数组的值,这就不加多赘述了

 按序号求线性表中的元素

bool GetElem(SqList* L, int i, ElemType& e)
{if (i<1 || i>L->length)return false;e = L->data[i - 1];return true;
}

就是直接通过下标去访问数组,得到这个下标对应的值

bool GetElem(SqList* L, int i, ElemType& e) 意思是去找数组里第i个元素的值,并把值用e去接收。第i个元素对应的是逻辑序号,物理序号从0开始,要转变为数组下标的物理序号需要减1

按元素值查找

int LocateElem(SqList* L, ElemType e)
{ int i = 0;while(i < L->length && L->data[i] != e)i++;if (i >= L->length)return 0;elsereturn i + 1;
}

 while(i < L->length && L->data[i] != e)
        i++;

退出循环有两种条件,要么i>=L->length,意思是查找到表末尾都没有L->data[i]=e,那么就返回0;

要么退出循环就只是因为找到值了,因为此时是数组物理下标,但是一般要返回逻辑序号,所以要加1。

整体上创建顺序表

void CreateList(SqList*& L, ElemType a[], int n)
{int i = 0; int k = 0;L = (SqList*)malloc(sizeof(SqList));while (i<n){L->data[k] = a[i];i++; k++;}L->length = k;
}

实质上就是把要存的元素,事先先放进一个数组里,然后把这个数组整体存进data[MaxSize]数组中,也就是从一个数组存到另一个数组

  1. 初始化两个整数变量ik,都为0。这两个变量将用于遍历数组和顺序表。
  2. 使用malloc函数为顺序表分配内存。sizeof(SqList)返回顺序表结构的大小,确保足够的空间用于存储数据。
  3. 使用while循环遍历数组的前n个元素。循环条件是索引i小于n
  4. 在循环内部,将数组元素a[i]赋值给顺序表的当前位置L->data[k]。增加索引ik的值,以便在下一次迭代中处理下一个数组元素和顺序表位置。
  5. 将顺序表的长度设置为已复制的元素数量,即变量k的值

 你也可以不用这个,直接用ListInsert,把需要的元素一个一个地插进去

顺序表实验

如果你不知道对应的main函数里写什么,可以参考我之前写的实验

http://t.csdnimg.cn/leA25

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

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

相关文章

初识QT(上篇):What Qt

初识QT&#xff08;上篇&#xff09;&#xff1a;What Qt 前言 & 说明前言说明 初识QT1.1 QT的what1. 介绍2. 发展历程3. QT架构的主要内容4.QT的常用模块 1.2 QT的 why1. QT的核心机制 下篇笔记链接 前言 & 说明 前言 前言&#xff1a; 之前说要share的qt相关知识&am…

log4j rename方法

log4j日志切割 os.rename [rootzz test]# cat a2.py import os os.rename(a.txt,b.txt); [rootzz test]# cat a.txt 111111111111111111111 222222222222222222222 [rootzz test]# ls a1.py a2.py a.txt tst.log.1 tst.log.2 [rootzz test]# python ^C [rootzz test]# s…

【AI提示词人物篇】创新艺术未来,让科技改变想象空间

AI 绘画学习难度和练习技巧 学习绘画的技巧 学习能难度&#xff1a; 外貌特征&#xff1a;AI需要学习识别和理解各种外貌特征&#xff0c;如发型、肤色、眼睛颜色等。这可能需要大量的训练数据和复杂的模型架构。 镜头提示&#xff1a;AI需要学习理解不同镜头提示的含义&…

论文笔记--Learning Political Polarization on Social Media Using Neural Networks

论文笔记--Learning Political Polarization on Social Media Using Neural Networks 1. 文章简介2. 文章概括3. 相关工作4. 文章重点技术4.1 Collection of posts4.1.1 数据下载4.1.2 数据预处理4.1.3 统计显著性分析 4.2 Classification of Posts4.3 Polarization of users 5…

Microsoft Edge使用方法和心得

Microsoft Edge 是一款现代的网络浏览器&#xff0c;由微软开发&#xff0c;基于 Chromium 项目。Edge 提供了许多功能和工具&#xff0c;可以提高浏览体验。以下是使用 Microsoft Edge 的方法和一些心得&#xff1a; 基本使用方法 打开和关闭标签页: 点击窗口右上角的 “”…

5G边缘计算:解密边缘计算的魔力

引言 你是否曾想过&#xff0c;网络可以更贴心、更智能地为我们提供服务&#xff1f;5G边缘计算就像是网络的小助手&#xff0c;时刻待命在你身边&#xff0c;让数字生活变得更加便捷。 什么是5G边缘计算&#xff1f; 想象一下&#xff0c;边缘计算就像是在离你最近的一层“云…

SpringMVC:Ajax、拦截器、文件上传、文件下载

文章目录 SpringMVC - 06一、Ajax1. 概述2. Ajax 异步加载数据1. 单个数据2. 对象 3. 实践4. 总结 二、拦截器1. 概述2. 实现3. 实践4. 总结 三、文件上传&#xff1a;Upload1. 准备工作2. 步骤3. 效果 四、文件下载&#xff1a;Download1. 步骤2. 效果3. 总结 注意&#xff1a…

mac m1芯片 pytorch安装及gpu性能测试

pytorch 使用mac的m1芯片进行模型训练。 #小结&#xff1a;在数据量小和模型参数少&#xff0c;batch_size小时&#xff0c;cpu训练更快&#xff08;原因&#xff1a;每次训练时数据需要放入GPU中&#xff0c;由于batch_size小。数据放入gpu比模型计算时间还长&#xff09; 在…

Wav2Lip:准确生成一个唇语识别视频

最近小编在GitHub里面闲逛发现一个3年前的项目&#xff0c;里面的任务是AI生成唇语的&#xff0c;根据你输入的语音修改你输入的视频&#xff0c;使得你的视频能对的上你输入的语音。因为版本一直没有被维护&#xff0c;有一些python库太久无法安装&#xff0c;有一些还有冲突&…

mysql参数配置binlog

官网地址&#xff1a; MySQL :: MySQL Replication :: 2.6.4 Binary Logging Options and Variables 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. MySQL 复制 / ... / 二进制日志记录选项和变量 2.6.4 二进…

ChatGPT免费 | 8个免费使用GPT-4的方法

这篇文章为寻找免费使用GPT-4技术的读者提供了一份实用的指南。 每个推荐的平台都包括了简要的描述和链接&#xff0c;方便读者直接访问。 以下是根据你提供的内容&#xff0c;稍作整理的文章结构&#xff1a; 1. HuggingFace 描述: 提供GPT-4等多种语言模型的平台。 如何使用:…

前端性能优化二十:构建工具选型构建工具选型

(1). Grunt: ①. 最早的构建工具.②. 使用js写shell脚本的形式来处理开发过程中的代码压缩和合并工作.③. 一个项目需要定制多个小任务和引用多个插件:a. 如eslint代码检查,在配置文件写好eslint相关的配置任务.b. 其它类似写成多个小任务.c. grunt逐个运行每个任务.④. 弊端:…

【SPI和API有什么区别】

✅什么是SPI&#xff0c;和API有什么区别 ✅典型解析&#x1f7e2;拓展知识仓&#x1f7e2;如何定义一个SPI&#x1f7e2;SPI的实现原理 ✅SPI的应用场景SpringDubbo ✅典型解析 Java 中区分 API和 SPI&#xff0c;通俗的进: API和 SPI 都是相对的概念&#xff0c;他们的差别只…

装饰器模式(Decorator)

装饰器模式(Decorator Pattern)是一种结构型设计模式,用于动态地给一个对象添加额外的职责。装饰器提供了一个灵活的替代扩展功能的方案,相比继承更加灵活。 在Java中,装饰器模式通常涉及以下几个部分: 组件(Component):定义一个对象接口,可以给这些对象动态添加职责…

优化模型:MATLAB整数规划

一、整数规划介绍 1.1 整数规划的定义 若规划模型的所有决策变量只能取整数时&#xff0c;称为整数规划。若在线性规划模型中&#xff0c;变量限制为整数&#xff0c;则称为整数线性规划。 1.2 整数规划的分类 整数规划模型大致可分为两类&#xff1a; &#xff08;1&…

SQL进阶理论篇(二十):什么是SQL注入

文章目录 简介SQL注入的原理SQL注入的实例搭建sqli-labs注入环境实例一&#xff1a;猜测where条件判断查询语句的字段数获取当前数据库和用户信息获取MySQL中的所有数据库名称查询wucai数据库中的所有数据表查询heros数据表中的所有字段参考文献 简介 这节是纯兴趣篇了。 web…

less 查看文本时,提示may be a binary file.See it anyway?

解决办法 首先使用echo $LESSCHARSET查看less的编码 看情况设置less的编码格式(我的服务器上使用utf-8查看中文) 还要特别注意一下&#xff0c;Linux中存在的文本文件的编码一定要是utf - 8;&#xff08;这一步很关键&#xff09; 例如&#xff1a;要保证windows上传到Linux的…

Linux Shell 001-Bash简介

Linux Shell 001-Bash简介 本节关键字&#xff1a;Linux、Bash Shell、shell分类 相关指令&#xff1a;bash、sh、cat Shell的介绍 计算机只能认识&#xff08;识别&#xff09;机器语言(0和1)&#xff0c;如&#xff08;11000000 这种&#xff09;。但是&#xff0c;我们的…

力扣(leetcode)1148和1179题(MySQL)

1148.文章浏览I 题目链接&#xff1a;1148.文章浏览I 解答 # Write your MySQL query statement below select distinct author_id as id from Views where author_idviewer_id order by id;1179.重新格式化部门表 题目链接&#xff1a;1179.重新格式化部门表 解答 …

线程池构造方法的认识

线程池中构造方法的认识 文章目录 线程池中构造方法的认识corePoolSize (核心线程数)maximumPoolSize&#xff08;最大线程数&#xff09;keepAliveTime(非核心线程的空闲超时时间)TimeUnitworkQueuethreadFactoryRejectedExecutionHandler拒绝策略 标准库中提供了一个ThreadPo…