C语言中数据结构——顺序表

news2025/1/13 17:30:11

🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

 

🐰顺序表

🏡顺序表的定义

🏡顺序表的初始化

🏡顺序表空间的检查

🏡顺序表中指定位置插入数据

🏡顺序表中指定位置删除数据

🏡顺序表中的头插数据

🏡顺序表中的尾插数据

🏡顺序表中的头删数据

🏡顺序表中的尾删数据

🏡顺序表中查找数据

🏡顺序表中改动数据

🏡顺序表中的打印数据

🏡顺序表中的销毁数据

🏡顺序表中的源码

🌸main文件

🌸头文件test.h

🌸test.c文件


🐰顺序表

🏡顺序表的定义

有两种顺序表的定义,一种是静态的,一种是动态的

1.静态顺序表的定义

静态顺序表
1.空间是固定的,没有办法存储超过空间的数据
2.如果空间开辟大了,浪费空间
不推荐使用静态顺序表,没有实际用途
#define N 10
typedef int SLDatatype;

struct SeqList
{
    int a[N];
    int size;
};

2.动态顺序表的定义

动态定义的顺序表,有效规避了静态的不足
typedef int SLDatatype;
typedef struct SeqList
{
    SLDatatype* a;//有效数据
    SLDatatype size;//存储的有效数据个数
    SLDatatype capacity;//存放数据的最大容量
}SL;

🏡顺序表的初始化

初始时,顺序表动态开辟了4个空间,有效数据的个数为0,最大容量为4

void SLInit(SL* psl)
{
    assert(psl);
    psl->a=(SLDatatype*)malloc(sizeof(SLDatatype)*4);//初始化时开辟4个SLDatatype类型的空间给a
    if(psl->a==NULL)
    {
        perror("malloc fail");
        return ;
    }
    psl->size=0;
    psl->capacity=4;
}

🏡顺序表空间的检查

我们在给顺序表插入数据之前,我们应该检查一下顺序表的空间是否充足,如果充足我们就插入数据,如果不充足,就开辟更大的空间,然后再进行插入数据

void SLCheckCapacity(SL* psl)
{
    assert(psl);
    if(psl->size==psl->capacity)
    {
        SLDatatype* tmp=(SLDatatype*)realloc(psl->a,sizeof(SLDatatype)*psl->capacity*2);//在原来的的空间,扩为原来空间的二倍
        if(tmp==NULL)
        {
            perror("realloc fail");
            return ;
        }
        else
        {
            psl->a=tmp;
            psl->capacity=psl->capacity*2;
        }
    }
}

🏡顺序表中指定位置插入数据

我们可以在自己指定的位置插入数据,这里需要注意的是,我们指定的位置必须合法,也就说,只能从头到尾之间插入数据,且尾也可以插入数据

void SLInsert(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++;
}

🏡顺序表中指定位置删除数据

我们可以在自己指定的位置删除数据,这里需要注意的是,我们指定的位置必须合法,也就说,只能从头到尾之间删除数据

void SLEarse(SL* psl,int pos)
{
    assert(psl);
    assert(pos>=0&&pos<psl->size);//判断插入位置是否符合合法
    int start=pos+1;
    while(start<psl->size)
    {
        psl->a[start-1]=psl->a[start];
        start++;
    }
    psl->size--;
}

🏡顺序表中的头插数据

顺序表中的头插数据有两种方法

1.第一种方法

这种方法就是将最后的数据移动到后一个位置,然后倒数第二个数据往最后一个位置移动,依此类推,直到第一个数据移到第二个位置,然后在第一个位置插入数据

void SLPushFront(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++;
}

1.第二种方法

这种方法复用了顺序表中指定位置插入数据

void SLPushFront(SL* psl,SLDatatype x)
{
    assert(psl);
    SLInsert(psl,0,x);
}

🏡顺序表中的尾插数据

顺序表中的尾插数据有两种方法

1.第一种

直接在最后一个数据的位置后面插入数据

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

2.第二种

这种方法复用了顺序表中指定位置插入数据

void SLPushBack(SL* psl,SLDatatype x)
{
    assert(psl);
    SLInsert(psl,psl->size,x);
}

🏡顺序表中的头删数据

顺序表中的头删数据有两种方法

1.第一种:

将第二个数据放到第一个数据的位置,把第三个的数据放到第二个数据最开始的位置,以此类推,直到最后一个数据放到倒数第二个数据最开始的位置

void SLPopFront(SL* psl)
{
    assert(psl);
    assert(psl->size>0);
    //从前往后移动
    int start=0;
    while(start<psl->size-1)
    {
        psl->a[start]=psl->a[start+1];
        start++;
    }
    psl->size--;
}

2.第二种:

这种方法复用了顺序表中指定位置删除数据

void SLPopFront(SL* psl)
{
    assert(psl);
    SLEarse(psl,0);
}

🏡顺序表中的尾删数据

顺序表中的头删数据有两种方法

1.第一种

void SLPophBack(SL* psl)
{
    assert(psl);
    //(1)if是温柔处理顺序表为空
    if(psl->size==0)
    {
        printf("顺序表数据为空,不能尾删\n");
        return ;
    }
    else
    {
        psl->size--;
    }
    //(2)暴力解法
    assert(psl->size>0);
    psl->size--;
}

2.第二种

这种方法复用了顺序表中指定位置删除数据

void SLPophBack(SL* psl)
{
    assert(psl);
    SLEarse(psl,psl->a[psl->size-1]);
}

🏡顺序表中查找数据

如果找到数据我们就返回它的下标位置,如果找不到就返回-1,这里这种算法有一点缺陷,就是如果数据中有重复的数据,则只会返回这个数据第一次出现的位置

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

🏡顺序表中改动数据

直接在想要改变数据的位置,直接赋新值,但是要注意想要改变数据的位置是合法的

void SLModify(SL* psl,int pos,SLDatatype x)
{
    assert(psl);
    assert(pos>=0&&pos<psl->size);
    psl->a[pos]=x;
}

🏡顺序表中的打印数据

依次打印出顺序表中存储的数据

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

🏡顺序表中的销毁数据

将动态分配的空间归还给系统,将数据个数置为0,最大容量置为0

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

🏡顺序表中的源码

为了更形象观察顺序表,这里使用了菜单,如果想要方便调试,建议大家不要使用菜单

🌸main文件

//顺序表
//顺序表的本质就是一个数组
//链表不支持二分查找,数组可以

//顺序表的增、删、查、改

#include"test.h"
void menu(void)
{
    printf("****************顺序表****************\n");
    printf("        1.头插数据      2.尾插数据      \n");
    printf("        3.头删数据      4.尾删数据      \n");
    printf("        5.自定义插数据   6.自定义删数据   \n");
    printf("        7.查找数据      8.修改数据      \n");
    printf("        9.打印数据      x.销毁数据      \n");
    printf("        e.退出                        \n");
    printf("*************************************\n");
}
void test(void)
{
    SL s1;
    SLInit(&s1);
    char input=0;
    do
    {
        menu();
        printf("请选择:>");
        scanf("%c",&input);
        if(input=='1')
        {
            SLDatatype x=0;
            printf("请输入插入的数据\n");
            scanf("%d",&x);
            SLPushFront(&s1,x);
            printf("数据完成插入^_^\n");
        }
        else if(input=='2')
        {
            SLDatatype x=0;
            printf("请输入插入的数据\n");
            scanf("%d",&x);
            SLPushFront(&s1,x);
            printf("数据完成插入^_^\n");
        }
        else if(input=='3')
        {
            SLPophBack(&s1);
            printf("数据完成删除@_@\n");
        }
        else if(input=='4')
        {
            SLPophBack(&s1);
            printf("数据完成删除@_@\n");
        }
        else if(input=='5')
        {
            int pos=0;
            int x=0;
            printf("请输入你想要插入数据的位置\n");
            scanf("%d",&pos);
            printf("请输入插入的数据\n");
            scanf("%d",&x);
            SLInsert(&s1,pos,x);
            printf("数据完成插入^_^\n");
        }
        else if(input=='6')
        {
            int pos=0;
            printf("请输入你想要删除数据的位置\n");
            scanf("%d",&pos);
            SLEarse(&s1,pos);
            printf("数据完成删除@_@\n");
        }
        else if(input=='7')
        {
            int x=0;
            printf("请输入查找的数据\n");
            scanf("%d",&x);
            int num=SLFind(&s1,x);
            if(num!=-1)
            printf("数据的位置为%d\n",num);
            else
                printf("顺序表里没有此数据\n");
        }
        else if(input=='8')
        {
            int pos=0;
            printf("请输入你想要修改数据的位置\n");
            scanf("%d",&pos);
            int x=0;
            printf("请输入修改的数据\n");
            scanf("%d",&x);
            SLModify(&s1,pos,x);
            printf("修改数据成功O_o\n");
        }
        else if(input=='9')
        {
            SLPrint(&s1);
            printf("打印完成...\n");
        }
        else if(input=='x')
        {
            SLDestroy(&s1);
            printf("销毁数据成功...\n");
        }
        else if(input=='e')
        {
            printf("退出顺序表...\n");
        }
        else
        {
            printf("无此选项,请重新选择\n");
        }
        getchar();
    }while(input!='e');
}
int main()
{
    test();
    return 0;
}

🌸头文件test.h

#ifndef test_h
#define test_h
#include <stdio.h>
#include<stdlib.h>
#endif /* test_h */

#include<assert.h>

//静态顺序表
//1.空间是固定的,没有办法存储超过空间的数据
//2.如果空间开辟大了,浪费空间
//不推荐使用静态顺序表,没有实际用途
//#define N 10
//typedef int SLDatatype;
//
//struct SeqList
//{
//    int a[N];
//    int size;
//};



typedef int SLDatatype;
typedef struct SeqList
{
    SLDatatype* a;
    SLDatatype size;//存储的有效数据个数
    SLDatatype capacity;//容量
}SL;


//STL的命名风格(C++)
//顺序表的初始化
void SLInit(SL* psl);
//打印顺序表
void SLPrint(SL* psl);
//销毁顺序表
void SLDestroy(SL* psl);
//尾插数据
void SLPushBack(SL* psl,SLDatatype x);
//头插数据
void SLPushFront(SL* psl,SLDatatype x);
//尾删数据
void SLPophBack(SL* psl);
//头删数据
void SLPopFront(SL* psl);
//在pos位置插入一个数据
void SLInsert(SL* psl,int pos,SLDatatype x);
//在pos位置删除一个数据
void SLEarse(SL* psl,int pos);
//查找数据
//找到了返回下标,没找到返回-1
int SLFind(SL* psl,SLDatatype x);
//修改指定位置的数据
void SLModify(SL* psl,int pos,SLDatatype x);

🌸test.c文件

#include"test.h"
void SLInit(SL* psl)
{
    assert(psl);
    psl->a=(SLDatatype*)malloc(sizeof(SLDatatype)*4);//初始化时开辟4个SLDatatype类型的空间给a
    if(psl->a==NULL)
    {
        perror("malloc fail");
        return ;
    }
    psl->size=0;
    psl->capacity=4;
}

void SLDestroy(SL* psl)
{
    assert(psl);
    free(psl->a);
    psl->a=NULL;
    psl->size=0;
    psl->capacity=0;
}
void SLPrint(SL* psl)
{
    assert(psl);
    for(int i=0;i<psl->size;i++)
    {
        printf("%d ",psl->a[i]);
    }
    printf("\n");
}
//插入的时候要去判断容量是否充足
//可以写一个检查容量是否充足的函数
//如果空间不足,就需要扩容

void SLCheckCapacity(SL* psl)
{
    assert(psl);
    if(psl->size==psl->capacity)
    {
        SLDatatype* tmp=(SLDatatype*)realloc(psl->a,sizeof(SLDatatype)*psl->capacity*2);//在原来的的空间,扩为原来空间的二倍
        if(tmp==NULL)
        {
            perror("realloc fail");
            return ;
        }
        else
        {
            psl->a=tmp;
            psl->capacity=psl->capacity*2;
        }
    }
}
//尾插数据
//尾插数据的原理:在最后一个数据后面再添加一个数据
void SLPushBack(SL* psl,SLDatatype x)
{
    assert(psl);
//    SLCheckCapacity(psl);
//    psl->a[psl->size]=x;
//    psl->size++;
    
    SLInsert(psl,psl->size,x);
}
//头插数据
void SLPushFront(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++;
   // SLInsert(psl,0,x);
}
//尾删数据
void SLPophBack(SL* psl)
{
    assert(psl);
//    if是温柔处理顺序表为空
//    if(psl->size==0)
//    {
//        printf("顺序表数据为空,不能尾删\n");
//        return ;
//    }
//    else
//    {
//        psl->size--;
//    }
//    暴力解法
//    assert(psl->size>0);
//    psl->size--;
    
    SLEarse(psl,psl->a[psl->size-1]);
}
//头删数据
void SLPopFront(SL* psl)
{
    assert(psl);
    //方法一:
//    assert(psl->size>0);
//    //从前往后移动
//    int start=0;
//    while(start<psl->size-1)
//    {
//        psl->a[start]=psl->a[start+1];
//        start++;
//    }
//    psl->size--;
    
    //方法二:
    SLEarse(psl,0);
}

void SLInsert(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++;
}
void SLEarse(SL* psl,int pos)
{
    assert(psl);
    assert(pos>=0&&pos<psl->size);//判断插入位置是否符合合法
    int start=pos+1;
    while(start<psl->size)
    {
        psl->a[start-1]=psl->a[start];
        start++;
    }
    psl->size--;
}
int SLFind(SL* psl,SLDatatype x)
{
    assert(psl);
    for(int i=0;i<psl->size;i++)
    {
        if(psl->a[i]==x)
        {
            return i;
        }
    }
    return -1;
}
void SLModify(SL* psl,int pos,SLDatatype x)
{
    assert(psl);
    assert(pos>=0&&pos<psl->size);
    psl->a[pos]=x;
}

🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸  

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

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

相关文章

java多线程详细讲解 线程的创建、线程的状态、synchronized锁、Volatile关键字、和cas锁(自旋锁 乐观锁 无锁)

java多线程详细讲解 线程的创建、线程的状态、synchronized锁、Volatile关键字、和cas锁&#xff08;自旋锁 乐观锁 无锁&#xff09; 一、线程的概念二、创建线程的三种方式三、线程方法Sleep、Yield、Join四、线程的执行状态五、synchronized关键字1.为什么要上锁?2.锁定的内…

SDL初识(1)

简介 SDL(Simple DirectMedia Layer) 是一个跨平台开发库&#xff0c;旨在通过 OpenGL 和 Direct3D 提供对音频、键盘、鼠标、操纵杆和图形硬件的低级访问。 SDL 支持 Windows、Mac OS X、Linux、iOS 和 Android。可以在源代码中找到对其他平台的支持。SDL 是用 C 语言编写的…

JavaScript【六】JavaScript中的字符串(String)

文章目录 &#x1f31f;前言&#x1f31f;字符串(String)&#x1f31f;单引号和双引号的区别&#x1f31f;属性&#x1f31f; length :字符串的长度 &#x1f31f; 方法&#x1f31f; str.charAt(index);&#x1f31f; str.charCodeAt(index);&#x1f31f; String.fromCharCod…

死磕“增长”:火山引擎的实用主义

作者 | 曾响铃 文 | 响铃说 在刘慈欣的科幻小说《三体》中&#xff0c;地外文明为了封锁地球科技&#xff0c;在天文台向地球科学家展现了「宇宙闪烁」这一奇观&#xff0c;试图颠覆人类的认知&#xff0c;从而影响科技进步&#xff0c;促使地球科技发展陷入停滞。 如今&…

给你们讲个笑话——低代码会取代程序员

今天是正经男&#xff0c;我们严肃讨论一下一直以来争吵不休的取代问题。 低代码开发平台&#xff0c;低代码技术会取代开发人员么&#xff1f; 一、背景 低代码开发平台的普及&#xff0c;让很多公司对快速生成应用抱有很大期望。甚至有人认为&#xff0c;低代码开发平台未来…

MTLAB绘图

这里写目录标题 一、图例1、散点图 二、绘图1、总体图形参数2、坐标、图框、网格图框去上右边框小刻度网格坐标范围和刻度控制旋转 坐标、刻度 3、图例图例位置和方向 Location和Orientation图例加标题 、分多列 4、文本 字、字体、字号5、线型 符号6、颜色栏 colorbar7、颜色8…

【技能分享】CAD转SHP最好的方法

1、利用 ArcToolsbox 工具先将 DWG 文件转为 MDB 通过 CASS 软件生成的 DWG 文件&#xff0c;字段中包含有很多属性内容&#xff0c;所以我们先将 DWG 格式 的文件转换为 MDB 格式&#xff0c;再通过 MDB 转换为 SHP 格式数据进行整理。具体步骤如下&#xff1a; 通过 ArcTool…

2023Mathorcup高校数学建模挑战赛ABCD选题建议

提示&#xff1a;本科同学尽量选择C、D题进行作答&#xff0c;获奖率相对会高。C君认为的难度&#xff1a;AD<C<B&#xff0c;开放度&#xff1a;B<C<A<D 。 A题 量子计算机在信用评分卡组合优化中的应用 这道题目是传统的运筹学题目。需要建立客户信用等级的…

阿里ARouter 路由框架解析

一、简介 众所周知&#xff0c;在日常开发中&#xff0c;随着项目业务越来越复杂&#xff0c;项目中的代码量也越来越多&#xff0c;如果维护、扩展、解耦等成了一个非常头疼问题&#xff0c;随之孕育而生的诸如插件化、组件化、模块化等热门技术。 而其中组件化中一项的难点&…

Spring Cloud 之五:Feign使用Hystrix

系列目录&#xff08;持续更新。。。&#xff09; Spring Cloud之一&#xff1a;注册与发现-Eureka工程的创建 Spring Cloud之二&#xff1a;服务提供者注册到Eureka Server Spring Cloud之三&#xff1a;Eureka Server添加认证 Spring Cloud之四&#xff1a;使用Feign实现…

camunda如何监控流程执行

在 Camunda 中&#xff0c;可以使用 Camunda 提供的用户界面和 API 来监控流程的执行情况。以下是几种常用的监控流程执行的方式&#xff1a; 1、使用 Camunda Cockpit&#xff1a;Camunda Cockpit 是 Camunda 官方提供的流程监控和管理工具&#xff0c;可以在浏览器中访问 Co…

【百面成神】消息中间件基础7问,你能撑到第几问

前 言 &#x1f349; 作者简介&#xff1a;半旧518&#xff0c;长跑型选手&#xff0c;立志坚持写10年博客&#xff0c;专注于java后端 ☕专栏简介&#xff1a;纯手打总结面试题&#xff0c;自用备用 &#x1f330; 文章简介&#xff1a;消息中间件最基础、重要的9道面试题 文章…

Android中的MVVM架构:使用Jetpack组件实现现代化的应用架构

Android中的MVVM架构&#xff1a;使用Jetpack组件实现现代化的应用架构 Jetpack组件是构建现代Android应用的绝佳利器&#xff0c;组件化设计让构建App如此简单。 引言 随着移动应用的日益复杂和功能的不断增加&#xff0c;构建稳健、可扩展和易维护的Android应用变得越来越重…

[考研数据结构] 第3章之队列的基本知识与操作

文章目录 队列的基本概念 队列的顺序存储 顺序队列 存储类型 基本操作 循序队列 存储类型 基本操作 循环队列判空与判满的三种解决方案 方法一&#xff1a;牺牲一个存储单元 方法二&#xff1a;类型增设记录型变量size 方法三&#xff1a;类型增设标志型变量tag 队…

嵌入式【协议篇】CAN协议原理

一、CAN协议介绍 1、简介 CAN是控制器局域网络(Controller Area Network, CAN)的简称,是一种能够实现分布式实时控制的串行通信网络。 其实可以简单把CAN通信理解成开一场电话会议,当一个人讲话时其他人就听(广播),当多个人同时讲话时则根据一定规则来决定谁先讲话谁后讲…

【音视频】 zlm的几个代理接口解释

目录 12、/index/api/addStreamProxy 30、/index/api/addStreamPusherProxy 14、/index/api/addFFmpegSource 24、/index/api/openRtpServer 27、/index/api/startSendRtp 参考 12、/index/api/addStreamProxy 拉流代理 &#xff1a; 194上在播放。 而10.30.2.6上加上这个…

FastDGCNN

Faster Dynamic Graph CNN: Faster Deep Learning on 3D Point Cloud Data | IEEE Journals & Magazine | IEEE Xplore ​​​​​​​题目&#xff1a;Faster Dynamic Graph CNN: Faster Deep Learning on 3D Point Cloud Data&#xff08;更快的动态图形CNN&#xff1a;对…

Android 对View 进行旋转、缩放、平移的属性变换后,获取外矩形顶点

文章目录 前言改变 View 的属性&#xff0c;进行旋转、缩放、平移输出 View 的属性 使用 matrix 映射 view 变换后的外矩形前(左)乘(preXxx)、后(右)乘(postXxx) 对映射结果的影响前(左)乘(preXxx) 的意义后(右)乘(postXxx) 结论 来张图 前言 Android View 通过平移、旋转、…

找PPT模板就上这5个网站~

分享几个可以永久免费下载PPT模板、素材的网站&#xff0c;上万个模板随便下载&#xff0c;赶紧收藏起来~ 1、菜鸟图库 https://www.sucai999.com/search/ppt/0_0_0_1.html?vNTYxMjky 网站素材非常全面&#xff0c;主要以设计类素材为主&#xff0c;办公类素材也很多&#x…

4、RSA终端指令

RSA总结 加密算法,都是数学知识对称加密(传统加密算法)RSA(三个人的名字)非对称加密(现代加密算法) 原根欧拉函数、欧拉定理(费马小定理)模反元素 m^(e * d) mod n ≡ m迪菲赫尔曼密钥交换RSA算法 RSA: 拆解两个(大)质数的乘积很难!所以RSA想对安全.加密: M ^e % N C解密: C…