【数据结构】顺序表

写在前面

这是我们学习数据结构的第一步,万事开头难,我把我在学习之中遇到的种种问题渗透在讲解之中,文章的内容分为几个部分,希望读者能快速了解文章的脉络架构:

  1. 顺序表的存储结构——即用结构体定义

  1. 顺序表的基本操作——增删改查

  1. 顺序表的应用——完整的可执行程序(利用前面的基本操作)


先学思想

顺序表的存储结构

#define OK 1
#define ERROR 0
#define MAXSIZE 100

typedef int Status;
typedef int ElemType;//把int重命名

//顺序表存储结构
typedef struct
{
    ElemType data[MAXSIZE];
    int length;
}SqList;

上一篇文章的时候,我们讲解了typedef的使用,那么使用typedef就有它的好处

ElemType 实际上就是int,status实际上也是int,那么我们在更改数据类型char的时候,只要在这一行代码的地方把int改为char,就能很方便的更改,另外在下面代码的地方遇到这几个陌生单词,要记得哟

顺序表的基本操作

插入:说白了就是向数组内插入一个元素,直接插入在数组的末尾还好,若插入在数组的前面或者中间,可不敢直接就插入,我们得先把后面的元素都向后移动一个位置(前提是数组足够大),再将数据插入对应的位置

//插入,在L中的第i个位置之前插入新的数据——时间复杂度为O(n)
//小提示:SqList* L和SqList L什么场景,需要哪种选择?
//我们主要看这个传递的参数是否需要改变,详细的解答我们放到下面讲,先不要管参数带不带*号
Status InsertElem(SqList* L, int i, ElemType e)
{
    int k;
    //不考虑扩容,如果线性表满了,就没必要插入了
    if (L->length == MAXSIZE)
        return ERROR;
    /*如果查找的数据不在线性表的范围内,不能查找
       注意:我们通常将顺序表的第一个元素编号为1,放在数组下标为0的位置上,其他元素顺延*/
    if (i<1 || i>L->length)
        return ERROR;
    //若插入数据不在表尾
    if (i <= L->length)
    {
        //将要插入位置后数据元素向后移动一位,k是下标
        for (k = L->length - 1; k >= i - 1; k--)
            L->data[k + 1] = L->data[k];
        //将新元素插入
        L->data[i - 1] = e;
    }
    L->length++;//将计数器+1
    return OK;
}

删除:删除数组的元素也是十分简单的,要注意的是数组为空,或者要删除的位置很奇葩,就没必要执行这段程序了,删除和插入有点类似,从要删除的位置开始将后面的元素依次向前覆盖......SqList* L,ElemType* e这样的参数还是放到本篇文章的后面讲。

//删除元素
Status DeleteElem(SqList* L, int i, ElemType* e)
{
    int k;
    //表为空,或者查找的数据不在表范围,则返回错误
    if (L->length == 0 || i<1 || i>L->length)
        return ERROR;
    *e = L->data[i - 1];//记录要删除的数据
    //如果删除元素不在表尾
    if (i < L->length)
    {
        for (k = i; k < L->length; k++)
            L->data[k - 1] = L->data[k];
    }
    L->length--;//记录表长的变量-1
    return OK;
}

修改和查找就更简单了,就写在下面的代码中了,我们下面就直接对上面的代码进行调用

再学应用

这段代码利用上面所学的知识,进行了完整的调用,可以在VS2022上运行

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<time.h>

#define MAXSIZE 100
#define OK 1
#define ERROR 0

typedef int Status;
typedef int ElemType;

//顺序表存储结构
typedef struct
{
    ElemType data[MAXSIZE];
    int length;
}SqList;

// 顺序表的初始化
Status InitSqList(SqList* L)
{
    L->length = 5;
    return OK;
}

//插入
Status InsertElem(SqList* L, int i, ElemType e)
{
    int k;
    //不考虑扩容,如果线性表满了,就没必要插入了
    if (L->length == MAXSIZE)
        return ERROR;
    if (i<1 || i>L->length)
        return ERROR;
    //若插入数据不在表尾
    if (i <= L->length)
    {
        //将要插入位置后数据元素向后移动一位
        for (k = L->length - 1; k >= i - 1; k--)
            L->data[k + 1] = L->data[k];
        L->data[i - 1] = e;
    }
    L->length++;
    return OK;
}

//删除
Status DeleteElem(SqList* L, int i, ElemType* e)
{
    int k;
    //表为空,查找不在表范围,返回错误
    if (L->length == 0 || i<1 || i>L->length)
        return ERROR;
    *e = L->data[i - 1];
    //如果删除元素不在表尾
    if (i < L->length)
    {
        for (k = i; k < L->length; k++)
            L->data[k - 1] = L->data[k];
    }
    L->length--;//记录表长的变量-1
    return OK;
}

// 顺序表的查找
int GetElemType(SqList L, ElemType e)
{
    for (int i = 0; i < L.length; i++)
    {
        if (L.data[i] == e)
        {
            return i + 1;
        }
    }
    return 0;    // 查找失败
}

//打印顺序表
Status PrintSqList(SqList L,char* s)
{
    int i = 0;
    printf("%s", s);
    for (i = 0; i < L.length; i++)
        printf("%d ", L.data[i]);
    return OK;
}

int main()
{
    //创建并初始化顺序表
    SqList L;
    ElemType e;
    int i = 0;
    InitSqList(&L);
    printf("请输入5个整数录入线性表:");
    for (i = 0; i < 5; i++)
        scanf("%d", &L.data[i]);
    PrintSqList(L, (char*)"初始化成功,线性表存储数据为:");

    //插入
    printf("\n请输入要插入的位置和整数:");
    scanf("%d%d", &i, &e);
    InsertElem(&L, i, e);
    PrintSqList(L, (char*)"插入后的线性表为:");

    //查询
    printf("\n请输入要查询的数字:");
    scanf("%d", &e);
    int ret=GetElemType(L, e);
    if (ret == 0)
        printf("未找到!");
    else
        printf("找到了,%d在第%d个位置上!", e,ret);

    //删除
    printf("\n请输入删除的位置:");
    scanf("%d", &i);
    DeleteElem(&L, i, &e);
    PrintSqList(L, (char*)"删除后的线性表为:");

    return 0;
}

下面我们来讨论遗留的问题:

SqList* L和SqList L什么场景,需要哪种选择?(看看上面的完整调用,会理解更深)

答:根据需求。先说背景,使用C语言来实现上述的用函数封装起来的算法,我们要事先知道形参是实参的一份临时拷贝,我们在函数体内对参数的操作,出了函数就不起作用了,这时C语言的指针就起到了作用,我们就传这个变量的地址,函数部分的形参就用指针接收

例如:初始化InitSqList(&L);对应函数Status InitSqList(SqList* L) ;我们能得到什么信息呢?

  1. 结构体变量L的地址作为参数传给函数InitSqList

  1. 我们要在这个函数中对结构体变量的本体做点什么😁

  1. 这个函数的形参和实参名字是一样的

例如:查找GetElemType(L, e);对应函数int GetElemType(SqList L, ElemType e);我们能得到什么信息?

  1. 结构体变量L作为参数传给函数 GetElemType

  1. 我们不需要在这个函数中对变量的本体进行修改——毕竟只进行查找嘛😆

  1. 这和函数的形参和实参名字是一样的


写在最后

顺序表以及即将要学习的链表,在后面很重要,是后面的基础,同时顺序表和数组紧密相关,只要弄清楚结构,有C语言基础,就可以过关了

👍🏻 点赞,你的认可是我创作的动力!
收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

畅游星辰大海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值