数据结构之手撕顺序表(讲解➕源代码)

这篇具有很好参考价值的文章主要介绍了数据结构之手撕顺序表(讲解➕源代码)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

0.引言

        在本章之后,就要求大家对于指针、结构体、动态开辟等相关的知识要熟练的掌握,如果有小伙伴对上面相关的知识还不是很清晰,要先弄明白再过来接着学习哦!

        那进入正题,在讲解顺序表之前,我们先来介绍线性表这个数据结构。

0.1 线性表

        线性表是 n个具有相同特性的数据元素组成的有限的序列。
        并且在逻辑上是一对一的,一个接着一个的。比如我们之前学过的数组,字符串等。

        相同特性:同一种数据类型
        有限:数据元素的个数是有限的

        常见的线性表:顺序表、链表、栈、队列、字符串等。

        我们在讲解数据结构的时候通常要先看它的逻辑结构和物理结构。

0.2 线性表的逻辑结构和物理结构

0.2.1 逻辑结构

        线性表的逻辑结构是线性结构,线性结构 是一条连续的直线,也就是说 线性表在逻辑上是连续的,比如我们在C语言学过的的数组(顺序表),指针(可以构成链表)。

数据结构之手撕顺序表(讲解➕源代码),数据结构,数据结构

数据结构之手撕顺序表(讲解➕源代码),数据结构,数据结构

        上图分别为顺序表链表,他们在逻辑结构上都是一个接着一个,连续的。但是在物理结构他们还依旧连续吗?让我们带着疑问往下走。

0.2.2 线性表的物理结构

        明确告诉大家,线性表在物理结构上不一定连续,因为我们可以构成线性表的结构有数组和指针,指针又被称作链式结构。

那什么时候是连续的?

当线性表是由数组构成时:物理结构连续

        线性表的物理结构一定连续,因为数组是一个一个挨着的空间,地址上是紧挨着的,所以是连续的。

如图:

数据结构之手撕顺序表(讲解➕源代码),数据结构,数据结构

什么时候又不是连续的呢?​​​​​​​

当线性表为链式结构时:物理结构不连续

         首先链式结构在逻辑上一定是连续的,因为我们可以通过指针就找到该指针对应的地址。
        但指针的地址不一定是连续的,我们可以这存一个,那存一个,通过指针给他们链接起来。

如图:

数据结构之手撕顺序表(讲解➕源代码),数据结构,数据结构

        当了解了线性表的物理结构和逻辑结构之后,就让我们一起学习第一种数据结构---顺序表吧!

1. 顺序表

1.1概念

        顺序表是 用一段物理地址连续的存储单元依次存储数据元素的线性结构,通常采用数组的形式存储。在数组上完成数据的增删查改。
        这是什么意思呢?首先顺序表是物理地址连续的,那物理地址连续,就应该是用数组的形式来存储,之后根据数组的性质进行数据的增加,删除,查找和更改。

        我们知道顺序表是由什么构成之后,让我们看看顺序表都分为哪几种吧!

1.2 顺序表的分类

        我们顺序表只分为静态顺序表和动态顺序表两种,下面我们会给大家展示这两种顺序表。

1.2.1 静态顺序表

        静态顺序表指的是利用定长数组来存储元素

//顺序表的静态存储
#define N 7 //顺序表一次开辟的空间个数
typedef int SLDataType; //将数据类型重命名,以便我们未来换用其他的数据类型
typedef struct SeqList
{
    SLDataType arr[N]; //定长数组
    size_t size; //有效的数据个数,size_t指的是无符号整型
}Seqlist;

数据结构之手撕顺序表(讲解➕源代码),数据结构,数据结构

        我们在使用静态顺序表的时候,只能每次开辟N个大小的空间,这也就要求我们在使用之前就要想好你要存放多少个数据,非常不灵活,没有办法做到你想插入几个数据的时候就插入几个数据,所以我们大多时候不使用静态顺序表,而是改用动态顺序表作为我们日常应用。

这也是我们常说的要适应大环境的需要,而不是一味不变。

1.2.2 动态顺序表

        动态顺序表:使用动态开辟的数组存储。在这里需要大家对动态开辟内存知识有一定的掌握。

1. 动态顺序表的定义

我们首先要明确自己需要什么

1.动态开辟的数组

2.有效的数据个数(你存入的数据个数)

3.数组的容量(开辟的空间大小)

        这三个数据是绑定一起的吧!因为你有数组,你才可以存入元素,你存入元素,你的有效的数据个数才会增加,而在你存入元素之前,你必须开辟空间,给数组一定的容量。

        所以我们在这里用了结构体包含三者,目的就是能让他们三个绑定,便于大家完成代码。

        未来大家如果要创造更多的关系数据(具有关系的数据),强烈推荐使用结构体来给它们打包。

typedef int SLDataType; //数据类型的重命名,方便更改数据类型
typedef struct SeqList
{
    SLDataType *a; //指向动态开辟的数组
    int size;     //有效的数据个数
    int capacity; //动态开辟的数组的容量
}SL;
2.初始化

        在初始化这里,我们要给数组开辟一定的空间,方便在插入数据的时候进行操作,但是在这里,我们只是开辟空间,并没有给数组插入元素,所以我们的有效元素个数size就是0,容量就是你开辟的空间个数。

        我们一般开辟空间第一次给4个数据类型的空间。但是这个没有定性要求(固定的要求)你想开辟几个就开辟几个。

void SLInit(SL*ps) //初始化
{
    ps->a = (SLDataType*)malloc(sizeof(SLDataType)*4);
    if(ps->a == NULL)
    {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    ps ->size = 0;
    ps ->capacity = 4;
}
3.退出程序时的销毁

注意⚠️⚠️⚠️⚠️⚠️⚠️

        这个函数有讲头了,我们要记住一点,凡是通过动态开辟的空间,一定要进行销毁释放,因为由malloc,realloc等开辟的空间是在堆上开辟的,无法自动释放掉。我们没有这个函数,那么就会造成内存的泄漏。

        那么如何释放呢?

        free函数来释放开辟的空间,谁被开辟free谁,之后要将free的对象置为空就OK啦!不要忘了你释放空间之后,有效的数据元素是0了哈,容量也是0.

void SLDestroy(SL*ps) //退出时销毁
{
    free(ps->a);
    ps->a = NULL;
    ps->size = 0;
    ps->capacity = 0;
}
4.扩容

        这个函数是解决当你第一次开辟的空间不够的问题,就要用到这个函数来进行扩容,扩容一般是扩原来空间的二倍这么大。

        那扩容的条件是什么呢?

        就是当我们插入的  有效元素的个数size = 容量capacity  的时候,完成扩容之后一定要判断你扩容是否成功了,如果 tmp🟰NULL,那就说明开辟空间失败,用perror函数告诉你哪里失败了,之后用exit函数退出程序,exit函数是直接强制退出,不回到主函数,跟return不一样。当开辟成功了,就让a指向这段空间就OK,再更新一下capacity;

void SLCheckCapacity(SL*ps)  //扩容函数
{
    if(ps->size == ps->capacity)
    {
        SLDataType *tmp = (SLDataType*)realloc(ps->a,((sizeof(SLDataType)) * ((ps->capacity) * 2)));
        if(tmp == NULL)
        {
            perror("realloc");
            exit(EXIT_FAILURE);
        }
        ps -> a = tmp;
        ps->capacity *= 2;
    }
}
6.尾插尾删
        顺序表的尾插:

        在尾插的时候,我们要判断是否插满了,就需要用到我们的扩容函数来判断一下,没满就直接插入,满了则扩容。

如图:这就是没有插满的情况,我们目前已经插入了5个元素,ps->size=5,我们再插入一个元素的时候就可以在下标为size这里插入了,之后再size++就可以了

数据结构之手撕顺序表(讲解➕源代码),数据结构,数据结构

如图:是插满的情况,我们就要先扩容

数据结构之手撕顺序表(讲解➕源代码),数据结构,数据结构

如图:扩容之后,这个时候我们就可以插入啦!

数据结构之手撕顺序表(讲解➕源代码),数据结构,数据结构

        顺序表的尾删:

        尾删就好写多了,我们只需要将size减1即可,因为size代表有效的元素个数,将元素个数减一,就相当于删除了。

尾插
void SLPushBack(SL*ps,int i) 
{
    SLCheckCapacity(ps);
    ps->a[ps->size] = i;
    ps->size++;
}

尾删
void SLPopBack(SL*ps) 
{
    assert(ps->size > 0);
    ps->size--;
}
5.头插头删
 顺序表的头插:

        对于头插就要麻烦很多了,我们需要将数据一个个覆盖给下一个。再将我们的第一个元素值变成要插入的元素值,这里也要判断是否需要扩容哦!

数据结构之手撕顺序表(讲解➕源代码),数据结构,数据结构        

        顺序表的头删:

        同理头删也是需要覆盖数据的,要把第二个数据给第一个,第三个给第二个等等以此类推

数据结构之手撕顺序表(讲解➕源代码),数据结构,数据结构

头插
void SLPushFront(SL*ps,int i)
{
    SLCheckCapacity(ps);
    int end = ps->size;
    for(;end - 1 >= 0 ; end--)
    {
        ps->a[end] = ps->a[end - 1];
    }
    ps->a[0] = i;
    ps->size++;
}
 ///头删
void SLPopFront(SL*ps)
{
    assert(ps->size > 0);
    int i = 0;
    for(i = 0 ; i + 1 < ps->size ; i++)
    {
        ps->a[i] = ps->a[i+1];
    }
    ps->size--;
}
7.顺序表的查找

        查找某一值x是否存在顺序表里,存在返回数组下标,不存在返回-1.

int SeqListFind(SL*ps,SLDataType x) //查找
{
    int i = 0;
    for(i = 0 ; i < ps->size ; i++)
    {
        if(ps->a[i] == x)
        {
            return i;
        }
    }
    return -1;
}
8.在下标为pos的位置的插入

下面的大家自行画图理解哦,相信经过前面的讲解,大家有一定的收获啦!

void SeqListInsert(SL* ps, int pos, SLDataType x)// 顺序表在pos位置插入x
{
    if(ps->size == ps->capacity)
    {
        SLCheckCapacity(ps);
    }
    int i = SeqListFind(ps,pos);
    int j = ps->size;
    for(;j > i ; j--)
    {
        ps->a[j] = ps->a[j-1];
    }
    ps->a[i] = x;
    ps->size++;
}
9.删除下标为pos位置的值
void SeqListErase(SL* ps, int pos)// 顺序表删除pos位置的值
{
    assert(ps->size > 0);
    int i = SeqListFind(ps,pos);
    for(i;i < ps->size - 1; i++ )
    {
        ps->a[i] = ps->a[i+1];
    }
    ps->size--;
}
9.打印

打印就是遍历一边数组就OK啦!

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

以上就是顺序表的相关接口实现啦!谢谢大家过来与博主一起学习,如果觉得博主写的还可以,对各位有帮助,别忘了点赞和收藏,方便以后再次查看呀!文章来源地址https://www.toymoban.com/news/detail-713154.html

到了这里,关于数据结构之手撕顺序表(讲解➕源代码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【手撕数据结构】(三)顺序表和链表

    🎗️线性表是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串… 🎗️线性表在逻辑上是线性结构,也就说是一条连续的直线。但是在物理结构上并不一定是连续的,线性表在物理上存储

    2024年02月05日
    浏览(31)
  • 数据结构---手撕顺序表---顺序表增删查改寻找功能的实现

    顺序表作为数据结构的入门知识,整体知识较为简单,主要对动态内存开辟 结构体 指针有要求,其余难度较低 顺序表主要需要实现的有顺序表的增删查改和定向搜索销毁等,具体实现函数如下 要实现顺序表,就需要对顺序表进行定义,在c语言中通常使用结构体进行写入,

    2024年02月16日
    浏览(27)
  • 数据结构:手撕顺序表---顺序表增删查改寻找功能的实现

    顺序表作为数据结构的入门知识,整体知识较为简单,主要对动态内存开辟 结构体 指针有要求,其余难度较低 顺序表主要需要实现的有顺序表的增删查改和定向搜索销毁等,具体实现函数如下 要实现顺序表,就需要对顺序表进行定义,在c语言中通常使用结构体进行写入,

    2024年02月15日
    浏览(31)
  • [C语言实现]数据结构——手撕顺序栈之我出生就会写一个栈

    🥰作者: FlashRider 🌏专栏: 数据结构 目录 栈的前置知识 1.什么是栈? 2.生活中哪些地方有栈的影子? 顺序表实现栈 1.为什么通常采用顺序表实现栈? 2.栈的实现 栈( stack )又名堆栈,它是一种 运算受限的线性表 。限定仅在表尾进行插入和删除操作的线性表。这一端被称为

    2024年02月08日
    浏览(30)
  • 【数据结构】顺序表 | 详细讲解

    在计算机中主要有两种基本的存储结构用于存放线性表:顺序存储结构和链式存储结构。本篇文章介绍采用顺序存储的结构实现线性表的存储。 线性表的顺序存储结构,指的是一段地址连续的存储单元依次存储链性表的数据元素。 线性表的(,……)的顺序存储示意图如下

    2024年02月04日
    浏览(31)
  • 数据结构例题代码及其讲解-顺序表

    静态分配内存及初始化 动态分配内存及初始化 01 对顺序表L进行遍历并输出每个数据元素的数据值 02 假设有一个顺序表L,其存储的所有数据元素均为不重复的正数,查找 L 中值为 e 的数据元素,若找到则返回其下标,若找不到则返回-1。 03 假设有一个顺序表 L,其存储的所有

    2024年02月10日
    浏览(31)
  • 数组:矩阵快速转置 矩阵相加 三元组顺序表/三元矩阵 随机生成稀疏矩阵 压缩矩阵【C语言,数据结构】(内含源代码)

    目录 题目: 题目分析: 概要设计: 二维矩阵数据结构: 三元数组三元顺序表顺序表结构: 详细设计: 三元矩阵相加: 三元矩阵快速转置: 调试分析: 用户手册: 测试结果:  源代码: 主程序:  头文件SparseMatrix.h:  头文件Triple.h: 总结: 稀疏矩阵A,B均采用 三元组

    2023年04月26日
    浏览(52)
  • 数据结构-查找(顺序查找与二分查找的讲解与代码实现)

    顺序查找概念:从表的另一端开始,一次将记录的和给定值进行比较,若某个记录的和给定的值相等,则查找成功,反之则查找失败。 ASL:平均查找长度 pi查找概率,ci查找次数 eg:序列1,2,3 查找1的次数为1概率为1/3,2为两次概率1/3,3的次数为3概率1/3  将12

    2024年02月06日
    浏览(59)
  • 原神世界中的顺序表:派蒙的趣味数据结构讲解

    派蒙,那个总是带着疑问眼神的小家伙,是原神世界中的小精灵。他总是充满好奇心,无论是对新的冒险者,还是对各种奇妙的现象。而他的另一个身份,则是原神世界中的数据结构大师。 一天,派蒙遇到了旅行者小森,他带着一肚子的疑问和困惑。 小森:“派蒙,我一直

    2024年02月11日
    浏览(46)
  • 数据结构进阶篇 之 【二叉树顺序存储(堆)】的整体实现讲解(赋完整实现代码)

    做人要谦虚,多听听别人的意见,然后记录下来,看看谁对你有意见 3.1 向下调整算法 AdJustDown 3.2 向上调整算法 AdJustUP 3.3 堆的创建 3.3.1 向上建堆 3.3.2 向下建堆 3.3.3 堆的初始化与销毁 3.3.4 堆的插入(压栈) 3.3.5 取堆顶的数据 3.3.6 堆的删除 3.3.7 堆的数据个数 3.3.8 堆的判空

    2024年04月17日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包