数据结构—顺序表(如果想知道顺序表的全部基础知识点,那么只看这一篇就足够了!)

2024-04-12 16:44

本文主要是介绍数据结构—顺序表(如果想知道顺序表的全部基础知识点,那么只看这一篇就足够了!),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        前言:学习完了C语言的基础知识点之后,我们就需要使用我们所学的知识来进一步对存储在内存中的数据进行操作,这时候我们就需要学习数据结构。而这篇文章为数据结构中顺序表的讲解。


✨✨✨这里是秋刀鱼不做梦的BLOG

✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客

那么我们废话不多说,直接开始讲解。

先让我们看一下讲解的大体内容有哪些:

目录

1.初识顺序表

        (1)顺序表的定义

        (2)顺序表的特点

2.顺序表的分类

        【1】静态顺序表

        【2】动态顺序表

3.顺序表的功能

4.顺序表中各种功能的实现

        【1】 初始化顺序表中的数据。

        【2】 打印顺序表中的数据。

        【3】对顺序表进行尾插(末尾插入数据)。

        【4】对顺序表进行尾删(末尾删除数据)。

         【5】对顺序表进行头插(开头插入数据)。

      【6】 对顺序表进行头删(开头删除数据)。

          【7】 对顺序表查找数据。

        【8】对顺序表数据进行修改。

        【9】指定位置插入数据

        【10】删除指定位置数据

        【11】 销毁顺序表。


1.初识顺序表

在了解顺序表的定义之前,我们需要先了解一下什么是线性表:

线性表,全名为线性存储结构。使用线性表存储数据的方式可以这样理解,即“把所有数据用一根线儿串起来,再存储到物理空间中”

在了解完线性表的概念之后,我们在来看顺序表:        

        (1)顺序表的定义

数据结构在内存中的表示通常有两种形式,一种是顺序存储,另一种是链式存储。线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表的数据元素,我们把这种存储形式存储的线性表称为顺序表。

例如,使用顺序表存储集合 {1,2,3,4,5},数据最终的存储状态如图 1 所示:

由上图可知顺序表存储数据同数组非常接近。其实,顺序表存储数据使用的就是数组。       

        (2)顺序表的特点

1.  顺序表的逻辑结构和物理结构是一致的,都是连续的。

2.  顺序表中任意一个数据元素都可以随机存取,所以顺序表是一种随机存取的存储结构。

这样我们就初步的了解了顺序表。

2.顺序表的分类

        从上边我们已经了解到了顺序表存储数据使用的就是数组,而数组又分为了静态数组和动态数组,所以顺序表也顺其自然的分成了静态顺序表和动态顺序表。

我们直接使用代码来看一下两种顺序表的定义:

        【1】静态顺序表

//静态顺序表
#define SLDateType int
#define NUMBER 10
typedef struct SeqList
{SLDateType arr[NUMBER];int size;
}SL;

由上边的代码我们可以看到,静态顺序表由一个定长的数组和一个 int 类型的变量size组成(size的作用是用来记录该数组中的元素个数)。

        【2】动态顺序表

//动态顺序表
#define SLDateType int
typedef struct SeqList
{SLDateType* arr;int size;int capacity;
}SL;

由上边的代码我们可以看到,动态顺序表是由一个指针(该指针存放一个数组的地址,该数组可以使用一些方法使其长度发生变化),一个 int 类型的变量size(size的作用是用来记录该数组中的元素个数)和一个 int 类型的变量capacity组成(capacity用来记录数组的容量)。

注:当然在日常的使用或者工作中,我们大部分都是使用动态顺序表(相较于静态顺序表更加灵活)来存储数据并使用顺序表的一些功能来对数据进行操作的。

这样我们就了解了顺序表的分类和其它们的定义方式了。

3.顺序表的功能

        顺序表可以大致包含以下几个功能:

1. 初始化顺序表中的数据。

2. 打印顺序表中的数据。

3. 对顺序表进行尾插(末尾插入数据)。

4. 对顺序表进行尾删(末尾删除数据)。

5. 对顺序表进行头插(开头插入数据)。

6. 对顺序表进行头删(开头删除数据)。

7. 对顺序表查找数据。

8. 对顺序表数据进行修改。

9. 指定位置插入数据。

10. 删除指定位置数据。

11. 销毁顺序表。

这里我们只需要大致的了解顺序表又哪些功能就可以,下面我们会对这10个功能进行详细的讲解。

4.顺序表中各种功能的实现  

        接下来我们就开始对顺序表中的几个功能开始进行讲解(使用动态顺序表):

我们首先定义动态顺序表:

//动态顺序表
#define SLDateType int
typedef struct SeqList
{SLDateType* arr;int size;int capacity;
}SL;

        

        【1】 初始化顺序表中的数据。

我们直接使用代码来看一下:

//动态顺序表的初始化
void SLInit(SL* sl)
{assert(sl);sl->arr = NULL;sl->size = 0;sl->capacity = 0;
}

初始化顺序表时,我们先将数组长度设置为0(即为NULL,之后添加数据时在扩容),将元素个数和数组长度设置为0。

        【2】 打印顺序表中的数据。

我们直接使用代码来看一下:

//打印数据
void SLPrint(SL* sl)
{assert(sl);for (int i = 0; i < sl->size; i++){printf("%d ", sl->arr[i]);}printf("\n");
}

 打印数据只需要使用循环变量数组来打印就可以了。

        【3】对顺序表进行尾插(末尾插入数据)。

我们直接使用代码来看一下:

//向数据表的尾部插入数据
void SLPushBack(SL* sl, SLDateType n)
{//对传入的指针进行判断,判断是否为空指针assert(sl);//判断数组是否需要扩容if (sl->size == sl->capacity){//如果数组容量为0,则设置为5,如果不为0,则扩大为两倍int Newcapacity = sl->capacity = 0 ? 5 : 2 * (sl->capacity);SLDateType* temp = (SLDateType*)realloc(sl->arr, Newcapacity * sizeof(SLDateType));if (temp == NULL){perror("realloc is wrong");exit(1);}sl->arr = temp;temp = NULL;sl->capacity = Newcapacity;} //添加数据sl->arr[sl->size++] = n;
}

在上边的代码中我们发现,当数组满了之后,我们需要对数组进行扩容之后,在向数组中添加数据。   

  

        【4】对顺序表进行尾删(末尾删除数据)。

我们直接使用代码来看一下:

//删除顺序表尾部数据
void SLPopBack(SL* sl)
{//对传入的指针进行判断,判断是否为空指针assert(sl);//原来的数组中要有数据assert(sl->size);sl->size--;
}

对顺序表进行尾删的时候,我们根本不需要删除数组末尾的数据,我们只需要将记录元素个数的数减小1,这样我们在使用的时候就不会使用到末尾的数据了。       

         【5】对顺序表进行头插(开头插入数据)。

我们直接使用代码来看一下:

//向顺序表的头部插入数据
void SLPushFront(SL* sl, SLDateType n)
{//对传入的指针进行判断,判断是否为空指针assert(sl);//判断数组是否需要扩容if (sl->capacity == sl->size){//如果数组容量为0,则设置为5,如果不为0,则扩大为两倍int Newcapacity = sl->capacity = 0 ? 5 : 2 * (sl->capacity);SLDateType* temp = (SLDateType*)realloc(sl->arr, Newcapacity * sizeof(SLDateType));if (temp == NULL){perror("realloc is wrong");exit(1);}sl->arr = temp;temp = NULL;sl->capacity = Newcapacity;}//将所有的数据都往后移动一位for (int i = sl->size; i >=1 ; i--){sl->arr[i] = sl->arr[i-1];}//添加数据sl->arr[0] = n;sl->size++;
}

在进行对顺序表进行头插的时候,我们也需要判断数组是否可以添加一个数据,并且由于我们是头插,所以要将原来数组中所有的数据都往后移动一位

      【6】 对顺序表进行头删(开头删除数据)。

我们直接使用代码来看一下:

//删除顺序表头部数据
void SlPopFront(SL* sl)
{//对传入的指针进行判断,判断是否为空指针assert(sl);//原来的数组中要有数据assert(sl->size);//将除了第一个位置的其他位置的元素往前移动一位for (int i = 0; i<sl->size-1; i++){sl->arr[i] = sl->arr[i + 1];}sl->size--;
}

将除了第一个位置的其他位置的元素往前移动一位,这样就可以将第一位的数据进行覆盖掉,完成对顺序表进行头删的操作。  

          【7】 对顺序表查找数据。

我们直接使用代码来看一下:

//对顺序表查找数据
int SeqListFind(SL*sl, SLDateType n)
{//对传入的指针进行判断,判断是否为空指针assert(sl);  int i = 0;for (i = 0; i < sl->size; i++){if (sl->arr[i] == n){//找到则返回该值在数组中的下标return i;}}//没有查找到则返回-1return -1;  
}

我们遍历数组查找想要的数据就可以,如果没有找到,则返回-1。      

        

        【8】对顺序表数据进行修改。

我们直接使用代码来看一下:

//对顺序表数据进行修改
void SeqListModify(SL* sl, int pos, SLDateType x)
{//对传入的指针进行判断,判断是否为空指针assert(sl);  //原来的数组中要有数据assert(sl->size > 0);//检查pos下标的合法性assert(pos >= 0 && pos < sl->size); //修改pos下标处对应的数据sl->arr[pos] = x;  
}

总体的思路就是先判断是否可行后将对应位置的数据进行修改。     

        【9】指定位置插入数据

我们直接使用代码来看一下:

//在指定位置插入数据
void SeqInsert(SL* sl, int pos, SeqType n)
{//对传入的指针进行判断,判断是否为空指针assert(sl);//判断指定位置的合理性assert(pos >= 0 && pos <= sl->size);//判断是否需要扩容if (sl->size == sl->capacity){int newcapacity = (sl->capacity == 0 ? 5 : 2 * (sl->capacity));SeqType* temp = (SeqType*)realloc(sl, newcapacity * sizeof(SeqType));if (temp == NULL){perror("realloc fail");exit(1);}sl = temp;temp = NULL;sl->capacity = newcapacity;}//添加数据for (int i = sl->size - 1;i>=pos; i--){sl->arr[i + 1] = sl->arr[i];}sl->arr[pos] = n;sl->size++;
}

在指定位置插入数据时,我们需要判断位置的合理性,即是否是在可以插入的位置进行插入,判断完后,我们判断是否需要扩容,判断完后我们进行数据的插入。    

        【10】删除指定位置数据

我们直接使用代码来看一下:

//删除指定位置数据
void SeqListErase(SL* sl, int pos)
{//对传入的指针进行判断,判断是否为空指针assert(sl);//顺序表不能为空assert(sl->size > 0);  //检查pos下标的合法性assert(pos >= 0 && pos < sl->size);  //将pos位置后面的数据依次向前挪动一位,完成覆盖for (int i = pos + 1; i < sl->size; i++)  {sl->arr[i - 1] = sl->arr[i];}//存储的数据-1sl->size--;  
}

对于删除指定位置数据,我们只需要将指定位置数据后面的数据全部向前移动一位完成覆盖即可。        

        【11】 销毁顺序表。

我们直接使用代码来看一下:

//销毁顺序表
void SLDelete(SL* sl)
{//将创建的数据空间进行回收assert(sl);if (sl->arr){free(sl->arr);sl->arr = NULL;}sl->size = sl->capacity = 0;
}

从上边的代码中我们知道,我们开创的数组的空间是由malloc函数开辟的,所以在使用完顺序表之后要对该空间进行归还。


以上就是顺序表的全部内容了~~~

这篇关于数据结构—顺序表(如果想知道顺序表的全部基础知识点,那么只看这一篇就足够了!)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/897688

相关文章

浅析Spring如何控制Bean的加载顺序

《浅析Spring如何控制Bean的加载顺序》在大多数情况下,我们不需要手动控制Bean的加载顺序,因为Spring的IoC容器足够智能,但在某些特殊场景下,这种隐式的依赖关系可能不存在,下面我们就来... 目录核心原则:依赖驱动加载手动控制 Bean 加载顺序的方法方法 1:使用@DependsOn(最直

Python中你不知道的gzip高级用法分享

《Python中你不知道的gzip高级用法分享》在当今大数据时代,数据存储和传输成本已成为每个开发者必须考虑的问题,Python内置的gzip模块提供了一种简单高效的解决方案,下面小编就来和大家详细讲... 目录前言:为什么数据压缩如此重要1. gzip 模块基础介绍2. 基本压缩与解压缩操作2.1 压缩文

Spring如何使用注解@DependsOn控制Bean加载顺序

《Spring如何使用注解@DependsOn控制Bean加载顺序》:本文主要介绍Spring如何使用注解@DependsOn控制Bean加载顺序,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录1.javascript 前言2. 代码实现总结1. 前言默认情况下,Spring加载Bean的顺

从基础到进阶详解Pandas时间数据处理指南

《从基础到进阶详解Pandas时间数据处理指南》Pandas构建了完整的时间数据处理生态,核心由四个基础类构成,Timestamp,DatetimeIndex,Period和Timedelta,下面我... 目录1. 时间数据类型与基础操作1.1 核心时间对象体系1.2 时间数据生成技巧2. 时间索引与数据

安装centos8设置基础软件仓库时出错的解决方案

《安装centos8设置基础软件仓库时出错的解决方案》:本文主要介绍安装centos8设置基础软件仓库时出错的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录安装Centos8设置基础软件仓库时出错版本 8版本 8.2.200android4版本 javas

Java中JSON格式反序列化为Map且保证存取顺序一致的问题

《Java中JSON格式反序列化为Map且保证存取顺序一致的问题》:本文主要介绍Java中JSON格式反序列化为Map且保证存取顺序一致的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未... 目录背景问题解决方法总结背景做项目涉及两个微服务之间传数据时,需要提供方将Map类型的数据序列化为co

Linux基础命令@grep、wc、管道符的使用详解

《Linux基础命令@grep、wc、管道符的使用详解》:本文主要介绍Linux基础命令@grep、wc、管道符的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录grep概念语法作用演示一演示二演示三,带选项 -nwc概念语法作用wc,不带选项-c,统计字节数-

python操作redis基础

《python操作redis基础》Redis(RemoteDictionaryServer)是一个开源的、基于内存的键值对(Key-Value)存储系统,它通常用作数据库、缓存和消息代理,这篇文章... 目录1. Redis 简介2. 前提条件3. 安装 python Redis 客户端库4. 连接到 Re

SpringBoot基础框架详解

《SpringBoot基础框架详解》SpringBoot开发目的是为了简化Spring应用的创建、运行、调试和部署等,使用SpringBoot可以不用或者只需要很少的Spring配置就可以让企业项目快... 目录SpringBoot基础 – 框架介绍1.SpringBoot介绍1.1 概述1.2 核心功能2

Spring Boot集成SLF4j从基础到高级实践(最新推荐)

《SpringBoot集成SLF4j从基础到高级实践(最新推荐)》SLF4j(SimpleLoggingFacadeforJava)是一个日志门面(Facade),不是具体的日志实现,这篇文章主要介... 目录一、日志框架概述与SLF4j简介1.1 为什么需要日志框架1.2 主流日志框架对比1.3 SLF4