当前位置: 首页 > news >正文

【数据结构之C语言实现动态顺序表】

引    入:

  在讲顺序表之前得先了解线性表是什么?

        线性表是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表,链表,栈,队列,字符串……

        线性表在逻辑上(构想中)是线性结构,也就是说可以抽象成一条连续的直线。但在物理结构(内存存储上)上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

顺      序     表

1.顺序表的概念

顺序表是用一段物理地址连续的存储单元依次存储数据元素线性结构,一般情况下采用数

组存储。(顺序表的底层结构就是数组)顺序表就相当于在数组的基础上进行了“装修”,即

增删查数据的操作。

2.顺序表的结构

基于数组进行实现顺序表。实现时会有两种顺序表结构:静态顺序表和动态顺序表。

2.1定义静态顺序表的结构:

#define N 100
typedef struct SeqList
{int arr[N];int size;//有效的数据个数
}SL;

当然我们不肯能只对整型数据进行操作,我们还可以对其他的数据类型进行操作。因此我们需要在这里对类型进行重命名。typedef int SLDatatype;

即:

#define N 100
typedef int SLDatatype;
struct Seqlist
{SLDatatype arr[N];int size;//有效的数据个数
}SL;

总结:   我们可以很清楚地发现,静态顺序表的一个巨大弊端,那么就是数组的长度是有限

,但我们随机插入的数据的数量未必是在给定的范围之内,这会造成空间不够。当然有些

人可能会觉得给数组一个很大的长度就可以了呀,但如果我们在某段时间内不需要那么大的

长度,那就会造成空间的浪费

2.2定义动态顺序表的结构

结合上面静态顺序表的结构,那么实现动态顺序表的目的就是解决这一弊端。我们前面的C

语言部分学习的动态内存管理的知识就可以用到这里来了。在这里我们需要涉及到动态的内

存扩容,而不是直接向内存申请空间,所以在后面的实现中,我们需要用到realloc函数

在这里我们定义动态顺序表的时候需要定义三个部分,用指针定义一个所要操作的数据类型

的指针,再定义标记数据个数的和空间大小的两个整型变量。即:

typedef int SLDatatype;
typedef struct SeqList
{SLDatatype* arr;int size;//记录当前顺序表中有效的元素个数int capacity;//记录顺序表的空间大小
}SL;

那么我们在实现顺序表的时候就要实现动态顺序表,动态顺序表相较于静态顺序表更好,弥补了静

态顺序表的不足!

接下来就带着大家来实现一下动态顺序表的以下相关操作。

在这之前我们将头文件以及函数功能功能实现的声明放在SeqList.h中,将函数的实现部分放

在SeqList.c中,再建立一个test.c函数功能的测试部分。

1.  SeqList.h


//顺序表的函数的声明部分//顺序表的初始化
void SLInit(SL* ps);//顺序表的销毁
void SLDestroy(SL* ps);//顺序表的插入
//顺序表的尾插
void SLPushBack(SL* ps, SLDatatype x);
//顺序表的头插
void SLPushFront(SL* ps, SLDatatype x);//顺序表的删除
//顺序表的尾删
void SLPopBack(SL* ps);
//顺序表的头删
void SLPopFront(SL* ps);//顺序表指定位置的操作
//指定位置之前插入数据
void SLInsertBefore(SL* ps, int pos, SLDatatype x);
//指定位置的删除数据
void SLErase(SL* ps, int pos);//顺序表的数据的查找
int SLFind(SL* ps, SLDatatype x);

2.函数功能的实现部分  SeqList.c

(需要包含上面的自定义的头文件----#include "SeqList")

2.1  顺序表的初始化和销毁

//顺序表的初始化
void SLInit(SL* ps)
{assert(ps);ps->arr = NULL;ps->size = ps->capacity = 0;
}
//顺序表的销毁
void SLDestroy(SL* ps)
{if (ps->arr){free(ps->arr);}ps->arr = NULL;ps->size = ps->capacity = 0;
}

2.2 顺序表的数据的插入


void SLCheckCapacity(SL* ps)
{if (ps->size == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SLDatatype* temp = (SLDatatype*)realloc(ps->arr, newcapacity * sizeof(SLDatatype));if (temp == NULL){perror("realloc fail");exit(1);}ps->arr = temp;ps->capacity = newcapacity;}
}

       在进行顺序的插入之前我们需要先对顺序表的空间够不够进行检查(封装成函数),如果不

能够我们就需要通过realloc函数对顺序表的空间进行二倍扩容,当然如果刚开始的空间大小

为0是我们就需要给定一定的空间大小(在这里我给的是4)。

头插和尾插
//顺序表的尾插
void SLPushBack(SL* ps, SLDatatype x)
{assert(ps);SLCheckCapacity(ps);ps->arr[ps->size++] = x;
}
//顺序表的头插
void SLPushFront(SL* ps, SLDatatype x)
{assert(ps);SLCheckCapacity(ps);//数据整体向后移动1位for (int i = ps->size; i > 0; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[0] = x;ps->size++;
}

       在进行数据插入之前先进行对指针进行判空,再进行空间大小的检查。尾插就直接在

size的位置插入数据,随后再进行size++操作;头插就先将数据整体向后移动一位,然后再

进行数据插入,最后进行size++。

2.3顺序表的数据的删除

//顺序表的删除
//顺序表的尾删
void SLPopBack(SL* ps)
{assert(ps);assert(ps->size > 0);ps->size--;
}
//顺序表的头删
void SLPopFront(SL* ps)
{assert(ps && ps->size > 0);//数据整体向前移动for (int i = 0; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}

对于顺序表的尾删,就直接将size--;对于顺序表的头删整体向前移动一位,然后size--。

2.4顺序表中数据的查找

//顺序表的数据的查找
int SLFind(SL* ps, SLDatatype x)
{assert(ps);assert(ps->size);for (int i = 0; i < ps->size; i++){if (ps->arr[i] == x)return i;}return -1;
}

先进行地址判空,再进行对有效数据个数进行检查看是否大于0,随后进行遍历查找判断是否

为顺序表中数据,如果是就返回下标,如果不是就返回无效下标(我这里找不到的时候让返

回-1)。

2.5顺序表中指定位置的操作

//顺序表指定位置的操作
//指定位置之前插入数据
void SLInsertBefore(SL* ps, int pos, SLDatatype x)
{assert(ps);assert(pos >= 0&& pos <= ps->size);SLCheckCapacity(ps);//将pos 以及pos之后的数据整体向后移动一位for (int i = ps->size; i > pos; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[pos] = x;ps->size++;}
//指定位置的删除数据
void SLErase(SL* ps, int pos)
{assert(ps);assert( pos >= 0&&pos<ps->size);//pos之后的数据整体向前移动一位for (int i = pos; i < ps->size-1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}

在指定位置之前插入数据先进行pos的范围判断,pos大于等于0,小于等于size,随后将pos及

pos之后数据整体先向后移动一位,进行插入数据,size++;删除pos 位置的数据先进行pos

的范围判断,pos大于等于0,小于size-1,然后将pos之后的数据整体向前移动一位,size--.

 

3.函数的测试部分

#include "SeqList.h"void SLPrint(SL sl)
{for (int i = 0; i < sl.size; i++){printf("%d ", sl.arr[i]);}printf("\n");
}
void test()
{SL sl;SLInit(&sl);SLPushBack(&sl, 13);SLPushBack(&sl, 22);SLPushBack(&sl, 34);SLPushBack(&sl, 45);SLPrint(sl);/*SLPopBack(&sl);SLPrint(sl);SLPopFront(&sl);SLPrint(sl);*/int ret=SLFind(&sl, 45);if (ret < 0)printf("找不到该元素\n");elseprintf("找到了,该元素的下标为:%d\n", ret);//SLInsertBefore(&sl, ret, 99);SLErase(&sl, ret);SLPrint(sl);printf("size:%d\n", sl.size);SLPushBack(&sl, 99);SLPrint(sl);printf("size:%d\n", sl.size);SLDestroy(&sl);SLPrint(sl);
}
int main()
{test();return 0;
}

数据结构这块需要我们多加练习,多多画图思考,理解掌握!!!

如有错误,还望指出!!!

关注博主,优质内容不断更新!!!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • “/usr/local/nginx/logs/nginx.pid“ failed (2: No such file or directory)问题
  • k8s中的重启策略
  • 视觉SLAM第二讲
  • 【03】Java虚拟机是如何加载Java类的
  • AttributeError: module ‘selenium.webdriver‘ has no attribute ‘PhantomJS‘
  • QT 关于QTableWidget的常规使用
  • Postman测试工具详细解读
  • 如何将整个运行环境打包成docker
  • 每日一知识点 - Java Lambda 表达式
  • C++——类和对象(中)
  • DeFi革命:揭秘去中心化金融的核心技术与实操指南
  • Typesript的type和interface的异同?
  • vscode回退不显示了,不方便操作
  • Rust:cargo的常用命令
  • Flutter Geolocator插件使用指南:获取和监听地理位置
  • 【391天】每日项目总结系列128(2018.03.03)
  • Java 11 发布计划来了,已确定 3个 新特性!!
  • Java|序列化异常StreamCorruptedException的解决方法
  • Java编程基础24——递归练习
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • uni-app项目数字滚动
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • Vue2.0 实现互斥
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 设计模式(12)迭代器模式(讲解+应用)
  • 用Python写一份独特的元宵节祝福
  • k8s使用glusterfs实现动态持久化存储
  • mysql 慢查询分析工具:pt-query-digest 在mac 上的安装使用 ...
  • 回归生活:清理微信公众号
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • ​Python 3 新特性:类型注解
  • # Apache SeaTunnel 究竟是什么?
  • #宝哥教你#查看jquery绑定的事件函数
  • $.ajax()参数及用法
  • (1)svelte 教程:hello world
  • (C语言)二分查找 超详细
  • (六)vue-router+UI组件库
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (四)模仿学习-完成后台管理页面查询
  • (学习日记)2024.01.09
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • .gitignore文件设置了忽略但不生效
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .NET Core Web APi类库如何内嵌运行?
  • .NET Core WebAPI中封装Swagger配置
  • .NET 读取 JSON格式的数据
  • .NET/C# 项目如何优雅地设置条件编译符号?
  • .NET/C# 在 64 位进程中读取 32 位进程重定向后的注册表
  • .net连接oracle数据库
  • @font-face 用字体画图标
  • @GlobalLock注解作用与原理解析
  • @RequestBody与@RequestParam
  • @vueup/vue-quill使用quill-better-table报moduleClass is not a constructor
  • [ 隧道技术 ] cpolar 工具详解之将内网端口映射到公网
  • [3D游戏开发实践] Cocos Cyberpunk 源码解读-高中低端机性能适配策略